├── classifier ├── __init__.py ├── utils.py ├── model.py └── train.py ├── semi_supervised ├── __init__.py ├── utils.py ├── model_pred.py ├── model_class_test.py ├── model_class.py ├── train_pred.py └── train_class.py ├── classifier_attention ├── __init__.py ├── utils.py ├── model.py └── train.py ├── .gitignore ├── frequency_domain ├── README └── SVM_PUT_Dataset.ipynb ├── README.md └── LICENCE /classifier/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /semi_supervised/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /classifier_attention/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /classifier/data 2 | /classifier/save 3 | /classifier_attention/data 4 | /classifier_attention/save 5 | /semi_supervised/data 6 | /semi_supervised/save 7 | /frequency_domain/data 8 | *.pyc 9 | .vscode/ 10 | -------------------------------------------------------------------------------- /frequency_domain/README: -------------------------------------------------------------------------------- 1 | This is a python source code for frequency domain classifiers of PUT dataset implemented based on the information provided in the paper titled: "What am I touching? Learning to classify terrain via haptic sensing" 2 | The implementation is done in Jupyter-notebook. 3 | In this implementation, 10-fold cross validation is used to evaluate two models: SVMs and Fully Connected Neurons (FCNs). 4 | Requirements: 5 | • Python >= 3.X with Numpy, Scipy, Sklearn, Functools, Pandas, and Matplotlib 6 | • Tensorflow >= 1.12.0 7 | • Keras >= 2.2.4 8 | In order to run the codes: 9 | 1. Create the directory data inside the frequency_domain folder : mkdir data 10 | 2. Go to the data folder and download the PUT data : the webpage address can be found in the paper: “What am I touching? Learning to classify terrain via haptic sensing” 11 | 3. Return to the frequency_domain folder and run SVM_PUT_Dataset.ipynb for the SVM model and FCN_PUT_Dataset.ipynb for the fully connected neurons inside Jupyter-notebook. 12 | -------------------------------------------------------------------------------- /classifier_attention/utils.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import numpy as np 3 | import sys 4 | import csv 5 | 6 | def get_next_batch(x, y, l, start, end): 7 | x_batch = x[start:end,:,:] 8 | y_batch = y[start:end,:] 9 | l_batch = l[start:end] 10 | return x_batch, y_batch, l_batch 11 | 12 | def lazy_property(function): 13 | attribute = '_' + function.__name__ 14 | 15 | @property 16 | @functools.wraps(function) 17 | def wrapper(self): 18 | if not hasattr(self, attribute): 19 | setattr(self, attribute, function(self)) 20 | return getattr(self, attribute) 21 | return wrapper 22 | 23 | def read_lines(file): 24 | with open(file, newline="") as data: 25 | reader = csv.reader(data) 26 | ind = 0 27 | for row in reader: 28 | if(ind > 0): 29 | yield [float(i) for i in row] 30 | ind+=1 31 | 32 | def step_count(raw_inp, num_trials, num_steps): 33 | cnt = 0 34 | inputs = [[] for i in range(num_trials)] 35 | for i in range(raw_inp.shape[0]): 36 | if i > 0: 37 | if (raw_inp[i,3] != raw_inp[i-1,3]):# 3 is the column in csv files that shows the num of tiral 38 | cnt += 1 39 | inputs[cnt].append(raw_inp[i]) 40 | minimum = 1000000 41 | for i in range(num_trials): 42 | if (len(inputs[i]) < minimum): 43 | minimum = len(inputs[i]) 44 | each_step = np.floor(minimum/num_steps) 45 | return each_step, inputs 46 | 47 | 48 | -------------------------------------------------------------------------------- /classifier/utils.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import numpy as np 3 | import sys 4 | import csv 5 | 6 | def get_next_batch(x, y, l, start, end): 7 | x_batch = x[start:end,:,:] 8 | y_batch = y[start:end,:] 9 | l_batch = l[start:end] 10 | return x_batch, y_batch, l_batch 11 | 12 | def lazy_property(function): 13 | attribute = '_' + function.__name__ 14 | 15 | @property 16 | @functools.wraps(function) 17 | def wrapper(self): 18 | if not hasattr(self, attribute): 19 | setattr(self, attribute, function(self)) 20 | return getattr(self, attribute) 21 | return wrapper 22 | 23 | 24 | def read_lines(file): 25 | with open(file, newline="") as data: 26 | reader = csv.reader(data) 27 | ind = 0 28 | for row in reader: 29 | if(ind > 0): 30 | yield [float(i) for i in row] 31 | ind+=1 32 | 33 | 34 | def step_count(raw_inp, num_trials, num_steps): 35 | cnt = 0 36 | inputs = [[] for i in range(num_trials)] 37 | for i in range(raw_inp.shape[0]): 38 | if i > 0: 39 | if (raw_inp[i,3] != raw_inp[i-1,3]):# 3 is the column in csv files that shows the num of tiral 40 | cnt += 1 41 | inputs[cnt].append(raw_inp[i]) 42 | minimum = 1000000 43 | for i in range(num_trials): 44 | if (len(inputs[i]) < minimum): 45 | minimum = len(inputs[i]) 46 | each_step = np.floor(minimum/num_steps) 47 | return each_step, inputs 48 | 49 | 50 | -------------------------------------------------------------------------------- /semi_supervised/utils.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import numpy as np 3 | import sys 4 | import csv 5 | 6 | def get_next_batch(x, y, l, start, end): 7 | x_batch = x[start:end,:,:] 8 | y_batch = y[start:end,:] 9 | l_batch = l[start:end] 10 | return x_batch, y_batch, l_batch 11 | 12 | 13 | def lazy_property(function): 14 | attribute = '_' + function.__name__ 15 | 16 | @property 17 | @functools.wraps(function) 18 | def wrapper(self): 19 | if not hasattr(self, attribute): 20 | setattr(self, attribute, function(self)) 21 | return getattr(self, attribute) 22 | return wrapper 23 | 24 | 25 | def read_lines(file): 26 | with open(file, newline="") as data: 27 | reader = csv.reader(data) 28 | ind = 0 29 | for row in reader: 30 | if(ind > 0): 31 | yield [float(i) for i in row] 32 | ind+=1 33 | 34 | 35 | def step_count(raw_inp, num_trials, num_steps): 36 | cnt = 0 37 | inputs = [[] for i in range(num_trials)] 38 | for i in range(raw_inp.shape[0]): 39 | if i > 0: 40 | if (raw_inp[i,3] != raw_inp[i-1,3]):# 3 is the column in csv files that shows the num of tiral 41 | cnt += 1 42 | inputs[cnt].append(raw_inp[i]) 43 | minimum = 1000000 44 | for i in range(num_trials): 45 | if (len(inputs[i]) < minimum): 46 | minimum = len(inputs[i]) 47 | each_step = np.floor(minimum/num_steps) 48 | return each_step, inputs 49 | 50 | 51 | -------------------------------------------------------------------------------- /semi_supervised/model_pred.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 2 | # Commonwealth Scientific and Industrial Research Organisation (CSIRO) 3 | # ABN 41 687 119 230 4 | # 5 | # Author: Ahmadreza Ahmadi 6 | 7 | # This file includes the class that includes the deep learning model for semi-supervised terrrian classification: the prediction part 8 | 9 | import tensorflow as tf 10 | from tensorflow import nn 11 | from utils import lazy_property 12 | 13 | # The class does the one step prediction and it includes RNNs: 14 | class Prediction: 15 | 16 | def __init__(self, data, target, length, learning_rate, num_RNN, ext): 17 | self.data = data 18 | self.target = target 19 | length = tf.cast(length, tf.int32) 20 | self.length = length 21 | self.learning_rate = learning_rate 22 | self._num_RNN = num_RNN 23 | self.ext = ext 24 | self.prediction 25 | self.error 26 | self.optimize 27 | 28 | # returns the output prediction of the predictor RNNs 29 | @lazy_property 30 | def prediction(self): 31 | # Recurrent network. 32 | num_units = [self._num_RNN] 33 | cells = [nn.rnn_cell.GRUCell(n) for n in num_units] 34 | stacked_rnn = tf.contrib.rnn.MultiRNNCell(cells) 35 | output, _ = nn.dynamic_rnn( 36 | stacked_rnn, 37 | self.data, 38 | dtype=tf.float32, 39 | sequence_length=self.length, 40 | ) 41 | batch_size = tf.shape(output)[0] 42 | max_length = int(output.get_shape()[1]) 43 | output_size = int(output.get_shape()[2]) 44 | target_size = int(self.target.get_shape()[2]) 45 | 46 | output_reshape = tf.reshape(output, [-1, output_size]) 47 | 48 | weight, bias = self._weight_and_bias( 49 | self._num_RNN, target_size) 50 | # Tanh layer. 51 | prediction = self.ext * tf.nn.tanh(tf.matmul(output_reshape, weight) + bias) 52 | prediction_reshape = tf.reshape(prediction, [batch_size, max_length, target_size]) 53 | return prediction_reshape 54 | 55 | # returns the prediction cost 56 | @lazy_property 57 | def cost(self): 58 | MSE = tf.reduce_mean(tf.squared_difference(self.prediction, self.target)) 59 | tf.summary.scalar('MSE', MSE) 60 | return MSE 61 | 62 | # performs adam optimizer 63 | @lazy_property 64 | def optimize(self): 65 | optimizer = tf.train.AdamOptimizer(self.learning_rate) 66 | return optimizer.minimize(self.cost) 67 | 68 | # returns the prediction error 69 | @lazy_property 70 | def error(self): 71 | MSE = tf.reduce_mean(tf.squared_difference(self.prediction, self.target)) 72 | tf.summary.scalar('MSE', MSE) 73 | return (MSE / self.ext) 74 | 75 | @staticmethod 76 | def _weight_and_bias(in_size, out_size): 77 | weight = tf.truncated_normal([in_size, out_size], stddev=0.01) 78 | bias = tf.constant(0.1, shape=[out_size]) 79 | return tf.Variable(weight), tf.Variable(bias) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Semi-supervised Gated Recurrent Neural Networks for Robotic Terrain Classification 2 | 3 | This is full source code accompanying the paper titled "Semi-supervised Gated Recurrent Neural Networks for Robotic Terrain Classification" 4 | 5 | Requirements: 6 | • Python >= 3.X with Numpy, Scipy, Sklearn, CSV, Functools, and Matplotlib 7 | • Tensorflow >= 1.12.0 8 | 9 | There are three python packages in this repository: 10 | 11 | I. The classifier package is the supervised RNN classifier code (Gated Recuurent Unit (GRU)+Fully Connected Layer (FCL)) for 10 fold Cross-Validation (CV). 12 | In order to run it: 13 | 1. Go to the classifier folder and create data and save directories: 14 | mkdir save data 15 | 2. Go to data folder and download QCAT data from: https://doi.org/10.25919/5f88b9c730442 16 | 3. Return to the classifier folder and run the code with #N CV fold number: 17 | python train.py N 18 | N here is the fold number (N = 0-9). There are 10 fold numbers for 10 fold CV. They should be run separately by changing N from 0 to 9 or simultaneously using GPU clusters (a shell file needs to be added for GPU clusters tailored based on clusters). 19 | 20 | II. The classifier_attention is the supervised RNN classifier with attention mechanism for 10 fold CV. Attention helps training to converge faster for QCAT dataset. 21 | In order to run it: 22 | 1. Go to the classifier_attention folder and create data and save directories: 23 | mkdir save data 24 | 2. Go to data folder and download QCAT data from: https://doi.org/10.25919/5f88b9c730442 or copy it from the classifier package. 25 | 3. Return to the classifier_attention and run the code with #N CV fold number: 26 | python train.py N 27 | N here is the fold number (N = 0-9). There are 10 fold numbers for 10 fold CV. They should be run separately by changing N from 0 to 9 or simultaneously using GPU clusters (a shell file needs to be added for GPU clusters tailored based on clusters). 28 | 29 | III. The semi_supervised package is the semi-supervised RNN classifier code (GRU layers + FCL). The package includes the RNN predictor and the RNN classifier. 30 | In order to run it: 31 | 1. Go to the semi_supervised folder and create data and save directories: 32 | mkdir save data 33 | 2. Go to data folder and download QCAT data from: https://doi.org/10.25919/5f88b9c730442 34 | 3. Return to the semi_supervised folder and run the predictor RNN code (the unsupervised model): 35 | python model_pred.py M 36 | M is the ratio of the data that the classifier RNN will use later. 1-M is the ratio that the predictor RNN uses. It is good to start with M = 0.2, which means that 20% of the whole data will be used for the classifier RNN and 80% is used for the predictor RNN. 37 | 4. After training of the predictor RNN, run the classifier code (the supervised model): 38 | python model_class.py N M 39 | N here is the fold number (N = 0-1). There are 2 fold numbers for 2 fold CV. They should be run separately by changing N from 0 to 1 or simultaneously using GPU clusters (a shell file needs to be added for GPU clusters tailored based on clusters). Note that the predictor RNN must be trained first because the classifier RNNs need the predictor RNN’s parameters in their first RNN layer. M is exactly as explained for the predictor RNN, and it must be exactly as the same as that number (0.2 is a good start). 40 | 41 | Licence: 42 | This project is licensed under the CSIRO Open Source Software Licence Agreement (variation of the BSD / MIT License) - see the LICENSE file for details. 43 | -------------------------------------------------------------------------------- /classifier/model.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 2 | # Commonwealth Scientific and Industrial Research Organisation (CSIRO) 3 | # ABN 41 687 119 230 4 | # 5 | # Author: Ahmadreza Ahmadi 6 | 7 | # This file includes the class that includes the deep learning model for supervised terrrian classification 8 | 9 | import tensorflow as tf 10 | from tensorflow import nn 11 | from utils import lazy_property 12 | 13 | # The class does the terrain classification and it includes RNNs and a Fully Connected Layer (FCL) 14 | class Classification: 15 | 16 | def __init__(self, data, target, length, learning_rate, num_RNN, num_FCN): 17 | self.data = data 18 | self.target = target 19 | self.layer1 = num_FCN 20 | length = tf.cast(length, tf.int32) 21 | self.length = length 22 | self.learning_rate = learning_rate 23 | self._num_RNN = num_RNN 24 | self.prediction 25 | self.error 26 | self.optimize 27 | 28 | # returns the output prediction of the classifier 29 | @lazy_property 30 | def prediction(self): 31 | # Recurrent network. 32 | output_RNN, _ = nn.dynamic_rnn( 33 | nn.rnn_cell.GRUCell(self._num_RNN), 34 | self.data, 35 | dtype=tf.float32, 36 | sequence_length=self.length, 37 | ) 38 | 39 | batch_size = tf.shape(output_RNN)[0] 40 | max_length = int(output_RNN.get_shape()[1]) 41 | output_size = int(output_RNN.get_shape()[2]) 42 | 43 | output_reshape = tf.reshape(output_RNN, [-1, output_size]) 44 | weight_l1, bias_l1 = self._weight_and_bias(self._num_RNN, self.layer1) 45 | output_l1 = tf.nn.tanh(tf.matmul(output_reshape, weight_l1) + bias_l1) 46 | output_drop_out_l1 = tf.nn.dropout(output_l1, 0.2, seed=47) 47 | output_drop_out_reshape_l1 = tf.reshape(output_drop_out_l1, [batch_size, max_length, self.layer1]) 48 | 49 | last = self._last_relevant(output_drop_out_reshape_l1, self.length) 50 | 51 | weight_class, bias_class = self._weight_and_bias( 52 | self.layer1, int(self.target.get_shape()[1])) 53 | # Softmax layer. 54 | prediction = tf.nn.softmax(tf.matmul(last, weight_class) + bias_class) 55 | return prediction 56 | 57 | # returns the classification cost 58 | @lazy_property 59 | def cost(self): 60 | cross_entropy = -tf.reduce_sum(self.target * tf.log(self.prediction)) 61 | tf.summary.scalar('cross_entropy', cross_entropy) 62 | vars = tf.trainable_variables() 63 | lossL2 = tf.add_n([ tf.nn.l2_loss(v) for v in vars 64 | if 'bias' not in v.name ]) * 0.005 65 | return (cross_entropy+lossL2) 66 | 67 | # performs adam optimizer 68 | @lazy_property 69 | def optimize(self): 70 | optimizer = tf.train.AdamOptimizer(self.learning_rate) 71 | return optimizer.minimize(self.cost) 72 | 73 | # returns the classification error 74 | @lazy_property 75 | def error(self): 76 | mistakes = tf.not_equal( 77 | tf.argmax(self.target, 1), tf.argmax(self.prediction, 1)) 78 | tf.summary.scalar('error', tf.reduce_mean(tf.cast(mistakes, tf.float32))) 79 | return tf.reduce_mean(tf.cast(mistakes, tf.float32)) 80 | 81 | @staticmethod 82 | def _weight_and_bias(in_size, out_size): 83 | weight = tf.truncated_normal([in_size, out_size], stddev=0.01) 84 | bias = tf.constant(0.1, shape=[out_size]) 85 | return tf.Variable(weight), tf.Variable(bias) 86 | 87 | # returns the values of the last step (step T) of RNNs 88 | @staticmethod 89 | def _last_relevant(output, length): 90 | batch_size = tf.shape(output)[0] 91 | max_length = int(output.get_shape()[1]) 92 | output_size = int(output.get_shape()[2]) 93 | index = tf.range(0, batch_size) * max_length + (length - 1) 94 | flat = tf.reshape(output, [-1, output_size]) 95 | relevant = tf.gather(flat, index) 96 | return relevant -------------------------------------------------------------------------------- /frequency_domain/SVM_PUT_Dataset.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import json\n", 12 | "import os\n", 13 | "import numpy as np\n", 14 | "import pandas as pd\n", 15 | "from scipy.io import loadmat\n", 16 | "from sklearn.model_selection import train_test_split, KFold\n", 17 | "from sklearn.utils import shuffle\n", 18 | "from sklearn.svm import SVC\n", 19 | "from sklearn.metrics import classification_report, confusion_matrix\n", 20 | "from sklearn import preprocessing" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 2, 26 | "metadata": { 27 | "collapsed": true 28 | }, 29 | "outputs": [], 30 | "source": [ 31 | "# Load the data, create the one-hot labels, and prepare the K-Fold Cross Validation\n", 32 | "CWD = os.getcwd()\n", 33 | "string = os.path.join(CWD, 'data/put.mat')\n", 34 | "all_data = loadmat(string) \n", 35 | "data_steps = all_data['features']\n", 36 | "data_steps_array = np.array(data_steps)\n", 37 | "data_labels = all_data['labels']\n", 38 | "data_labels_arr = np.array(data_labels)\n", 39 | "data_labels_arr = np.reshape(data_labels_arr, (data_labels_arr.shape[1]))\n", 40 | "\n", 41 | "# normalization of the data\n", 42 | "normed = preprocessing.scale(data_steps_array) \n", 43 | "\n", 44 | "normed, data_labels_arr = shuffle(normed, data_labels_arr, random_state=47)\n", 45 | "\n", 46 | "# K-Fold Cross validation preparation\n", 47 | "n_split = 10 # 10-fold cross validation\n", 48 | "train_index = []\n", 49 | "test_index = []\n", 50 | "for train_ind,test_ind in KFold(n_split, random_state=47).split(normed):\n", 51 | " train_index.append(train_ind)\n", 52 | " test_index.append(test_ind)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 3, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "# train the Support Vector Machines for Frequency Features based on paper:\n", 62 | "# \"What am I touching? Learning to classify terrain via haptic sensing\"\n", 63 | "\n", 64 | "val_acc = {'{:1d}'.format(j):[] for j in range(n_split)}\n", 65 | "for i in range(n_split):\n", 66 | " svclassifier = SVC(kernel='rbf')\n", 67 | " x_train,x_test=normed[train_index[i]],normed[test_index[i]]\n", 68 | " y_train,y_test=data_labels_arr[train_index[i]],data_labels_arr[test_index[i]]\n", 69 | " svclassifier.fit(x_train, y_train)\n", 70 | " y_val = svclassifier.predict(x_test)\n", 71 | " tmp = classification_report(y_test,y_val) \n", 72 | " val_acc['{:1d}'.format(i)] = float(tmp[388:400])" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 4, 78 | "metadata": {}, 79 | "outputs": [ 80 | { 81 | "name": "stdout", 82 | "output_type": "stream", 83 | "text": [ 84 | "mean accuracy: 66.10000000000001 std: 1.6401219466856718 min: 64.0 max: 69.0\n" 85 | ] 86 | } 87 | ], 88 | "source": [ 89 | "# The final Report\n", 90 | "maxim = [np.max(val_acc['{:1d}'.format(i)]) for i in range(10)]\n", 91 | "\n", 92 | "print('mean accuracy: ', np.mean(maxim)*100, ' std: ', np.std(maxim)*100, ' min: ', np.min(maxim)*100, ' max: ', np.max(maxim)*100)" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": { 99 | "collapsed": true 100 | }, 101 | "outputs": [], 102 | "source": [] 103 | } 104 | ], 105 | "metadata": { 106 | "kernelspec": { 107 | "display_name": "Python 3", 108 | "language": "python", 109 | "name": "python3" 110 | }, 111 | "language_info": { 112 | "codemirror_mode": { 113 | "name": "ipython", 114 | "version": 3 115 | }, 116 | "file_extension": ".py", 117 | "mimetype": "text/x-python", 118 | "name": "python", 119 | "nbconvert_exporter": "python", 120 | "pygments_lexer": "ipython3", 121 | "version": "3.6.3" 122 | } 123 | }, 124 | "nbformat": 4, 125 | "nbformat_minor": 2 126 | } 127 | -------------------------------------------------------------------------------- /semi_supervised/model_class_test.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from tensorflow import nn 3 | from utils import lazy_property 4 | 5 | # The RNN implementation is based on http://danijar.com/variable-sequence-lengths-in-tensorflow/ 6 | class Classification: 7 | def __init__(self, data, target, length, learning_rate, stage, num_RNN, num_FCN): 8 | self.data = data 9 | self.target = target 10 | self.layer1 = num_FCN 11 | self.stage = stage 12 | length = tf.cast(length, tf.int32) 13 | self.length = length 14 | self.learning_rate = learning_rate 15 | self._num_RNN = num_RNN 16 | self.prediction 17 | self.error 18 | self.optimize 19 | 20 | @lazy_property 21 | def prediction(self): 22 | num_units = [self._num_RNN, self._num_RNN] 23 | cells = [nn.rnn_cell.GRUCell(n) for n in num_units] 24 | stacked_rnn = tf.contrib.rnn.MultiRNNCell(cells) 25 | # Recurrent network. 26 | output_RNN, _ = nn.dynamic_rnn( 27 | stacked_rnn, 28 | self.data, 29 | dtype=tf.float32, 30 | sequence_length=self.length, 31 | ) 32 | 33 | batch_size = tf.shape(output_RNN)[0] 34 | max_length = int(output_RNN.get_shape()[1]) 35 | output_size = int(output_RNN.get_shape()[2]) 36 | 37 | output_reshape = tf.reshape(output_RNN, [-1, output_size]) 38 | weight_l1, bias_l1 = self._weight_and_bias(self._num_RNN, self.layer1) 39 | output_l1 = tf.nn.tanh(tf.matmul(output_reshape, weight_l1) + bias_l1) 40 | output_drop_out_l1 = tf.nn.dropout(output_l1, 0.2, seed=47) 41 | output_drop_out_reshape_l1 = tf.reshape(output_drop_out_l1, [batch_size, max_length, self.layer1]) 42 | 43 | last = self._last_relevant(output_drop_out_reshape_l1, self.length) 44 | 45 | weight_class, bias_class = self._weight_and_bias( 46 | self.layer1, int(self.target.get_shape()[1])) 47 | # Softmax layer. 48 | prediction = tf.nn.softmax(tf.matmul(last, weight_class) + bias_class) 49 | return prediction, weight_l1, bias_l1, weight_class, bias_class 50 | 51 | @lazy_property 52 | def cost(self): 53 | prediction,_,_,_,_ = self.prediction 54 | cross_entropy = -tf.reduce_sum(self.target * tf.log(prediction)) 55 | tf.summary.scalar('cross_entropy', cross_entropy) 56 | vars = tf.trainable_variables() 57 | lossL2 = tf.add_n([ tf.nn.l2_loss(v) for v in vars 58 | if 'bias' not in v.name ]) * 0.005 59 | return (cross_entropy+lossL2) 60 | 61 | @lazy_property 62 | def optimize(self): 63 | optimizer = tf.train.AdamOptimizer(self.learning_rate) 64 | variables = tf.trainable_variables() 65 | # Optimizing only second layer RNNs 66 | variables_to_optimize = [v for v in variables if v.name.split('/')[0]=='rnn' 67 | and v.name.split('/')[2]=='cell_1'] 68 | _,var1,var2, var3, var4 = self.prediction 69 | opt_cond = tf.cond(self.stage < 1, lambda: optimizer.minimize(self.cost, var_list=[variables_to_optimize, var1, var2, var3, var4]), lambda: optimizer.minimize(self.cost)) 70 | return opt_cond 71 | 72 | 73 | @lazy_property 74 | def error(self): 75 | prediction, _,_,_,_ = self.prediction 76 | mistakes = tf.not_equal( 77 | tf.argmax(self.target, 1), tf.argmax(prediction, 1)) 78 | tf.summary.scalar('error', tf.reduce_mean(tf.cast(mistakes, tf.float32))) 79 | return tf.reduce_mean(tf.cast(mistakes, tf.float32)) 80 | 81 | @staticmethod 82 | def _weight_and_bias(in_size, out_size): 83 | weight = tf.truncated_normal([in_size, out_size], stddev=0.01) 84 | bias = tf.constant(0.1, shape=[out_size]) 85 | return tf.Variable(weight), tf.Variable(bias) 86 | 87 | @staticmethod 88 | def _last_relevant(output, length): 89 | batch_size = tf.shape(output)[0] 90 | max_length = int(output.get_shape()[1]) 91 | output_size = int(output.get_shape()[2]) 92 | index = tf.range(0, batch_size) * max_length + (length - 1) 93 | flat = tf.reshape(output, [-1, output_size]) 94 | relevant = tf.gather(flat, index) 95 | return relevant -------------------------------------------------------------------------------- /semi_supervised/model_class.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 2 | # Commonwealth Scientific and Industrial Research Organisation (CSIRO) 3 | # ABN 41 687 119 230 4 | # 5 | # Author: Ahmadreza Ahmadi 6 | 7 | # This file includes the class that includes the deep learning model for semi-supervised terrrian classification: the classification part 8 | 9 | import tensorflow as tf 10 | from tensorflow import nn 11 | from utils import lazy_property 12 | 13 | # The class does the terrain classification and it includes RNN layers and a Fully Connected Layer (FCL) 14 | class Classification: 15 | def __init__(self, data, target, length, learning_rate, stage, num_RNN, num_FCN): 16 | self.data = data 17 | self.target = target 18 | self.layer1 = num_FCN 19 | self.stage = stage 20 | length = tf.cast(length, tf.int32) 21 | self.length = length 22 | self.learning_rate = learning_rate 23 | self._num_RNN = num_RNN 24 | self.prediction 25 | self.error 26 | self.optimize 27 | 28 | # returns the output prediction of the classifier 29 | @lazy_property 30 | def prediction(self): 31 | num_units = [self._num_RNN, self._num_RNN] 32 | cells = [nn.rnn_cell.GRUCell(n) for n in num_units] 33 | stacked_rnn = tf.contrib.rnn.MultiRNNCell(cells) 34 | # Recurrent network. 35 | output_RNN, _ = nn.dynamic_rnn( 36 | stacked_rnn, 37 | self.data, 38 | dtype=tf.float32, 39 | sequence_length=self.length, 40 | ) 41 | 42 | batch_size = tf.shape(output_RNN)[0] 43 | max_length = int(output_RNN.get_shape()[1]) 44 | output_size = int(output_RNN.get_shape()[2]) 45 | 46 | output_reshape = tf.reshape(output_RNN, [-1, output_size]) 47 | weight_l1, bias_l1 = self._weight_and_bias(self._num_RNN, self.layer1) 48 | output_l1 = tf.nn.tanh(tf.matmul(output_reshape, weight_l1) + bias_l1) 49 | output_drop_out_l1 = tf.nn.dropout(output_l1, 0.2, seed=47) 50 | output_drop_out_reshape_l1 = tf.reshape(output_drop_out_l1, [batch_size, max_length, self.layer1]) 51 | 52 | last = self._last_relevant(output_drop_out_reshape_l1, self.length) 53 | 54 | weight_class, bias_class = self._weight_and_bias( 55 | self.layer1, int(self.target.get_shape()[1])) 56 | # Softmax layer. 57 | prediction = tf.nn.softmax(tf.matmul(last, weight_class) + bias_class) 58 | return prediction, weight_l1, bias_l1, weight_class, bias_class 59 | 60 | # returns the classification cost 61 | @lazy_property 62 | def cost(self): 63 | prediction,_,_,_,_ = self.prediction 64 | cross_entropy = -tf.reduce_sum(self.target * tf.log(prediction)) 65 | tf.summary.scalar('cross_entropy', cross_entropy) 66 | vars = tf.trainable_variables() 67 | lossL2 = tf.add_n([ tf.nn.l2_loss(v) for v in vars 68 | if 'bias' not in v.name ]) * 0.005 69 | return (cross_entropy+lossL2) 70 | 71 | # performs adam optimizer 72 | @lazy_property 73 | def optimize(self): 74 | optimizer = tf.train.AdamOptimizer(self.learning_rate) 75 | variables = tf.trainable_variables() 76 | # Optimizing only second layer RNNs 77 | variables_to_optimize = [v for v in variables if v.name.split('/')[0]=='rnn' 78 | and v.name.split('/')[2]=='cell_1'] 79 | _,var1,var2, var3, var4 = self.prediction 80 | # The stage 0 is for FE Semi-supervised learning and the stage 1 is for FE+FT Semi-supervised learning 81 | opt_cond = tf.cond(self.stage < 1, lambda: optimizer.minimize(self.cost, var_list=[variables_to_optimize, var1, var2, var3, var4]), lambda: optimizer.minimize(self.cost)) 82 | return opt_cond 83 | 84 | # returns the classification error 85 | @lazy_property 86 | def error(self): 87 | prediction, _,_,_,_ = self.prediction 88 | mistakes = tf.not_equal( 89 | tf.argmax(self.target, 1), tf.argmax(prediction, 1)) 90 | tf.summary.scalar('error', tf.reduce_mean(tf.cast(mistakes, tf.float32))) 91 | return tf.reduce_mean(tf.cast(mistakes, tf.float32)) 92 | 93 | @staticmethod 94 | def _weight_and_bias(in_size, out_size): 95 | weight = tf.truncated_normal([in_size, out_size], stddev=0.01) 96 | bias = tf.constant(0.1, shape=[out_size]) 97 | return tf.Variable(weight), tf.Variable(bias) 98 | 99 | # returns the values of the last step (step T) of RNNs 100 | @staticmethod 101 | def _last_relevant(output, length): 102 | batch_size = tf.shape(output)[0] 103 | max_length = int(output.get_shape()[1]) 104 | output_size = int(output.get_shape()[2]) 105 | index = tf.range(0, batch_size) * max_length + (length - 1) 106 | flat = tf.reshape(output, [-1, output_size]) 107 | relevant = tf.gather(flat, index) 108 | return relevant -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2 | 3 | CSIRO Open Source Software Licence Agreement (variation of the BSD / MIT License) 4 | Copyright (c) 2020, Commonwealth Scientific and Industrial Research Organisation (CSIRO) ABN 41 687 119 230. 5 | All rights reserved. CSIRO is willing to grant you a licence to this software (deep-terrain-classification) on the following terms, except where otherwise indicated for third party material. 6 | Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | • Neither the name of CSIRO nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of CSIRO. 10 | EXCEPT AS EXPRESSLY STATED IN THIS AGREEMENT AND TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS". CSIRO MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. 11 | TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL CSIRO BE LIABLE ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION FOR BREACH OF CONTRACT, NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER LIABILITY HOWSOEVER INCURRED. WITHOUT LIMITING THE SCOPE OF THE PREVIOUS SENTENCE THE EXCLUSION OF LIABILITY SHALL INCLUDE: LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT, ACCESS OF THE SOFTWARE OR ANY OTHER DEALINGS WITH THE SOFTWARE, EVEN IF CSIRO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS, DAMAGES OR OTHER LIABILITY. 12 | APPLICABLE LEGISLATION SUCH AS THE AUSTRALIAN CONSUMER LAW MAY APPLY REPRESENTATIONS, WARRANTIES, OR CONDITIONS, OR IMPOSES OBLIGATIONS OR LIABILITY ON CSIRO THAT CANNOT BE EXCLUDED, RESTRICTED OR MODIFIED TO THE FULL EXTENT SET OUT IN THE EXPRESS TERMS OF THIS CLAUSE ABOVE "CONSUMER GUARANTEES". TO THE EXTENT THAT SUCH CONSUMER GUARANTEES CONTINUE TO APPLY, THEN TO THE FULL EXTENT PERMITTED BY THE APPLICABLE LEGISLATION, THE LIABILITY OF CSIRO UNDER THE RELEVANT CONSUMER GUARANTEE IS LIMITED (WHERE PERMITTED AT CSIRO’S OPTION) TO ONE OF FOLLOWING REMEDIES OR SUBSTANTIALLY EQUIVALENT REMEDIES: 13 | (a) THE REPLACEMENT OF THE SOFTWARE, THE SUPPLY OF EQUIVALENT SOFTWARE, OR SUPPLYING RELEVANT SERVICES AGAIN; 14 | (b) THE REPAIR OF THE SOFTWARE; 15 | (c) THE PAYMENT OF THE COST OF REPLACING THE SOFTWARE, OF ACQUIRING EQUIVALENT SOFTWARE, HAVING THE RELEVANT SERVICES SUPPLIED AGAIN, OR HAVING THE SOFTWARE REPAIRED. 16 | IN THIS CLAUSE, CSIRO INCLUDES ANY THIRD PARTY AUTHOR OR OWNER OF ANY PART OF THE SOFTWARE OR MATERIAL DISTRIBUTED WITH IT. CSIRO MAY ENFORCE ANY RIGHTS ON BEHALF OF THE RELEVANT THIRD PARTY. 17 | 18 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 19 | Third Party Components 20 | The following third party components are distributed with the Software. You agree to comply with the licence terms for these components as part of accessing the Software. Other third party software may also be identified in separate files distributed with the Software. 21 | ___________________________________________________________________ 22 | TensorFLow https://www.tensorflow.org/ 23 | This software is licensed under the Apache License 2.0 license. 24 | ___________________________________________________________________ 25 | ___________________________________________________________________ 26 | Variable Sequence Lengths in TensorFlow https://danijar.com/variable-sequence-lengths-in-tensorflow/ 27 | This software is licensed under the open CC BY-SA 3.0 license. 28 | ___________________________________________________________________ 29 | ___________________________________________________________________ 30 | Tensorflow implementation of attention mechanism for text classification tasks https://github.com/ilivans/tf-rnn-attention 31 | This software is licensed under the MIT license. 32 | ___________________________________________________________________ 33 | 34 | 35 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /classifier_attention/model.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 2 | # Commonwealth Scientific and Industrial Research Organisation (CSIRO) 3 | # ABN 41 687 119 230 4 | # 5 | # Author: Ahmadreza Ahmadi 6 | 7 | # This file includes the class that includes the deep learning model for supervised terrrian classification with attention mechanism 8 | 9 | import tensorflow as tf 10 | from tensorflow import nn 11 | from utils import lazy_property 12 | 13 | # The class does the terrain classification and it includes RNNs with attention 14 | class Classification: 15 | 16 | def __init__(self, data, target, length, learning_rate, num_RNNs): 17 | self.data = data 18 | self.target = target 19 | length = tf.cast(length, tf.int32) 20 | self.length = length 21 | self.learning_rate = learning_rate 22 | self._num_RNNs = num_RNNs 23 | self.prediction 24 | self.error 25 | self.optimize 26 | 27 | # returns the output prediction of the classifier 28 | @lazy_property 29 | def prediction(self): 30 | # Recurrent network. 31 | output_RNN, _ = nn.dynamic_rnn( 32 | nn.rnn_cell.GRUCell(self._num_RNNs), 33 | self.data, 34 | dtype=tf.float32, 35 | sequence_length=self.length, 36 | ) 37 | last = self._attention(output_RNN) 38 | weight, bias = self._weight_and_bias( 39 | self._num_RNNs, int(self.target.get_shape()[1])) 40 | # Softmax layer. 41 | prediction = tf.nn.softmax(tf.matmul(last, weight) + bias) 42 | return prediction 43 | 44 | # returns the classification cost 45 | @lazy_property 46 | def cost(self): 47 | cross_entropy = -tf.reduce_sum(self.target * tf.log(self.prediction)) 48 | tf.summary.scalar('cross_entropy', cross_entropy) 49 | vars = tf.trainable_variables() 50 | lossL2 = tf.add_n([ tf.nn.l2_loss(v) for v in vars 51 | if 'bias' not in v.name ]) * 0.005 52 | return (cross_entropy+lossL2) 53 | 54 | # performs adam optimizer 55 | @lazy_property 56 | def optimize(self): 57 | optimizer = tf.train.AdamOptimizer(self.learning_rate) 58 | return optimizer.minimize(self.cost) 59 | 60 | # returns the classification error 61 | @lazy_property 62 | def error(self): 63 | mistakes = tf.not_equal( 64 | tf.argmax(self.target, 1), tf.argmax(self.prediction, 1)) 65 | tf.summary.scalar('error', tf.reduce_mean(tf.cast(mistakes, tf.float32))) 66 | return tf.reduce_mean(tf.cast(mistakes, tf.float32)) 67 | 68 | @staticmethod 69 | def _weight_and_bias(in_size, out_size): 70 | weight = tf.truncated_normal([in_size, out_size], stddev=0.01) 71 | bias = tf.constant(0.1, shape=[out_size]) 72 | return tf.Variable(weight), tf.Variable(bias) 73 | 74 | # returns the values of the last step (step T) of RNNs 75 | @staticmethod 76 | def _last_relevant(output, length): 77 | batch_size = tf.shape(output)[0] 78 | max_length = int(output.get_shape()[1]) 79 | output_size = int(output.get_shape()[2]) 80 | index = tf.range(0, batch_size) * max_length + (length - 1) 81 | flat = tf.reshape(output, [-1, output_size]) 82 | relevant = tf.gather(flat, index) 83 | return relevant 84 | 85 | # The attention mechanism is from https://github.com/ilivans/tf-rnn-attention 86 | @staticmethod 87 | def _attention(inputs, attention_size=50, time_major=False, return_alphas=False): 88 | 89 | if isinstance(inputs, tuple): 90 | # In case of Bi-RNN, concatenate the forward and the backward RNN outputs. 91 | inputs = tf.concat(inputs, 2) 92 | 93 | if time_major: 94 | # (T,B,D) => (B,T,D) 95 | inputs = tf.array_ops.transpose(inputs, [1, 0, 2]) 96 | 97 | hidden_size = inputs.shape[2].value # D value - hidden size of the RNN layer 98 | 99 | initializer = tf.random_normal_initializer(stddev=0.1) 100 | 101 | # Trainable parameters 102 | w_omega = tf.get_variable(name="w_omega", shape=[hidden_size, attention_size], initializer=initializer) 103 | b_omega = tf.get_variable(name="b_omega", shape=[attention_size], initializer=initializer) 104 | u_omega = tf.get_variable(name="u_omega", shape=[attention_size], initializer=initializer) 105 | 106 | with tf.name_scope('v'): 107 | # Applying fully connected layer with non-linear activation to each of the B*T timestamps; 108 | # the shape of `v` is (B,T,D)*(D,A)=(B,T,A), where A=attention_size 109 | v = tf.tanh(tf.tensordot(inputs, w_omega, axes=1) + b_omega) 110 | 111 | # For each of the timestamps its vector of size A from `v` is reduced with `u` vector 112 | vu = tf.tensordot(v, u_omega, axes=1, name='vu') # (B,T) shape 113 | alphas = tf.nn.softmax(vu, name='alphas') # (B,T) shape 114 | 115 | # Output of (Bi-)RNN is reduced with attention vector; the result has (B,D) shape 116 | output = tf.reduce_sum(inputs * tf.expand_dims(alphas, -1), 1) 117 | 118 | if not return_alphas: 119 | return output 120 | else: 121 | return output, alphas -------------------------------------------------------------------------------- /classifier_attention/train.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 2 | # Commonwealth Scientific and Industrial Research Organisation (CSIRO) 3 | # ABN 41 687 119 230 4 | # 5 | # Author: Ahmadreza Ahmadi 6 | 7 | # This file includes the main function that reads the data, train the classifier with attention mechanism for supervised learning, evaluate the models, and save the models in the save directory. 8 | 9 | import tensorflow as tf 10 | import numpy as np 11 | import os 12 | from scipy.io import loadmat 13 | from sklearn.model_selection import train_test_split, KFold 14 | from sklearn.utils import shuffle 15 | import sys 16 | import json 17 | from utils import get_next_batch, read_lines, step_count 18 | from model import Classification 19 | import tensorflow.contrib.slim as slim 20 | 21 | sys.path.append(os.getcwd()) 22 | 23 | if __name__ == '__main__': 24 | epochs = 5000 # epoch size 25 | num_RNNs = 350 # number of RNN units 26 | batch_size = 10 # batch size 27 | num_classes = 6 # we have 6 terrain classes 28 | num_trials = 10 # the robot walked on each terrain 10 times 29 | num_steps = 8 # the robot walked 8 steps on each terrain 30 | num_diff_speeds = 6 # the robot walks on the terrains with 6 different speeds 31 | max_steps = 662 # the maximum T (time length) is obtained based on our data 32 | all_colms = 14 # this is based on number of all colms in the csv files 33 | relevant_colms = 10 # the IMU sensor dimension 34 | all_seq = num_classes * num_diff_speeds * num_trials * num_steps 35 | n_split = 10 # The k in k-fold cross-validation 36 | 37 | #for early stopping : 38 | best_cost = 1000000 39 | stop = False 40 | last_improvement = 0 41 | patience = 100 42 | 43 | all_data = np.zeros([all_seq, max_steps, all_colms]) 44 | data_steps_array = np.zeros([all_seq, max_steps, relevant_colms]) 45 | data_labels_array = np.zeros((all_seq, num_classes)) 46 | data_length_array = np.zeros((all_seq)) 47 | data_length_array = data_length_array.astype(int) 48 | 49 | CWD = os.getcwd() 50 | string = data_path = os.path.join(CWD, 'data') 51 | count = 0 52 | for i in range(num_classes): 53 | for j in range(1,7): # different speeds 54 | tmp_data = [] 55 | tmp_list = [] 56 | path = '{:s}/{:1d}_{:1d}_legSensors_imu.csv'.format(string,i,j) 57 | tmp_data = list(read_lines(path)) 58 | tmp_arr = np.array(tmp_data) 59 | step, tmp_list = step_count(tmp_arr, num_trials, num_steps) 60 | step = int(step) 61 | for k in range(num_trials): 62 | for l in range(num_steps): 63 | all_data[count,0:step,:] = tmp_list[k][l*step:(l+1)*step] 64 | data_labels_array[count,i] = 1.0 65 | data_length_array[count] = step 66 | count += 1 67 | data_steps_array = all_data[:,:,4:14] # to have last relevant data in csv files 68 | 69 | # Normalize data to have mean 0 and SD 1.0 70 | normed = np.zeros_like(data_steps_array) 71 | for i in range(data_steps_array.shape[0]): 72 | normed[i,0:data_length_array[i]] = (data_steps_array[i,0:data_length_array[i]] - data_steps_array[i,0:data_length_array[i]].mean(axis=0)) / data_steps_array[i,0:data_length_array[i]].std(axis=0) 73 | # Shuffle data 74 | normed, data_labels_array, data_length_array = shuffle(normed, data_labels_array, data_length_array, random_state=47) 75 | 76 | data = tf.placeholder(tf.float32, [None, normed.shape[1], normed.shape[2]]) 77 | target = tf.placeholder(tf.float32, [None, num_classes]) 78 | length = tf.placeholder(tf.float32, [None]) 79 | learning_rate = tf.placeholder(tf.float32, shape=[]) 80 | 81 | model = Classification(data, target, length, learning_rate, num_RNNs) 82 | 83 | # Only save one checkpoint 84 | saver = tf.train.Saver(max_to_keep=1) 85 | 86 | all_error = [] 87 | best_error = {'epoch':[], 'best_acc':[]} 88 | 89 | train_index = [] 90 | test_index = [] 91 | for train_ind,test_ind in KFold(n_split, random_state=47).split(normed): 92 | train_index.append(train_ind) 93 | test_index.append(test_ind) 94 | 95 | arg_index = int(sys.argv[1]) 96 | sess = tf.Session() 97 | sess.run(tf.global_variables_initializer()) 98 | x_train,x_test=normed[train_index[arg_index]],normed[test_index[arg_index]] 99 | y_train,y_test=data_labels_array[train_index[arg_index]],data_labels_array[test_index[arg_index]] 100 | l_train,l_test=data_length_array[train_index[arg_index]],data_length_array[test_index[arg_index]] 101 | 102 | string1 = data_path = os.path.join(CWD, 'save') 103 | num_tr_iter = int(len(y_train) / batch_size) 104 | error_file = '{:s}/error{:1d}.txt'.format(string1, arg_index) 105 | error_file_best = '{:s}/best_acc{:1d}.txt'.format(string1, arg_index) 106 | epoch = 0 107 | curr_stage = 0 108 | l_r = 0.0005 109 | while epoch < epochs and stop == False: 110 | for iteration in range(num_tr_iter): 111 | start = iteration * batch_size 112 | end = (iteration + 1) * batch_size 113 | x_batch, y_batch, l_batch = get_next_batch(x_train, y_train, l_train, start, end) 114 | sess.run(model.optimize, {data: x_batch, target: y_batch, length: l_batch, learning_rate: l_r}) 115 | error = sess.run(model.error, {data: x_test, target: y_test, length: l_test, learning_rate: l_r}) 116 | if error < best_cost: 117 | path = '{:s}/model_CV_{:1d}.ckpt'.format(string1, arg_index) 118 | saver.save(sess, path) 119 | last_improvement = 0 120 | best_cost = error 121 | best_error['epoch'] = str(epoch) 122 | best_error['best_acc'] = str(1.0 - best_cost) 123 | file2 = open(error_file_best,"a+") 124 | file2.write(json.dumps(best_error)) 125 | file2.close() 126 | else: 127 | last_improvement += 1 128 | if last_improvement > patience: 129 | if curr_stage == 0: 130 | print('The current learning stage is: {:1d}'.format(curr_stage)) 131 | variables = slim.get_variables_to_restore() 132 | model_path = '{:s}/model_CV_{:1d}.ckpt'.format(string1, arg_index) 133 | saver = tf.train.Saver(variables) 134 | saver.restore(sess, model_path) 135 | l_r = 0.00005 136 | curr_stage += 1 137 | last_improvement = 0 138 | else: 139 | print('The current learning stage is: {:1d}'.format(curr_stage)) 140 | print("The patience is over") 141 | stop = True 142 | 143 | all_error.append(error) 144 | print("fold number %d:" %arg_index) 145 | print('Epoch {:2d} validation accuracy {:3.4f}%'.format(epoch, 100 * (1.0-error))) 146 | print(50*'*') 147 | file1 = open(error_file,"a+") 148 | file1.writelines(str(all_error)) 149 | file1.close() 150 | epoch += 1 151 | 152 | 153 | -------------------------------------------------------------------------------- /classifier/train.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 2 | # Commonwealth Scientific and Industrial Research Organisation (CSIRO) 3 | # ABN 41 687 119 230 4 | # 5 | # Author: Ahmadreza Ahmadi 6 | 7 | # This file includes the main function that reads the data, train the classifier for supervised learning, evaluate the models, and save the models in the save directory. 8 | 9 | import tensorflow as tf 10 | import numpy as np 11 | import os 12 | from scipy.io import loadmat 13 | from sklearn.model_selection import train_test_split, KFold 14 | from sklearn.utils import shuffle 15 | import sys 16 | import json 17 | from utils import get_next_batch, read_lines, step_count 18 | from model import Classification 19 | import tensorflow.contrib.slim as slim 20 | 21 | sys.path.append(os.getcwd()) 22 | 23 | if __name__ == '__main__': 24 | epochs = 5000 # epoch size 25 | batch_size = 10 # batch size 26 | num_RNN = 350 # number of RNN units 27 | num_FCN = 100 # number of neurons in fully connected layer 28 | num_classes = 6 # we have 6 terrain classes 29 | num_trials = 10 # the robot walked on each terrain 10 times 30 | num_steps = 8 # the robot walked 8 steps on each terrain 31 | num_diff_speeds = 6 # the robot walks on the terrains with 6 different speeds 32 | max_steps = 662 # the maximum T (time length) is obtained based on our data 33 | all_colms = 14 # this is based on number of all colms in the csv files 34 | relevant_colms = 10 # the IMU sensor dimension 35 | all_seq = num_classes * num_diff_speeds * num_trials * num_steps 36 | n_split = 10 # The k in k-fold cross-validation 37 | 38 | #for early stopping : 39 | best_cost = 1000000 40 | stop = False 41 | last_improvement = 0 42 | patience = 100 43 | 44 | all_data = np.zeros([all_seq, max_steps, all_colms]) 45 | data_steps_array = np.zeros([all_seq, max_steps, relevant_colms]) 46 | data_labels_array = np.zeros((all_seq, num_classes)) 47 | data_length_array = np.zeros((all_seq)) 48 | data_length_array = data_length_array.astype(int) 49 | 50 | CWD = os.getcwd() 51 | string = os.path.join(CWD, 'data') 52 | count = 0 53 | for i in range(num_classes): 54 | for j in range(1,7): # different speeds 55 | tmp_data = [] 56 | tmp_list = [] 57 | path = '{:s}/{:1d}_{:1d}_legSensors_imu.csv'.format(string,i,j) 58 | tmp_data = list(read_lines(path)) 59 | tmp_arr = np.array(tmp_data) 60 | step, tmp_list = step_count(tmp_arr, num_trials, num_steps) 61 | step = int(step) 62 | for k in range(num_trials): 63 | for l in range(num_steps): 64 | all_data[count,0:step,:] = tmp_list[k][l*step:(l+1)*step] 65 | data_labels_array[count,i] = 1.0 66 | data_length_array[count] = step 67 | count += 1 68 | data_steps_array = all_data[:,:,4:14] # to have last relevant data in csv files 69 | 70 | # Normalize data to have mean 0 and SD 1.0 71 | normed = np.zeros_like(data_steps_array) 72 | for i in range(data_steps_array.shape[0]): 73 | normed[i,0:data_length_array[i]] = (data_steps_array[i,0:data_length_array[i]] - data_steps_array[i,0:data_length_array[i]].mean(axis=0)) / data_steps_array[i,0:data_length_array[i]].std(axis=0) 74 | # Shuffle data 75 | normed, data_labels_array, data_length_array = shuffle(normed, data_labels_array, data_length_array, random_state=47) 76 | 77 | data = tf.placeholder(tf.float32, [None, normed.shape[1], normed.shape[2]]) 78 | target = tf.placeholder(tf.float32, [None, num_classes]) 79 | length = tf.placeholder(tf.float32, [None]) 80 | learning_rate = tf.placeholder(tf.float32, shape=[]) 81 | 82 | model = Classification(data, target, length, learning_rate, num_RNN, num_FCN) 83 | 84 | # Save only one checkpoint 85 | saver = tf.train.Saver(max_to_keep=1) 86 | 87 | all_error = [] 88 | best_error = {'epoch':[], 'best_acc':[]} 89 | 90 | train_index = [] 91 | test_index = [] 92 | for train_ind,test_ind in KFold(n_split, random_state=47).split(normed): 93 | train_index.append(train_ind) 94 | test_index.append(test_ind) 95 | 96 | arg_index = int(sys.argv[1]) 97 | sess = tf.Session() 98 | sess.run(tf.global_variables_initializer()) 99 | x_train,x_test=normed[train_index[arg_index]],normed[test_index[arg_index]] 100 | y_train,y_test=data_labels_array[train_index[arg_index]],data_labels_array[test_index[arg_index]] 101 | l_train,l_test=data_length_array[train_index[arg_index]],data_length_array[test_index[arg_index]] 102 | 103 | string1 = os.path.join(CWD, 'save') 104 | num_tr_iter = int(len(y_train) / batch_size) 105 | error_file = '{:s}/error{:1d}.txt'.format(string1, arg_index) 106 | error_file_best = '{:s}/best_acc{:1d}.txt'.format(string1, arg_index) 107 | epoch = 0 108 | curr_stage = 0 109 | l_r = 0.0005 110 | while epoch < epochs and stop == False: 111 | for iteration in range(num_tr_iter): 112 | start = iteration * batch_size 113 | end = (iteration + 1) * batch_size 114 | x_batch, y_batch, l_batch = get_next_batch(x_train, y_train, l_train, start, end) 115 | sess.run(model.optimize, {data: x_batch, target: y_batch, length: l_batch, learning_rate: l_r}) 116 | error = sess.run(model.error, {data: x_test, target: y_test, length: l_test, learning_rate: l_r}) 117 | if error < best_cost: 118 | path = '{:s}/model_CV_{:1d}.ckpt'.format(string1, arg_index) 119 | saver.save(sess, path) 120 | last_improvement = 0 121 | best_cost = error 122 | best_error['epoch'] = str(epoch) 123 | best_error['best_acc'] = str(1.0 - best_cost) 124 | file2 = open(error_file_best,"a+") 125 | file2.write(json.dumps(best_error)) 126 | file2.close() 127 | else: 128 | last_improvement += 1 129 | if last_improvement > patience: 130 | if curr_stage == 0: 131 | print('The current learning stage is: {:1d}'.format(curr_stage)) 132 | variables = slim.get_variables_to_restore() 133 | model_path = '{:s}/model_CV_{:1d}.ckpt'.format(string1, arg_index) 134 | saver = tf.train.Saver(variables) 135 | saver.restore(sess, model_path) 136 | l_r = 0.00005 137 | curr_stage += 1 138 | last_improvement = 0 139 | else: 140 | print('The current learning stage is: {:1d}'.format(curr_stage)) 141 | print("The patience is over") 142 | stop = True 143 | 144 | all_error.append(error) 145 | print("fold number %d:" %arg_index) 146 | print('Epoch {:2d} validation accuracy {:3.4f}%'.format(epoch, 100 * (1.0-error))) 147 | print(50*'*') 148 | file1 = open(error_file,"a+") 149 | file1.writelines(str(all_error)) 150 | file1.close() 151 | epoch += 1 152 | 153 | 154 | -------------------------------------------------------------------------------- /semi_supervised/train_pred.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 2 | # Commonwealth Scientific and Industrial Research Organisation (CSIRO) 3 | # ABN 41 687 119 230 4 | # 5 | # Author: Ahmadreza 6 | 7 | # This file includes the main function that reads the data, train the predictor RNNs for semi-supervised learning, evaluate the models, and save the models in the save directory. 8 | 9 | import tensorflow as tf 10 | import numpy as np 11 | import os 12 | from scipy.io import loadmat 13 | from sklearn.model_selection import train_test_split, KFold 14 | from sklearn.utils import shuffle 15 | import sys 16 | import json 17 | from utils import get_next_batch, read_lines, step_count 18 | from model_pred import Prediction 19 | import tensorflow.contrib.slim as slim 20 | 21 | sys.path.append(os.getcwd()) 22 | 23 | if __name__ == '__main__': 24 | epochs = 5000 # epoch size 25 | batch_size = 10 # batch size 26 | class_ratio = float(sys.argv[1]) # The ratio of data that classifier uses, the predictor ration is 1.0 - class_ratio 27 | num_RNN = 200 # number of RNN units 28 | num_classes = 6 # we have 6 terrain classes 29 | num_trials = 10 # the robot walked on each terrain 10 times 30 | num_steps = 8 # the robot walked 8 steps on each terrain 31 | num_diff_speeds = 6 # the robot walks on the terrains with 6 different speeds 32 | max_steps = 662 # the maximum T (time length) is obtained based on our data 33 | all_colms = 14 # this is based on number of all colms in the csv files 34 | relevant_colms = 10 # the IMU sensor dimension 35 | all_seq = num_classes * num_diff_speeds * num_trials * num_steps 36 | 37 | #for early stopping : 38 | best_cost = 1000000 39 | stop = False 40 | last_improvement = 0 41 | patience = 100 42 | 43 | all_data = np.zeros([all_seq, max_steps, all_colms]) 44 | data_steps_array = np.zeros([all_seq, max_steps, relevant_colms]) 45 | data_labels_array = np.zeros((all_seq, num_classes)) 46 | data_length_array = np.zeros((all_seq)) 47 | data_length_array = data_length_array.astype(int) 48 | 49 | CWD = os.getcwd() 50 | string = os.path.join(CWD, 'data') 51 | count = 0 52 | for i in range(num_classes): 53 | for j in range(1,7): # different speeds 54 | tmp_data = [] 55 | tmp_list = [] 56 | path = '{:s}/{:1d}_{:1d}_legSensors_imu.csv'.format(string,i,j) 57 | tmp_data = list(read_lines(path)) 58 | tmp_arr = np.array(tmp_data) 59 | step, tmp_list = step_count(tmp_arr, num_trials, num_steps) 60 | step = int(step) 61 | for k in range(num_trials): 62 | for l in range(num_steps): 63 | all_data[count,0:step,:] = tmp_list[k][l*step:(l+1)*step] 64 | data_labels_array[count,i] = 1.0 65 | data_length_array[count] = step 66 | count += 1 67 | data_steps_array = all_data[:,:,4:14] # to have last relevant data in csv files 68 | 69 | # Normalize data to have mean 0 and SD 1.0 70 | normed = np.zeros_like(data_steps_array) 71 | for i in range(data_steps_array.shape[0]): 72 | normed[i,0:data_length_array[i]] = (data_steps_array[i,0:data_length_array[i]] - data_steps_array[i,0:data_length_array[i]].mean(axis=0)) / data_steps_array[i,0:data_length_array[i]].std(axis=0) 73 | 74 | max_tmp = np.max(np.abs(normed), axis=0) # Extremum value 75 | max_mul = np.max(max_tmp, axis=0)/0.9 76 | ext = np.max(max_mul) # Enlarged extremum value 77 | 78 | # The train is used for unsupervised learning (next step prediction). The save is used later for classification models 79 | x_train1, x_saved, y_train1, y_saved, l_train1, l_saved = train_test_split(normed, data_labels_array, 80 | data_length_array, test_size = class_ratio, random_state = 47) 81 | x_train2 = np.zeros([int(x_train1.shape[0]), max_steps, relevant_colms]) 82 | y_train2 = np.zeros([int(x_train1.shape[0]), max_steps, relevant_colms]) 83 | l_train2 = np.zeros([int(x_train1.shape[0])]) 84 | 85 | # Prepare the prediction targets for one step prediction 86 | for i in range(x_train1.shape[0]): 87 | x_train2[i,0:data_length_array[i]-1] = x_train1[i,0:data_length_array[i]-1] 88 | y_train2[i,0:data_length_array[i]-1] = x_train1[i,1:data_length_array[i]] 89 | l_train2[i] = l_train1[i]-1 90 | 91 | x_train3, x_test, y_train3, y_test, l_train3, l_test = train_test_split(x_train2, y_train2, 92 | l_train2, test_size = 0.1, random_state = 47) 93 | 94 | x_train, x_valid, y_train, y_valid, l_train, l_valid = train_test_split(x_train3, y_train3, 95 | l_train3, test_size = 0.1, random_state = 47) 96 | 97 | data = tf.placeholder(tf.float32, [None, x_train.shape[1], x_train.shape[2]]) 98 | target = tf.placeholder(tf.float32, [None, x_train.shape[1], x_train.shape[2]]) 99 | length = tf.placeholder(tf.float32, [None]) 100 | learning_rate = tf.placeholder(tf.float32, shape=[]) 101 | 102 | model = Prediction(data, target, length, learning_rate, num_RNN, ext) 103 | 104 | # Save only one checkpoint 105 | saver = tf.train.Saver(max_to_keep=1) 106 | 107 | all_error = [] 108 | best_error = {'epoch':[], 'eval_acc':[], 'test_acc':[]} 109 | 110 | sess = tf.Session() 111 | sess.run(tf.global_variables_initializer()) 112 | 113 | string1 = os.path.join(CWD, 'save') 114 | num_tr_iter = int(len(y_train) / batch_size) 115 | error_file = '{:s}/error_predictor.txt'.format(string1) 116 | error_file_best = '{:s}/best_acc_predictor.txt'.format(string1) 117 | epoch = 0 118 | l_r = 0.001 119 | while epoch < epochs and stop == False: 120 | for iteration in range(num_tr_iter): 121 | start = iteration * batch_size 122 | end = (iteration + 1) * batch_size 123 | x_batch, y_batch, l_batch = get_next_batch(x_train, y_train, l_train, start, end) 124 | sess.run(model.optimize, {data: x_batch, target: y_batch, length: l_batch, learning_rate: l_r}) 125 | error = sess.run(model.error, {data: x_valid, target: y_valid, length: l_valid, learning_rate: l_r}) 126 | test_error = sess.run(model.error, {data: x_test, target: y_test, length: l_test, learning_rate: l_r}) 127 | if error < best_cost: 128 | path = '{:s}/model_Prediction.ckpt'.format(string1) 129 | saver.save(sess, path) 130 | last_improvement = 0 131 | best_cost = error 132 | best_error['epoch'] = str(epoch) 133 | best_error['eval_acc'] = str(1.0 - best_cost) 134 | best_error['test_acc'] = str(1.0 - test_error) 135 | file2 = open(error_file_best,"a+") 136 | file2.write(json.dumps(best_error)) 137 | file2.close() 138 | else: 139 | last_improvement += 1 140 | if last_improvement > patience: 141 | print("The patience is over") 142 | stop = True 143 | 144 | all_error.append(error) 145 | print('Epoch {:2d} validation accuracy {:3.4f}%'.format(epoch , 100 * (1.0-error))) 146 | print('Epoch {:2d} test accuracy {:3.4f}%'.format(epoch, 100 * (1.0-test_error))) 147 | print(50*'*') 148 | file1 = open(error_file,"a+") 149 | file1.writelines(str(all_error)) 150 | file1.close() 151 | epoch += 1 152 | 153 | 154 | -------------------------------------------------------------------------------- /semi_supervised/train_class.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 2 | # Commonwealth Scientific and Industrial Research Organisation (CSIRO) 3 | # ABN 41 687 119 230 4 | # 5 | # Author: Ahmadreza Ahmadi 6 | 7 | # This file includes the main function that reads the data, read the predictor RNNs parameters, train the classifier for semi-supervised learning, evaluate the models, and save the models in the save directory. 8 | 9 | import tensorflow as tf 10 | import numpy as np 11 | import os 12 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # preventing the "exceeds 10% of system memory." warning 13 | from scipy.io import loadmat 14 | from sklearn.model_selection import train_test_split, KFold 15 | from sklearn.utils import shuffle 16 | import sys 17 | import json 18 | from utils import get_next_batch, read_lines, step_count 19 | from model_class import Classification 20 | import tensorflow.contrib.slim as slim 21 | 22 | sys.path.append(os.getcwd()) 23 | 24 | if __name__ == '__main__': 25 | epochs = 5000 # epoch size 26 | batch_size = 10 # batch size 27 | class_ratio = float(sys.argv[2]) # The ratio of data that classifier uses, the predictor ration is 1.0 - class_ratio 28 | num_RNN = 200 # number of RNN units 29 | num_FCN = 100 # number of neurons in fully connected layer 30 | num_classes = 6 # we have 6 terrain classes 31 | num_trials = 10 # the robot walked on each terrain 10 times 32 | num_steps = 8 # the robot walked 8 steps on each terrain 33 | num_diff_speeds = 6 # the robot walks on the terrains with 6 different speeds 34 | max_steps = 662 # the maximum T (time length) is obtained based on our data 35 | all_colms = 14 # this is based on number of all colms in the csv files 36 | relevant_colms = 10 # the IMU sensor dimension 37 | all_seq = num_classes * num_diff_speeds * num_trials * num_steps 38 | n_split = 2 # The k in k-fold cross-validation 39 | 40 | #for early stopping : 41 | best_cost = 1000000 42 | stop = False 43 | last_improvement = 0 44 | patience = 100 45 | 46 | all_data = np.zeros([all_seq, max_steps, all_colms]) 47 | data_steps_array = np.zeros([all_seq, max_steps, relevant_colms]) 48 | data_labels_array = np.zeros((all_seq, num_classes)) 49 | data_length_array = np.zeros((all_seq)) 50 | data_length_array = data_length_array.astype(int) 51 | 52 | CWD = os.getcwd() 53 | string = os.path.join(CWD, 'data') 54 | count = 0 55 | for i in range(num_classes): 56 | for j in range(1,7): # different speeds 57 | tmp_data = [] 58 | tmp_list = [] 59 | path = '{:s}/{:1d}_{:1d}_legSensors_imu.csv'.format(string,i,j) 60 | tmp_data = list(read_lines(path)) 61 | tmp_arr = np.array(tmp_data) 62 | step, tmp_list = step_count(tmp_arr, num_trials, num_steps) 63 | step = int(step) 64 | for k in range(num_trials): 65 | for l in range(num_steps): 66 | all_data[count,0:step,:] = tmp_list[k][l*step:(l+1)*step] 67 | data_labels_array[count,i] = 1.0 68 | data_length_array[count] = step 69 | count += 1 70 | data_steps_array = all_data[:,:,4:14] # to have last relevant data in csv files 71 | 72 | # Normalize data to have mean 0 and SD 1.0 73 | normed = np.zeros_like(data_steps_array) 74 | for i in range(data_steps_array.shape[0]): 75 | normed[i,0:data_length_array[i]] = (data_steps_array[i,0:data_length_array[i]] - data_steps_array[i,0:data_length_array[i]].mean(axis=0)) / data_steps_array[i,0:data_length_array[i]].std(axis=0) 76 | 77 | x_train1, x_saved, y_train1, y_saved, l_train1, l_saved = train_test_split(normed, data_labels_array, 78 | data_length_array, test_size = class_ratio, random_state = 47) 79 | arg_index = int(sys.argv[1]) 80 | train_index = [] 81 | test_index = [] 82 | for train_ind,test_ind in KFold(n_split, random_state=47).split(x_saved): 83 | train_index.append(train_ind) 84 | test_index.append(test_ind) 85 | x_train,x_test=x_saved[train_index[arg_index]],x_saved[test_index[arg_index]] 86 | y_train,y_test=y_saved[train_index[arg_index]],y_saved[test_index[arg_index]] 87 | l_train,l_test=l_saved[train_index[arg_index]],l_saved[test_index[arg_index]] 88 | 89 | data = tf.placeholder(tf.float32, [None, normed.shape[1], normed.shape[2]]) 90 | target = tf.placeholder(tf.float32, [None, num_classes]) 91 | length = tf.placeholder(tf.float32, [None]) 92 | learning_rate = tf.placeholder(tf.float32, shape=[]) 93 | stage = tf.placeholder(tf.int32, shape=[]) 94 | 95 | model = Classification(data, target, length, learning_rate, stage, num_RNN, num_FCN) 96 | 97 | # Save only one checkpoint 98 | saver = tf.train.Saver(max_to_keep=1) 99 | 100 | all_error = [] 101 | best_error = {'epoch':[], 'val_acc':[], 'test_acc':[]} 102 | 103 | sess = tf.Session() 104 | sess.run(tf.global_variables_initializer()) 105 | 106 | # Freezing first layer RNN weights from prediction task for the classification task 107 | string1 = os.path.join(CWD, 'save') 108 | variables = slim.get_variables_to_restore() 109 | variables_to_restore = [v for v in variables if v.name.split('/')[0]=='rnn' and v.name.split('/')[2]=='cell_0'] 110 | model_path = '{:s}/model_Prediction.ckpt'.format(string1) 111 | saver_pred = tf.train.Saver(variables_to_restore) 112 | saver_pred.restore(sess, model_path) 113 | 114 | num_tr_iter = int(len(y_train) / batch_size) 115 | error_file = '{:s}/error_classifier{:1d}.txt'.format(string1, arg_index) 116 | error_file_best = '{:s}/best_acc_classifier{:1d}.txt'.format(string1, arg_index) 117 | epoch = 0 118 | curr_stage = 0 119 | l_r = 0.001 120 | while epoch < epochs and stop == False: 121 | for iteration in range(num_tr_iter): 122 | start = iteration * batch_size 123 | end = (iteration + 1) * batch_size 124 | x_batch, y_batch, l_batch = get_next_batch(x_train, y_train, l_train, start, end) 125 | sess.run(model.optimize, {data: x_batch, target: y_batch, length: l_batch, learning_rate: l_r, stage: curr_stage}) 126 | error = sess.run(model.error, {data: x_test, target: y_test, length: l_test, learning_rate: l_r, stage: curr_stage}) 127 | if error < best_cost: 128 | test_error= sess.run(model.error, {data: x_train1, target: y_train1, length: l_train1, learning_rate: l_r, stage: curr_stage}) 129 | path = '{:s}/model_CV_{:1d}.ckpt'.format(string1, arg_index) 130 | saver.save(sess, path) 131 | last_improvement = 0 132 | best_cost = error 133 | best_error['epoch'] = str(epoch) 134 | best_error['val_acc'] = str(1.0 - best_cost) 135 | best_error['test_acc'] = str(1.0 - test_error) 136 | file2 = open(error_file_best,"a+") 137 | file2.write(json.dumps(best_error)) 138 | file2.close() 139 | else: 140 | last_improvement += 1 141 | if last_improvement > patience: 142 | if curr_stage == 0: 143 | print('The current learning stage is: {:1d}'.format(curr_stage)) 144 | print(30*'*', 'The stage is changing from Feature Extraction to Feature Extraction+Fine Tuning ', 30*'*') 145 | variables_class = slim.get_variables_to_restore() 146 | model_path = '{:s}/model_CV_{:1d}.ckpt'.format(string1, arg_index) 147 | saver_class = tf.train.Saver(variables_class) 148 | saver_class.restore(sess, model_path) 149 | l_r = 0.00001 150 | curr_stage += 1 151 | last_improvement = 0 152 | else: 153 | print('The current learning stage is: {:1d}'.format(curr_stage)) 154 | print("The patience is over") 155 | stop = True 156 | 157 | all_error.append(error) 158 | print("fold number %d:" %arg_index) 159 | print('Epoch {:2d} validation accuracy {:3.4f}%'.format(epoch, 100 * (1.0-error))) 160 | print('Epoch {:2d} test accuracy {:3.4f}%'.format(epoch, 100 * (1.0-test_error))) 161 | print(50*'*') 162 | file1 = open(error_file,"a+") 163 | file1.writelines(str(all_error)) 164 | file1.close() 165 | epoch += 1 166 | 167 | 168 | --------------------------------------------------------------------------------