Přeskočit na obsah
coden

Neuroevoluce: evoluce vah i tvaru neuronových sítí a algoritmus NEAT

Neuron a síť v kostce, evoluce regulátoru pro kyvadlo na vozíku, proč evoluce místo gradientu, XOR a skryté neurony, NEAT s historickými značkami a speciací, co se stane bez speciace a následovníci od HyperNEAT po AmoebaNet.

15 minut Matěj Žalmánek 2026-10-15

Série Základy AI Díl 31 z 83
  1. Mapa umělé inteligence: co je co a jak to do sebe zapadá
  2. Stručná historie umělé inteligence: od Turinga po jazykové modely
  3. Data, model, trénink, inference: základní pojmy na jednom příkladu
  4. Jak číst matematický zápis: symboly, indexy, sumy a kvantifikátory
  5. Množiny a relace: stavebnice, ze které se skládají definice v AI
  6. Funkce a zobrazení: proč je každý model v AI funkce
  7. Logika a důkazy: pravidla, podle kterých se v AI uvažuje
  8. Grafy a stromy: struktura, na které stojí hledání i neuronové sítě
  9. Lineární algebra pro strojové učení: vektory, matice a proč AI hlavně násobí
  10. Derivace, gradient a řetízkové pravidlo: jak model zjistí, kterým směrem se učit
  11. Gradientní sestup: jak se model učí
  12. Co je pravděpodobnost: od hodu kostkou ke Kolmogorovovým axiomům
  13. Podmíněná pravděpodobnost a Bayesova věta: jak změnit odhad, když se dozvíte něco nového
  14. Náhodná veličina a distribuční funkce: jedna funkce, která o rozdělení řekne všechno
  15. Funkce hustoty a pravděpodobnostní funkce: proč má spojitá veličina v bodě pravděpodobnost nula
  16. Střední hodnota, rozptyl a kovariance: kde rozdělení leží, jak je široké a co s čím souvisí
  17. Přehled pravděpodobnostních rozdělení: Bernoulli, binomické, Poisson, rovnoměrné, normální a exponenciální
  18. Zákon velkých čísel a centrální limitní věta: proč se průměry chovají tak předvídatelně
  19. Statistika a odhady parametrů: maximální věrohodnost, MAP a intervaly spolehlivosti
  20. Teorie informace: entropie, křížová entropie a KL divergence — odkud se berou ztrátové funkce
  21. Prohledávání stavového prostoru: BFS, DFS, UCS a A* s animacemi
  22. Hry a protivník: minimax, alfa-beta ořezávání a Monte Carlo tree search
  23. Splňování omezujících podmínek: backtracking, propagace omezení a AC-3 na sudoku a mapě krajů
  24. Logika a znalostní systémy: dopředné a zpětné řetězení, rezoluce a expertní systémy
  25. Plánování: STRIPS, svět kostek, heuristiky z relaxace a plánování v AI agentech
  26. Lokální hledání a simulované žíhání: obchodní cestující přes krajská města
  27. Genetické algoritmy: populace, křížení, mutace a výběr na batohu na výlet
  28. Evoluční strategie a genetické programování: od pravidla jedné pětiny po Keplerův zákon
  29. Optimalizace mravenčí kolonií: jak feromonová stopa najde krátkou cestu
  30. Optimalizace hejnem částic: setrvačnost, vlastní zkušenost a zkušenost hejna
  31. Neuroevoluce: evoluce vah i tvaru neuronových sítí a algoritmus NEAT
  32. Fuzzy množiny a funkce příslušnosti: jak zapsat „trochu teplo“
  33. Fuzzy logika a pravděpodobnost: proč „trochu teplo“ neznamená „pravděpodobně teplo“
  34. Fuzzy logika: t-normy, implikace a pravidla KDYŽ–PAK
  35. Fuzzy řízení: Mamdani a Sugeno od ventilátoru po kyvadlo na vozíku
  36. Fuzzy shlukování: algoritmus fuzzy c-means a body mezi shluky
  37. Neuro-fuzzy systémy (ANFIS): fuzzy pravidla, která se učí z dat
  38. Markovovy řetězce: přechodová matice, stacionární rozdělení a PageRank
  39. Skryté Markovovy modely: Viterbiho algoritmus a nepoctivé kasino
  40. Bayesovské sítě: proč je tráva mokrá a co z toho plyne pro postřikovač
  41. Kalmanův filtr: jak z nepřesných měření odhadnout, kde auto je a jak rychle jede
  42. Druhy strojového učení: s učitelem, bez učitele, s částečným učitelem a další
  43. Přeučení a regularizace: proč model, který zná data nazpaměť, selže
  44. Vyhodnocení modelu: křížová validace, F1 a křivka ROC
  45. Shlukování a snížení dimenze: k-means, PCA a t-SNE
  46. Klasifikace a regrese: dvě úlohy učení s učitelem
  47. Lineární regrese: nejmenší čtverce geometricky i maticově
  48. Polynomiální a nelineární regrese: jak přímku ohnout
  49. Logistická regrese: sigmoida, šance a křížová entropie
  50. Vícetřídní klasifikace a softmax: od dvou tříd k mnoha
  51. Naivní Bayesův klasifikátor: spamový filtr, který funguje lépe, než by měl
  52. Ztrátové funkce: co přesně model minimalizuje
  53. Rozhodovací stromy a k nejbližších sousedů: modely bez vzorců
  54. Ansámbly: náhodný les a gradient boosting
  55. SVM a jádrový trik: nejširší hranice a jak ji ohnout
  56. Signál a vzorkování: proč platí Nyquistův teorém
  57. Fourierova transformace: rozklad signálu na frekvence
  58. Filtry a konvoluce: vyhlazení, hrany a odstranění šumu
  59. Zvuk a řeč: spektrogram, melová škála a MFCC
  60. Obraz jako signál: pixely, barvy, konvoluce a hrany
  61. Perceptron a umělý neuron: nejjednodušší neuronová síť a co neumí
  62. Neuronová síť od nuly: zpětné šíření chyby krok za krokem
  63. Aktivace, inicializace a normalizace: drobnosti, na kterých hluboká síť stojí
  64. Konvoluční sítě: jak síť poznává obrázky
  65. Rekurentní sítě: paměť pro posloupnosti a mizející gradient
  66. LSTM a GRU: brány, které rozhodují, co si síť zapamatuje
  67. Autoenkodéry: síť, která se učí data stlačit a zase rozbalit
  68. Embeddingy a word2vec: jak se slovo stane vektorem
  69. Mechanismus pozornosti: jak se model naučí, kam se dívat
  70. Transformery a velké jazykové modely: architektura krok za krokem
  71. Tokenizace: jak se text rozseká na kousky pro model
  72. Předtrénování a škálování: proč větší model a víc dat funguje
  73. Doladění a RLHF: jak se z doplňovače textu stane asistent
  74. Prompty, kontext a RAG: jak modelu dát správné informace
  75. Variační autoenkodéry (VAE): nové obrázky ze spojitého latentního prostoru
  76. Generativní adversariální sítě (GAN): padělatel proti detektivovi
  77. Difúzní modely: jak se z čistého šumu stane obrázek
  78. Markovovy rozhodovací procesy: stavy, akce, odměny a Bellmanovy rovnice
  79. Q-learning a DQN: učení hodnoty akcí od tabulky po neuronovou síť
  80. Policy gradient a PPO: učení přímo strategie
  81. Jak funguje AI agent: jazykový model ve smyčce s nástroji
  82. Programování s AI agenty: zadání, testy a kontrola
  83. Vyhodnocení a bezpečnost AI systémů: jak měřit a jak hlídat

Celá osnova série 83 z 83 témat hotovo

Co si odnesete
  • Jak evoluce najde váhy sítě, když se o úspěchu dozvíme až na konci.
  • Proč na XOR nestačí ladit váhy a jak NEAT nechává síť růst od minima.
  • Proč NEAT bez speciace skoro nefunguje a kam neuroevoluce vede dnes.

Co se hodí znát předem: Genetické algoritmy: populace, křížení, mutace a výběr na batohu na výlet, Evoluční strategie a genetické programování: od pravidla jedné pětiny po Keplerův zákon

Neuronové sítě se dnes učí skoro výhradně gradientním sestupem: síť udělá chybu, spočítá se, kterým směrem pootočit každou váhu, a pootočí se. Co když ale chybu nejde derivovat — když se o úspěchu dozvíme až na konci hry, nebo když nevíme ani to, jak má síť vypadat? Pak přichází na řadu evoluce. Neuroevoluce nechává evoluční algoritmy pěstovat váhy sítí, a v nejzajímavější podobě i jejich tvar. Tímhle dílem končí modul o přírodou inspirovaných algoritmech a zároveň se otevírají dveře k neuronovým sítím.

Navazuje na díly Genetické algoritmy a Evoluční strategie a genetické programování.

1. Neuronová síť v kostce

Definice — umělý neuron a síť

Nechť n ∈ ℕ, n ≥ 1, w = (w1, …, wn) ∈ ℝn jsou váhy, b ∈ ℝ je práh a σ : ℝ → ℝ je funkce, které říkáme aktivační funkce. Neuron s těmito parametry je funkce y : ℝn → ℝ, která vstupům x = (x1, …, xn) přiřadí

y(x) = σ(w1x1 + … + wnxn + b) = σ(∑i=1n wixi + b).

Běžné aktivační funkce jsou sigmoida σ(z) = 1/1 + e−z a skok σ(z) = 1 pro z > 0, σ(z) = 0 pro z ≤ 0.

Neuronová síť je orientovaný graf G = (V, E), kde

  1. množina uzlů V = Vin ∪ VN je disjunktní sjednocení vstupů sítě Vin a neuronů VN, přičemž do vstupů nevede žádná hrana;
  2. každá hrana (u, v) ∈ E vede do neuronu v ∈ VN a má váhu wuv ∈ ℝ;
  3. každý neuron v ∈ VN má práh bv ∈ ℝ a aktivační funkci σv a jeho hodnota je yv = σv(∑u : (u, v) ∈ E wuv yu + bv), kde yu je pro vstup u ∈ Vin zadaná vstupní hodnota;
  4. neprázdná množina Vout ⊆ VN jsou výstupní neurony; jejich hodnoty jsou výstupem sítě.

Síť je dopředná, právě když graf G nemá orientovaný cyklus — pak lze hodnoty neuronů spočítat jednu po druhé v topologickém pořadí. Neurony z VN ∖ Vout (nejsou vstupem ani výstupem) jsou skryté.

Laicky řečeno

Neuron sečte vstupy, každý vynásobený svou vahou, a podle součtu se „rozsvítí“, nebo ne. Váhy určují, na čem mu záleží. Síť je mnoho neuronů zapojených za sebou. Celé chování sítě je v číslech vah a v tom, kdo je s kým spojený — a obojí se dá pěstovat evolucí. Neuronovým sítím a jejich učení gradientem se v osnově věnuje celý samostatný modul.

y = σ( ∑i=1n wi xi + b )

xi
vstupy — to, co neuron „vidí“ (u kyvadla poloha, rychlost, úhel); neuron je nemění, jen s nimi počítá
wi
váhy — jediné, co se učí nebo evolvuje; znaménko říká, jestli vstup neuron podporuje, nebo tlumí, velikost, jak moc na něm záleží
b
práh — posune rozhodovací hranici; bez něj by nulové vstupy daly vždy totéž σ(0) a hranice by musela procházet počátkem
σ
aktivační funkce — nelinearita; bez ní by i síť o mnoha vrstvách počítala jen lineární funkci, protože složení lineárních funkcí je zase lineární
Součet ∑ wixi + b je vážené hlasování vstupů; σ z něj udělá výstup. Hranice mezi „rozsvítí se“ a „nerozsvítí“ je množina, kde je součet nula — přímka (v rovině), obecně nadrovina.

2. Evoluce vah: kyvadlo na vozíku

Klasická úloha řízení: na vozíku stojí tyč na kloubu a vozík ji musí udržet ve svislé poloze tím, že popojíždí vlevo a vpravo — jako když balancujete koště na dlani.

Definice — úloha kyvadla na vozíku
  1. Stav je čtveřice s = (x, v, θ, ω) ∈ ℝ4: poloha x (m) a rychlost v (m/s) vozíku, úhel θ (rad) tyče od svislice a její úhlová rychlost ω (rad/s). Vozík má hmotnost 1 kg, tyč 0,1 kg a délku 1 m.
  2. Akce: v každém kroku t = 0, 1, 2, … (krok trvá 0,02 s) zvolí regulátor sílu Ft ∈ {−10 N, +10 N}.
  3. Přechod: st+1 se spočítá z st a Ft podle pohybových rovnic níže.
  4. Konec pokusu: pokus skončí po kroku t, právě když |θt+1| > 12° ∨ |xt+1| > 2,4 m (tyč spadla nebo vozík vyjel z koleje), nebo když proběhlo 1 000 kroků (20 s). Cílem je vydržet 1 000 kroků.

Regulátorem bude jediný neuron se skokovou aktivací: pro váhy (w1, w2, w3, w4, b) ∈ ℝ5 je

u(s) = w1x + w2v + w3θ + w4ω + b,   F(s) = +10 N pro u(s) > 0,   F(s) = −10 N pro u(s) ≤ 0.

Regulátor tedy tlačí vozík ve směru kladného x, právě když je vážený součet stavu kladný. Zdatnost regulátoru (průměrný počet kroků ze tří různých startů) definujeme níže.

Laicky řečeno

Pět čísel rozhoduje, kdy vozík cuknout doleva a kdy doprava. Žádný učitel neříká, jaká síla byla v kterém okamžiku správná — dozvíme se jen, jak dlouho tyč vydržela. Přesně taková situace se gradientem řeší těžko a evolucí snadno.

Definice — pohybové rovnice kyvadla na vozíku

Nechť s = (x, v, θ, ω) je stav (úhel θ měříme od svislice) a F ∈ {−10, +10} N síla regulátoru; kladná síla tlačí vozík ve směru kladného x. Konstanty: hmotnost vozíku mv = 1 kg, hmotnost tyče mt = 0,1 kg, jejich součet M = mv + mt = 1,1 kg, l = 0,5 m polovina délky tyče (vzdálenost těžiště od kloubu) a tíhové zrychlení g = 9,8 m/s². Bez tření (rovnice ve tvaru, jak je uvádí Barto, Sutton a Anderson, 1983, a jak je dodnes používá většina implementací) jsou pomocné zrychlení aF, úhlové zrychlení tyče ε a zrychlení vozíku a dány předpisy

aF = F + mt l ω² sin θ/M

ε = g sin θ − cos θ · aF/l (4/3 − mt cos² θ/M)

a = aF − mt l ε cos θ/M

Simulace postupuje Eulerovou metodou s krokem Δt = 0,02 s: ze stavu st a síly Ft se spočí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 ε,

tj. nová poloha je stará plus Δt krát stará rychlost a nová rychlost je stará plus Δt krát zrychlení.

ε = g sin θ − cos θ · aF/l (4/3 − mt cos² θ/M)

g sin θ
tíže — důvod, proč tyč padá: čím víc je nakloněná, tím silněji ji gravitace překlápí dál; ve svislé poloze je nulová, takže svislá poloha je rovnováha, jenže vratká
aF
zrychlení vozíku od síly regulátoru (plus malá odstředivá síla tyče) — jediná cesta, kterou regulátor na tyč působí: vozík podjede pod tyč a kloub ji „postrčí“ zpátky
cos θ
jak velká část vodorovného postrčení tyč otáčí — u svislé tyče skoro všechno, u ležící nic; proto se tyč nakloněná o víc než pár stupňů zachraňuje těžko
l (4/3 − …)
setrvačnost tyče — 4/3 pochází z momentu setrvačnosti homogenní tyče kolem konce, 1/3 m(2l)² = 4/3 ml²; odečtený člen opravuje to, že při otáčení tyče ucukne i vozík pod ní
Úhlové zrychlení tyče je souboj dvou členů: tíže tyč překlápí, zrychlení vozíku ji vrací.
Příklad — jeden krok simulace

Start (0, 0, 0,05, 0), tedy tyč nakloněná o 0,05 rad ≈ 2,9°; cos 0,05 ≈ 0,9988 a sin 0,05 ≈ 0,0500. Barvy podle rozboru vzorce pro ε výše. Jmenovatel: 0,5 · (4/3 − 0,1 · 0,9988²/1,1) ≈ 0,621.

bez síly (F = 0, tedy i aF = 0): ε = 9,8 · 0,0500/0,621 ≈ +0,79 rad/s² — tyč začíná padat

síla +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

Síla ±10 N je proti tíži obrovská — jediné cuknutí převrátí směr pádu. Úloha tedy není v síle, ale v načasování: kdy přestat tlačit, aby se tyč nepřehoupla na druhou stranu.

Kolik dá náhoda? Z tisíce regulátorů s náhodnými vahami vydržel všech 20 sekund jediný; medián je 9 kroků — tyč spadne za necelou pětinu sekundy. Přímočarý regulátor, který jen jede tam, kam se tyč naklání, vydrží 39 kroků: tyč sice chytí, ale rozkmitá ji. Evoluční strategie (5, 20) z dílu o evolučních strategiích našla regulátor, který vydrží celých 20 sekund ze všech tří startů, v 15. generaci — po zhruba třech stech vyzkoušených regulátorech:

jen podle úhlu 0,8 s evoluce vah 20,0 s+
Kyvadlo na vozíku: prvních 8 sekund simulace

Vyvinutý regulátor dává největší váhu úhlové rychlosti — tyč nechytá, až když padá, ale už když se do pádu rozjíždí. Nezanedbatelné váhy má i úhel a rychlost vozíku, takže vozík nekmitá a nevyjede z koleje. Takové „pravidlo“ nikdo nenapsal; vypadlo z evoluce.

Definice — zdatnost regulátoru a evoluce vah

Nechť w = (w1, …, w4, b) ∈ ℝ5 jsou váhy regulátoru 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) tři startovní stavy. Pro k ∈ {1, 2, 3} označme Tk(w) ∈ {1, …, 1 000} počet kroků, které pokus ze startu s(k) s tímto regulátorem trvá (do pádu tyče či vyjetí vozíku, nejvýš 1 000). Zdatnost regulátoru je

Z(w) = T1(w) + T2(w) + T3(w)/3 ∈ [1, 1 000].

Tři starty místo jednoho brání tomu, aby evoluce našla regulátor, který umí jen jednu výchozí polohu. Z je po částech konstantní — malá změna vah počet kroků většinou nezmění vůbec, takže gradient je skoro všude nula. Proto evoluce.

Evoluce vah evoluční strategií (5, 20) (viz díl Evoluční strategie a genetické programování): vstupem je funkce Z a počet generací G ∈ ℕ, výstupem nejlepší nalezené váhy.

  1. Zvol 5 rodičů w(1), …, w(5) ∈ ℝ5, každou jejich složku nezávisle a rovnoměrně z [−1, 1].
  2. V každé generaci g = 1, …, G vytvoř 20 potomků: pro každého zvol rodiče w rovnoměrně náhodně z pěti a polož w′ = w + 0,5 · z, kde z ∈ ℝ5 má složky nezávislé se standardním normálním rozdělením N(0, 1) (viz díl Přehled pravděpodobnostních rozdělení).
  3. Novými rodiči je 5 potomků s největší zdatností Z; staří rodiče do další generace nepostupují.
  4. Po G generacích vrať váhy s největší zdatností, jaká se za běh objevila.
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á aktivace: síla ±10 N

def zdatnost(w):                     # simuluj(): kroky do pádu, nejvýš 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): přežijí jen potomci
Příklad — jak se vyvinutý regulátor rozhoduje

Váhy nalezené evolucí (zaokrouhleně): w = (0,05; 1,01; 1,37; 4,23), b = 0,09 pro (x, v, θ, ω). Barvy podle rozboru neuronu na začátku dílu: váhy, vstupy, práh.

tyč nakloněná, stojí: (0, 0, 0,05, 0) → u = 1,37 · 0,05 + 0,09 ≈ +0,16 → +10 N, vozík podjede pod tyč

tyč nakloněná, ale už se vrací: (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í

Ve druhém případě je tyč nakloněná stejně, ale regulátor tlačí opačně: úhlová rychlost −0,1 rad/s váží s vahou 4,23 víc než úhel 0,05 rad s vahou 1,37. Tyč se vrací sama, a kdyby vozík dál tlačil, přehoupla by se. Přímočarý regulátor „jen podle úhlu“ by v obou stavech tlačil stejně — proto tyč rozkmitá.

3. Proč evoluce, a ne gradient

  • Řídká odměna. U kyvadla, hry nebo robota se kvalita pozná až po celé epizodě. Evoluci stačí jedno číslo na konci.
  • Nederivovatelné části. Skoková aktivace, simulátor fyziky, pravidla hry — evoluce je nemusí derivovat.
  • Paralelnost. Každého jedince lze ohodnotit na jiném počítači nezávisle.
  • Struktura. Gradient umí ladit váhy, ale ne přidat neuron. Evoluce může měnit i to, jak síť vypadá.

Nevýhodou je hladovost: místo jednoho gradientu, který řekne směr pro všechny váhy najednou, zkouší evoluce náhodné změny. Pro sítě s miliony vah bývá gradient mnohem úspornější, pokud ho vůbec jde spočítat.

4. Když nestačí váhy: XOR

Funkce XOR vrací 1, když je právě jeden ze dvou vstupů 1. Jak ukázal díl Logika a důkazy, jediný neuron ji neumí: jeho výstup dělí rovinu vstupů přímkou a body (0, 1), (1, 0) od (0, 0), (1, 1) žádná přímka neoddělí. Na XOR je potřeba aspoň jeden skrytý neuron. A tím se otevírá otázka, kterou samotná evoluce vah nevyřeší: kolik neuronů a jak je zapojit?

Věta — XOR není lineárně separabilní

Nechť XOR : {0, 1}2 → {0, 1} je funkce daná předpisem XOR(x1, x2) = 1 ⇔ x1 ≠ x2. Pak neexistují čísla w1, w2, b ∈ ℝ taková, že pro všechna (x1, x2) ∈ {0, 1}2 platí

w1x1 + w2x2 + b > 0  ⇔  XOR(x1, x2) = 1.

Žádná přímka tedy neoddělí body, kde je XOR roven 1, od bodů, kde je roven 0.

Důkaz. Kdyby taková čísla existovala, platilo by

(0, 0): b ≤ 0    (1, 1): w1 + w2 + b ≤ 0

(1, 0): w1 + b > 0    (0, 1): w2 + b > 0

Sečtením prvního řádku dostaneme w1 + w2 + 2b ≤ 0, sečtením druhého w1 + w2 + 2b > 0. Spor. ∎

Důkaz nepoužívá tvar aktivační funkce — platí pro každý jediný neuron, jehož výstup závisí jen na znaménku váženého součtu (skok i sigmoida s prahem 0,5).

Odpovídat se dá ručně — navrhnout architekturu a evolucí ladit jen váhy. Ale u složitějších úloh netušíme, jaká architektura je správná. Proč ji nenechat vyvinout taky?

5. NEAT: evoluce rostoucích sítí

Pokusy evolvovat strukturu sítí narážely na tři problémy. Jak křížit dvě sítě s jiným tvarem? Jak dát šanci nové struktuře, která je zpočátku horší, protože její nové váhy ještě nejsou vyladěné? A jak zabránit, aby sítě zbytečně bobtnaly? Kenneth Stanley a Risto Miikkulainen v roce 2002 odpověděli algoritmem NEAT (NeuroEvolution of Augmenting Topologies) se třemi myšlenkami.

Definice — genom NEAT a historické značky

Nechť uzly sítě (vstupy, práh, výstupy a skryté neurony, viz definici neuronové sítě výše) jsou označené přirozenými čísly. Gen spoje je pětice (u, v, w, e, i), kde u je zdrojový a v cílový uzel spoje u → v, w ∈ ℝ jeho váha, e ∈ {0, 1} příznak (e = 1: spoj je zapnutý a v síti se počítá, e = 0: vypnutý) a i ∈ ℕ jeho inovační číslo. Genom je konečná množina genů spojů, v níž mají různé geny různá inovační čísla; určuje síť, jejíž hrany jsou zapnuté spoje.

Inovační čísla přiděluje jeden čítač pro celou populaci: kdykoli mutace poprvé vytvoří spoj u → v, dostane další volné číslo; vznikne-li stejná strukturální změna (spoj mezi týmiž uzly) u jiného jedince, dostane číslo stejné.

Mutace genomu jsou tři:

  1. změna vah — váhy w genů se změní (přičtením náhodného čísla nebo novou náhodnou hodnotou);
  2. přidání spoje — přibude gen (u, v, w, 1, i) s náhodnou váhou w pro dva dosud nespojené uzly u, v (náš program přidá spoj, jen když nevznikne cyklus, takže síť zůstává dopředná);
  3. přidání neuronu — pro zvolený zapnutý gen (a, b, w, 1, i) vznikne nový skrytý neuron h, gen se vypne (e ← 0) a přibudou geny (a, h, 1, 1, i′) a (h, b, w, 1, i″) s novými inovačními čísly.

Křížení dvou rodičů zarovná jejich geny podle inovačních čísel. Potomek dostane každý shodný gen (inovační číslo je v obou rodičích) od rodiče zvoleného náhodně se stejnou pravděpodobností a každý ostatní gen (je jen v jednom z rodičů) jen tehdy, je-li v genomu zdatnějšího rodiče.

Laicky řečeno

Inovační číslo je rodný list spoje. Když dvě sítě mají spoj s číslem 7, jde o „tentýž“ spoj, i když se k němu každá dostala jinou cestou — a při křížení se dají spárovat jako stejné geny u dvou rodičů. Nový neuron se vkládá tak, aby síť zpočátku počítala podobně jako předtím; nic zásadního se nerozbije, jen přibude možnost.

Příklad — přidání neuronu na spoj s vahou 2

Náš NEAT používá stejně jako původní článek strmější sigmoidu σ(z) = 1/1 + e−4,9z. Spoj x1 → y s vahou 2 přispíval do výstupu 2x1. Po rozdělení vede x1 → h s vahou 1 a h → y s vahou 2:

x1 = 1:   2 · σ(1) = 2 · 0,993 ≈ 1,985   (předtím 2)

x1 = 0:   2 · σ(0) = 2 · 0,5 = 1   (předtím 0)

„Podobně“ tu tedy znamená jen zčásti: pro vstup 1 je změna zanedbatelná, pro vstup 0 přibude do součtu jednička, protože sigmoida v nule vrací polovinu. Síť se tím trochu pokazí — a právě proto potřebuje nová struktura ochranu, o které je řeč dál.

Definice — speciace a sdílení zdatnosti

Nechť G1, G2 jsou neprázdné genomy (viz definici genomu výše) a I1, I2 množiny inovačních čísel jejich genů. Označme m = min(max I1, max I2) a

  1. shodné geny: inovační čísla z I1 ∩ I2;
  2. disjunktní geny: čísla i ∈ (I1 ∖ I2) ∪ (I2 ∖ I1) s i ≤ m (chybí jednomu z genomů „uprostřed“); D je jejich počet;
  3. přebytečné geny: čísla i ∈ (I1 ∖ I2) ∪ (I2 ∖ I1) s i > m (za koncem kratšího genomu); E je jejich počet;
  4. W̄ je průměr |wi(1) − wi(2)| přes shodné geny i (rozdíl vah téhož genu v obou genomech; nemají-li shodné geny, W̄ = 0);
  5. N = max(|G1|, |G2|) je počet genů většího genomu, pokud je aspoň 20, jinak N = 1.

Pro konstanty c1, c2, c3 ≥ 0 je kompatibilitní vzdálenost genomů G1, G2 číslo

δ(G1, G2) = c1 E/N + c2 D/N + c3 W̄.

Speciace: nechť δt > 0 je práh a každý druh má zástupce. Genom patří do prvního druhu, s jehož zástupcem Z má δ(genom, Z) < δt; neexistuje-li takový, založí nový druh. Druhy S1, …, SK tak rozdělí populaci velikosti P na disjunktní neprázdné části.

Sdílení zdatnosti: má-li jedinec i ∈ Sk zdatnost fi ≥ 0, je jeho sdílená zdatnost f′i = fi/|Sk|, druh k má F̄k = ∑i ∈ Sk f′i (průměrnou zdatnost svých členů) a dostane

nk = P · F̄k/∑j=1K F̄j

potomků (zaokrouhleno dolů, zbytek dostane druh s nejlepší sítí). Podobné genomy tedy tvoří druh, zdatnost jedince se dělí velikostí jeho druhu a potomci se rozdělují mezi druhy podle jejich průměrné zdatnosti.

Laicky řečeno

Sítě s podobnou stavbou soutěží hlavně mezi sebou, ne s celou populací. Nový neuron tak dostane pár generací na to, aby se jeho váhy vyladily, místo aby ho hned smetly zavedené sítě. A protože se zdatnost v druhu dělí, žádný druh nemůže ovládnout celou populaci.

δ = c1 E/N + c2 D/N + c3 W̄

c1 E
přebytečné geny — struktura, kterou jeden genom získal až po posledním společném „vynálezu“; znamená mladší, odlišnou větev vývoje
c2 D
disjunktní geny — vynálezy z doby, kdy už oba existovali, které má jen jeden z nich; další míra rozdílu stavby
N
velikost většího genomu — aby dva velké genomy, které se liší o pár genů z mnoha, nevyšly stejně vzdálené jako dva malé, které se liší skoro ve všem; u genomů pod 20 genů se bere N = 1
c3 W̄
průměrný rozdíl vah shodných genů — stejně zapojené sítě s velmi jinými vahami počítají jiné funkce; váha c3 je menší, protože stavba se mění vzácněji a víc znamená
Konstanty c1 = c2 = 1, c3 = 0,4 a práh δt = 3 jsou hodnoty, které pro XOR použili Stanley a Miikkulainen (2002); stejné má i náš program.
Příklad — vzdálenost po přidání neuronu

Genom A má geny 1–5. Genom B vznikl z podobného předka: má také geny 1–5 (gen 3 vypnutý, protože ho rozdělil nový neuron) a navíc geny 6 a 7 z přidání neuronu. Váhy shodných genů se liší o 0,2; 0,6; 0; 0,9 a 0,8.

shodné: 1–5 → W̄ = 0,2 + 0,6 + 0 + 0,9 + 0,8/5 = 0,5

přebytečné: 6, 7 (za koncem kratšího genomu, ten končí genem 5) → E = 2;   disjunktní: žádné → D = 0;   genomy mají pod 20 genů → N = 1

δ = 1 · 2/1 + 1 · 0/1 + 0,4 · 0,5 = 2,2 < 3 → stejný druh   (barvy podle vzorce výše)

Kdyby B získal ještě jeden spoj (gen 8), vyšlo by E = 3 a δ = 3,2 ≥ 3 — B by založil nový druh. Jediný nový neuron tedy síť z druhu nevyřadí, ale nový neuron s novým spojem už ano.

nk = P · F̄k/∑j F̄j,   F̄k = ∑i ∈ Sk fi/|Sk|

nk
počet potomků druhu k v další generaci — tím se v NEATu odměňuje úspěch, ne výběrem jednotlivců z celé populace
P
velikost populace (150) — potomci se dělí jako koláč, populace neroste ani nezmenšuje
|Sk|
počet členů druhu — sdílení zdatnosti: zdatnost každého člena se dělí velikostí jeho druhu, f′i = fi/|Sk|; velký druh tak nemůže získat víc jen tím, že je velký
F̄k
součet sdílených zdatností druhu, tedy jeho průměrná zdatnost — o podílu na koláči rozhoduje kvalita, ne počet
∑j F̄j
součet přes všechny druhy — dělením vznikne podíl, který se sečte na 1, takže se rozdělí přesně P potomků (po zaokrouhlení dolů dostane zbytek nejlepší druh)
Příklad — proč sdílení chrání nový druh

Populace 150: zavedený druh A má 120 sítí s průměrnou zdatností 9,0, nový druh B se skrytým neuronem 30 sítí s průměrnou zdatností 7,5.

se sdílením (barvy podle vzorce výše): nA = 150 · 9,0/16,5 ≈ 81,8 → 81 (+1 zbytek) = 82,   nB = 150 · 7,5/16,5 ≈ 68,2 → 68

bez sdílení (podle součtu zdatností 120 · 9,0 = 1 080 a 30 · 7,5 = 225): A ≈ 150 · 1 080/1 305 ≈ 124,   B ≈ 26

Bez sdílení by nový druh za pár generací vymřel, protože je horší a menší. Se sdílením dostane víc potomků, než má členů, a má čas vyladit váhy.

Třetí myšlenka je nejjednodušší: začít od minima. Všechny sítě na začátku nemají žádný skrytý neuron — vstupy vedou rovnou do výstupu. Struktura přibývá jen tehdy, když se vyplatí. Výsledné sítě proto bývají malé.

Všechno dohromady — jedna generace našeho zjednodušeného NEATu (pravděpodobnosti jsou ty, se kterými běží program pro XOR):

populace ← 150 minimálních sítí (x₁, x₂ a práh rovnou do y, váhy náhodně z [−2, 2])
pro generaci g = 0, 1, …, 100:
    ohodnoť každou síť zdatností f
    pokud některá síť řeší úlohu: konec
    rozděl sítě do druhů: síť patří do prvního druhu, s jehož zástupcem má δ < 3,
                          jinak založí nový
    vyřaď druhy, které se 15 generací nezlepšily (kromě druhu s nejlepší sítí)
    druhu k přiděl n_k = 150 · F̄_k / ∑ F̄_j potomků
    v každém druhu:
        rodiče ← nejlepších 20 % členů
        má-li druh víc než 5 členů, jeho nejlepší síť přejde beze změny
        každý další potomek:
            s pravděpodobností 0,75 křížení dvou rodičů, jinak kopie jednoho
            s pravděpodobností 0,8 změň váhy (90 %: w ← w + N(0, 1), 10 %: nová náhodná)
            s pravděpodobností 0,1 přidej spoj
            s pravděpodobností 0,03 přidej neuron (rozděl náhodný zapnutý spoj)

6. NEAT na XOR

Náš zjednodušený NEAT má populaci 150 sítí a nejvýš 100 generací. V běhu z obrázku vyřešil XOR v generaci 27 sítí s jediným skrytým neuronem a sedmi spoji — což je nejmenší možné řešení:

f = ( 4 − ∑ |y − t| )2

∑ |y − t|
chyba — součet odchylek výstupu y od správné hodnoty t přes všechny čtyři vstupy; absolutní hodnota, aby se chyby nahoru a dolů nevyrušily
4
největší možná chyba (čtyři vstupy, každá odchylka nejvýš 1) — odečtením se z chyby, kterou chceme zmenšit, stane zdatnost, kterou evoluce zvětšuje, a ta je vždy nezáporná
2
umocnění — zesílí rozdíly blízko řešení: síť s chybou 0,5 má zdatnost 12,25, síť s chybou 1 jen 9, takže výběr víc odmění posledních pár procent
Zdatnost pro XOR podle původního článku NEAT (Stanley a Miikkulainen, 2002); nejvýš 16. Síť, která na všechno odpoví 0,5, má zdatnost (4 − 2)2 = 4. Za řešení se síť počítá, když po zaokrouhlení výstupu odpoví správně na všechny čtyři vstupy.
−1,4 −3,0 3,3 −3,4 −5,7 −3,7 0,9 x₁ x₂ 1 y h x₁x₂y 00 0,00 01 0,86 10 1,00 11 0,01
Síť pro XOR, kterou vypěstoval NEAT; vpravo její výstupy

Síť se dá přečíst. Skrytý neuron h se rozsvítí jen tehdy, když jsou oba vstupy 0 (oba mají velkou zápornou váhu, práh je kladný). Přímé spoje do výstupu by samy počítaly „ne oba zároveň“ — výstup 1 pro všechno kromě (1, 1) —, ale silně záporná váha od h ho pro (0, 0) vypne. Výstupy 0,000; 0,855; 1,000 a 0,005 jsou po zaokrouhlení přesně XOR. Počet druhů mezitím vzrostl z jednoho na zhruba dvacet.

Příklad — výpočet sítě pro všechny čtyři vstupy

Váhy (zaokrouhleně): 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. Aktivace je σ(z) = 1/1 + e−4,9z. Nejdřív se spočítá h, pak y (tabulka počítá s nezaokrouhlenými vahami, takže ruční přepočet se může lišit v poslední cifře):

(x1, x2)zhhzyy|y − t|
(0, 0)0,950,9903,32 − 5,69 · 0,990 = −2,320,0000,000
(0, 1)−2,720,000−2,96 + 3,32 = 0,360,8550,145
(1, 0)−2,430,000−1,42 + 3,32 = 1,891,0000,000
(1, 1)−6,090,000−1,42 − 2,96 + 3,32 = −1,060,0050,005

Chyba je 0,150 a zdatnost f = (4 − 0,150)2 ≈ 14,82 z 16 (barvy podle vzorce zdatnosti výše). Nejhůř síť odpovídá pro (0, 1): výstup 0,855 je správně nad polovinou, ale ne u jedničky — na řešení to stačí, další ladění vah by zdatnost ještě zvedlo.

Z padesáti běhů s různými semínky vyřešil NEAT XOR ve 47, v průměru za 31 generací, s 2,6 skrytého neuronu, které opravdu něco dělají. Původní článek uvádí 32 generací a 2,35 skrytého neuronu — náš zjednodušený NEAT je tedy blízko.

7. Na čem NEAT stojí

Stejných 50 běhů s vypnutou částí algoritmu:

VariantaVyřešilo XORPrůměrná generace
NEAT47 z 5031,1
bez speciace (jeden druh)1 z 50—
bez křížení50 z 5047,3

Bez speciace NEAT skoro nefunguje. Síť se skrytým neuronem je po vzniku horší než zavedené sítě bez něj, protože její nové váhy jsou náhodné — a v jedné společné soutěži ji výběr okamžitě vyřadí. Speciace ji ochrání, dokud nedozraje. Bez křížení se XOR vyřeší také, jen pomaleji a s většími sítěmi (3,1 aktivního skrytého neuronu): křížení pomáhá skládat dohromady dílčí objevy různých jedinců.

8. Následovníci NEATu

  • HyperNEAT (Stanley a kol., 2009) evolvuje malou síť, která teprve vygeneruje váhy velké sítě podle geometrie úlohy — jako genom, který nepopisuje každou buňku, ale pravidla růstu.
  • Hledání novosti (Lehman a Stanley, 2011) neodměňuje zdatnost, ale nové chování. V bludišti s klamavými slepými uličkami našlo cíl častěji než hledání řízené zdatností.
  • Hluboká neuroevoluce. V roce 2017 ukázal tým Uber AI, že prostý genetický algoritmus dokáže trénovat sítě s miliony vah na hrách Atari srovnatelně se zpětnovazebním učením.
  • Evoluční hledání architektur. Síť AmoebaNet (Google, 2019) vznikla evolucí stavebních bloků a v rozpoznávání obrázků na ImageNetu patřila v té době k nejlepším. Dnes architektury častěji navrhují lidé nebo jiné metody, ale evoluce zůstává jednou z možností.

9. Shrnutí

  • Neuroevoluce pěstuje neuronové sítě evolučními algoritmy — hodí se tam, kde gradient nejde spočítat nebo kde odměna přichází až na konci.
  • Evoluce vah jednoho neuronu udrží kyvadlo na vozíku 20 sekund po zhruba třech stech pokusech; náhodné váhy dají v mediánu 9 kroků.
  • Na XOR nestačí jeden neuron — je potřeba změnit strukturu sítě.
  • NEAT evolvuje váhy i strukturu: historické značky umožní křížení, speciace chrání nové struktury a sítě rostou od minima.
  • Bez speciace vyřešil NEAT XOR v 1 z 50 běhů, se speciací ve 47 — a nejlepší řešení mělo jediný skrytý neuron.

Chcete si to osahat? Nechte AI agenta napsat kyvadlo na vozíku s evolucí regulátoru a pak zkuste dvě tyče různé délky na jednom vozíku — slavnou těžší verzi, na které NEAT kdysi vynikal.

Máte na to jiný názor? Napište na support@coden-app.com.

Agent na vašem počítači, ovládaný z telefonu