Neuroevolúcia: evolúcia váh aj tvaru neurónových sietí a algoritmus NEAT
Neurón a sieť v kocke, evolúcia regulátora pre kyvadlo na vozíku, prečo evolúcia namiesto gradientu, XOR a skryté neuróny, NEAT s historickými značkami a speciáciou, čo sa stane bez speciácie a nasledovníci od HyperNEAT po AmoebaNet.
Séria Základy AI Diel 31 z 52
- Mapa umelej inteligencie: čo je čo a ako to do seba zapadá
- Stručná história umelej inteligencie: od Turinga po jazykové modely
- Dáta, model, tréning, inferencia: základné pojmy na jednom príklade
- Ako čítať matematický zápis: symboly, indexy, sumy a kvantifikátory
- Množiny a relácie: stavebnica, z ktorej sa skladajú definície v AI
- Funkcie a zobrazenia: prečo je každý model v AI funkcia
- Logika a dôkazy: pravidlá, podľa ktorých sa v AI uvažuje
- Grafy a stromy: štruktúra, na ktorej stojí hľadanie aj neurónové siete
- Lineárna algebra pre strojové učenie: vektory, matice a prečo AI hlavne násobí
- Derivácie, gradient a reťazové pravidlo: ako model zistí, ktorým smerom sa učiť
- Gradientný zostup: ako sa model učí
- Čo je pravdepodobnosť: od hodu kockou ku Kolmogorovovým axiómam
- Podmienená pravdepodobnosť a Bayesova veta: ako zmeniť odhad, keď sa dozviete niečo nové
- Náhodná premenná a distribučná funkcia: jedna funkcia, ktorá o rozdelení povie všetko
- Funkcia hustoty a pravdepodobnostná funkcia: prečo má spojitá premenná v bode pravdepodobnosť nula
- Stredná hodnota, rozptyl a kovariancia: kde rozdelenie leží, aké je široké a čo s čím súvisí
- Prehľad pravdepodobnostných rozdelení: Bernoulliho, binomické, Poissonovo, rovnomerné, normálne a exponenciálne
- Zákon veľkých čísel a centrálna limitná veta: prečo sa priemery správajú tak predvídateľne
- Štatistika a odhady parametrov: maximálna vierohodnosť, MAP a intervaly spoľahlivosti
- Teória informácie: entropia, krížová entropia a KL divergencia — odkiaľ sa berú stratové funkcie
- Prehľadávanie stavového priestoru: BFS, DFS, UCS a A* s animáciami
- Hry a protivník: minimax, alfa-beta orezávanie a Monte Carlo tree search
- Splňovanie obmedzujúcich podmienok: backtracking, propagácia obmedzení a AC-3 na sudoku a mape krajov
- Logika a znalostné systémy: dopredné a spätné reťazenie, rezolúcia a expertné systémy
- Plánovanie: STRIPS, svet kociek, heuristiky z relaxácie a plánovanie v AI agentoch
- Lokálne hľadanie a simulované žíhanie: obchodný cestujúci cez krajské mestá
- Genetické algoritmy: populácia, kríženie, mutácia a výber na batohu na výlet
- Evolučné stratégie a genetické programovanie: od pravidla jednej pätiny po Keplerov zákon
- Optimalizácia mravčou kolóniou: ako feromónová stopa nájde krátku cestu
- Optimalizácia rojom častíc: zotrvačnosť, vlastná skúsenosť a skúsenosť roja
- Neuroevolúcia: evolúcia váh aj tvaru neurónových sietí a algoritmus NEAT
- Fuzzy množiny a funkcie príslušnosti: ako zapísať „trochu teplo“
- Fuzzy logika a pravdepodobnosť: prečo „trochu teplo“ neznamená „pravdepodobne teplo“
- Fuzzy logika: t-normy, implikácie a pravidlá AK–TAK
- Fuzzy riadenie: Mamdani a Sugeno od ventilátora po kyvadlo na vozíku
- Fuzzy zhlukovanie: algoritmus fuzzy c-means a body medzi zhlukmi
- Neuro-fuzzy systémy (ANFIS): fuzzy pravidlá, ktoré sa učia z dát
- Markovove reťazce: prechodová matica, stacionárne rozdelenie a PageRank
- Skryté Markovove modely: Viterbiho algoritmus a nepoctivé kasíno
- Bayesovské siete: prečo je tráva mokrá a čo z toho vyplýva pre postrekovač
- Kalmanov filter: ako z nepresných meraní odhadnúť, kde auto je a ako rýchlo ide
- Druhy strojového učenia: s učiteľom, bez učiteľa, s čiastočným učiteľom a ďalšie
- Prompty, kontext a RAG: ako modelu dať správne informácie
- Variačné autoenkodéry (VAE): nové obrázky zo spojitého latentného priestoru
- Generatívne adversariálne siete (GAN): falšovateľ proti detektívovi
- Difúzne modely: ako sa z čistého šumu stane obrázok
- Markovove rozhodovacie procesy: stavy, akcie, odmeny a Bellmanove rovnice
- Q-learning a DQN: učenie hodnoty akcií od tabuľky po neurónovú sieť
- Policy gradient a PPO: učenie priamo stratégie
- Ako funguje AI agent: jazykový model v slučke s nástrojmi
- Programovanie s AI agentmi: zadanie, testy a kontrola
- Vyhodnocovanie a bezpečnosť AI systémov: ako merať a ako strážiť
Celá osnova série Hotovo: 52 z 83 tém
- Ako evolúcia nájde váhy siete, keď sa o úspechu dozvieme až na konci.
- Prečo na XOR nestačí ladiť váhy a ako NEAT necháva sieť rásť od minima.
- Prečo NEAT bez speciácie takmer nefunguje a kam neuroevolúcia vedie dnes.
Čo sa hodí vedieť vopred: Genetické algoritmy: populácia, kríženie, mutácia a výber na batohu na výlet, Evolučné stratégie a genetické programovanie: od pravidla jednej pätiny po Keplerov zákon
Neurónové siete sa dnes učia takmer výlučne gradientovým zostupom: sieť urobí chybu, vypočíta sa, ktorým smerom pootočiť každú váhu, a pootočí sa. Čo ak sa však chyba derivovať nedá — keď sa o úspechu dozvieme až na konci hry, alebo keď nevieme ani to, ako má sieť vyzerať? Vtedy prichádza na rad evolúcia. Neuroevolúcia necháva evolučné algoritmy pestovať váhy sietí a v najzaujímavejšej podobe aj ich tvar. Týmto dielom sa končí modul o algoritmoch inšpirovaných prírodou a zároveň sa otvárajú dvere k neurónovým sieťam.
Nadväzuje na diely Genetické algoritmy a Evolučné stratégie a genetické programovanie.
1. Neurónová sieť v kocke
Definícia — umelý neurón a sieť
Nech n ∈ ℕ, n ≥ 1, w = (w1, …, wn) ∈ ℝn sú váhy, b ∈ ℝ je prah a σ : ℝ → ℝ je funkcia, ktorú nazývame aktivačná funkcia. Neurón s týmito parametrami je funkcia y : ℝn → ℝ, ktorá vstupom x = (x1, …, xn) priradí
y(x) = σ(w1x1 + … + wnxn + b) = σ(∑i=1n wixi + b).
Bežné aktivačné funkcie sú sigmoida σ(z) = 1/1 + e−z a skok σ(z) = 1 pre z > 0, σ(z) = 0 pre z ≤ 0.
Neurónová sieť je orientovaný graf G = (V, E), kde
- množina uzlov V = Vin ∪ VN je disjunktné zjednotenie vstupov siete Vin a neurónov VN, pričom do vstupov nevedie žiadna hrana;
- každá hrana (u, v) ∈ E vedie do neurónu v ∈ VN a má váhu wuv ∈ ℝ;
- každý neurón v ∈ VN má prah bv ∈ ℝ a aktivačnú funkciu σv a jeho hodnota je yv = σv(∑u : (u, v) ∈ E wuv yu + bv), kde yu je pre vstup u ∈ Vin zadaná vstupná hodnota;
- neprázdna množina Vout ⊆ VN sú výstupné neuróny; ich hodnoty sú výstupom siete.
Sieť je dopredná práve vtedy, keď graf G nemá orientovaný cyklus — potom možno hodnoty neurónov vypočítať jednu po druhej v topologickom poradí. Neuróny z VN ∖ Vout (nie sú vstupom ani výstupom) sú skryté.
Neurón sčíta vstupy, každý vynásobený svojou váhou, a podľa súčtu sa „rozsvieti“, alebo nie. Váhy určujú, na čom mu záleží. Sieť je veľa neurónov zapojených za sebou. Celé správanie siete je v číslach váh a v tom, kto je s kým spojený — a oboje sa dá pestovať evolúciou. Neurónovým sieťam a ich učeniu gradientom sa v osnove venuje celý samostatný modul.
y = σ( ∑i=1n wi xi + b )
- xi
- vstupy — to, čo neurón „vidí“ (pri kyvadle poloha, rýchlosť, uhol); neurón ich nemení, len s nimi počíta
- wi
- váhy — jediné, čo sa učí alebo vyvíja evolúciou; znamienko hovorí, či neurón vstup podporuje, alebo tlmí, veľkosť, ako veľmi na ňom záleží
- b
- prah — posunie rozhodovaciu hranicu; bez neho by nulové vstupy dali vždy to isté σ(0) a hranica by musela prechádzať začiatkom
- σ
- aktivačná funkcia — nelinearita; bez nej by aj sieť s mnohými vrstvami počítala len lineárnu funkciu, pretože zloženie lineárnych funkcií je opäť lineárne
2. Evolúcia váh: kyvadlo na vozíku
Klasická úloha riadenia: na vozíku stojí tyč na kĺbe a vozík ju musí udržať vo zvislej polohe tým, že popojíždza doľava a doprava — ako keď balansujete metlu na dlani.
Definícia — úloha kyvadla na vozíku
- Stav je štvorica s = (x, v, θ, ω) ∈ ℝ4: poloha x (m) a rýchlosť v (m/s) vozíka, uhol θ (rad) tyče od zvislice a jej uhlová rýchlosť ω (rad/s). Vozík má hmotnosť 1 kg, tyč 0,1 kg a dĺžku 1 m.
- Akcia: v každom kroku t = 0, 1, 2, … (krok trvá 0,02 s) zvolí regulátor silu Ft ∈ {−10 N, +10 N}.
- Prechod: st+1 sa vypočíta z st a Ft podľa pohybových rovníc nižšie.
- Koniec pokusu: pokus skončí po kroku t práve vtedy, keď |θt+1| > 12° ∨ |xt+1| > 2,4 m (tyč spadla alebo vozík vyšiel z koľajnice), alebo keď prebehlo 1 000 krokov (20 s). Cieľom je vydržať 1 000 krokov.
Regulátorom bude jediný neurón so skokovou aktiváciou: pre váhy (w1, w2, w3, w4, b) ∈ ℝ5 je
u(s) = w1x + w2v + w3θ + w4ω + b, F(s) = +10 N pre u(s) > 0, F(s) = −10 N pre u(s) ≤ 0.
Regulátor teda tlačí vozík v smere kladného x práve vtedy, keď je vážený súčet stavu kladný. Zdatnosť regulátora (priemerný počet krokov z troch rôznych štartov) definujeme nižšie.
Päť čísel rozhoduje, kedy vozíkom trhnúť doľava a kedy doprava. Žiadny učiteľ nepovie, aká sila bola v ktorej chvíli správna — dozvieme sa len, ako dlho tyč vydržala. Presne takáto situácia sa gradientom rieši ťažko a evolúciou ľahko.
Definícia — pohybové rovnice kyvadla na vozíku
Nech s = (x, v, θ, ω) je stav (uhol θ meriame od zvislice) a F ∈ {−10, +10} N sila regulátora; kladná sila tlačí vozík v smere kladného x. Konštanty: hmotnosť vozíka mv = 1 kg, hmotnosť tyče mt = 0,1 kg, ich súčet M = mv + mt = 1,1 kg, l = 0,5 m polovica dĺžky tyče (vzdialenosť ťažiska od kĺbu) a tiažové zrýchlenie g = 9,8 m/s². Bez trenia (rovnice v tvare, ako ich uvádzajú Barto, Sutton a Anderson, 1983, a ako ich dodnes používa väčšina implementácií) sú pomocné zrýchlenie aF, uhlové zrýchlenie tyče ε a zrýchlenie vozíka a dané predpismi
aF = F + mt l ω² sin θ/M
ε = g sin θ − cos θ · aF/l (4/3 − mt cos² θ/M)
a = aF − mt l ε cos θ/M
Simulácia postupuje Eulerovou metódou s krokom Δt = 0,02 s: zo stavu st a sily Ft sa vypočítajú a a ε a nový stav je
xt+1 = xt + Δt vt, vt+1 = vt + Δt a, θt+1 = θt + Δt ωt, ωt+1 = ωt + Δt ε,
t. j. nová poloha je stará plus Δt krát stará rýchlosť a nová rýchlosť je stará plus Δt krát zrýchlenie.
ε = g sin θ − cos θ · aF/l (4/3 − mt cos² θ/M)
- g sin θ
- tiaž — dôvod, prečo tyč padá: čím viac je naklonená, tým silnejšie ju gravitácia prevracia ďalej; vo zvislej polohe je nulová, takže zvislá poloha je rovnováha, lenže vratká
- aF
- zrýchlenie vozíka od sily regulátora (plus malá odstredivá sila tyče) — jediná cesta, ktorou regulátor na tyč pôsobí: vozík podíde pod tyč a kĺb ju „postrčí“ späť
- cos θ
- aká veľká časť vodorovného postrčenia tyč otáča — pri zvislej tyči takmer všetko, pri ležiacej nič; preto sa tyč naklonená o viac než pár stupňov zachraňuje ťažko
- l (4/3 − …)
- zotrvačnosť tyče — 4/3 pochádza z momentu zotrvačnosti homogénnej tyče okolo konca, 1/3 m(2l)² = 4/3 ml²; odčítaný člen opravuje to, že pri otáčaní tyče ucukne aj vozík pod ňou
Príklad — jeden krok simulácie
Štart (0, 0, 0,05, 0), teda tyč naklonená o 0,05 rad ≈ 2,9°; cos 0,05 ≈ 0,9988 a sin 0,05 ≈ 0,0500. Farby podľa rozboru vzorca pre ε vyššie. Menovateľ: 0,5 · (4/3 − 0,1 · 0,9988²/1,1) ≈ 0,621.
bez sily (F = 0, teda aj aF = 0): ε = 9,8 · 0,0500/0,621 ≈ +0,79 rad/s² — tyč začína padať
sila +10 N: aF = 10/1,1 ≈ 9,09 m/s², ε = 0,490 − 0,999 · 9,09/0,621 ≈ −13,8 rad/s²
po kroku: ω = 0 + 0,02 · (−13,8) ≈ −0,28 rad/s, v ≈ 0 + 0,02 · 9,72 ≈ 0,19 m/s
Sila ±10 N je oproti tiaži obrovská — jediné trhnutie obráti smer pádu. Úloha teda nie je v sile, ale v načasovaní: kedy prestať tlačiť, aby sa tyč neprehupla na druhú stranu.
Koľko dá náhoda? Z tisícky regulátorov s náhodnými váhami vydržal všetkých 20 sekúnd jediný; medián je 9 krokov — tyč spadne za necelú pätinu sekundy. Priamočiary regulátor, ktorý len ide tam, kam sa tyč nakláňa, vydrží 39 krokov: tyč síce chytí, ale rozkmitá ju. Evolučná stratégia (5, 20) z dielu o evolučných stratégiách našla regulátor, ktorý vydrží celých 20 sekúnd zo všetkých troch štartov, v 15. generácii — po zhruba troch stovkách vyskúšaných regulátorov:
Vyvinutý regulátor dáva najväčšiu váhu uhlovej rýchlosti — tyč nechytá, až keď padá, ale už keď sa do pádu rozbieha. Nezanedbateľné váhy má aj uhol a rýchlosť vozíka, takže vozík nekmitá a nevyjde z koľajnice. Takéto „pravidlo“ nikto nenapísal; vypadlo z evolúcie.
Definícia — zdatnosť regulátora a evolúcia váh
Nech w = (w1, …, w4, b) ∈ ℝ5 sú váhy regulátora z úlohy kyvadla a s(1) = (0, 0, 0,05, 0), s(2) = (0, 0, −0,08, 0), s(3) = (0,5, 0, 0,02, 0,1) tri štartovacie stavy. Pre k ∈ {1, 2, 3} označme Tk(w) ∈ {1, …, 1 000} počet krokov, ktoré pokus zo štartu s(k) s týmto regulátorom trvá (do pádu tyče alebo vyjazdu vozíka, najviac 1 000). Zdatnosť regulátora je
Z(w) = T1(w) + T2(w) + T3(w)/3 ∈ [1, 1 000].
Tri štarty namiesto jedného bránia tomu, aby evolúcia našla regulátor, ktorý zvláda len jednu východiskovú polohu. Z je po častiach konštantná — malá zmena váh počet krokov väčšinou nezmení vôbec, takže gradient je takmer všade nula. Preto evolúcia.
Evolúcia váh evolučnou stratégiou (5, 20) (pozri diel Evolučné stratégie a genetické programovanie): vstupom je funkcia Z a počet generácií G ∈ ℕ, výstupom najlepšie nájdené váhy.
- Zvoľ 5 rodičov w(1), …, w(5) ∈ ℝ5, každú ich zložku nezávisle a rovnomerne z [−1, 1].
- V každej generácii g = 1, …, G vytvor 20 potomkov: pre každého zvoľ rodiča w rovnomerne náhodne z piatich a polož w′ = w + 0,5 · z, kde z ∈ ℝ5 má zložky nezávislé so štandardným normálnym rozdelením N(0, 1) (pozri diel Prehľad pravdepodobnostných rozdelení).
- Novými rodičmi je 5 potomkov s najväčšou zdatnosťou Z; starí rodičia do ďalšej generácie nepostupujú.
- Po G generáciách vráť váhy s najväčšou zdatnosťou, aká sa počas behu objavila.
import random
def regulator(w, s): # s = (x, v, θ, ω)
u = w[0]*s[0] + w[1]*s[1] + w[2]*s[2] + w[3]*s[3] + w[4]
return 10 if u > 0 else -10 # skoková aktivácia: sila ±10 N
def zdatnost(w): # simuluj(): kroky do pádu, najviac 1000
return sum(simuluj(regulator, w, start) for start in STARTY) / 3
rodice = [[random.uniform(-1, 1) for _ in range(5)] for _ in range(5)]
for generace in range(30):
deti = [[wi + 0.5 * random.gauss(0, 1) for wi in random.choice(rodice)]
for _ in range(20)]
deti.sort(key=zdatnost, reverse=True)
rodice = deti[:5] # (5, 20): prežijú len potomkovia
Príklad — ako sa vyvinutý regulátor rozhoduje
Váhy nájdené evolúciou (zaokrúhlene): w = (0,05; 1,01; 1,37; 4,23), b = 0,09 pre (x, v, θ, ω). Farby podľa rozboru neurónu na začiatku dielu: váhy, vstupy, prah.
tyč naklonená, stojí: (0, 0, 0,05, 0) → u = 1,37 · 0,05 + 0,09 ≈ +0,16 → +10 N, vozík podíde pod tyč
tyč naklonená, ale už sa vracia: (0, 0, 0,05, −0,1) → u = 1,37 · 0,05 + 4,23 · (−0,1) + 0,09 ≈ 0,07 − 0,42 + 0,09 ≈ −0,26 → −10 N, vozík brzdí
V druhom prípade je tyč naklonená rovnako, ale regulátor tlačí opačne: uhlová rýchlosť −0,1 rad/s s váhou 4,23 má väčšiu váhu než uhol 0,05 rad s váhou 1,37. Tyč sa vracia sama, a keby vozík ďalej tlačil, prehupla by sa. Priamočiary regulátor „len podľa uhla“ by v oboch stavoch tlačil rovnako — preto tyč rozkmitá.
3. Prečo evolúcia, a nie gradient
- Riedka odmena. Pri kyvadle, hre alebo robotovi sa kvalita pozná až po celej epizóde. Evolúcii stačí jedno číslo na konci.
- Nederivovateľné časti. Skoková aktivácia, simulátor fyziky, pravidlá hry — evolúcia ich nemusí derivovať.
- Paralelnosť. Každého jedinca možno ohodnotiť na inom počítači nezávisle.
- Štruktúra. Gradient vie ladiť váhy, ale nie pridať neurón. Evolúcia môže meniť aj to, ako sieť vyzerá.
Nevýhodou je nenásytnosť: namiesto jedného gradientu, ktorý povie smer pre všetky váhy naraz, skúša evolúcia náhodné zmeny. Pre siete s miliónmi váh býva gradient oveľa úspornejší, ak sa ho vôbec dá vypočítať.
4. Keď nestačia váhy: XOR
Funkcia XOR vracia 1, keď je práve jeden z dvoch vstupov 1. Ako ukázal diel Logika a dôkazy, jediný neurón ju nezvládne: jeho výstup delí rovinu vstupov priamkou a body (0, 1), (1, 0) od (0, 0), (1, 1) žiadna priamka neoddelí. Na XOR treba aspoň jeden skrytý neurón. A tým sa otvára otázka, ktorú samotná evolúcia váh nevyrieši: koľko neurónov a ako ich zapojiť?
Veta — XOR nie je lineárne separovateľný
Nech XOR : {0, 1}2 → {0, 1} je funkcia daná predpisom XOR(x1, x2) = 1 ⇔ x1 ≠ x2. Potom neexistujú čísla w1, w2, b ∈ ℝ také, že pre všetky (x1, x2) ∈ {0, 1}2 platí
w1x1 + w2x2 + b > 0 ⇔ XOR(x1, x2) = 1.
Žiadna priamka teda neoddelí body, kde sa XOR rovná 1, od bodov, kde sa rovná 0.
Dôkaz. Keby také čísla existovali, platilo by
(0, 0): b ≤ 0 (1, 1): w1 + w2 + b ≤ 0
(1, 0): w1 + b > 0 (0, 1): w2 + b > 0
Sčítaním prvého riadka dostaneme w1 + w2 + 2b ≤ 0, sčítaním druhého w1 + w2 + 2b > 0. Spor. ∎
Dôkaz nepoužíva tvar aktivačnej funkcie — platí pre každý jediný neurón, ktorého výstup závisí len od znamienka váženého súčtu (skok aj sigmoida s prahom 0,5).
Odpovedať sa dá ručne — navrhnúť architektúru a evolúciou ladiť len váhy. Ale pri zložitejších úlohách netušíme, aká architektúra je správna. Prečo ju nenechať vyvinúť tiež?
5. NEAT: evolúcia rastúcich sietí
Pokusy vyvíjať evolúciou štruktúru sietí narážali na tri problémy. Ako krížiť dve siete s iným tvarom? Ako dať šancu novej štruktúre, ktorá je spočiatku horšia, pretože jej nové váhy ešte nie sú vyladené? A ako zabrániť, aby siete zbytočne napučiavali? Kenneth Stanley a Risto Miikkulainen v roku 2002 odpovedali algoritmom NEAT (NeuroEvolution of Augmenting Topologies) s tromi myšlienkami.
Definícia — genóm NEAT a historické značky
Nech uzly siete (vstupy, prah, výstupy a skryté neuróny, pozri definíciu neurónovej siete vyššie) sú označené prirodzenými číslami. Gén spoja je pätica (u, v, w, e, i), kde u je zdrojový a v cieľový uzol spoja u → v, w ∈ ℝ jeho váha, e ∈ {0, 1} príznak (e = 1: spoj je zapnutý a v sieti sa počíta, e = 0: vypnutý) a i ∈ ℕ jeho inovačné číslo. Genóm je konečná množina génov spojov, v ktorej majú rôzne gény rôzne inovačné čísla; určuje sieť, ktorej hrany sú zapnuté spoje.
Inovačné čísla prideľuje jeden čítač pre celú populáciu: kedykoľvek mutácia prvýkrát vytvorí spoj u → v, dostane ďalšie voľné číslo; ak vznikne rovnaká štruktúrna zmena (spoj medzi tými istými uzlami) u iného jedinca, dostane rovnaké číslo.
Mutácie genómu sú tri:
- zmena váh — váhy w génov sa zmenia (pripočítaním náhodného čísla alebo novou náhodnou hodnotou);
- pridanie spoja — pribudne gén (u, v, w, 1, i) s náhodnou váhou w pre dva doteraz nespojené uzly u, v (náš program pridá spoj, len keď nevznikne cyklus, takže sieť zostáva dopredná);
- pridanie neurónu — pre zvolený zapnutý gén (a, b, w, 1, i) vznikne nový skrytý neurón h, gén sa vypne (e ← 0) a pribudnú gény (a, h, 1, 1, i′) a (h, b, w, 1, i″) s novými inovačnými číslami.
Kríženie dvoch rodičov zarovná ich gény podľa inovačných čísel. Potomok dostane každý zhodný gén (inovačné číslo je v oboch rodičoch) od rodiča zvoleného náhodne s rovnakou pravdepodobnosťou a každý ostatný gén (je len v jednom z rodičov) len vtedy, ak je v genóme zdatnejšieho rodiča.
Inovačné číslo je rodný list spoja. Keď dve siete majú spoj s číslom 7, ide o „ten istý“ spoj, aj keď sa k nemu každá dostala inou cestou — a pri krížení sa dajú spárovať ako rovnaké gény u dvoch rodičov. Nový neurón sa vkladá tak, aby sieť spočiatku počítala podobne ako predtým; nič zásadné sa nerozbije, len pribudne možnosť.
Príklad — pridanie neurónu na spoj s váhou 2
Náš NEAT používa rovnako ako pôvodný článok strmšiu sigmoidu σ(z) = 1/1 + e−4,9z. Spoj x1 → y s váhou 2 prispieval do výstupu 2x1. Po rozdelení vedie x1 → h s váhou 1 a h → y s váhou 2:
x1 = 1: 2 · σ(1) = 2 · 0,993 ≈ 1,985 (predtým 2)
x1 = 0: 2 · σ(0) = 2 · 0,5 = 1 (predtým 0)
„Podobne“ tu teda znamená len sčasti: pre vstup 1 je zmena zanedbateľná, pre vstup 0 pribudne do súčtu jednotka, pretože sigmoida v nule vracia polovicu. Sieť sa tým trochu pokazí — a práve preto potrebuje nová štruktúra ochranu, o ktorej je reč ďalej.
Definícia — speciácia a zdieľanie zdatnosti
Nech G1, G2 sú neprázdne genómy (pozri definíciu genómu vyššie) a I1, I2 množiny inovačných čísel ich génov. Označme m = min(max I1, max I2) a
- zhodné gény: inovačné čísla z I1 ∩ I2;
- disjunktné gény: čísla i ∈ (I1 ∖ I2) ∪ (I2 ∖ I1) s i ≤ m (chýbajú jednému z genómov „v strede“); D je ich počet;
- prebytočné gény: čísla i ∈ (I1 ∖ I2) ∪ (I2 ∖ I1) s i > m (za koncom kratšieho genómu); E je ich počet;
- W̄ je priemer |wi(1) − wi(2)| cez zhodné gény i (rozdiel váh toho istého génu v oboch genómoch; ak nemajú zhodné gény, W̄ = 0);
- N = max(|G1|, |G2|) je počet génov väčšieho genómu, ak je aspoň 20, inak N = 1.
Pre konštanty c1, c2, c3 ≥ 0 je kompatibilitná vzdialenosť genómov G1, G2 číslo
δ(G1, G2) = c1 E/N + c2 D/N + c3 W̄.
Speciácia: nech δt > 0 je prah a každý druh má zástupcu. Genóm patrí do prvého druhu, s ktorého zástupcom Z má δ(genóm, Z) < δt; ak taký neexistuje, založí nový druh. Druhy S1, …, SK tak rozdelia populáciu veľkosti P na disjunktné neprázdne časti.
Zdieľanie zdatnosti: ak má jedinec i ∈ Sk zdatnosť fi ≥ 0, je jeho zdieľaná zdatnosť f′i = fi/|Sk|, druh k má F̄k = ∑i ∈ Sk f′i (priemernú zdatnosť svojich členov) a dostane
nk = P · F̄k/∑j=1K F̄j
potomkov (zaokrúhlené nadol, zvyšok dostane druh s najlepšou sieťou). Podobné genómy teda tvoria druh, zdatnosť jedinca sa delí veľkosťou jeho druhu a potomkovia sa rozdeľujú medzi druhy podľa ich priemernej zdatnosti.
Siete s podobnou stavbou súťažia hlavne medzi sebou, nie s celou populáciou. Nový neurón tak dostane pár generácií na to, aby sa jeho váhy vyladili, namiesto toho, aby ho hneď zmietli zavedené siete. A pretože sa zdatnosť v druhu delí, žiadny druh nemôže ovládnuť celú populáciu.
δ = c1 E/N + c2 D/N + c3 W̄
- c1 E
- prebytočné gény — štruktúra, ktorú jeden genóm získal až po poslednom spoločnom „vynáleze“; znamená mladšiu, odlišnú vetvu vývoja
- c2 D
- disjunktné gény — vynálezy z čias, keď už oba existovali, ktoré má len jeden z nich; ďalšia miera rozdielu stavby
- N
- veľkosť väčšieho genómu — aby dva veľké genómy, ktoré sa líšia o pár génov z mnohých, nevyšli rovnako vzdialené ako dva malé, ktoré sa líšia takmer vo všetkom; pri genómoch pod 20 génov sa berie N = 1
- c3 W̄
- priemerný rozdiel váh zhodných génov — rovnako zapojené siete s veľmi odlišnými váhami počítajú iné funkcie; váha c3 je menšia, pretože stavba sa mení zriedkavejšie a znamená viac
Príklad — vzdialenosť po pridaní neurónu
Genóm A má gény 1–5. Genóm B vznikol z podobného predka: má tiež gény 1–5 (gén 3 vypnutý, pretože ho rozdelil nový neurón) a navyše gény 6 a 7 z pridania neurónu. Váhy zhodných génov sa líšia o 0,2; 0,6; 0; 0,9 a 0,8.
zhodné: 1–5 → W̄ = 0,2 + 0,6 + 0 + 0,9 + 0,8/5 = 0,5
prebytočné: 6, 7 (za koncom kratšieho genómu, ten končí génom 5) → E = 2; disjunktné: žiadne → D = 0; genómy majú menej ako 20 génov → N = 1
δ = 1 · 2/1 + 1 · 0/1 + 0,4 · 0,5 = 2,2 < 3 → rovnaký druh (farby podľa vzorca vyššie)
Keby B získal ešte jeden spoj (gén 8), vyšlo by E = 3 a δ = 3,2 ≥ 3 — B by založil nový druh. Jediný nový neurón teda sieť z druhu nevyradí, ale nový neurón s novým spojom už áno.
nk = P · F̄k/∑j F̄j, F̄k = ∑i ∈ Sk fi/|Sk|
- nk
- počet potomkov druhu k v ďalšej generácii — týmto sa v NEATe odmeňuje úspech, nie výberom jednotlivcov z celej populácie
- P
- veľkosť populácie (150) — potomkovia sa delia ako koláč, populácia nerastie ani sa nezmenšuje
- |Sk|
- počet členov druhu — zdieľanie zdatnosti: zdatnosť každého člena sa delí veľkosťou jeho druhu, f′i = fi/|Sk|; veľký druh tak nemôže získať viac len tým, že je veľký
- F̄k
- súčet zdieľaných zdatností druhu, teda jeho priemerná zdatnosť — o podiele na koláči rozhoduje kvalita, nie počet
- ∑j F̄j
- súčet cez všetky druhy — delením vznikne podiel, ktorý sa sčíta na 1, takže sa rozdelí presne P potomkov (po zaokrúhlení nadol dostane zvyšok najlepší druh)
Príklad — prečo zdieľanie chráni nový druh
Populácia 150: zavedený druh A má 120 sietí s priemernou zdatnosťou 9,0, nový druh B so skrytým neurónom 30 sietí s priemernou zdatnosťou 7,5.
so zdieľaním (farby podľa vzorca vyššie): nA = 150 · 9,0/16,5 ≈ 81,8 → 81 (+1 zvyšok) = 82, nB = 150 · 7,5/16,5 ≈ 68,2 → 68
bez zdieľania (podľa súčtu zdatností 120 · 9,0 = 1 080 a 30 · 7,5 = 225): A ≈ 150 · 1 080/1 305 ≈ 124, B ≈ 26
Bez zdieľania by nový druh za pár generácií vymrel, pretože je horší a menší. So zdieľaním dostane viac potomkov, než má členov, a má čas vyladiť váhy.
Tretia myšlienka je najjednoduchšia: začať od minima. Všetky siete na začiatku nemajú žiadny skrytý neurón — vstupy vedú rovno do výstupu. Štruktúra pribúda len vtedy, keď sa oplatí. Výsledné siete preto bývajú malé.
Všetko dohromady — jedna generácia nášho zjednodušeného NEATu (pravdepodobnosti sú tie, s ktorými beží program pre XOR):
populácia ← 150 minimálnych sietí (x₁, x₂ a prah rovno do y, váhy náhodne z [−2, 2])
pre generáciu g = 0, 1, …, 100:
ohodnoť každú sieť zdatnosťou f
ak niektorá sieť rieši úlohu: koniec
rozdeľ siete do druhov: sieť patrí do prvého druhu, s ktorého zástupcom má δ < 3,
inak založí nový
vyraď druhy, ktoré sa 15 generácií nezlepšili (okrem druhu s najlepšou sieťou)
druhu k prideľ n_k = 150 · F̄_k / ∑ F̄_j potomkov
v každom druhu:
rodičia ← najlepších 20 % členov
ak má druh viac než 5 členov, jeho najlepšia sieť prejde bez zmeny
každý ďalší potomok:
s pravdepodobnosťou 0,75 kríženie dvoch rodičov, inak kópia jedného
s pravdepodobnosťou 0,8 zmeň váhy (90 %: w ← w + N(0, 1), 10 %: nová náhodná)
s pravdepodobnosťou 0,1 pridaj spoj
s pravdepodobnosťou 0,03 pridaj neurón (rozdeľ náhodný zapnutý spoj)
6. NEAT na XOR
Náš zjednodušený NEAT má populáciu 150 sietí a najviac 100 generácií. V behu z obrázka vyriešil XOR v generácii 27 sieťou s jediným skrytým neurónom a siedmimi spojmi — čo je najmenšie možné riešenie:
f = ( 4 − ∑ |y − t| )2
- ∑ |y − t|
- chyba — súčet odchýlok výstupu y od správnej hodnoty t cez všetky štyri vstupy; absolútna hodnota, aby sa chyby nahor a nadol navzájom nevyrušili
- 4
- najväčšia možná chyba (štyri vstupy, každá odchýlka najviac 1) — odčítaním sa z chyby, ktorú chceme zmenšiť, stane zdatnosť, ktorú evolúcia zväčšuje, a tá je vždy nezáporná
- 2
- umocnenie — zosilní rozdiely blízko riešenia: sieť s chybou 0,5 má zdatnosť 12,25, sieť s chybou 1 len 9, takže výber viac odmení posledných pár percent
Sieť sa dá prečítať. Skrytý neurón h sa rozsvieti len vtedy, keď sú oba vstupy 0 (oba majú veľkú zápornú váhu, prah je kladný). Priame spoje do výstupu by samy počítali „nie oba zároveň“ — výstup 1 pre všetko okrem (1, 1) —, ale silne záporná váha od h ho pre (0, 0) vypne. Výstupy 0,000; 0,855; 1,000 a 0,005 sú po zaokrúhlení presne XOR. Počet druhov medzitým vzrástol z jedného na zhruba dvadsať.
Príklad — výpočet siete pre všetky štyri vstupy
Váhy (zaokrúhlene): do h z x1, x2 a prahu −3,37; −3,67; 0,95; do y z x1, x2, prahu a h −1,42; −2,96; 3,32; −5,69. Aktivácia je σ(z) = 1/1 + e−4,9z. Najprv sa vypočíta h, potom y (tabuľka počíta s nezaokrúhlenými váhami, takže ručný prepočet sa môže líšiť v poslednej cifre):
| (x1, x2) | zh | h | zy | y | |y − t| |
|---|---|---|---|---|---|
| (0, 0) | 0,95 | 0,990 | 3,32 − 5,69 · 0,990 = −2,32 | 0,000 | 0,000 |
| (0, 1) | −2,72 | 0,000 | −2,96 + 3,32 = 0,36 | 0,855 | 0,145 |
| (1, 0) | −2,43 | 0,000 | −1,42 + 3,32 = 1,89 | 1,000 | 0,000 |
| (1, 1) | −6,09 | 0,000 | −1,42 − 2,96 + 3,32 = −1,06 | 0,005 | 0,005 |
Chyba je 0,150 a zdatnosť f = (4 − 0,150)2 ≈ 14,82 zo 16 (farby podľa vzorca zdatnosti vyššie). Najhoršie sieť odpovedá pre (0, 1): výstup 0,855 je správne nad polovicou, ale nie pri jednotke — na riešenie to stačí, ďalšie ladenie váh by zdatnosť ešte zvýšilo.
Z päťdesiatich behov s rôznymi semienkami vyriešil NEAT XOR v 47, v priemere za 31 generácií, s 2,6 skrytého neurónu, ktoré naozaj niečo robia. Pôvodný článok uvádza 32 generácií a 2,35 skrytého neurónu — náš zjednodušený NEAT je teda blízko.
7. Na čom NEAT stojí
Rovnakých 50 behov s vypnutou časťou algoritmu:
| Variant | Vyriešilo XOR | Priemerná generácia |
|---|---|---|
| NEAT | 47 z 50 | 31,1 |
| bez speciácie (jeden druh) | 1 z 50 | — |
| bez kríženia | 50 z 50 | 47,3 |
Bez speciácie NEAT takmer nefunguje. Sieť so skrytým neurónom je po vzniku horšia než zavedené siete bez neho, pretože jej nové váhy sú náhodné — a v jednej spoločnej súťaži ju výber okamžite vyradí. Speciácia ju ochráni, kým nedozrie. Bez kríženia sa XOR vyrieši tiež, len pomalšie a s väčšími sieťami (3,1 aktívneho skrytého neurónu): kríženie pomáha skladať dohromady čiastkové objavy rôznych jedincov.
8. Nasledovníci NEATu
- HyperNEAT (Stanley a kol., 2009) vyvíja evolúciou malú sieť, ktorá až vygeneruje váhy veľkej siete podľa geometrie úlohy — ako genóm, ktorý neopisuje každú bunku, ale pravidlá rastu.
- Hľadanie novosti (Lehman a Stanley, 2011) neodmeňuje zdatnosť, ale nové správanie. V bludisku so zavádzajúcimi slepými uličkami našlo cieľ častejšie než hľadanie riadené zdatnosťou.
- Hlboká neuroevolúcia. V roku 2017 ukázal tím Uber AI, že obyčajný genetický algoritmus dokáže trénovať siete s miliónmi váh na hrách Atari porovnateľne s učením posilňovaním.
- Evolučné hľadanie architektúr. Sieť AmoebaNet (Google, 2019) vznikla evolúciou stavebných blokov a v rozpoznávaní obrázkov na ImageNete patrila v tom čase k najlepším. Dnes architektúry častejšie navrhujú ľudia alebo iné metódy, ale evolúcia zostáva jednou z možností.
9. Zhrnutie
- Neuroevolúcia pestuje neurónové siete evolučnými algoritmami — hodí sa tam, kde sa gradient nedá vypočítať alebo kde odmena prichádza až na konci.
- Evolúcia váh jedného neurónu udrží kyvadlo na vozíku 20 sekúnd po zhruba troch stovkách pokusov; náhodné váhy dajú v mediáne 9 krokov.
- Na XOR nestačí jeden neurón — treba zmeniť štruktúru siete.
- NEAT vyvíja váhy aj štruktúru: historické značky umožnia kríženie, speciácia chráni nové štruktúry a siete rastú od minima.
- Bez speciácie vyriešil NEAT XOR v 1 z 50 behov, so speciáciou v 47 — a najlepšie riešenie malo jediný skrytý neurón.
Chcete si to vyskúšať na vlastnej koži? Nechajte AI agenta napísať kyvadlo na vozíku s evolúciou regulátora a potom skúste dve tyče rôznej dĺžky na jednom vozíku — slávnu ťažšiu verziu, v ktorej NEAT kedysi vynikal.
Máte na to iný názor? Napíšte na support@coden-app.com.