Plánovanie: STRIPS, svet kociek, heuristiky z relaxácie a plánovanie v AI agentoch
Jazyk STRIPS a PDDL, dopredné a spätné plánovanie, heuristiky hmax a hadd, Sussmanova anomália, hierarchické plánovanie a preplánovanie — od robota Shakeyho po AI agentov, ktorí si píšu zoznam úloh.
Séria Základy AI Diel 25 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 zapísať plánovaciu úlohu ako atómy, akcie s predpokladmi a účinkami a cieľ.
- Ako si plánovač vypočíta heuristiku sám z relaxovanej úlohy a koľko práce tým ušetrí.
- Prečo nejde čiastkové ciele plniť jeden po druhom a ako plánujú dnešní AI agenti.
Čo sa hodí vedieť vopred: Prehľadávanie stavového priestoru: BFS, DFS, UCS a A* s animáciami, Logika a znalostné systémy: dopredné a spätné reťazenie, rezolúcia a expertné systémy
Robot Shakey zo Stanfordského výskumného inštitútu jazdil koncom šesťdesiatych rokov po niekoľkých miestnostiach, posúval škatule a zhasínal svetlá. Bol to prvý robot, ktorý o svojich činoch uvažoval: dostal cieľ („dostaň škatuľu do vedľajšej miestnosti“) a sám si vymyslel, ktoré akcie a v akom poradí k nemu vedú. Jazyk, v ktorom to robil, sa volá STRIPS — a jeho myšlienky dnes nájdete v logistike, v počítačových hrách aj v slučke AI agenta, ktorý vám píše kód.
Nadväzuje na diely Prehľadávanie stavového priestoru a Logika a znalostné systémy.
1. Plánovanie: hľadanie, ktoré vidí dovnútra
Plánovanie je hľadanie postupnosti akcií, ktorá vedie k cieľu — presne ako v diele o prehľadávaní. Rozdiel je v tom, ako je úloha zapísaná. Pri bludisku bol stav čierna skrinka a algoritmus o ňom vedel len to, kam z neho vedú akcie. Plánovač vidí dovnútra: stav je zoznam faktov o svete a akcia hovorí, ktoré fakty potrebuje a ktoré zmení. Vďaka tomu si plánovač vie sám odvodiť odhad, ako ďaleko je cieľ — žiadnu heuristiku mu nemusíte písať ručne.
2. Jazyk STRIPS
Definícia — plánovacia úloha STRIPS
Nech F je konečná množina atómov (výrokov o svete). Stav je ľubovoľná podmnožina s ⊆ F; atóm p ∈ F v stave s platí práve vtedy, keď p ∈ s (čo v s nie je, neplatí).
Akcia je trojica a = (pre(a), add(a), del(a)) podmnožín F: predpoklady, pridávané a odoberané atómy. Akcia a je v stave s použiteľná práve vtedy, keď pre(a) ⊆ s, a pre také s a a je výsledný stav
T(s, a) = (s ∖ del(a)) ∪ add(a)
- T(s, a)
- stav po vykonaní akcie — prechodová funkcia, ktorú v diele o prehľadávaní dodával programátor; tu ju plánovač odvodí z opisu akcie sám
- s
- východiskový stav: všetko, čo akcia nespomenie, sa do nového stavu prenesie bez zmeny (predpoklad STRIPS, ktorý rieši problém rámca — nemusíme vypisovať, čo sa nemení)
- del(a)
- atómy, ktoré akcia zneplatní; odčítajú sa množinovým rozdielom ∖
- add(a)
- atómy, ktoré akcia zavedie; pridávajú sa zjednotením až po odobratí, takže atóm, ktorý je v oboch zoznamoch, nakoniec platí
Plánovacia úloha je štvorica Π = (F, A, s0, G), kde A je konečná množina akcií nad F, s0 ⊆ F počiatočný stav a G ⊆ F cieľ. Stav s je cieľový práve vtedy, keď G ⊆ s.
Plán pre Π je postupnosť akcií a1, …, ak ∈ A (k ≥ 0) taká, že pre stavy si = T(si−1, ai), i = 1, …, k, platí
- pre(ai) ⊆ si−1 pre každé i = 1, …, k (každá akcia je použiteľná v stave po predchádzajúcich);
- G ⊆ sk (posledný stav je cieľový).
Číslo k je dĺžka plánu; plán najmenšej dĺžky je optimálny. Slovami: plán je postupnosť akcií, ktorú možno z počiatočného stavu postupne vykonať a po ktorej platia všetky cieľové atómy.
Stav je zoznam viet, ktoré práve platia: „C leží na A“, „na B nič neleží“. Akcia je recept s tromi kolónkami: čo musí platiť, aby ste ju mohli urobiť; čo začne platiť; čo platiť prestane. Cieľ nemusí opisovať celý svet — stačí povedať, na čom vám záleží, a zvyšok je jedno.
Príklad — jedna akcia krok za krokom
Kocka C leží na A, B stojí vedľa. Akcia na stôl(C, A) má pre = {na(C, A), voľná(C)}, add = {stôl(C), voľná(A)}, del = {na(C, A)} (celý opis akcií je v ďalšom oddiele; farby podľa vzorca pre T(s, a) vyššie).
s = {na(C, A), stôl(A), stôl(B), voľná(B), voľná(C)}
pre ⊆ s? na(C, A) ∈ s, voľná(C) ∈ s → akcia je použiteľná
s ∖ del = {stôl(A), stôl(B), voľná(B), voľná(C)}
T(s, a) = (s ∖ del) ∪ add = {stôl(A), stôl(B), stôl(C), voľná(A), voľná(B), voľná(C)} — všetky tri kocky na stole
STRIPS vznikol v roku 1971 (Fikes a Nilsson) práve pre Shakeyho. Jeho dnešný nástupca je jazyk PDDL, v ktorom sa od roku 1998 zadávajú úlohy pre medzinárodné súťaže plánovačov. Akcia sa v ňom píše ako schéma s premennými:
(:action na-stol
:parameters (?a ?b)
:precondition (and (na ?a ?b) (volna ?a))
:effect (and (stol ?a) (volna ?b) (not (na ?a ?b))))
3. Svet kociek
Klasická skúšobná úloha plánovania: na stole ležia kocky, niektoré na sebe. Jednou akciou vezmete kocku, na ktorej nič neleží, a položíte ju na stôl alebo na inú voľnú kocku. Atómy sú troch druhov: na(A, B) — A leží na B, stôl(A) a voľná(A).
Akcie vo svete kociek
Nech K je konečná množina kociek. Atómy sú F = {na(x, y) : x, y ∈ K, x ≠ y} ∪ {stôl(x), voľná(x) : x ∈ K}. Pre každú voľbu navzájom rôznych kociek A, B, C ∈ K sú v úlohe akcie:
- na stôl(A, B): pre = {na(A, B), voľná(A)}, add = {stôl(A), voľná(B)}, del = {na(A, B)}
- zo stola(A, C): pre = {stôl(A), voľná(A), voľná(C)}, add = {na(A, C)}, del = {stôl(A), voľná(C)}
- presun(A, B, C): pre = {na(A, B), voľná(A), voľná(C)}, add = {na(A, C), voľná(B)}, del = {na(A, B), voľná(C)}
Keď zložíte A z B na stôl, A bude na stole, B sa uvoľní a A prestane ležať na B. Všetko ostatné zostane, ako bolo — a to je dôležité: STRIPS predpokladá, že akcia mení len to, čo sama hovorí.
Schému s premennými plánovač najprv uzemní: dosadí za premenné všetky kombinácie kociek. Pre n kociek je n(n − 1) akcií „na stôl“, rovnako „zo stola“ a n(n − 1)(n − 2) presunov, spolu n2(n − 1). Pre tri kocky je to 9 · 2 = 18 akcií, pre šesť 36 · 5 = 180. V každom stave je však použiteľných len pár z nich — kociek, na ktorých nič neleží, je málo.
Svet vyzerá ako hračka, ale rastie rýchlo. Tri kocky sa dajú rozostaviť 13 spôsobmi, štyri 73, päť 501 a šesť už 4 051. Odkiaľ tie čísla sú:
počet stavov = ∑k=1n n! · C(n − 1, k − 1)/k!
- n!
- zoradíme všetky kocky do jedného radu — každé poradie je kandidát; veže z neho dostaneme rozrezaním
- C(n − 1, k − 1)
- rad rozrežeme na k neprázdnych veží: vyberieme k − 1 z n − 1 medzier medzi kockami. Na poradí vnútri veže záleží (A na B nie je B na A), preto režeme poradie, nie množinu
- k!
- na poradí veží na stole nezáleží — dve veže vedľa seba sú ten istý stav, nech ich vypíšeme v akomkoľvek poradí. Každý stav sme teda započítali k!-krát
n = 3: k = 1: 6 · 1/1 = 6, k = 2: 6 · 2/2 = 6, k = 3: 6 · 1/6 = 1 → 13
n = 4: 24 + 36 + 12 + 1 = 73
n = 6: 720 + 1 800 + 1 200 + 300 + 30 + 1 = 4 051
Plánovač ich spočítal inak — prešiel všetky dosiahnuteľné stavy — a vyšlo mu to isté. Skúsime dve úlohy. V tej väčšej stoja na stole dve veže A–B–C a D–E–F (písané odspodu) a cieľom je jediná veža F–E–D–C–B–A:
4. Dopredné plánovanie
Definícia — dopredné plánovanie (progresia)
Nech Π = (F, A, s0, G) je plánovacia úloha STRIPS. Dopredné plánovanie rieši Π prehľadávaním (do šírky, A* … — pozri Prehľadávanie stavového priestoru) stavového priestoru, v ktorom
- stavy sú množiny s ⊆ F a počiatočný stav je s0;
- nasledovníci stavu s sú Succ(s) = {T(s, a) : a ∈ A ∧ pre(a) ⊆ s}, každý prechod má cenu 1;
- stav s je cieľový práve vtedy, keď G ⊆ s.
Nájdená cesta s0 → … → sk do cieľového stavu dáva plán: akcie, ktoré jednotlivé prechody spôsobili, v poradí od začiatku. Keďže stavov je najviac 2|F|, prehľadávanie s kontrolou navštívených stavov vždy skončí.
Skúšate z východiskovej situácie všetky ťahy, zo všetkých výsledkov zase všetky ťahy, kým nenarazíte na situáciu, v ktorej platí cieľ. Žiadna novinka — je to BFS alebo A* z dielu o prehľadávaní, len nad stavmi zapísanými ako množiny faktov.
from collections import deque
def proved(stav, akce):
return (stav - akce.odeber) | akce.pridej
def planuj(start, cil, akce):
okraj, rodic = deque([start]), {start: None}
while okraj:
stav = okraj.popleft()
if cil <= stav: # všetky cieľové atómy platia
return plan_z(rodic, stav)
for a in akce:
if a.predpoklady <= stav:
dalsi = proved(stav, a)
if dalsi not in rodic:
rodic[dalsi] = (stav, a)
okraj.append(dalsi)
Na úlohe s vežou nájde prehľadávanie do šírky najkratší plán so 6 akciami, ale rozbalí pritom 2 132 stavov — viac ako polovicu zo všetkých 4 051. Nevie totiž nič o tom, ktorým smerom cieľ leží.
5. Heuristiky z relaxácie
V diele o prehľadávaní sme si heuristiku pre bludisko vymysleli sami. Plánovač ju vie vypočítať z opisu akcií — tak, že si úlohu zjednoduší, vyrieši ju a cenu zjednodušeného riešenia použije ako odhad.
Definícia — relaxácia bez odoberania
Nech Π = (F, A, s0, G) je plánovacia úloha STRIPS. Pre akciu a položme a+ = (pre(a), add(a), ∅). Relaxovaná úloha (bez odoberania) je
Π+ = (F, {a+ : a ∈ A}, s0, G).
V Π+ je T(s, a+) = s ∪ add(a) ⊇ s, takže atóm, ktorý raz platí, platí navždy.
Nech s ⊆ F je stav a ⊕ ∈ {max, ∑} zvolená agregácia. Cenu množiny atómov P ⊆ F definujeme ako c(P) = maxq ∈ P c(q) pre ⊕ = max, resp. c(P) = ∑q ∈ P c(q) pre ⊕ = ∑ (pre P = ∅ je oboje 0). Cena atómu c : F → ℕ ∪ {∞} zo stavu s je riešenie sústavy
- c(p) = 0 pre p ∈ s;
- c(p) = mina ∈ A : p ∈ add(a) [1 + c(pre(a))] pre p ∉ s (minimum cez prázdnu množinu je ∞),
ktoré získame iteráciou: začneme s c(p) = 0 pre p ∈ s a c(p) = ∞ inak a hodnoty podľa pravej strany znižujeme, kým sa menia (kód nižšie). Heuristiky stavu s sú
hmax(s) = maxg ∈ G c(g) (s agregáciou max), hadd(s) = ∑g ∈ G c(g) (s agregáciou ∑).
Slovami: c(p) odhaduje počet akcií potrebných na dosiahnutie atómu p vo svete, kde sa nič neodoberá. hmax je prípustná (veta nižšie), hadd je presnejšie vodidlo, ale môže preceniť.
c(p) = mina : p ∈ add(a) [ 1 + c(pre(a)) ]
- c(p)
- odhad, koľko akcií je potrebných, aby začal platiť atóm p (pre atómy, ktoré už platia, je 0)
- minimum cez akcie s p ∈ add(a)
- atóm môže zaviesť viac akcií; vyberieme tú najlacnejšiu, pretože plánovač si cestu volí sám
- 1
- cena samotnej akcie, ktorá p nakoniec pridá
- c(pre(a))
- cena toho, aby akcia bola vôbec použiteľná — splniť všetky jej predpoklady. Tu sa hmax a hadd líšia: maximum predpokladá, že sa predpoklady splnia „naraz“ a ich prípravy sa prekrývajú, súčet, že každý stojí samostatnú prácu
Predstavte si svet, v ktorom sa nič nedá pokaziť: keď kocku raz odkryjete, zostane odkrytá, aj keď na ňu niečo položíte. V takom svete je plánovanie ľahké a jeho cena je optimistický odhad ceny skutočnej. hmax počíta len s najťažším čiastkovým cieľom (opatrná, nikdy nepreceňuje), hadd sčíta všetky (odvážnejšia, môže prestreliť, pretože jedna akcia niekedy pomôže viacerým cieľom naraz).
def ceny(stav, akce, agreguj): # agreguj = max (hmax) alebo sum (hadd)
c = {p: 0 for p in stav}
zmena = True
while zmena: # opakuj, kým sa nejaká cena zlepší
zmena = False
for a in akce:
if all(p in c for p in a.predpoklady):
nova = 1 + agreguj(c[p] for p in a.predpoklady)
for p in a.pridej: # a.odeber sa ignoruje — relaxácia
if nova < c.get(p, float("inf")):
c[p], zmena = nova, True
return c
def h(stav, cil, akce, agreguj):
c = ceny(stav, akce, agreguj)
return agreguj(c[g] for g in cil) # nedosiahnuteľný cieľ: h = ∞
Príklad — hmax a hadd pre Sussmanovu anomáliu
Začiatok: C leží na A, B stojí vedľa; cieľ G = {na(A, B), na(B, C)} (úlohu rozoberieme nižšie). Ceny atómov po vrstvách:
cena 0 (platí): stôl(A), stôl(B), na(C, A), voľná(B), voľná(C)
cena 1: na stôl(C, A) → stôl(C), voľná(A); zo stola(B, C) → na(B, C); presun(C, A, B) → na(C, B)
cena 2: zo stola(A, B) potrebuje stôl(A), voľná(A), voľná(B) s cenami 0, 1, 0
hmax: 1 + max(0, 1, 0) = 2, hadd: 1 + (0 + 1 + 0) = 2 → na(A, B) má cenu 2 (farby podľa vzorca pre c(p) vyššie)
hmax(s0) = max(2, 1) = 2, hadd(s0) = 2 + 1 = 3, skutočne potrebné: h* = 3
hmax podcení, pretože započíta len najdrahší cieľ: na(A, B) stojí dve akcie, ale na(B, C) potrebuje ešte vlastnú tretiu, a maximum ju prehltne. Súčet ju započíta a tu trafí presne. Na úlohe s vežou je to výraznejšie: zo štartu je h* = 6, hmax = 3, počet nesplnených cieľov 5 a hadd = 15 — súčet započíta spoločnú prípravu (odkrytie kociek) pri každom cieli znova a skutočnú cenu precení dva a pol krát.
Veta — hmax a počet nesplnených cieľov sú prípustné
Nech Π = (F, A, s0, G) je plánovacia úloha STRIPS a pre stav s ⊆ F je h*(s) dĺžka najkratšieho plánu zo s do cieľa G (∞, ak neexistuje). Heuristika h je prípustná (ako v diele o prehľadávaní) práve vtedy, keď h(s) ≤ h*(s) pre každý stav s.
Veta. (1) Pre každú úlohu STRIPS je hmax prípustná. (2) Nech Π je úloha vo svete kociek, ktorej cieľ obsahuje len atómy tvaru na(x, y). Potom heuristika h#(s) = |G ∖ s| (počet nesplnených cieľov) je prípustná.
Dôkaz (1). Ak je h*(s) = ∞, nie je čo dokazovať. Inak vezmime najkratší plán a1, …, ak skutočnej úlohy. Je to plán aj pre relaxovanú úlohu (bez odoberania platia v každom kroku aspoň tie isté atómy, takže predpoklady zostanú splnené). Indukciou podľa i: každý atóm, ktorý platí po i akciách, má cmax ≤ i — buď platil už skôr, alebo ho pridala akcia ai, ktorej predpoklady platili po i − 1 akciách a majú teda cenu ≤ i − 1, takže 1 + max ≤ i. Všetky cieľové atómy platia po k akciách, preto hmax(s) = maxg ∈ G c(g) ≤ k = h*(s).
Dôkaz (2). Ciele sú atómy na(·, ·) a každá akcia pridá najviac jeden taký atóm. Na splnenie m chýbajúcich cieľov je preto treba aspoň m akcií.
Pre hadd dôkaz zlyhá v poslednom kroku: súčet cien môže byť väčší ako k, pretože tie isté akcie plánu sa započítajú pri viacerých cieľoch.
Tri heuristiky na úlohe s vežou, všetky s algoritmom A*:
| Hľadanie | Rozbalených stavov | Dĺžka plánu |
|---|---|---|
| Do šírky (bez heuristiky) | 2 132 | 6 |
| A* s hmax | 136 | 6 |
| A* s počtom nesplnených cieľov | 19 | 6 |
| A* s hadd | 12 | 7 |
Prípustná hmax nájde optimum a ušetrí cez 90 % práce. Počet nesplnených cieľov je v našom svete tiež prípustný (každá akcia položí len jednu kocku, takže splní najviac jeden cieľ) a tu funguje ešte lepšie. hadd rozbalí najmenej, ale zaplatí za to: plán má o krok viac, než je nutné. Žiadna heuristika nevyhráva vždy — a skutočné plánovače ako FF alebo Fast Downward majú celé sady heuristík, ktoré kombinujú.
Ako A* s hmax pracuje, je najlepšie vidieť na malej úlohe — Sussmanovej anomálii, ktorú rozoberieme o dva oddiely ďalej. Každý riadok je jeden rozbalený stav (veže odspodu); A* berie vždy stav s najmenším f = g + h, kde g je počet akcií od začiatku, a pri zhode ten, ktorý objavil skôr:
| Krok | Rozbalený stav | Posledná akcia | g | hmax | f |
|---|---|---|---|---|---|
| 1 | A–C, B | — (začiatok) | 0 | 2 | 2 |
| 2 | A, B, C | na stôl(C, A) | 1 | 1 | 2 |
| 3 | A, B–C | presun(C, A, B) | 1 | 2 | 3 |
| 4 | A, C–B | zo stola(B, C) | 2 | 1 | 3 |
| 5 | C–B–A | zo stola(A, B) | 3 | 0 | 3 — cieľ |
Hľadanie do šírky na tej istej úlohe rozbalí všetkých 13 stavov, A* s hmax len 5. V treťom kroku odbočí zle — položí C na B — pretože stav má f = 3 rovnako ako správna cesta a bol objavený skôr. Hneď ďalší krok to napraví. Prvý rozbalený cieľový stav má najkratší plán — to A* zaručuje, keď je heuristika prípustná (a hmax je dokonca konzistentná, takže sa k uzavretým stavom nemusí vracať).
6. Spätné plánovanie
Definícia — spätné plánovanie (regresia)
Nech Π = (F, A, s0, G) je plánovacia úloha STRIPS. Podcieľ je množina atómov g ⊆ F, ktoré ešte musia platiť. Akcia a ∈ A je pre podcieľ g relevantná práve vtedy, keď
add(a) ∩ g ≠ ∅ ∧ del(a) ∩ g = ∅,
t. j. akcia zavedie aspoň jeden atóm podcieľa a žiadny nezničí. Regresia podcieľa g cez relevantnú akciu a je podcieľ
g′ = (g ∖ add(a)) ∪ pre(a)
- g′
- čo musí platiť pred akciou a, aby po nej platilo g — nový, skorší podcieľ
- g
- doterajší podcieľ; atómy, ktoré akcia nespomenie, musia platiť už predtým, pretože ich akcia sama nezavedie (a vďaka podmienke relevancie ich ani nezničí)
- add(a)
- odčítame, pretože tieto atómy zariadi akcia sama — predtým platiť nemusia
- pre(a)
- pridávame, pretože bez predpokladov akciu nemožno vykonať — stávajú sa novými podcieľmi
Spätné plánovanie prehľadáva priestor podcieľov, v ktorom
- počiatočný podcieľ je g0 = G;
- nasledovníci podcieľa g sú regresie g′ cez všetky akcie a ∈ A relevantné pre g;
- podcieľ g je koncový práve vtedy, keď g ⊆ s0.
Ak nájde cestu g0 → g1 → … → gk ⊆ s0 cez akcie b1, …, bk, je plánom postupnosť bk, …, b1 — nájdené akcie v obrátenom poradí.
Pýtate sa: „Ktorá akcia by mi mohla dať to, čo chcem, a pritom nič z toho nezničiť? A čo by muselo platiť predtým?“ Rovnaká úvaha ako pri spätnom reťazení v minulom diele. Výhoda: skúmate len akcie, ktoré s cieľom súvisia. Nevýhoda: pracujete s množinami cieľov namiesto úplných stavov, a tie sa horšie odhadujú.
Príklad — regresia cieľa Sussmanovej anomálie
Cieľ g = {na(A, B), na(B, C)}, začiatok s0 = {na(C, A), stôl(A), stôl(B), voľná(B), voľná(C)}. Akcie berieme od poslednej (farby podľa vzorca pre regresiu vyššie):
zo stola(A, B): add = {na(A, B)} zasahuje do g, del = {stôl(A), voľná(B)} nie → relevantná
g′ = {na(B, C)} ∪ {stôl(A), voľná(A), voľná(B)}
zo stola(B, C): add = {na(B, C)}, del = {stôl(B), voľná(C)} → relevantná
g″ = {stôl(A), voľná(A), voľná(B)} ∪ {stôl(B), voľná(B), voľná(C)} = {stôl(A), stôl(B), voľná(A), voľná(B), voľná(C)}
na stôl(C, A): add = {stôl(C), voľná(A)}, del = {na(C, A)} → relevantná
g‴ = {stôl(A), stôl(B), voľná(B), voľná(C)} ∪ {na(C, A), voľná(C)} = {na(C, A), stôl(A), stôl(B), voľná(B), voľná(C)} ⊆ s0 ✓
Plán čítaný odzadu: na stôl(C, A), zo stola(B, C), zo stola(A, B). Keby sme však ako poslednú akciu skúsili zo stola(B, C), dostali by sme podcieľ {na(A, B), stôl(B), voľná(B), voľná(C)} — A leží na B a B je zároveň voľná. Taký stav neexistuje, ale regresia to sama nespozná; spätné plánovače preto potrebujú dodatočné pravidlá, ktoré nemožné kombinácie odhalia.
7. Sussmanova anomália
Najjednoduchší nápad, ako plánovať: rozdeliť cieľ na časti a splniť ich jednu po druhej. Funguje to často — a zlyhá to už na troch kockách. Úloha nesie meno Geralda Sussmana, ktorý ju v sedemdesiatych rokoch rozobral: C leží na A, B stojí vedľa, cieľom je A na B a zároveň B na C.
Najkratší plán pre „A na B“ zloží C a položí A na B. Lenže potom je B pod A a dostať B na C znamená A zase zložiť. Na konci platí len druhý cieľ a stálo to 4 kroky. Opačné poradie dopadne rovnako: položíme B na C, ale tým zasypeme A pod C a B — a uvoľniť ho zase zničí prvý cieľ. Ciele sa navzájom rušia, nech začnete ktorýmkoľvek.
Riešenie potrebuje kroky oboch cieľov preložiť: najprv uvoľniť A (krok pre prvý cieľ), potom B na C (druhý cieľ) a až potom A na B (prvý cieľ). Plánovač, ktorý hľadá v priestore celých stavov, to nájde sám — prešiel tu všetkých 13 stavov sveta troch kociek. Plánovač, ktorý skladá čiastkové plány, ich musí vedieť rozpletať a znova spájať. To je téma celej rodiny „plánovania v priestore plánov“.
8. Hierarchické plánovanie
Definícia — HTN
Uvádzame úplne usporiadanú variantu HTN, ktorú používa plánovač SHOP2 aj kód nižšie. Nech F je konečná množina atómov a A konečná množina akcií STRIPS nad F. Úlohy sú dvoch druhov: primitívne — to sú akcie a ∈ A — a zložené z konečnej množiny U (U ∩ A = ∅).
Metóda pre zloženú úlohu u ∈ U je dvojica m = (pre(m), (u1, …, uj)), kde pre(m) ⊆ F je podmienka a u1, …, uj ∈ A ∪ U (j ≥ 0) sú podúlohy. Úloha HTN je (F, A, U, M, s0, w0), kde M je konečná množina metód, s0 ⊆ F počiatočný stav a w0 počiatočná postupnosť úloh (zvyčajne jediná úloha najvyššej úrovne).
Dvojicu (stav s, postupnosť úloh w = (t, w′)) spracujeme takto:
- ak je t primitívna a pre(t) ⊆ s, prejdeme na (T(s, t), w′) a t pripíšeme na koniec plánu;
- ak je t zložená a m ∈ M jej metóda s pre(m) ⊆ s, prejdeme na (s, (u1, …, uj, w′)) — úlohu t nahradíme podúlohami metódy.
Riešenie je plán (postupnosť primitívnych akcií), ktorý vznikne konečne mnohými takými krokmi z (s0, w0) až do prázdnej postupnosti úloh. Slovami: plánovanie začína úlohou najvyššej úrovne a podľa metód ju rozkladá, kým nezostanú len primitívne akcie, ktoré sa dajú vykonať.
Nikto neplánuje dovolenku po jednotlivých krokoch nôh. Rozložíte ju na „dopraviť sa tam“, „ubytovať sa“ a „vrátiť sa“; „dopraviť sa“ na „kúpiť cestovný lístok“ a „dostať sa na stanicu“ — a až úplne dole sú konkrétne úkony. Metódy sú osvedčené recepty, ako zložitú vec rozložiť, a vďaka nim plánovač neskúša nezmysly.
def rozloz(ukoly, stav): # ukoly: zoznam zostávajúcich úloh
if not ukoly:
return [] # všetko rozložené
u, zbytek = ukoly[0], ukoly[1:]
if u.primitivni: # obyčajná akcia STRIPS
if not u.predpoklady <= stav:
return None
plan = rozloz(zbytek, proved(stav, u))
return None if plan is None else [u] + plan
for metoda in u.metody: # skús recepty jeden po druhom
if metoda.podminka <= stav:
plan = rozloz(metoda.podukoly + zbytek, stav)
if plan is not None:
return plan
return None # žiadna metóda nevyšla — návrat späť
Hľadá sa tu v priestore rozkladov, nie stavov: vetví sa len podľa toho, ktorú metódu pre zloženú úlohu zvoliť. Úlohy sa rozkladajú v poradí, v akom sa budú vykonávať, takže plánovač vždy pozná aktuálny stav — rovnako postupuje napríklad plánovač SHOP2.
Hierarchické plánovanie sa používa tam, kde majú odborníci osvedčené postupy: v logistike, pri riadení výroby a veľa v počítačových hrách. Akčná hra F.E.A.R. (2005) preslávila vojakov, ktorí si taktiku plánovali za behu jazykom v štýle STRIPS — a z toho istého nápadu vychádzajú plánovače v rade ďalších hier.
9. Plánovanie v neistom svete
STRIPS predpokladá, že svet je presne taký, ako si myslíme, a akcie dopadnú presne podľa opisu. Skutočný robot však kocku pustí a skutočný server neodpovie. Najčastejšie odpovede na to sú tri:
- Sledovanie a preplánovanie. Po každej akcii skontroluj, či svet vyzerá, ako plán čakal. Ak nie, naplánuj znova z toho, čo je. Jednoduché a prekvapivo účinné (slučka je nižšie).
- Podmienené plány majú vetvenie: „keď sa dvere otvoria, choď ďalej, inak použi druhý vchod“.
- Pravdepodobnostné plánovanie. Keď má akcia viac možných výsledkov s danými pravdepodobnosťami, nehľadáme postupnosť akcií, ale stratégiu pre každú situáciu — Markovove rozhodovacie procesy majú v osnove vlastný diel.
def proved_s_dohledem(cil, akce, svet):
plan = planuj(svet.pozoruj(), cil, akce)
while plan:
a = plan.pop(0)
cekany = proved(svet.pozoruj(), a) # čo by malo platiť podľa modelu
svet.udelej(a)
skutecny = svet.pozoruj()
if cil <= skutecny:
return True
if skutecny != cekany: # svet sa zachoval inak
plan = planuj(skutecny, cil, akce) # preplánuj z toho, čo je
return cil <= svet.pozoruj()
Stačí pritom strážiť len to, na čom zvyšok plánu závisí: keď sa zmení atóm, ktorý nie je predpokladom žiadnej ďalšej akcie ani súčasťou cieľa, plán platí ďalej. Túto úsporu zaviedol už systém PLANEX, ktorý vykonával plány Shakeyho (Fikes, Hart a Nilsson, 1972).
10. Plánovanie v AI agentoch
Jazykový agent, ktorý opravuje chybu v kóde, tiež plánuje: rozpíše si úlohu do zoznamu krokov, po každom kroku sa pozrie na výsledok (testy prešli? súbor existuje?) a podľa toho plán upraví. Je to sledovanie a preplánovanie, len akcie sú príkazy v termináli a predpoklady a účinky nie sú nikde formálne zapísané — model ich odhaduje z textu.
Práve tu je slabina. Výskum na úlohách zo sveta kociek (napríklad sada PlanBench) ukázal, že jazykové modely v klasickom plánovaní často chybujú, a zvlášť keď sa kocky premenujú na nezmyselné slová, takže model nemôže čerpať z naučených príkladov. Novšie modely s dlhším uvažovaním si vedú oveľa lepšie, ale záruku správnosti nedávajú. Osvedčuje sa preto deľba práce: model úlohu preloží do PDDL alebo navrhne plán a klasický plánovač či validátor ho skontroluje — každý robí to, čo vie.
11. Zhrnutie
- Plánovanie je hľadanie postupnosti akcií k cieľu; STRIPS opisuje stav ako množinu atómov a akciu predpokladmi, pridávanými a odoberanými atómami.
- Dopredné plánovanie je prehľadávanie stavov; spätné regreduje cieľ cez relevantné akcie.
- Plánovač si heuristiku vypočíta sám z relaxovanej úlohy bez odoberania: hmax je prípustná, hadd rýchlejšia, ale môže viesť k dlhšiemu plánu.
- Sussmanova anomália ukazuje, že čiastkové ciele nejde vždy plniť jeden po druhom — kroky sa musia preložiť.
- Hierarchické plánovanie rozkladá úlohy podľa osvedčených metód; v neistom svete sa plán sleduje a preplánováva — presne to robia dnešní AI agenti.
Chcete si to vyskúšať? Nechajte AI agenta zapísať svet kociek v PDDL a pustiť naň voľne dostupný plánovač Fast Downward — a potom skúste, koľko kociek zvládne model sám bez neho.
Máte na to iný názor? Napíšte na support@coden-app.com.