Neuronové sítě II.

V minulém díle jsme si ukázali, jak funguje nejjednodušší neuronová síť. Měli jsme jeden vstupní neuron a jeden výstupní neuron, vstup jsme označili \(i\), chtěný výstup \(y\) a výstup spočítaný neuronovou sítí \(a\). Neuronová síť k výpočtu potřebuje ještě proměnnou jménem váha, kterou jsme označili \(w\), a spočte výstup jako \(a = wi\).

Zatajili jsme ale, že existuje ještě jeden parametr neuronu, a to tzv. bias. Označme si jej \(b\). Potom neuronová síť počítá výstup jako \(a = wi+b\). Pokud nastavíme váhu \(w = 1\), pak je výstup \(a = i+b\) neboli ke vstupu se jen přičítá nějaké číslo. Můžeme tedy naučit neuronovou síť sčítat! (Nebojte, k zajímavějším příkladům se pomalu blížíme).

Mějme stejnou síť jako v minulém článku

Nastavme tentokrát váhu \(w = 1\) a náhodně si vygenerujme bias, dostáváme \(b = 0.7\). Nyní budeme chtít neuronovou síť naučit, že bias má být \(1\). Mějme vstup \(i = 10\) a chtěný výstup \(y = 11\).

Jako první nám neuronová síť spočte výstup \(a = 10 \cdot 1+0.7 = 10.7\). Výstup je funkcí jen biasu, neboť váhu necháme fixní, tedy \(a(b) = wi+b = i+b\). Chybovou funkci budeme mít pořád stejnou, tedy \(C(a) = (a-y)^2\), v našem případě vyjde \(C(10.7) = (10.7-11)^2 = 0.09\).

Chceme vědět, jak moc se chybová funkce mění, když trochu změníme bias, musíme tedy chybovou funkci zderivovat podle biasu. Dostáváme \(\frac{\mathbb d C}{\mathbb d b} = \frac{\mathbb d C}{\mathbb d a} \cdot \frac{\mathbb d a}{\mathbb d b} = 2(a-y) \cdot 1 = 2(a-y)\). Pro naše hodnoty vychází \(\frac{\mathbb d C}{\mathbb d b} = 2(10.7-11) = -0.6\). To znamená, že směrnice tečny k chybové funkci je záporná a my musíme zvýšit náš bias

Zvolme učící koeficient např. \(r = 0.1\), potom nový bias bude \(b_1 = b+r\frac{\mathbb d C}{\mathbb d b} = 0.7-0.1 \cdot (-0.6) = 0.76\)

Vidíme, že jsme se přiblížili jedničce. Opakováním tohoto postupu bychom se rychle dostali velice blízko jedničce.

\(3i+2\)

Nyní zkusme naučit neuronovou síť vynásobit vstup trojkou a přičíst k němu dvojku. Tedy budeme chtít mít \(a = 3i+2\). Musíme tedy upravovat dvě hodnoty v předpisu \(a = wi+b\), neboť spočítaný výstup je tentokrát funkcí dvou proměnných, konkrétně váhy \(w\) a biasu \(b\).

K tomu si ale nejprve budeme muset říct něco o parciálních derivacích.

Funkce více proměnných a parciální derivace

Funkce obecně nemusí mít jen jeden vstup a jeden výstup, ale libovolný počet vstupů a výstupů. My se omezíme na příklad, kdy má více vstupů, ale jen jeden výstup. Takovou funkcí může být \(f(x,y) = x+y\), která si vezme dvojici čísel a vrátí nám jejich součet.

Nyní nás bude zajímat, jak moc se změní výstup funkce, když trochu změníme jen jeden ze vstupů, např. \(x\). V takovém případě ponecháme \(y\) jako konstantu a na funkci \(f(x,y)\) hledíme jako na funkci jedné proměnné. Neznačíme ale \(\frac{\mathbb d f}{\mathbb d x}\), nýbrž \(\frac{\partial f}{\partial x}\). Máme tedy zderivovat funkci \(x+y\) podle proměnné \(x\), tedy na \(y\) hledíme jako na konstantu. Dostáváme \(\frac{\partial f}{\partial x} = \frac{\partial (x+y)}{\partial x} = 1\).

Vidíme, že parciálně zderivovat funkci je stejně jednoduché jako normálně zderivovat funkci. Všechny proměnné, podle kterých nederivujeme, považujeme za konstanty a zderivujeme funkci jako funkci jen jedné proměnné.

Zpět k příkladu, ale síť se nechová přesně, jak chceme

V našem případě jsme měli \(a(w, b) = wi+b\) a \(C(a) = (a-y)^2\). Vygenerujme si náhodně bias a váhu: \(b = 4, w = 1\). Potom nám pro vstup \(i = 5\) vyjde \(a(1,4) = 1 \cdot 5 + 4 = 9\). My bychom ale chtěli výstup vynásobený trojkou a k němu mít přičteno dva, tedy \(y = 3 \cdot 5 + 2 = 17\). Musíme tedy upravit váhu a bias.

Zajímá nás tedy \(\frac{\partial C}{\partial w}\) a \(\frac{\partial C}{\partial b}\). Chain rule v tomto případě funguje úplně stejně jako u funkce jedné proměnné, dostáváme \(\frac{\partial C}{\partial w} = \frac{\partial C}{\partial a} \frac{\partial a}{\partial w}\) a \(\frac{\partial C}{\partial b} = \frac{\partial C}{\partial a} \frac{\partial a}{\partial b}\).

Každou z těchto částí zderivujeme jednoduše:
\(\frac{\partial C}{\partial a} = 2(a-y)\)
\(\frac{\partial a}{\partial w} = i\)
\(\frac{\partial a}{\partial b} = 1\)

Dohromady tedy máme
\(\frac{\partial C}{\partial w} = \frac{\partial C}{\partial a} \frac{\partial a}{\partial w} = 2(a-y)i\)

\(\frac{\partial C}{\partial b} = \frac{\partial C}{\partial a} \frac{\partial a}{\partial b} = 2(a-y)\)

Pro \(a = 9, y = 17, i = 5\) dostáváme \(\frac{\partial C}{\partial w} = -80\) a \(\frac{\partial C}{\partial b} = -16\)

Musíme tedy váhu i bias zvýšit, zvolme učící koeficient \(r = 0.01\), potom \(w_1 = w \ – \ r \frac{\partial C}{\partial w} = 1-0.01 \cdot (-80) = 1.8\) a
\(b_1 = b-r \frac{\partial C}{\partial b} = 4-0.01 \cdot (-16) = 4.16\) . Odtud spočteme \(a = w_1i+b_1 = 1.8 \cdot 5 + 4.16 = 13.16\)

S těmito hodnotami opět spočítáme parciální derivace a dostáváme

\(\frac{\partial C}{\partial w} = 2(13.16-17)5 = -38.4\) a \(\frac{\partial C}{\partial b} = 2(13.16-17) = -7.68\).

Opět tedy zvýšíme váhu a bias a dostaneme \(w_2 = 2.184, b_2 = 4.237\). Pokračujeme-li takto dále a dále, dostaneme po \(11\) iteracích \(w = 2.538, b = 4.308\). S těmito čísly nám neuronová síť spočte \(5w+b = 5 \cdot 2.538+4.308 = 16.998\). To je opravdu velmi blízko číslu \(17\). ALE POČKAT. To ještě neznamená, že naše síť obecně násobí trojkou a přičítá dvojku. Momentálně násobí číslem \(2.538\) a přičítá k tomu \(4.308\), takže např. pro číslo \(10\) nedostaneme \(3 \cdot 10 +2 = 32\), ale \(2.538 \cdot 10+4.308 = 29.688\).

Znovu a lépe

Musíme tedy trochu upravit svůj přístup.

V první řadě potřebujeme více čísel, na kterých budeme učit naši síť. Mějme \(i_1 = 5, y_1 = 17\), potom \(i_2 = 10, y_2 = 32\) a \(i_3 = 3, y_3 = 11\). Budeme postupovat tak, že upravíme váhu a bias pomocí \(i_1, y_1\) stejně jako v minulém případě, hned na to pomocí \(i_2, y_2\) a konečně podle \(i_3, y_3\).


Máme tedy opět bias rovný \(4\) a váhu rovnou \(1\). Na vstup \(i_1 = 5\) dostáváme \(a = 5 \cdot 1 + 4 = 9\). Pro tato čísla jsme již spočetli novou váhu a bias a vyšlo nám, že nová váha je \(w = 1.8\) a bias \(b= 4.16\).

Nyní použijeme tuto váhu a tento bias spolu s \(i_2, y_2\). Pro \(i_2 = 10\) dostaneme \(a = 1.8 \cdot 10 + 4.16 = 22.16\).

Chybová funkce bude \(C = (22.16-32)^2 = 96.8256\). Opět ji chceme minimalizovat, takže provedeme úplně stejné výpočty, tedy

\(\frac{\partial C}{\partial w} = \frac{\partial C}{\partial a} \frac{\partial a}{\partial w} = 2(a-y_2)i_2 = 2 \cdot (22.16-32) \cdot 10 = -196.8\)

\(\frac{\partial C}{\partial b} = \frac{\partial C}{\partial a} \frac{\partial a}{\partial b} = 2(a-y_2) = 2 \cdot (22.16-32) = -19.68\)

Nová váha tedy bude \(w = 1.8-0.01 \cdot (-188) = 3.768\) a bias \(b = 4.16-0.01 \cdot (-19.68) = 4.3568\).

Tuto váhu a bias použijeme spolu s \(i_3, y_3\), opět stejným způsobem dostaneme novou váhu a bias, tu použijeme společně s \(i_1, y_1\) a tak dále a tak dále.

b = 4               #bias
w = 1               #váha

i_1 = 5             #první input
y_1 = 17            #output chtěný na první input

i_2 = 10            #druhý input
y_2 = 32            #output chtěný na druhý input

i_3 = 3             #třetí input
y_3 = 11            #output chtěný na třetí input

r = 0.01            #učící koeficient


def del_c_w(a, i, y):   #funkce na výpočet parciální derivace podle váhy
    return 2*(a-y)*i

def del_c_b(a,y ):      #funkce na výpočet parciální derivace podle biasu
    return 2*(a-y)

def a(i):               #funcke na výpočet toho, co nám vrací neuronová síť
    return w*i+b

def new_weight(w, i, y):                    #funkce na výpočet nové váhy
    return w - r*del_c_w(a(i),i, y)

def new_bias(b, i, y):                      #funkce na výpočet nového biasu
    return b - r*del_c_b(a(i), y)


for j in range(1,150):
    print("5->17")
    w, b = new_weight(w, i_1,y_1), new_bias(b, i_1, y_1)        #aktualizujeme váhu a bias podle prvního inputu a outputu
    print(w, b)

    print()

    print("10->32")
    w, b = new_weight(w, i_2, y_2), new_bias(b, i_2, y_2)   #aktualizujeme váhu a bias podle druhého inputu a outputu
    print(w, b)
    print()

    print("3->11")
    w, b = new_weight(w, i_3, y_3), new_bias(b, i_3, y_3)   #aktualizujeme váhu a bias podle třetího inputu a outputu
    print(w, b)
    print()

Po tolika opakováních máme již velmi přesný výsledek, váha vychází \(2.98\) a bias vychází \(2.18\).

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *