Genetické algoritmy: populace, křížení, mutace a výběr na batohu na výlet
Genom a zdatnost, turnajový výběr, jednobodové křížení, mutace a elitismus, věta o schématech a předčasná konvergence — na úloze batohu se známým optimem, od stanu po FunSearch a AlphaEvolve.
Série Základy AI Díl 27 z 83
- Mapa umělé inteligence: co je co a jak to do sebe zapadá
- Stručná historie umělé inteligence: od Turinga po jazykové modely
- Data, model, trénink, inference: základní pojmy na jednom příkladu
- Jak číst matematický zápis: symboly, indexy, sumy a kvantifikátory
- Množiny a relace: stavebnice, ze které se skládají definice v AI
- Funkce a zobrazení: proč je každý model v AI funkce
- Logika a důkazy: pravidla, podle kterých se v AI uvažuje
- Grafy a stromy: struktura, na které stojí hledání i neuronové sítě
- Lineární algebra pro strojové učení: vektory, matice a proč AI hlavně násobí
- Derivace, gradient a řetízkové pravidlo: jak model zjistí, kterým směrem se učit
- Gradientní sestup: jak se model učí
- Co je pravděpodobnost: od hodu kostkou ke Kolmogorovovým axiomům
- Podmíněná pravděpodobnost a Bayesova věta: jak změnit odhad, když se dozvíte něco nového
- Náhodná veličina a distribuční funkce: jedna funkce, která o rozdělení řekne všechno
- Funkce hustoty a pravděpodobnostní funkce: proč má spojitá veličina v bodě pravděpodobnost nula
- Střední hodnota, rozptyl a kovariance: kde rozdělení leží, jak je široké a co s čím souvisí
- Přehled pravděpodobnostních rozdělení: Bernoulli, binomické, Poisson, rovnoměrné, normální a exponenciální
- Zákon velkých čísel a centrální limitní věta: proč se průměry chovají tak předvídatelně
- Statistika a odhady parametrů: maximální věrohodnost, MAP a intervaly spolehlivosti
- Teorie informace: entropie, křížová entropie a KL divergence — odkud se berou ztrátové funkce
- Prohledávání stavového prostoru: BFS, DFS, UCS a A* s animacemi
- Hry a protivník: minimax, alfa-beta ořezávání a Monte Carlo tree search
- Splňování omezujících podmínek: backtracking, propagace omezení a AC-3 na sudoku a mapě krajů
- Logika a znalostní systémy: dopředné a zpětné řetězení, rezoluce a expertní systémy
- Plánování: STRIPS, svět kostek, heuristiky z relaxace a plánování v AI agentech
- Lokální hledání a simulované žíhání: obchodní cestující přes krajská města
- 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
- Optimalizace mravenčí kolonií: jak feromonová stopa najde krátkou cestu
- Optimalizace hejnem částic: setrvačnost, vlastní zkušenost a zkušenost hejna
- Neuroevoluce: evoluce vah i tvaru neuronových sítí a algoritmus NEAT
- Fuzzy množiny a funkce příslušnosti: jak zapsat „trochu teplo“
- Fuzzy logika a pravděpodobnost: proč „trochu teplo“ neznamená „pravděpodobně teplo“
- Fuzzy logika: t-normy, implikace a pravidla KDYŽ–PAK
- Fuzzy řízení: Mamdani a Sugeno od ventilátoru po kyvadlo na vozíku
- Fuzzy shlukování: algoritmus fuzzy c-means a body mezi shluky
- Neuro-fuzzy systémy (ANFIS): fuzzy pravidla, která se učí z dat
- Markovovy řetězce: přechodová matice, stacionární rozdělení a PageRank
- Skryté Markovovy modely: Viterbiho algoritmus a nepoctivé kasino
- Bayesovské sítě: proč je tráva mokrá a co z toho plyne pro postřikovač
- Kalmanův filtr: jak z nepřesných měření odhadnout, kde auto je a jak rychle jede
- Druhy strojového učení: s učitelem, bez učitele, s částečným učitelem a další
- Přeučení a regularizace: proč model, který zná data nazpaměť, selže
- Vyhodnocení modelu: křížová validace, F1 a křivka ROC
- Shlukování a snížení dimenze: k-means, PCA a t-SNE
- Klasifikace a regrese: dvě úlohy učení s učitelem
- Lineární regrese: nejmenší čtverce geometricky i maticově
- Polynomiální a nelineární regrese: jak přímku ohnout
- Logistická regrese: sigmoida, šance a křížová entropie
- Vícetřídní klasifikace a softmax: od dvou tříd k mnoha
- Naivní Bayesův klasifikátor: spamový filtr, který funguje lépe, než by měl
- Ztrátové funkce: co přesně model minimalizuje
- Rozhodovací stromy a k nejbližších sousedů: modely bez vzorců
- Ansámbly: náhodný les a gradient boosting
- SVM a jádrový trik: nejširší hranice a jak ji ohnout
- Signál a vzorkování: proč platí Nyquistův teorém
- Fourierova transformace: rozklad signálu na frekvence
- Filtry a konvoluce: vyhlazení, hrany a odstranění šumu
- Zvuk a řeč: spektrogram, melová škála a MFCC
- Obraz jako signál: pixely, barvy, konvoluce a hrany
- Perceptron a umělý neuron: nejjednodušší neuronová síť a co neumí
- Neuronová síť od nuly: zpětné šíření chyby krok za krokem
- Aktivace, inicializace a normalizace: drobnosti, na kterých hluboká síť stojí
- Konvoluční sítě: jak síť poznává obrázky
- Rekurentní sítě: paměť pro posloupnosti a mizející gradient
- LSTM a GRU: brány, které rozhodují, co si síť zapamatuje
- Autoenkodéry: síť, která se učí data stlačit a zase rozbalit
- Embeddingy a word2vec: jak se slovo stane vektorem
- Mechanismus pozornosti: jak se model naučí, kam se dívat
- Transformery a velké jazykové modely: architektura krok za krokem
- Tokenizace: jak se text rozseká na kousky pro model
- Předtrénování a škálování: proč větší model a víc dat funguje
- Doladění a RLHF: jak se z doplňovače textu stane asistent
- Prompty, kontext a RAG: jak modelu dát správné informace
- Variační autoenkodéry (VAE): nové obrázky ze spojitého latentního prostoru
- Generativní adversariální sítě (GAN): padělatel proti detektivovi
- Difúzní modely: jak se z čistého šumu stane obrázek
- Markovovy rozhodovací procesy: stavy, akce, odměny a Bellmanovy rovnice
- Q-learning a DQN: učení hodnoty akcí od tabulky po neuronovou síť
- Policy gradient a PPO: učení přímo strategie
- Jak funguje AI agent: jazykový model ve smyčce s nástroji
- Programování s AI agenty: zadání, testy a kontrola
- Vyhodnocení a bezpečnost AI systémů: jak měřit a jak hlídat
Celá osnova série 83 z 83 témat hotovo
- Jak zakódovat řešení jako genom a jak výběr, křížení a mutace vylepšují celou populaci.
- Proč bez mutace evoluce předčasně zkonverguje a k čemu je křížení.
- Kde se genetické algoritmy používají dnes — i s jazykovým modelem v roli mutace.
Co se hodí znát předem: Lokální hledání a simulované žíhání: obchodní cestující přes krajská města
Příroda nemá inženýra, a přesto vyrobila oko, křídlo i mozek. Stačily jí tři věci: jedinci se od sebe liší, své vlastnosti předávají potomkům a ti zdatnější mají potomků víc. V sedmdesátých letech John Holland z Michiganské univerzity ukázal, že tytéž tři věci fungují i v počítači — jako obecná metoda, jak hledat dobrá řešení úloh, u kterých nevíme, jak je řešit chytře. Genetický algoritmus nepotřebuje gradient, nepotřebuje vzorec, potřebuje jen umět říct, které ze dvou řešení je lepší.
Navazuje na díl Lokální hledání a simulované žíhání. Žíhání vylepšovalo jedno řešení; genetický algoritmus jich vylepšuje celou populaci najednou.
1. Úloha: batoh na výlet
Chystáte se na několikadenní výlet. Doma máte 24 věcí — stan, spacák, vařič, foťák, knihu… — a každá něco váží a k něčemu je. Batoh smí vážit nejvýš 10 kg. Co vzít, aby byl užitek co největší?
Definice — úloha batohu (0/1)
Nechť n ∈ ℕ, n ≥ 1, je počet věcí, w1, …, wn > 0 jejich hmotnosti, u1, …, un > 0 jejich užitky a W > 0 nosnost batohu. Výběr věcí zapíšeme vektorem x = (x1, …, xn) ∈ {0, 1}n, kde xi = 1, právě když i-tou věc bereme. Výběr x je přípustný, právě když ∑i=1n wixi ≤ W. Úloha batohu (0/1) je úloha najít
x* ∈ argmax { ∑i=1n uixi : x ∈ {0, 1}n, ∑i=1n wixi ≤ W }.
Hledáme tedy přípustný výběr s největším součtem užitků; „0/1“ v názvu znamená, že každou věc lze vzít jen celou a nejvýš jednou.
Každá věc je otázka „beru, neberu“ — jednička, nebo nula. Možností je 224, tedy 16 777 216 batohů. Hladová strategie „nejdřív to nejužitečnější na kilo“ často funguje, ale optimum nezaručí: jedna těžká věc může vytlačit tři lehké, které byly dohromady cennější.
Pro celočíselné hmotnosti se dá optimum spočítat přesně dynamickým programováním — ze všech 24 věcí a nosnosti 1 000 dekagramů je to 24 000 kroků. Nejlepší batoh má 727 bodů užitku a váží 9,9 kg; doma zůstane jídlo navíc, foťák, kniha, sandály a opalovací krém. Díky tomu zase přesně uvidíme, jak blízko se evoluce dostane. Genetický algoritmus se ale hodí hlavně tam, kde takový přesný postup neexistuje.
Dynamické programování vyplňuje tabulku T[i][c] — nejlepší užitek, kterého lze dosáhnout jen z prvních i věcí, když smějí vážit nejvýš c. Každé políčko se spočítá z řádku nad ním:
T[i][c] = max( T[i − 1][c] , T[i − 1][c − wi] + ui )
- T[i][c]
- nejlepší užitek z prvních i věcí při nosnosti c; políčko T[n][W] je odpověď na celou úlohu
- T[i − 1][c]
- možnost „i-tou věc neberu“ — pak je nejlepší to, co šlo složit z předchozích věcí se stejnou nosností
- T[i − 1][c − wi]
- možnost „beru“ — věc zabere wi, takže na ostatní zbude jen c − wi; nejlepší využití zbytku už v tabulce máme (smí se jen pro c ≥ wi)
- ui
- užitek věci, kterou jsme v té druhé možnosti přibalili
Příklad — tabulka pro čtyři věci a nosnost 50 dkg
Čelovka (10 dkg, 25 bodů), nůž (10 dkg, 18), vařič (40 dkg, 30) a karimatka (50 dkg, 45). Všechny hmotnosti jsou násobky deseti, takže stačí sloupce po 10 dkg:
| věci | c = 0 | 10 | 20 | 30 | 40 | 50 |
|---|---|---|---|---|---|---|
| žádná | 0 | 0 | 0 | 0 | 0 | 0 |
| + čelovka | 0 | 25 | 25 | 25 | 25 | 25 |
| + nůž | 0 | 25 | 43 | 43 | 43 | 43 |
| + vařič | 0 | 25 | 43 | 43 | 43 | 55 |
| + karimatka | 0 | 25 | 43 | 43 | 43 | 55 |
Nůž, c = 20: T[2][20] = max(T[1][20], T[1][10] + 18) = max(25, 25 + 18) = 43
Vařič, c = 40: T[3][40] = max(T[2][40], T[2][0] + 30) = max(43, 0 + 30) = 43 — vařič se nevyplatí
Vařič, c = 50: T[3][50] = max(T[2][50], T[2][10] + 30) = max(43, 25 + 30) = 55 — vařič a čelovka
Karimatka, c = 50: T[4][50] = max(T[3][50], T[3][0] + 45) = max(55, 0 + 45) = 55
(Barvy podle vzorce výše.)
Hladová strategie by vzala věci podle užitku na dekagram: čelovku (2,5 bodu/dkg), nůž (1,8), pak by se karimatka (0,9) ani vařič (0,75) do zbylých 30 dkg nevešly — jen 43 bodů. Ve velké úloze s 24 věcmi skončí hladová strategie na 702 bodech: naplní batoh drobnostmi a na stan (220 dkg) už nezbude místo.
def batoh(w, u, W): # w, u: hmotnosti a užitky, W: nosnost
T = [0] * (W + 1) # řádek pro „žádná věc“
for i in range(len(w)):
for c in range(W, w[i] - 1, -1): # odzadu: T[c − w[i]] je ještě z řádku i − 1
T[c] = max(T[c], T[c - w[i]] + u[i])
return T[W] # n · W kroků: 24 · 1000 = 24 000
2. Jedinec, genom a zdatnost
Definice — genom, populace, zdatnost
Nechť je dána úloha batohu s n věcmi, hmotnostmi wi a nosností W v dekagramech a užitky ui (i = 1, …, n; u nás n = 24).
- Genom (chromozom) je zakódované řešení; pro batoh je to řetězec x = (x1, …, xn) ∈ {0, 1}n. Jeho složky xi — jeden bit na věc — nazýváme geny.
- Populace velikosti μ ∈ ℕ je μ-tice genomů P = (x(1), …, x(μ)), x(j) ∈ {0, 1}n; tentýž genom v ní může být víckrát (na pořadí nezáleží, jde tedy o multimnožinu s μ prvky). Prvkům populace říkáme jedinci.
- Zdatnost (fitness) je funkce F : {0, 1}n → ℝ, kterou algoritmus maximalizuje. Pro batoh ji definujeme s trestem za přetížení: F(x) = ∑i=1n uixi, je-li ∑i=1n wixi ≤ W, F(x) = ∑i=1n uixi − 3 · (∑i=1n wixi − W), jinak.
Pro přípustný batoh je tedy zdatnost rovna jeho užitku a za každý dekagram přes nosnost se odečtou 3 body.
Jedinec je jeden konkrétní batoh zapsaný jako řada jedniček a nul. Zdatnost říká, jak je dobrý. Přetížený batoh nezakážeme, jen ho potrestáme — za každý dekagram navíc tři body dolů. Algoritmus se tak o hranici nosnosti dozví postupně, a i přetížený batoh může mít geny, které se později hodí.
F(x) = ∑ uixi − 3 · max(0, ∑ wixi − W)
- F(x)
- zdatnost batohu x — jediné číslo, podle kterého výběr porovnává jedince
- ∑ uixi
- užitek zabalených věcí (xi = 1 věc započítá, 0 vynechá) — to, co doopravdy chceme maximalizovat
- 3
- cena jednoho dekagramu přes limit — je větší než nejlepší poměr užitku a hmotnosti (čelovka, 2,5 bodu/dkg), takže přibalit cokoli do už přetíženého batohu zdatnost vždy sníží
- max(0, ∑ wixi − W)
- přetížení v dekagramech; max s nulou zajistí, že batoh, který se vejde, trest nedostane a lehčí batoh není zvýhodněn
Příklad — zdatnost dvou batohů
Optimum: užitek 727, hmotnost 990 dkg ≤ 1 000 ⇒ F = 727 − 3 · 0 = 727
Optimum + foťák (80 dkg, 20 bodů): užitek 747, hmotnost 1 070 dkg ⇒ F = 747 − 3 · 70 = 537
(Barvy podle vzorce výše.)
Foťák přidá 20 bodů, ale přetížení 70 dkg stojí 210 — výběr takový batoh spolehlivě odsune.
3. Výběr
Definice — turnajový a ruletový výběr
Nechť P = (x(1), …, x(μ)) je populace velikosti μ a F : {0, 1}n → ℝ zdatnost. Výběr je náhodný postup, který z P vrátí jednoho jedince (rodiče):
- Turnajový výběr velikosti k ∈ ℕ, k ≥ 1: vylosuj nezávisle a rovnoměrně indexy i1, …, ik ∈ {1, …, μ} (s vracením, tentýž index může padnout víckrát) a vrať jedince x(i*), kde i* ∈ argmaxj ∈ {i1, …, ik} F(x(j)) (při shodě zdatností kteréhokoli z nejlepších).
- Ruletový výběr (předpokládá F(x(j)) > 0 pro všechna j): vrať jedince x(i), i ∈ {1, …, μ}, s pravděpodobností P(vybrán x(i)) = F(x(i))/∑j=1μ F(x(j)).
Selekční tlak je kvalitativní pojem: jak silně výběr upřednostňuje zdatnější jedince. Měřit ho lze například poměrem očekávaného počtu výběrů nejlepšího a průměrného jedince (viz příklad níže); u turnaje roste s k.
Turnaj: vytáhnete tři náhodné batohy a rodičem se stane ten nejlepší z nich. Lepší batohy tak mají víc dětí, ale i průměrný má šanci, když se potká se slabšími. Kdyby se množili jen ti úplně nejlepší, populace by rychle zdegenerovala na kopie jednoho jedince — a s ní by zmizela rozmanitost, ze které evoluce žije.
Jak silný je turnaj, se dá spočítat přesně. Náš program losuje k jedinců s vracením (tentýž jedinec se může do turnaje dostat dvakrát). Seřaďme populaci od nejlepšího (i = 1) po nejhoršího (i = μ):
P(vyhraje i-tý) = (μ − i + 1)k − (μ − i)k/μk
- P(vyhraje i-tý)
- šance, že se rodičem stane právě i-tý nejlepší jedinec
- (μ − i + 1)k
- počet turnajů, ve kterých nikdo není lepší než i-tý — všech k losů padne mezi něj a horší
- (μ − i)k
- z nich odečteme turnaje, ve kterých i-tý vůbec není — ty by vyhrál někdo horší; rozdíl jsou turnaje, kde je i-tý nejlepší přítomný
- μk
- počet všech možných turnajů (k losů, každý z μ jedinců) — dělením dostaneme pravděpodobnost
Příklad — turnaj ze tří ve 40 batozích
μk = 403 = 64 000. Za generaci se vybírá 38 rodičů (dvě místa zaberou elitní jedinci); barvy podle vzorce výše:
nejlepší: 403 − 393/64 000 = 64 000 − 59 319/64 000 ≈ 7,31 %, očekávaně 38 · 0,0731 ≈ 2,78 výběru
20. nejlepší: 213 − 203/64 000 = 9 261 − 8 000/64 000 ≈ 1,97 %, očekávaně ≈ 0,75 výběru
nejhorší: 13 − 03/64 000 ≈ 0,0016 %, očekávaně ≈ 0,0006 výběru
Průměrný jedinec dostane 38/40 = 0,95 výběru, nejlepší skoro třikrát tolik. Obecně pro velkou populaci vychází nejlepšímu zhruba k-krát víc než průměru — proto selekční tlak roste s k.
4. Křížení a mutace
Definice — jednobodové křížení
Nechť n ≥ 2, a = (a1, …, an) a b = (b1, …, bn) ∈ {0, 1}n jsou genomy rodičů a pc ∈ [0, 1] pravděpodobnost křížení. Jednobodové křížení vytvoří dva potomky takto:
- S pravděpodobností 1 − pc křížení neproběhne a potomci jsou kopie rodičů a a b.
- Jinak vylosuj rovnoměrně bod křížení c ∈ {1, …, n − 1} a potomci jsou a′ = (a1, …, ac, bc+1, …, bn), b′ = (b1, …, bc, ac+1, …, an).
Potomci tedy převezmou prvních c genů od jednoho rodiče a zbylých n − c od druhého. Další varianty jsou dvoubodové křížení (dva body, prohodí se úsek mezi nimi) a uniformní křížení, kde pro každé i = 1, …, n nezávisle s pravděpodobností 1/2 platí a′i = ai, b′i = bi, jinak a′i = bi, b′i = ai.
Dva batohy si rozstřihnete na stejném místě a prohodíte konce. Dítě dostane začátek seznamu od jednoho rodiče a konec od druhého. Pokud jeden rodič dobře vyřešil spaní a druhý jídlo, má dítě šanci zdědit obojí.
Definice — bitová mutace
Nechť x = (x1, …, xn) ∈ {0, 1}n je genom a pm ∈ [0, 1] pravděpodobnost mutace. Bitová mutace vytvoří genom x′ ∈ {0, 1}n tak, že pro každé i = 1, …, n nezávisle na ostatních genech
x′i = 1 − xi s pravděpodobností pm, x′i = xi s pravděpodobností 1 − pm.
Každý gen se tedy s pravděpodobností pm překlopí (0 ↔ 1). Obvykle se volí pm = 1/n, takže se v průměru překlopí n · pm = 1 gen na jedince.
Občas se dítě od rodičů v jedné drobnosti liší: přibalí věc, kterou nikdo z rodičů neměl, nebo nějakou vyndá. Mutace je jediný zdroj úplně nových genů — křížení umí jen přeskládat to, co už v populaci je.
Příklad — kolik genů mutace překlopí
Počet překlopených genů má binomické rozdělení: P(j genů) = (n nad j) · pmj · (1 − pm)n−j. Pro n = 24 a pm = 1/24:
očekávaný počet: n · pm = 24 · 1/24 = 1
žádná změna: (23/24)24 ≈ 0,360 (pro velké n se blíží 1/e ≈ 0,368)
právě jeden gen: 24 · 1/24 · (23/24)23 ≈ 0,376
Zhruba třetina potomků tedy zůstane beze změny, třetina se liší v jednom genu a zbytek ve dvou a více.
Rodiče jsou dva nejlepší batohy z počáteční populace (423 a 398 bodů), střih je za dvanáctou věcí. Žádný z potomků není lepší než lepší z rodičů — mají 403 a 418 bodů. Křížení zlepšení nezaručuje; jen nabízí nové kombinace a výběr pak rozhodne, které přežijí. Mutace u prvního potomka přibalila filtr na vodu (15 dkg, 32 bodů) a ten má rázem 435 bodů — víc než oba rodiče.
Příklad — přepočet křížení z obrázku
Užitek se sčítá po genech, takže stačí sečíst užitek začátku (věci 1–12) a konce (věci 13–24) zvlášť:
rodič 1: 310 + 113 = 423, rodič 2: 305 + 93 = 398
potomek 1 = začátek rodiče 1 + konec rodiče 2: 310 + 93 = 403
potomek 2 = začátek rodiče 2 + konec rodiče 1: 305 + 113 = 418
mutace přibalí filtr na vodu: 403 + 32 = 435
Rodič 1 je lepší v obou polovinách (310 > 305 a 113 > 93), takže s tímhle střihem ho žádný potomek překonat nemůže — křížení nemá z čeho složit lepší celek. Zlepšení přinesla až mutace.
5. Celý algoritmus
Algoritmus — genetický algoritmus
Vstup: délka genomu n ≥ 2, zdatnost F : {0, 1}n → ℝ, velikost populace μ ∈ ℕ, počet elitních jedinců e ∈ {0, …, μ − 1}, velikost turnaje k ≥ 1, pravděpodobnost křížení pc ∈ [0, 1], pravděpodobnost mutace pm ∈ [0, 1] a počet generací G ∈ ℕ. Výstup: nejzdatnější jedinec poslední generace; při e ≥ 1 je to zároveň nejzdatnější jedinec, kterého algoritmus kdy ohodnotil.
- Vytvoř náhodnou počáteční populaci P0 s μ jedinci (u nás má každý gen hodnotu 1 s pravděpodobností 0,3), ohodnoť je funkcí F a polož t ← 0.
- Je-li t = G, skonči a vrať jedince z Pt s největší zdatností.
- Do nové generace Pt+1 zkopíruj e nejzdatnějších jedinců z Pt beze změny (elitismus).
- Dokud má Pt+1 méně než μ jedinců: vyber z Pt turnajem velikosti k dva rodiče, proveď jejich jednobodové křížení s pravděpodobností pc, oba potomky zmutuj bitovou mutací s pm a přidej je do Pt+1; přebývá-li nakonec jedinec nad μ, zahoď ho.
- Ohodnoť jedince Pt+1, polož t ← t + 1 a pokračuj krokem 2.
Algoritmus se zastaví v kroku 2 po přesně G generacích.
Generace za generací: nejlepší dva přežijí rovnou, ostatní místa obsadí děti zdatných rodičů, trochu přeskládané a trochu pozměněné. Elitismus zaručí, že nejlepší nalezený batoh se nikdy neztratí.
import random
def evoluce(zdatnost, n, velikost=40, generaci=60, p_krizeni=0.9, elita=2):
pop = [[int(random.random() < 0.3) for _ in range(n)] for _ in range(velikost)]
for _ in range(generaci):
pop.sort(key=zdatnost, reverse=True)
dalsi = [g[:] for g in pop[:elita]] # elitismus
while len(dalsi) < velikost:
a, b = turnaj(pop, zdatnost), turnaj(pop, zdatnost)
if random.random() < p_krizeni:
bod = random.randrange(1, n)
a, b = a[:bod] + b[bod:], b[:bod] + a[bod:]
dalsi += [mutuj(a), mutuj(b)]
pop = dalsi[:velikost]
return max(pop, key=zdatnost)
def turnaj(pop, zdatnost, k=3):
return max(random.choices(pop, k=k), key=zdatnost) # k losů s vracením
def mutuj(g):
return [1 - x if random.random() < 1 / len(g) else x for x in g]
Cenu algoritmu měříme počtem ohodnocení zdatnosti — u skutečných úloh (simulace, měření) je to nejdražší krok. Ohodnotí se počáteční populace a pak každá generace: μ + G · μ = 40 + 60 · 40 = 2 440 ohodnocení pro μ = 40 jedinců a G = 60 generací. Elitní jedinci se ohodnocují znovu, i když se nezměnili; chytřejší program by si jejich zdatnost pamatoval.
6. Evoluce batohu
Pusťme algoritmus: 40 batohů, 60 generací, turnaj ze tří, křížení s pravděpodobností 0,9, mutace 1/24 a dva elitní jedinci. Obrázek ukazuje populaci v generacích 0, 5, 15, 30 a 60 — každý řádek je jeden batoh, každý sloupec jedna věc, nahoře pro srovnání optimum:
Na začátku je populace pestrá a batohy jsou spíš poloprázdné: každá věc se do nich dostala s pravděpodobností 0,3, takže váží kolem čtyř kilo (očekávaná hmotnost je 0,3 · ∑ wi = 0,3 · 12,75 kg ≈ 3,8 kg). Nejlepší má 423 bodů, průměr 231. Po pěti generacích nese stan 36 ze 40 batohů, láhev s vodou 35 a nejlepší batoh má 634 bodů. Kolem patnácté generace populace narazí na nosnost — 12 batohů je přetížených — a začne se učit, co obětovat: jídlo navíc a sandály skoro zmizely, foťák ale zatím nese 39 batohů. Optimum, 727 bodů, najde algoritmus poprvé v generaci 26; v generaci 30 už foťák zbyl jen v jednom batohu. Populace se ale nikdy neslije do jediného řešení — mutace pořád zkouší drobné odchylky.
Algoritmus k tomu ohodnotil 2 440 batohů — necelé dvě setiny procenta ze všech 16 777 216 možností. Náhodné hledání se stejným počtem pokusů ve sto opakováních optimum nenašlo ani jednou a v průměru skončilo na 574 bodech.
Příklad — proč náhodné hledání optimum nenajde
Náhodný batoh bere každou věc nezávisle s pravděpodobností 0,3. Optimum obsahuje 19 věcí a 5 jich vynechává, takže
P(náhodný batoh = optimum) = 0,319 · 0,75 ≈ 1,16 · 10−10 · 0,168 ≈ 1,95 · 10−11
očekávaný počet zásahů ve 2 440 pokusech: 2 440 · 1,95 · 10−11 ≈ 4,8 · 10−8
I kdyby se losovalo rovnoměrně (každá věc s pravděpodobností 1/2), je šance jedna ku 16 777 216 na pokus. Genetický algoritmus nevylosuje optimum najednou — skládá ho po kouscích z batohů, které už jsou dobré.
7. K čemu je křížení a k čemu mutace
Oranžová čára v grafu je týž běh s vypnutou mutací. Po jedenácti generacích uvízne na 573 bodech a už se nehne. Proč, ukáže srovnání ze sta běhů s různými semínky:
| Varianta | Našla optimum | Průměrný užitek |
|---|---|---|
| Výběr + křížení + mutace | 88 ze 100 | 726,6 |
| Výběr + mutace (bez křížení) | 70 ze 100 | 725,0 |
| Výběr + křížení (bez mutace) | 0 ze 100 | 596,8 |
| Náhodné hledání, stejně pokusů | 0 ze 100 | 573,5 |
Bez mutace ztratí populace rozmanitost: když gen v žádném jedinci není, křížení ho nevyrobí, a výběr navíc rychle vytlačí všechno kromě nejlepších. Tomu se říká předčasná konvergence. Bez křížení algoritmus funguje — je to vlastně populace horolezců s výběrem —, ale je pomalejší. Křížení pomáhá skládat dohromady dobré kusy, které vznikly v různých jedincích.
Věta — Hollandova věta o schématech
Nechť n ≥ 2. Schéma je řetězec H = (H1, …, Hn) ∈ {0, 1, ∗}n, kde ∗ znamená „cokoli“. Genom x ∈ {0, 1}n odpovídá schématu H, právě když xi = Hi pro všechna i s Hi ≠ ∗. Pozice i s Hi ≠ ∗ jsou pevné; předpokládejme, že aspoň jedna existuje. Definujme
- řád o(H) = |{i : Hi ≠ ∗}| — počet pevných pozic,
- délku δ(H) = max{i : Hi ≠ ∗} − min{i : Hi ≠ ∗} — vzdálenost první a poslední pevné pozice.
Nechť genetický algoritmus s populací velikosti μ a kladnou zdatností F > 0 tvoří celou novou generaci ruletovým výběrem, jednobodovým křížením s pravděpodobností pc a bitovou mutací s pravděpodobností pm (bez elitismu). Nechť m(H, t) je počet jedinců generace t, kteří odpovídají H, a je-li m(H, t) > 0, nechť F(H) je jejich průměrná zdatnost a F̄ průměrná zdatnost celé generace t. Pak pro očekávaný počet v další generaci (při dané generaci t) platí
E[m(H, t + 1)] ≥ m(H, t) · F(H)/F̄ · [1 − pc · δ(H)/n − 1 − o(H) · pm].
Slovy: výběr počet nositelů schématu násobí poměrem jejich zdatnosti k průměru a křížení s mutací z něj nejvýš odečtou uvedené ztráty.
Schéma je „stavební kámen“, například „beru stan i spacák, na ostatním nezáleží“. Věta říká, že krátké stavební kameny s nadprůměrnou zdatností se v populaci šíří — a to exponenciálně rychle, protože každou generaci se jejich počet zhruba násobí poměrem F(H)/F̄. Krátké proto, že je křížení méně často rozstřihne. Věta je jen dolní odhad a o tom, jak dobře algoritmus funguje, se dodnes vedou diskuse.
E[m(H, t + 1)] ≥ m(H, t) · F(H)/F̄ · [1 − pc · δ(H)/n − 1 − o(H) · pm]
- m(H, t)
- kolik jedinců nese stavební kámen teď — další generace z nich vychází, proto se s ním násobí
- F(H)/F̄
- o kolik jsou nositelé schématu zdatnější než průměr — ruleta jim dá úměrně víc potomků; nad 1 se schéma množí, pod 1 vymírá
- pc · δ(H)/n − 1
- šance (shora), že křížení schéma rozstřihne: křížení proběhne s pc a bod střihu padne s pravděpodobností δ(H)/n − 1 mezi pevné pozice — proto vadí dlouhá schémata
- o(H) · pm
- šance (shora), že mutace překlopí některou z o(H) pevných pozic — proto vadí schémata vysokého řádu
Příklad — krátké a dlouhé schéma na batohu
Hranatá závorka pro nastavení našeho běhu (pc = 0,9, n = 24, pm = 1/24). Obě schémata mají řád 2; barvy podle vzorce výše:
„stan i spacák“ (geny 1 a 2, δ = 1): 1 − 0,9 · 1/23 − 2 · 1/24 ≈ 1 − 0,039 − 0,083 = 0,878
„stan i ponožky navíc“ (geny 1 a 24, δ = 23): 1 − 0,9 · 23/23 − 2 · 1/24 ≈ 1 − 0,9 − 0,083 = 0,017
Krátkému schématu stačí, aby jeho nositelé byli o 14 % zdatnější než průměr (1/0,878 ≈ 1,14), a podle věty se už šíří. Dlouhé schéma by muselo být šedesátkrát zdatnější — věta o něm v podstatě nic neslibuje. Náš algoritmus používá turnaj, ne ruletu, takže pro něj platí jen hranatá závorka; první dva činitele by se počítaly jinak.
8. Genetické algoritmy v praxi
- Návrh tvarů. Anténa družic NASA ST5 (vypuštěných v roce 2006) byla navržena evolučním algoritmem: zvláštně pokroucený drátek, který by inženýra nenapadl, ale splnil zadání aspoň stejně dobře jako ručně navržená anténa (v pozdějších pokusech i lépe).
- Rozvrhy a logistika. Rozvrhy, plány směn nebo uspořádání skladu — úlohy s mnoha podmínkami, kde se zdatnost dá spočítat, ale přesný algoritmus by běžel věky.
- Strojové učení. Evoluce ladí hyperparametry modelů a v neuroevoluci, které má osnova vlastní díl, i váhy a architektury neuronových sítí.
- Evoluce s jazykovými modely. Systémy jako FunSearch (2023) a AlphaEvolve (2025) od Google DeepMind udržují populaci programů a jako mutaci používají jazykový model, který program upraví. Výběr zajistí automatické hodnocení. Takhle se podařilo najít nové matematické konstrukce i rychlejší algoritmy.
9. Shrnutí
- Genetický algoritmus vylepšuje celou populaci řešení: výběrem zdatných, křížením a mutací.
- Zdatnost je jediné, co o úloze potřebuje vědět; porušení podmínek se dá řešit trestem.
- Turnajový výběr drží selekční tlak, elitismus nedovolí ztratit nejlepší řešení.
- Na batohu s 16,7 miliony možností našel optimum v 88 ze 100 běhů po ohodnocení 2 440 batohů; náhodné hledání se stejným rozpočtem ani jednou.
- Mutace dodává rozmanitost — bez ní populace předčasně zkonverguje. Křížení skládá dobré stavební kameny a evoluci zrychluje.
Chcete si to osahat? Nechte AI agenta napsat genetický algoritmus pro váš vlastní batoh na výlet — a pak zkuste vypnout mutaci, zvětšit turnaj nebo zmenšit populaci a sledujte, co se stane s rozmanitostí.
Máte na to jiný názor? Napište na support@coden-app.com.