Skip to content

Sieci neuronowe – definicja klasy i modelu z użyciem TensorFlow

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

 

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *