Umělá inteligence
Obsah Soubory
Prohledávání

Hry a herní strom

Aktualizováno 8 min čtení 1 504 slov

Hry a prohledávání herního stromu

Deep Blue porazil Kasparova v roce 1997 a novinové titulky psaly o počítači, který se naučil hrát šachy. Nenaučil. Deep Blue neuměl nic, co by neuměl program napsaný v roce 1960 - jen to dělal osmdesátkrát rychleji a měl lepší ohodnocovací funkci.

Algoritmus za tím se jmenuje minimax, je z roku 1944 a vejde se na deset řádků. Jeho jediný problém je, že v šachách potřebuje prohledat 35^100 ≈ 10^154 uzlů, což je víc, než je ve vesmíru atomů. Celý obor počítačových her je pak osmdesát let hledání toho, jak z toho stromu ubrat, aniž by se změnil výsledek.

Tahle stránka je o dvou algoritmech: minimaxu a alfa-beta prořezávání. Předpokládá to stavový prostor a prohledávání - hlavně smysl parametrů b a m. O strojovém učení v moderních herních systémech se tu mluví jen na konci; AlphaGo je jiná stránka příběhu.

Osmdesát let historie na sedmi řádcích

Rok Kdo Co
1846 Babbage počítač porovnává přínos různých herních tahů
1944 von Neumann algoritmy perfektní hry
1945-50 Zuse, Wiener, Shannon přibližné vyhodnocování pozice
1951 Turing první šachový program - jen na papíře, počítač na něj nestačil
1952-57 Samuel strojové učení pro zpřesnění vyhodnocování
1956 McCarthy prořezávání, a tím možnost hlubšího prohledávání

Za pozornost stojí, že všechny podstatné nápady jsou z padesátých let. Turingův šachový program z roku 1951 se počítal tužkou na papíře, protože žádný stroj tehdy nebyl dost rychlý. Samuel dělal strojové učení na hraní dámy v roce 1952, což je čtyřicet let před tím, než se strojovému učení začalo tak říkat.

A jak to dopadlo:

  • Othello - od roku 1980 světoví šampioni odmítají hrát s počítači, protože jsou stroje příliš dobré.
  • Dáma - 1994, program Chinook porazil světovou šampionku.
  • Šachy - 1997, Deep Blue porazil Kasparova 3½ : 2½.
  • Go - do roku 2008 byly stroje příliš slabé, od roku 2016 AlphaGo poráží mistry.

Čtyři typy her a proč jen jeden z nich umíme

Deterministické S náhodou
Perfektní znalosti šachy, dáma, go, othello backgammon, monopoly
Nepřesné znalosti - bridž, poker, scrabble

Minimax a alfa-beta řeší jen levý horní roh té tabulky. Hry s náhodou vyžadují expectimax (průměrování přes možné hody), hry s neúplnou informací vyžadují modelování soupeřova přesvědčení a jsou o řád těžší. Poker padl mnohem později než šachy právě proto.

Prázdné políčko vlevo dole není chyba. Deterministická hra s nepřesnými znalostmi je vzácnost - když je hra deterministická a oba vidí všechno, informace nemá kam zmizet.

Formulace hry jako prohledávání

Dva hráči, MAX a MIN, se střídají. MAX chce co nejvyšší hodnotu, MIN co nejnižší. Úloha se formuluje čtyřmi věcmi:

  • Počáteční stav - herní situace a informace o tom, kdo je na tahu.
  • Přechodová funkce - vrací dvojice (legální tah, výsledný stav).
  • Ukončovací podmínka - určuje, kdy hra končí, tedy které stavy jsou koncové.
  • Utilitární funkce - numerické ohodnocení koncových stavů.

Rozdíl oproti běžnému prohledávání je jediný, ale zásadní: v každé druhé vrstvě si tah nevybíráš ty. Nemůžeš předpokládat, že se stane to nejlepší. Musíš předpokládat, že se stane to nejhorší.

Minimax

Hodnota uzlu se definuje rekurzivně:

minimax(n) =
    utility(n),                        pro koncový stav n
    max nad s∈moves(n) z minimax(s),   pro MAX uzel n
    min nad s∈moves(n) z minimax(s),   pro MIN uzel n

Slovy: v koncovém stavu je hodnota daná, jinde je to nejlepší (nebo nejhorší) z hodnot následníků, podle toho, kdo je na tahu.

Spočítej si to

Strom hloubky 2, listy zleva: 3, 12, 8 | 2, 4, 6 | 14, 5, 2.

MIN vybírá minimum ze svých trojic:

min(3, 12, 8) = 3
min(2, 4, 6)  = 2
min(14, 5, 2) = 2

MAX vybírá maximum z výsledků MIN:

max(3, 2, 2) = 3

Výsledek je 3 a MAX zahraje první tah. Všimni si, že ta dvanáctka a čtrnáctka v listech na nic nemají vliv - MIN by tam nikdy nešel. To je první náznak toho, že se velká část stromu prohledávat nemusí.

Vlastnosti

Vlastnost Hodnota
Úplnost ano, ale jen pro konečné stromy
Optimalita proti optimálnímu oponentovi
Čas O(b^m)
Prostor O(b·m) - prohledávání do hloubky

Ta optimalita má háček, na který se snadno zapomene. Minimax je optimální proti optimálnímu soupeři. Proti soupeři, který dělá chyby, je jen bezpečný - najde tah, který nejhůř dopadne co nejlíp, ale nevyužije toho, že by protihráč mohl chybovat. Proti slabému soupeři existují lepší strategie a minimax je nezná.

Pro šachy: b ≈ 35, m ≈ 100, takže 35^100 ≈ 10^154 uzlů. Přesné řešení není možné a nikdy nebude.

Pseudokód

function minimax(pozice, hloubka):
    if pozice je koncová or hloubka = 0 then
        return heuristické ohodnocení pozice
    else
        ohod ← −∞
        for all potomek pozice do
            ohod ← max(ohod, −minimax(potomek, hloubka−1))
        end for
        return ohod
    end if

Všimni si toho minusu před rekurzivním voláním. Tomuhle triku se říká negamax a je to důvod, proč se nemusí psát dvě větve pro MAX a MIN. Funguje jen za předpokladu, že je ohodnocení hry nulový součet - co je dobré pro mě, je stejně špatné pro soupeře.

Ohodnocovací funkce

Vstupem je pozice, výstupem celé číslo. Funkce se vytváří z pohledu jednoho hráče a ohodnocení z pohledu druhého je totéž se záporným znaménkem.

Co se v šachách hodnotí:

  • Materiální složka - rozdíl v počtu a hodnotě figur. Nejsilnější jednotlivá složka.
  • Statická poziční složka - bonusy za umístění figur (kůň uprostřed, věž na otevřeném sloupci).
  • Dynamická poziční složka - bloky figur, osamělé pěšce, struktura.

Kvalita ohodnocovací funkce rozhoduje víc než hloubka prohledávání a je to ta část, kterou nikdo neumí odvodit - ladí se ručně nebo se učí z partií, což dělal Samuel už v roce 1952.

Alfa-beta prořezávání

V řadě situací nemusí minimax zkoumat další pozice, protože je už teď jasné, že na volbu tahu nebudou mít vliv.

  • Alfa ořezávání - nalezena příliš malá hodnota, tuhle větev hráč na tahu nezvolí.
  • Beta ořezávání - nalezená hodnota je příliš velká, soupeř tuhle větev nezvolí.

Vrať se k příkladu výš. Když MAX ví, že první větev dá 3, a v druhé větvi hned narazí na list s hodnotou 2, může zbytek druhé větve zahodit. MIN v ní totiž nikdy nevrátí víc než 2, a to už je horší než jistá trojka. Ať je pod tou větví cokoliv, na výsledek to nemá vliv.

function alfabeta(pozice, hloubka, alfa, beta):
    if je_prohra(pozice) then return −MAX
    if je_výhra(pozice) then return MAX
    if je_remíza(pozice) then return 0
    if hloubka = 0 then
        return ohodnocovaci_funkce(pozice)
    end if
    tahy ← generuj_tahy(pozice)
    for all tah v kolekci tahy do
        pot ← zahraj(pozice, tah)
        ohod ← −alfabeta(pot, hloubka−1, −beta, −alfa)
        if ohod > alfa then
            alfa ← ohod
            if ohod ≥ beta then return beta
        end if
    end for
    return alfa

Prohození a znegování alfa a beta v rekurzivním volání je opět negamax - z pohledu soupeře se role obou mezí vymění.

Vlastnosti prořezávání

Prořezávání neovlivní výsledek. Vrací přesně to, co by vrátil minimax. To je nejdůležitější vlastnost celého algoritmu - není to aproximace, je to zrychlení.

Uspořádání tahů rozhoduje o efektivitě. Když prohlédneš dobré tahy první, meze se rychle utáhnou a ořeže se hodně. Při náhodném pořadí se ořeže málo.

Při nejlepším uspořádání je čas O(b^(m/2)). To je odmocnina původního počtu uzlů, tedy zdvojnásobení dosažitelné hloubky za stejný čas.

V šachách to znamená hloubku 8, což je už použitelná úroveň hry. Ta jedna odmocnina je celý rozdíl mezi programem, který hraje jako začátečník, a programem, který porazí většinu lidí.

Praktický důsledek: do generátoru tahů se vyplatí investovat. Zkoušet nejdřív brát figury, pak šachy, pak tahy, které se osvědčily v jiných větvích - to všechno zlepšuje uspořádání a tím i hloubku.

Časové omezení a minimax cutoff

Předpokládej sto sekund na tah a 10^4 uzlů za sekundu, tedy 10^6 uzlů na jeden tah. Do 35^100 to má daleko a hra musí být odehrána.

Řešením je minimax cutoff: nahradí se dvě věci ze základní formulace.

Původně Nahrazeno Proč
Utilitární funkce (jen koncové stavy) Ohodnocovací funkce (jakákoliv pozice) musíš umět ohodnotit i nedohranou pozici
Koncový test Ořezávací test (cutoff test) typicky hloubka, nebo hodnota ohodnocovací funkce

Tím se z algoritmu, který hraje perfektně, stane algoritmus, který hraje dobře. Cena za to je, že se program dá napálit na hranici horizontu - špatnou věc, která se stane o jeden tah za limitem, prostě neuvidí a bude ji odsouvat. Tomu se říká horizon effect a řeší se prohlubováním v „neklidných" pozicích, kde se právě berou figury.

Kdy tohle přestává stačit

Faktor větvení je moc velký. V go je b ≈ 250 proti šachovým 35. Alfa-beta tam nepomůže dost a dobrou ohodnocovací funkci nikdo neuměl napsat - pozice v go se nedá rozložit na materiál a strukturu. Proto go padlo až v roce 2016, a to úplně jinou metodou: Monte Carlo Tree Search plus neuronová síť, která ohodnocovací funkci nahradila naučeným modelem.

Ve hře je náhoda. Backgammon potřebuje expectimax, kde se v uzlu s hodem kostkou počítá vážený průměr přes možné výsledky. Prořezávání tam funguje mnohem hůř, protože průměr nemá tvrdé meze.

Hráči nevidí totéž. V pokeru a bridži se nedá postavit jeden herní strom, protože každý hráč prohledává jiný. Řeší se to teorií her a hledáním rovnováhy, ne minimaxem.

Co se na tom nejčastěji rozbije

Příznak Kde je problém
Program hraje sebevražedně znaménko - ohodnocení počítáš z pohledu špatného hráče
Alfa-beta dává jiný výsledek než minimax chybně předávané meze v rekurzi, typicky neprohozené −beta, −alfa
Prořezává skoro nic špatné uspořádání tahů, generátor vrací tahy v pořadí polí
Program odsouvá nevyhnutelnou ztrátu horizon effect - chybí prohlubování v neklidných pozicích
Hraje dobře v otevření, blbě v koncovce ohodnocovací funkce laděná na střední hru, koncovka má jiná pravidla
Přeteče zásobník chybí ořezávací test na hloubku, rekurze nemá dno

Co si odnést

Minimax předpokládá nejlepšího možného soupeře. Proti chybujícímu je bezpečný, ne optimální.

Alfa-beta nemění výsledek. Je to čisté zrychlení, ne aproximace.

Dobré uspořádání tahů zdvojnásobí hloubku. O(b^(m/2)) místo O(b^m).

Ohodnocovací funkce rozhoduje víc než hloubka. A je to ta část, kterou musíš vymyslet ty.

Cutoff dělá z perfektní hry hru dobrou. A vyrábí horizon effect.

Go padlo jinou metodou. Když je b moc velké a ohodnocení se nedá napsat, alfa-beta nestačí.

Kam dál