Kolejny projekt związany z machine learning. Trening z nauczycielem sieci neuronowej zdefiniowanej przy użyciu Google’owej biblioteki TensorFlow. Dane do uczenia sieci to dane zbioru MNIST zawierającego ręcznie pisane cyfry wraz z ich etykietami. W sieci znajdziecie mnóstwo podobnych przykładów jak zdefiniować i rozwiązać problem rozpoznawania znaków MNIST z użyciem TensorFlow. Ale moim celem było coś innego niż kolejne rozwiązanie tego zadania, mianowicie chciałem stworzyć w miarę ogólną klasę obiektu sieci neuronowej do szerszego zastosowania. Definicja klasy znajduje się w pliku nn.py, sam program i uruchomienie dla przykładowych danych (w tym wypadku MNIST) w pliku run.py. Do utworzenia klasy, podaje się jako parametr, listę zawierającą ilość węzłów w każdej z warstw sieci przy czym pierwszy element na liście definiuje ilość węzłów warstwy wejściowej a ostatni dla warstwy wyjściowej. Na tej podstawie konstruktor klasy (nie programuję od ponad 20 lat więc proszę o wyrozumiałość wobec mojej terminologii i kodu :)) tworzy model sieci przy użyciu TensorFlow. Pozostałe metody klasy to:
train(X,Y) – uczy sieć przekazaną paczką danych,
test(X,Y) – testuje sieć i wylicza dokładność na podstawie testowej paczki danych
info() – zwraca string z informacją na temat zdefiniowanego obiektu klasy
ask(X) – zwraca odpowiedź sieci dla wektora wejściowego X.
Szukamy rozkładu prawdopodobieństwa przynależności wektora danych wejściowych do jednej z 10 wykluczających się klas (cyfr), dlatego do wyliczenia wartości błędu wyjścia z sieci neuronowej użyta została funkcja softmax. Do oceny trafności sieci, obliczamy średnią błędów wyjścia przypisanego dla każdej z tych klas i następnie przeprowadzamy jej minimalizację. Do minimalizacji użyty został algorytm AdamOptimizer z wartością learningrate ustawioną na 0.005, która definiuje szybkości i zbieżność procesu minimalizacji tak zdefiniowanego błędu.
self.cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=self.Ylogits, labels=self.Ylabels)) self.train_step = tf.train.AdamOptimizer(0.005).minimize(self.cross_entropy)
Całość definicji klasy:
import tensorflow as tf import numpy as np # class to represent the Neural Network model class NN: # build model of nn, layers define number of nodes in each layer # first element of layers is numer of nodes in input layer # last element of layers is numer of nodes in output layer def __init__(self, layers): self.sess = tf.Session() self.inLayer = layers.pop(0) self.outLayer = layers.pop(-1) self.hiddenLayers = layers #number of hidden layers self.nH = len(self.hiddenLayers) self.learning_rate = 0.005 self.W = [0] * (self.nH+1) self.B = [0] * (self.nH+1) # output for each layers self.Y = [0] * (self.nH) self.Ylogits = [0] * (self.outLayer) # vector of input data self.X = tf.placeholder(tf.float32, [None, self.inLayer]) # vector of labels self.Ylabels = tf.placeholder(tf.float32, [None, self.outLayer]) # define model for input layer self.W[0] = tf.Variable(tf.truncated_normal([self.inLayer, self.hiddenLayers[0]], stddev=0.1)) self.B[0] = tf.Variable(tf.zeros([self.hiddenLayers[0]])) self.Y[0] = tf.nn.sigmoid(tf.matmul(self.X, self.W[0]) + self.B[0]) # iterate through the rest of layers for idx, val in enumerate(self.hiddenLayers): # define model for output layer if idx+1 == self.nH: self.W[idx+1] = tf.Variable(tf.truncated_normal([val, self.outLayer], stddev=0.1)) self.B[idx+1] = tf.Variable(tf.zeros(self.outLayer)) self.Ylogits = tf.matmul(self.Y[idx], self.W[idx+1]) + self.B[idx+1] break # define model for hidden layer self.W[idx+1] = tf.Variable(tf.truncated_normal([val, self.hiddenLayers[idx+1]], stddev=0.1)) self.B[idx+1] = tf.Variable(tf.zeros(self.hiddenLayers[idx+1])) self.Y[idx+1] = tf.nn.sigmoid(tf.matmul(self.Y[idx], self.W[idx+1]) + self.B[idx+1]) self.cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=self.Ylogits, labels=self.Ylabels)) self.train_step = tf.train.AdamOptimizer(0.005).minimize(self.cross_entropy) self.sess = tf.InteractiveSession() tf.global_variables_initializer().run() #return string with info about nn def info(self): info = "This is neural network object with nodes in layers\n" info += "Input layer: {} nodes\n".format(self.inLayer) for idx, val in enumerate(self.hiddenLayers): info += "Hidden layer [{}]: {} nodes\n".format(idx+1, val) info += "Output layer: {} nodes\n".format(self.outLayer) return info # train nn with batch of data def train(self, batchX, batchY): if np.shape(batchX)[1] != self.inLayer: print ("Rows of X must be {} element vectors".format(self.inLayer)) return if np.shape(batchY)[1] != self.outLayer: print ("Rows of Y must be {} element vectors".format(self.outLayer)) return return self.sess.run(self.train_step, feed_dict={self.X: batchX, self.Ylabels: batchY}) # test nn with testset, return accuracy def test(self,testX,testY): self.correct_prediction = tf.equal(tf.argmax(self.Ylogits,1), tf.argmax(self.Ylabels,1)) self.accuracy = tf.reduce_mean(tf.cast(self.correct_prediction, tf.float32)) return self.sess.run(self.accuracy, feed_dict={self.X: testX, self.Ylabels: testY}) def ask(self,askX): return self.sess.run(self.Ylogits, feed_dict={self.X: askX}) def __del__(self): self.sess.close()
W dalszym planie użycie klasy nn.py do danych obrazów CIFAR
Strona GitHub projektu: https://github.com/majchernet/mnist-with-neural-network-class