Ako si vytvoriť prvý model neurónovej siete

tréningová, testovacia a validačná fáza

Blog Admin

V našom prvom modeli/programe neurónovej siete budeme riešiť jednoduchú úlohu. Predstavme si, že chceme definovať akúsi zvláštnu operáciu s výrokmi podobnú konjunkcii AND alebo alternatíve OR. Na vstupe budú 3 výroky, resp. ich pravdivostné hodnoty 0 - výrok neplatí, 1 - výrok platí. Na výstupe bude výsledok tejto ternárnej operácie. Táto zvláštna ternárna operácia je daná nasledujúcou tabuľkou:

ternárna operácia

Už pri prvom pohľade na tabuľku nás zrejme napadne, že výsledok ternárnej operácie závisí len od pravdivostnej hodnoty v prvom stĺpci. Preto odpoveď neurónovej siete na nový situáciu by mala byť blízka 1. Prečo nie 1, ale blízka 1? Je to preto, lebo v konštrukcii neurónovej siete použijeme okrem input vrstvy a ouput vrstvy aj aktivačnú funkciu, v tomto prípade to bude známy sigmoid (logistická aktivačná funkcia). Existuje množstvo iných aktivačných funkcií napr. tanh, ReLu, f(x)=x, .... . Všetky tieto funkcie zobrazujú reálne čísla alebo nejaký interval reálnych čisiel obyčajne do nejakého vhodného intervalu reálnych čísiel, častokrát do intervalu <0,1>, čo sa hodí, keď chceme niečo vyjadrovať pravdepodobnosťami. A teda tu máme odpoveď na vyššie položenú otázku, totiž odpoveď neurónovej siete bude pravdepodobnosť, čím sa vyjadrí istý stupeň neurčitosti, ktorý pri neurónových sieťach existuje veľmi často (aj vzhľadom na nepresnosti v aritmetike programovacích jazykov). Keby bola odpoveď na všetko presne 1 alebo 0, tak sa jedná o jav istý, resp. nemožný a deterministickú úlohu, kde sa hľadá funkcia, ktorá zobrazí vstupy presne na výstupy. Taká funkcia by sa dala nájsť snáď aj bez neurónovej siete. Aj tu, v tomto príklade, vieme takú funkciu nájsť aj bez neurónovej siete. Žijeme však v stochastickom svete a preto sa zvykneme vyjadrovať v pravdepodobnostiach. Pre hlbšie pochopenie si predstavme, že máme 1 milión farebných a 1 milión takých istých ale čiernobielych fotografií. Našou úlohou je zafarbiť ľubovoľnú čiernobielu fotku spred 100 rokov. Tu by bol ľudský mozog bezradný, lebo sa jedná o obrovské množstvo premenných, kde nám robí problém už len ten obrovský počet fotiek a nehovoriac o tom, že každá fotka pozostáva z 10-tok až 100-viek tisíc pixelov, pričom okrem x-ovej a y-ovej súradnice pixelu treba zobrať v úvahu ešte pri farebnej fotke kombináciu RGB (tu je skrytá farba pixelu, napr. [255, 0, 0] je farba červená) a pri čiernobielej fotke stupeň šede (vyjadruje sa od 0 po 255). Na vyriešenie takýchto úloh je práve dobrá neurónová sieť. Opäť sa ukázalo, že ľudský mozog nemá limity. Zistil, že pri takejto úlohe by zlyhal a preto vymyslel neurónové siete.

Tu je prehľad základných aktivačných funkcií s grafmi a deriváciami:

aktivačné funkcie

Program v jazyku python 3.x obsahuje definíciu triedy NeuralNetwork(), ktorá má metódu na generovanie náhodných váh z intervalu od -1 po 1 do vstupnej matice 3x1, metódu na definíciu sigmoidu a jeho derivácie a metódu train, ktorá obsahuje aj úpravu váh v smere najväčšieho spádu (preto je potrebná derivácia sigmoidu) na základe výpočtu chýb určených ako odchýlka vypočítaných outputov s aktuálnymi váhami a skutočných ouputov (error = training_set_outputs - output). Metóda train má medzi parametrami aj počet iterácií, ktoré v našom prípade ukončujú celý iteračný proces a za optimálne váhy sa pokladajú váhy, kedy bola stratová alebo chybová funkcia najmenšia v priebehu celého iteračného procesu. Kód programu main.py, ktorý nevyužíva tensorflow, je zobrazený nižšie a je ho možné jednak spustiť na vašom počítači ale aj tu na blogu pomocou buttonu Spustiť skript, ktorý je dole pod kódom. Spustenie skriptu v pythone nebýva obvyklé na blogoch a dokonca ani nie na weboch :). Výsledky vo vašom počítači sa môžu odlišovať hlavne čo sa týka štartovacích váh, keďže sa generujú pomocou funkcie random bez seed. Avšak optimálne váhy po tréningu a výsledná pravdepodobnosť by sa mala líšiť len minimálne.

Čítajte aj Pohľad do hĺbky neurónovej siete, Operácia XOR a ekvivalencia

Zdrojový kód v jazyku Python 3.x

# main.py for python 3.x

from numpy import exp, array, random, dot

class NeuralNetwork():
    def __init__(self):
        # Seed the random number generator, so it generates the same numbers
        # every time the program runs.
        # random.seed(1)

        # We model a single neuron, with 3 input connections and 1 output connection.
        # We assign random weights to a 3 x 1 matrix, with values in the range -1 to 1
        # and mean 0.
        self.synaptic_weights = 2 * random.random((3, 1)) - 1

    # The Sigmoid function, which describes an S shaped curve.
    # We pass the weighted sum of the inputs through this function to
    # normalise them between 0 and 1.
    def __sigmoid(self, x):
        return 1 / (1 + exp(-x))

    # The derivative of the Sigmoid function.
    # This is the gradient of the Sigmoid curve.
    # It indicates how confident we are about the existing weight.
    def __sigmoid_derivative(self, x):
        return x * (1 - x)

    # We train the neural network through a process of trial and error.
    # Adjusting the synaptic weights each time.
    def train(self, training_set_inputs, training_set_outputs, number_of_training_iterations):
        for iteration in range(number_of_training_iterations):
            # Pass the training set through our neural network (a single neuron).
            output = self.think(training_set_inputs)

            # Calculate the error (The difference between the desired output
            # and the predicted output).
            error = training_set_outputs - output

            # Multiply the error by the input and again by the gradient of the Sigmoid curve.
            # This means less confident weights are adjusted more.
            # This means inputs, which are zero, do not cause changes to the weights.
            adjustment = dot(training_set_inputs.T, error * self.__sigmoid_derivative(output))

            # Adjust the weights.
            self.synaptic_weights += adjustment

    # The neural network thinks.
    def think(self, inputs):
        # Pass inputs through our neural network (our single neuron).
        return self.__sigmoid(dot(inputs, self.synaptic_weights))

if __name__ == "__main__":

    #Intialise a single neuron neural network.
    neural_network = NeuralNetwork()
    print ("Starting weights can be different, because we generate them via random function !!!")
    print ("<br>")
    print ("Random starting weights: ")
    print("<br>")
    print (neural_network.synaptic_weights)

    # The training set. We have 4 examples, each consisting of 3 input values
    # and 1 output value.
    training_set_inputs = array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
    training_set_outputs = array([[0, 1, 1, 0]]).T

    # Train the neural network using a training set.
    # Do it 10,000 times and make small adjustments each time.
    neural_network.train(training_set_inputs, training_set_outputs, 10000)
    print("<br>")
    print ("Optimal weights after training: ")
    print("<br>")
    print (neural_network.synaptic_weights)
    print("<br>") 

    # Test the neural network with a new situation.
    print ("<b>Considering new situation [1, 0, 0] -> ")
    print (neural_network.think(array([1, 0, 0])))
    print ("</b><br>")

Autor príspevku: F. Gachulinec Dr., PhD.

Tágy:
Tensorflow neurónová sieť deep learning