
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





