Programmazione Dinamica
★★★☆☆ Compare quasi solo negli snippet di codice (policy/value iteration) e in vero/falso su convergenza e numero di iterazioni.
Il capitolo precedente ha costruito il linguaggio dei Processi Decisionali di Markov e lo ha portato fino alle equazioni di Bellman: quelle di aspettativa, che caratterizzano la value function di una policy data e formano un sistema lineare, e quelle di ottimalità, che caratterizzano la value function ottima ma, a causa dell’operatore di massimo, non ammettono soluzione in forma chiusa. Questo capitolo affronta la domanda naturale che ne segue: assumendo di conoscere completamente il modello dell’MDP, cioè la dinamica one-step e la funzione di reward , come si calcolano concretamente , e ? La risposta è la famiglia degli algoritmi di programmazione dinamica (Dynamic Programming, DP): iterative policy evaluation per il problema di valutazione, policy improvement e policy iteration per il problema di controllo, la cornice unificante della generalized policy iteration (GPI) e la sua istanza più celebre, value iteration, fino alle varianti asincrone. Il capitolo si chiude con l’analisi dei costi computazionali e con i due limiti strutturali della DP, la maledizione della dimensionalità e la necessità del modello, che motivano il passaggio ai metodi model-free dei capitoli successivi. Un esempio numerico svolto passo-passo, sia su un gridworld sia su un piccolo MDP a due stati, accompagna ogni algoritmo.
Riferimenti sul testo: Sutton e Barto, Reinforcement Learning: An Introduction, capitolo 4. Materiale complementare consigliato: il corso online Fundamentals of Reinforcement Learning (Coursera).
1. Se conosco il modello, posso pianificare#
1.1 I due problemi: prediction e control#
Tutto il capitolo si svolge sotto un’ipotesi forte: l’MDP è noto per intero. Sono dati gli insiemi e , la dinamica di transizione , il reward atteso e il discount factor . In queste condizioni non c’è nulla da “imparare” dall’esperienza: si tratta di pianificare, cioè di estrarre dal modello, con puro calcolo, le quantità di interesse. I problemi da risolvere sono due, in ordine crescente di difficoltà.
Dato un MDP completamente noto e una policy , calcolare la state-value function .
- Input: , , , ;
- Output: (ed eventualmente ).
Dato un MDP completamente noto, trovare la value function ottima e una policy ottima.
- Input: , , ;
- Output: e .
I due problemi non sono indipendenti: la prediction è il mattone del control. Come si vedrà, gli algoritmi di controllo funzionano alternando una fase in cui si valuta la policy corrente (prediction) e una fase in cui la si migliora sfruttando la valutazione appena ottenuta. Gli strumenti matematici sono sempre le equazioni di Bellman: quelle di aspettativa per e nel caso della prediction, quelle di ottimalità per e nel caso del control.
In parole semplici: prediction risponde a “quanto rende questa strategia?”; control risponde a “qual è la strategia migliore?”. La seconda domanda si affronta rispondendo ripetutamente alla prima: valuto la strategia che ho, scopro dove sbaglia, la correggo, e ricomincio.
1.2 Perché la forza bruta non funziona#
Il capitolo precedente ha già fornito, in linea di principio, una soluzione per entrambi i problemi. Per la prediction c’è la forma chiusa , che costa . Per il control c’è la ricerca esaustiva: il teorema di esistenza garantisce una policy ottima deterministica, quindi basterebbe enumerare tutte le policy deterministiche, valutare ciascuna e tenere la dominante. Il conteggio però condanna questo approccio: le policy deterministiche sono
perché in ogni stato si sceglie indipendentemente una tra azioni, e per ciascuna di esse andrebbe risolto un sistema di equazioni lineari. Anche un gridworld modesto, con 4 azioni, produce policy candidate: la ricerca brute-force è fuori scala già sui problemi giocattolo. Serve un metodo che sfrutti la struttura del problema invece di enumerarne le soluzioni.
1.3 Che cos’è la programmazione dinamica e perché si applica agli MDP#
Metodo generale di risoluzione che affronta un problema complesso spezzandolo ricorsivamente in sottoproblemi più semplici: si risolvono i sottoproblemi e si combinano le loro soluzioni nella soluzione del problema originale.
La programmazione dinamica non è nata per gli MDP: è un paradigma algoritmico generale (lo stesso, per esempio, degli algoritmi di cammino minimo). Perché sia applicabile, un problema deve possedere due proprietà strutturali:
- sottostruttura ottima: la soluzione ottima del problema si può comporre a partire dalle soluzioni ottime dei sottoproblemi; il principio di ottimalità deve valere, cioè “comportarsi in modo ottimo da qui in poi” deve decomporsi in “prima mossa ottima, poi comportamento ottimo dal punto d’arrivo”;
- sottoproblemi ricorrenti (overlapping): gli stessi sottoproblemi si ripresentano molte volte, così che la loro soluzione possa essere calcolata una volta, memorizzata e riutilizzata.
Gli MDP soddisfano entrambe le proprietà, ed è esattamente ciò che le equazioni di Bellman esprimono. La sottostruttura ottima è la ricorsione di Bellman: il valore di uno stato si decompone in reward immediato più valore scontato dello stato successivo, quindi “quanto rende partire da ” si risolve conoscendo “quanto rende partire da ciascun possibile ”. I sottoproblemi ricorrenti sono gli stati stessi: il valore di uno stato serve nel calcolo del valore di tutti gli stati che possono transitare in , e la value function è precisamente la cache che memorizza le soluzioni dei sottoproblemi per riutilizzarle.
Idea chiave: le equazioni di Bellman sono la ricetta di decomposizione della programmazione dinamica applicata agli MDP: ogni stato è un sottoproblema, la value function è la tabella delle soluzioni parziali, e l’aggiornamento di Bellman è l’operazione che propaga le soluzioni da uno stato ai suoi predecessori.
La strategia che la DP mette in campo per il control è già visibile in filigrana: produrre una successione di policy via via migliori, ciascuna valutata con le equazioni di aspettativa e corretta con quelle di ottimalità, finché la successione non si stabilizza sulla policy dominante.
In parole semplici: invece di provare tutte le strategie una per una, si compila una tabella con il valore di ogni situazione, sfruttando il fatto che il valore di una situazione dipende solo dal valore delle situazioni in cui si può finire. Si aggiorna la tabella finché i numeri non tornano coerenti tra loro: a quel punto la tabella contiene la risposta.
2. Valutare una policy: iterative policy evaluation#
2.1 Dall’equazione di Bellman all’aggiornamento iterativo#
Il punto di partenza è l’equazione di aspettativa di Bellman, che soddisfa in ogni stato:
Risolvere direttamente il sistema lineare costa ed è impraticabile su spazi di stati grandi. La programmazione dinamica segue un’altra strada: trasforma l’identità in una regola di aggiornamento. Si parte da una stima iniziale arbitraria (per esempio per ogni , con l’unico vincolo che gli eventuali stati terminali abbiano valore 0) e si genera una successione di approssimazioni applicando a ogni passo il membro destro dell’equazione alla stima corrente:
Un’applicazione dell’aggiornamento a tutti gli stati si chiama sweep (spazzata) dello spazio degli stati. Ogni singolo aggiornamento è un backup completo (full-width backup): per calcolare il nuovo valore di si considerano tutte le azioni possibili in e, per ciascuna, tutti i possibili stati successori con le rispettive probabilità; è qui che la conoscenza del modello ( e ) viene usata in modo essenziale.
In forma compatta, usando l’operatore di Bellman di aspettativa introdotto nel capitolo precedente, la successione è . La convergenza è allora immediata dalle proprietà già dimostrate: è l’unico punto fisso di e, per , è una -contrazione in norma del massimo. Ne segue che
quindi per , qualunque sia l’inizializzazione , con errore che si riduce almeno di un fattore a ogni sweep. Nei task episodici la convergenza è garantita anche con , purché ogni policy considerata raggiunga prima o poi uno stato terminale.
Idea chiave: l’equazione di Bellman viene usata non come vincolo da risolvere ma come operazione da ripetere: si “gira la manovella” del backup finché i valori smettono di cambiare. Quando l’aggiornamento non modifica più nulla, la stima soddisfa l’equazione di Bellman, e quindi è .
In parole semplici: si parte con una tabella di valori tutti a zero e la si corregge a ogni giro: il nuovo valore di ogni stato è “premio medio immediato più valore scontato medio di dove si finisce”, calcolato con i valori del giro precedente. Ogni giro avvicina la tabella alla verità di un fattore , quindi dopo abbastanza giri la tabella è (quasi) esatta.
2.2 Pseudocodice e criterio d’arresto#
In pratica l’iterazione si arresta quando i valori si sono stabilizzati: si monitora la variazione massima su tutti gli stati in uno sweep e ci si ferma quando scende sotto una soglia scelta piccola.
Iterative Policy Evaluation
Input: policy π da valutare, modello (p, r), discount γ, soglia θ > 0
Inizializza V(s) arbitrariamente per ogni s ∈ S (V = 0 sugli stati terminali)
ripeti
Δ ← 0
per ogni s ∈ S:
v ← V(s)
V(s) ← Σ_a π(a|s) [ r(s,a) + γ Σ_{s'} p(s'|s,a) V(s') ]
Δ ← max(Δ, |v − V(s)|)
finché Δ < θ
Output: V ≈ V^π
Il criterio d’arresto ha una lettura precisa: se dopo uno sweep la variazione massima è , significa che la stima corrente soddisfa l’equazione di Bellman a meno di ; grazie alla contrazione si può anche limitare la distanza residua dalla soluzione vera, che è dell’ordine di in norma del massimo. Più è piccolo, più la valutazione è accurata, al prezzo di più sweep.
2.3 Versione a due array e versione in place#
La formula descrive un aggiornamento sincrono: tutti i nuovi valori sono calcolati usando esclusivamente i valori del passo precedente, il che richiede due array, uno per e uno per . Lo pseudocodice sopra implementa invece la variante in place: un solo array, in cui ogni valore appena aggiornato è immediatamente disponibile per gli aggiornamenti successivi all’interno dello stesso sweep. Le due versioni convergono entrambe a ; quella in place di solito converge più in fretta, perché l’informazione nuova si propaga già durante lo sweep invece di aspettare il successivo, ma il risultato intermedio dipende dall’ordine in cui gli stati vengono visitati. Questa osservazione, apparentemente un dettaglio implementativo, è il seme della programmazione dinamica asincrona della sezione 7.
In parole semplici: nella versione “pulita” si calcolano tutti i nuovi valori guardando solo la fotografia del giro precedente; nella versione in place si sovrascrive man mano, così chi viene aggiornato dopo sfrutta già i valori freschi dei vicini aggiornati prima. La seconda risparmia memoria e tipicamente accelera la convergenza.
2.4 Esempio numerico: il piccolo gridworld#
L’esempio classico su cui vedere l’algoritmo in azione è un gridworld con queste regole:
- le due celle d’angolo opposte (in alto a sinistra e in basso a destra) sono terminali: raggiungerle conclude l’episodio; formalmente costituiscono un unico stato terminale con valore 0;
- gli altri 14 stati sono le celle non terminali; le azioni sono le quattro direzioni , con effetto deterministico; un’azione che porterebbe fuori dalla griglia lascia l’agente fermo nella cella corrente;
- ogni transizione produce reward , finché non si raggiunge uno stato terminale; il task è episodico e non scontato, ;
- la policy da valutare è quella casuale uniforme: per ogni azione in ogni stato.
Poiché reward e transizioni sono deterministici data l’azione, l’aggiornamento si semplifica in
dove è la cella in cui l’azione conduce da . Partendo da ovunque:
Sweep 1. Per ogni cella non terminale, tutti i successori hanno valore , quindi ovunque (0 sui terminali).
Sweep 2. Ora i valori dei vicini non sono più tutti uguali. Per una cella adiacente a un terminale, per esempio quella in prima riga, seconda colonna: andando a ovest si entra nel terminale (), andando a est, a sud o sbattendo verso nord si finisce in celle con . Quindi
Per una cella interna lontana dai terminali tutti e quattro i successori valgono , quindi .
Sweep 3. Di nuovo per la cella in prima riga, seconda colonna, usando i valori esatti di : ovest porta al terminale (), est e sud portano in celle con , nord fa sbattere e restare sul posto ():
La successione dei valori, arrotondati alla prima cifra decimale, sulle sei istantanee più significative (le celle d’angolo in alto a sinistra e in basso a destra sono i terminali, sempre a 0):
(dopo il primo sweep):
:
:
:
(limite della successione):
I valori limite hanno un’interpretazione trasparente: con reward a ogni passo e , è l’opposto del numero atteso di passi che una passeggiata casuale impiega, partendo da , per raggiungere un terminale. Dalla cella più sfavorita (l’angolo opposto diagonale rispetto a ciascun terminale) servono in media 22 passi; dalle celle adiacenti a un terminale ne servono in media 14: la policy casuale è molto inefficiente, e la value function lo quantifica esattamente.
In parole semplici: a ogni giro i valori negativi “si propagano” dai terminali verso l’interno, come un’onda: prima si sistemano le celle vicine alle uscite, poi via via quelle più lontane. Al limite ogni cella riporta quanti passi (in media, cambiati di segno) mancano all’uscita muovendosi a caso.
3. Migliorare una policy: policy improvement#
3.1 Agire greedy rispetto a una value function#
Il calcolo di non è fine a se stesso: serve per capire se e dove la policy può essere migliorata. Dal capitolo precedente è noto che, se si conoscessero le value function ottime, la policy ottima si otterrebbe agendo in modo greedy: . La domanda naturale è: che cosa succede applicando la stessa ricetta a una value function non ottima? Data , si costruisce la policy deterministica
che in ogni stato sceglie l’azione con il miglior compromesso tra reward immediato e valore (secondo ) dello stato d’arrivo. Il calcolo dell’ richiede di nuovo il modello: per ogni azione si esegue un lookahead a un passo attraverso e . Due esiti sono possibili:
- : la scelta greedy non cambia nulla in nessuno stato. Allora soddisfa per ogni , cioè la sua value function soddisfa l’equazione di ottimalità di Bellman: è già la policy ottima ;
- : in almeno uno stato esiste un’azione con strettamente maggiore di . In tal caso, come garantisce il teorema seguente, è una policy migliore.
3.2 Il teorema di policy improvement#
Siano e due policy deterministiche tali che, per ogni stato ,
Allora è migliore o uguale a , cioè per ogni . Se inoltre la disuguaglianza dell’ipotesi è stretta in qualche stato , allora anche .
L’ipotesi va letta così: deviare da per un solo passo (eseguendo invece di ) e poi tornare a seguire non peggiora mai le cose. La tesi afferma qualcosa di più forte: allora anche seguire per sempre non peggiora mai le cose. La dimostrazione trasforma la deviazione di un passo in una deviazione permanente, espandendo la value function un passo alla volta.
Dimostrazione. Si parte dall’ipotesi nello stato e si espande con la sua definizione a un passo:
L’ultima uguaglianza vale perché condizionare all’azione equivale a dire che il primo passo è compiuto secondo . Ora, dentro il valore atteso compare ; applicando l’ipotesi del teorema nello stato si ottiene , e quindi
dove il secondo passaggio espande di nuovo a un passo: ora anche la seconda azione è scelta da . Iterando lo stesso argomento (applicare l’ipotesi in , espandere, e così via) si sostituisce con un passo alla volta:
Al limite, il termine residuo svanisce (perché se , oppure perché l’episodio termina), e resta l’intero return generato seguendo :
che è la tesi. Se in qualche stato l’ipotesi vale con disuguaglianza stretta, la stessa catena parte con un e produce un miglioramento stretto in quello stato.
La policy greedy della sezione 3.1 soddisfa automaticamente l’ipotesi del teorema: per ogni ,
perché il massimo di un insieme di valori non è mai inferiore a una loro media pesata. Quindi il miglioramento greedy non può mai peggiorare la policy; e se non la cambia, la policy era già ottima.
Idea chiave: il teorema di policy improvement trasforma un vantaggio locale in un vantaggio globale: se in ogni stato la deviazione di un solo passo verso non è dannosa, allora adottare ovunque e per sempre non è dannoso. È questa amplificazione dal singolo passo all’intera traiettoria che rende il miglioramento greedy uno strumento sicuro.
In parole semplici: se cambiare una sola mossa qua e là non fa mai danno, cambiare tutte le mosse insieme non fa danno: i piccoli vantaggi si accumulano lungo la traiettoria invece di annullarsi. Per questo scegliere sempre l’azione col più alto della vecchia strategia produce una strategia nuova che è almeno altrettanto buona.
3.3 Il gridworld rivisitato: greedy su una value function non ottima#
Si torni al piccolo gridworld e alla value function della policy casuale. Poiché il reward è per ogni mossa e le transizioni sono deterministiche con , l’azione greedy in una cella è semplicemente quella che porta nel vicino con il valore più alto.
Applicando il miglioramento greedy alle istantanee della sezione 2.4 si osserva un fatto notevole:
- rispetto a (tutti tranne i terminali) le uniche celle in cui la scelta greedy è determinata sono quelle adiacenti a un terminale: lì l’azione che entra nel terminale (valore 0) batte le altre (valore ); altrove tutte le azioni sono in pareggio;
- rispetto a e il fronte delle scelte determinate avanza verso l’interno della griglia, seguendo la propagazione dei valori;
- rispetto a , e a maggior ragione rispetto a , la policy greedy risultante è già la policy ottima del gridworld: da ogni cella punta al terminale più vicino lungo un cammino di lunghezza minima.
Ci sono due lezioni. La prima: agire greedy rispetto alla value function di una policy mediocre (quella casuale) può produrre direttamente una policy eccellente; in questo piccolo esempio, addirittura ottima al primo miglioramento. La seconda, ancora più utile in pratica: la policy greedy si è stabilizzata già a , molto prima che la valutazione converga ( dista ancora parecchio da ). Valutare con precisione assoluta una policy destinata a essere subito rimpiazzata è uno spreco: questa osservazione motiverà la generalized policy iteration e value iteration.
In parole semplici: per capire da che parte andare non serve conoscere i valori esatti, basta che l’ordinamento tra i vicini sia giusto. E l’ordinamento giusto emerge dopo pochi giri di valutazione, molto prima dei valori esatti: quindi si può migliorare la strategia in anticipo, senza aspettare la fine dei conti.
4. Alternare valutazione e miglioramento: policy iteration#
4.1 L’algoritmo e la sua convergenza#
I due strumenti costruiti finora si compongono naturalmente in un algoritmo per il problema di control. Si parte da una policy arbitraria (per esempio quella casuale) e si alternano i due passi:
- valutazione (E): si calcola con la iterative policy evaluation (fino alla soglia );
- miglioramento (I): si costruisce greedy rispetto a .
La successione generata è
e l’algoritmo termina quando il passo di miglioramento non modifica più la policy. La convergenza è garantita da un argomento in tre mosse:
- per il teorema di policy improvement ogni è migliore o uguale a : la successione delle value function è monotona non decrescente in ogni stato;
- finché la policy non è ottima, il miglioramento è stretto in almeno uno stato: nessuna policy può ripresentarsi due volte nella successione;
- in un MDP finito le policy deterministiche sono in numero finito (), quindi la successione deve arrestarsi dopo un numero finito di iterazioni; e si arresta soltanto quando la policy è greedy rispetto alla propria value function, cioè quando soddisfa l’equazione di ottimalità di Bellman: la policy finale è .
Lo pseudocodice completo:
Policy Iteration
Input: modello (p, r), discount γ, soglia θ > 0
1. Inizializzazione:
V(s) arbitraria e π(s) ∈ A(s) arbitraria, per ogni s ∈ S
2. Policy Evaluation:
ripeti
Δ ← 0
per ogni s ∈ S:
v ← V(s)
V(s) ← r(s, π(s)) + γ Σ_{s'} p(s'|s, π(s)) V(s')
Δ ← max(Δ, |v − V(s)|)
finché Δ < θ
3. Policy Improvement:
policy_stabile ← vero
per ogni s ∈ S:
a_old ← π(s)
π(s) ← argmax_a [ r(s,a) + γ Σ_{s'} p(s'|s,a) V(s') ]
se a_old ≠ π(s): policy_stabile ← falso
se policy_stabile: restituisci V ≈ V* e π ≈ π*
altrimenti: vai al passo 2
Un accorgimento pratico importante: al ritorno al passo 2 la valutazione della nuova policy non riparte da zero, ma dalla value function della policy precedente. Poiché policy consecutive sono simili, le loro value function lo sono altrettanto, e il “warm start” riduce drasticamente il numero di sweep necessari.
Idea chiave: policy iteration è una scalata monotona nello spazio (finito) delle policy deterministiche: ogni giro produce una policy non peggiore, nessuna policy viene mai rivisitata, e l’unica condizione di arresto possibile è l’ottimalità. La convergenza non è asintotica ma esatta e in un numero finito di passi.
In parole semplici: valuto la strategia che ho, poi in ogni situazione sostituisco la mossa prescritta con la migliore secondo i valori appena calcolati, e ricomincio. A ogni giro la strategia migliora davvero da qualche parte; siccome le strategie possibili sono in numero finito, prima o poi il giro non cambia più nulla, e a quel punto ho in mano la strategia ottima certificata.
4.2 Un esempio più ricco: gridworld con celle penalizzanti#
Per vedere la dinamica di policy iteration su qualche iterazione in più conviene un gridworld meno banale. L’ambiente è una griglia con lo stato terminale nell’angolo in alto a sinistra e un gruppo di celle penalizzanti disposte su due file: ogni passo ordinario costa , ma entrare in una cella penalizzante costa ; il task è episodico e non scontato (). La struttura del problema rende sconveniente qualunque cammino che attraversi l’area penalizzante: anche quando il terminale è “in linea d’aria” oltre le celle cattive, il percorso ottimo le aggira, perché un solo ingresso nell’area costa quanto una decina di passi normali. L’esecuzione di policy iteration partendo dalla policy casuale uniforme procede così.
Prima valutazione e primo miglioramento. La value function della policy casuale è molto negativa ovunque (fino a nell’angolo più lontano), perché una passeggiata casuale vaga a lungo e attraversa ripetutamente l’area penalizzante. Ciononostante i valori sono già informativi: contengono l’ordinamento giusto tra i vicini in gran parte della griglia. Per esempio, dalla cella con valore il vicino “in alto” vale e il vicino “a sinistra” : il miglioramento greedy sceglie di andare a sinistra, non perché sia un buon valore, ma perché è meno peggio degli altri. La policy greedy risultante è già ragionevole, ma non ovunque: le celle della prima riga puntano ancora a sinistra attraverso l’area penalizzante, perché i valori della policy casuale non distinguono ancora bene il cammino diretto da quello che aggira le celle blu.
Seconda valutazione e correzioni successive. Valutando la nuova policy i valori cambiano radicalmente (molto meno negativi, perché ora la policy “ha senso”) e rendono visibili gli errori residui. Un esempio concreto: la cella d’angolo in alto a destra vale perché la sua policy passa per la cella penalizzante adiacente (valore ); il confronto tra i al miglioramento successivo rende evidente che conviene invece scendere e aggirare l’area. Lo stesso accade nell’ultima riga: il cammino corretto esce a destra e risale lungo la colonna libera, e la correzione si propaga all’indietro una cella per giro (prima , poi , infine ), perché a ogni giro l’informazione buona arretra di un passo lungo il percorso. Gli stati vicini al terminale si sistemano per primi; quelli più lontani richiedono più iterazioni. Dopo pochi giri il miglioramento non modifica più alcuna azione: la policy è ottima e la value function corrente è .
In parole semplici: anche i valori di una strategia pessima insegnano qualcosa, perché dicono quale mossa è “meno peggio” delle altre. Il primo giro sistema le scelte vicino all’obiettivo, i giri successivi propagano la correzione alle zone lontane, come un’onda che torna indietro dal traguardo. Quando l’onda ha raggiunto tutto, nessuna mossa cambia più: si è arrivati all’ottimo.
4.3 Il collo di bottiglia#
Il costo di policy iteration è dominato dal passo di valutazione: ogni iterazione esterna richiede molti sweep completi dello spazio degli stati solo per valutare, con precisione , una policy che con ogni probabilità verrà scartata subito dopo. L’esempio del gridworld ha già suggerito che si tratta di uno spreco: la policy greedy si stabilizza ben prima che la valutazione converga. La domanda diventa: quanto si può troncare la valutazione senza perdere la convergenza all’ottimo? La cornice concettuale che risponde “quanto si vuole” è la generalized policy iteration della prossima sezione; la realizzazione estrema, un solo sweep di valutazione per miglioramento, è value iteration.
5. Generalized policy iteration#
L’idea che valutazione e miglioramento possano essere interlacciati a qualunque granularità ha un nome: generalized policy iteration (GPI). Il termine indica ogni schema in cui due processi interagiscono:
- un processo di valutazione, che spinge la value function corrente verso la coerenza con la policy corrente (verso );
- un processo di miglioramento, che spinge la policy corrente verso la scelta greedy rispetto alla value function corrente.
Policy iteration è il caso estremo in cui la valutazione arriva a convergenza prima di ogni miglioramento; value iteration, oggetto della prossima sezione, è il caso estremo opposto, con un solo sweep di valutazione per miglioramento; la DP asincrona della sezione 7 interlaccia i due processi a grana ancora più fine, aggiornando singoli stati. In tutti i casi il comportamento qualitativo è lo stesso della scalata a zigzag di policy iteration: una traiettoria che rimbalza tra due “bersagli” mobili, con la valutazione che tira la value function verso il vincolo “ coerente con ” e il miglioramento che tira la policy verso il vincolo “ greedy rispetto a ”. I due processi in parte competono, perché ogni miglioramento rende la value function corrente obsoleta e ogni valutazione rende la policy corrente non più greedy; ma nel complesso cooperano, e la traiettoria converge verso l’unico punto in cui entrambi i vincoli sono soddisfatti simultaneamente.
Quel punto è caratterizzato con precisione: se la value function è coerente con la policy () e la policy è greedy rispetto alla value function, allora
cioè vale l’equazione di ottimalità di Bellman: e . La stabilità congiunta dei due processi implica l’ottimalità, e viceversa; per questo qualunque interlacciamento che continui a far progredire entrambi i processi finisce nell’ottimo.
La portata della GPI va molto oltre questo capitolo: quasi tutti i metodi di reinforcement learning che si incontreranno, compresi quelli model-free, sono istanze di GPI in cui cambia soltanto come viene realizzato il processo di valutazione (per esempio con stime campionarie invece che con backup esatti sul modello) e quanto spesso si migliora.
Idea chiave: valutazione e miglioramento sono due forze che si tirano a vicenda: qualunque modo di alternarle, anche parziale, sbilanciato o asincrono, converge allo stesso punto di equilibrio, l’unico in cui la policy è greedy rispetto alla propria value function. Quel punto è l’ottimo di Bellman.
In parole semplici: non importa se si misura tanto e si corregge poco, o si misura poco e si corregge subito: finché si continua sia a misurare sia a correggere, si finisce sempre nello stesso posto, dove misura e strategia non si contraddicono più. Quel posto è la soluzione ottima, e quasi tutto il reinforcement learning è una variazione su questo schema.
6. La scorciatoia: value iteration#
6.1 Fondere valutazione e miglioramento in un unico aggiornamento#
Si consideri l’istanza di GPI in cui il passo di valutazione esegue un solo sweep e si ferma. La sequenza delle operazioni per uno stato diventa: un backup di valutazione con la policy corrente ,
seguito subito dal miglioramento greedy, che ridefinisce . Ma se il miglioramento viene comunque eseguito subito dopo, tanto vale usare direttamente l’azione massimizzante dentro il backup di valutazione: i due passi si fondono in un unico aggiornamento che non fa più riferimento ad alcuna policy esplicita,
Questo è l’aggiornamento di value iteration, e la sua forma è inconfondibile: è l’equazione di ottimalità di Bellman trasformata in regola di aggiornamento, esattamente come la iterative policy evaluation era l’equazione di aspettativa trasformata in regola di aggiornamento. In forma compatta, con operatore di ottimalità di Bellman.
Idea chiave: value iteration elimina la policy dal ciclo: a ogni sweep ogni stato prende direttamente il valore della sua azione migliore rispetto alla stima corrente. Valutazione e miglioramento avvengono simultaneamente dentro il , e l’informazione fluisce verso l’ottimo a ogni sweep, senza sprecare sweep per valutare con precisione policy intermedie.
In parole semplici: invece di “prima misuro bene quanto rende la mia strategia, poi la correggo”, si fa tutto in un colpo: ogni situazione assume subito il valore della sua mossa migliore, ricalcolato a ogni giro. Non esiste più una strategia esplicita durante l’esecuzione; la strategia “implicita” cambia da sola a ogni giro, e alla fine si estrae quella ottima dai valori.
6.2 Convergenza e proprietà#
La convergenza di value iteration discende dalle proprietà di stabilite nel capitolo precedente: per , è una -contrazione in norma del massimo e il suo unico punto fisso è . Quindi, per qualunque inizializzazione ,
La convergenza è geometrica di fattore ma, a differenza di policy iteration, asintotica: in generale nessuna iterata finita coincide esattamente con , e ci si arresta quando la variazione massima di uno sweep scende sotto una soglia (con la stessa garanzia sulla distanza residua vista per la policy evaluation). Due osservazioni caratterizzano l’algoritmo:
- le iterate intermedie in generale non sono la value function di nessuna policy: sono oggetti intermedi che interpolano tra la stima iniziale e ; questo non è un problema, perché interessa solo il limite;
- durante l’esecuzione non viene mai costruita né memorizzata una policy; al termine, la policy ottima (approssimata) si estrae dai valori con un ultimo passo greedy:
Questo passo finale è legittimo proprio perché applicato a (un’approssimazione di) : come stabilito nel capitolo precedente, la policy greedy rispetto alla value function ottima è la policy ottima.
Lo pseudocodice, sensibilmente più semplice di quello di policy iteration (un solo loop invece di due annidati):
Value Iteration
Input: modello (p, r), discount γ, soglia θ > 0
Inizializza V(s) arbitrariamente per ogni s ∈ S (V = 0 sugli stati terminali)
ripeti
Δ ← 0
per ogni s ∈ S:
v ← V(s)
V(s) ← max_a [ r(s,a) + γ Σ_{s'} p(s'|s,a) V(s') ]
Δ ← max(Δ, |v − V(s)|)
finché Δ < θ
Output: policy deterministica π(s) = argmax_a [ r(s,a) + γ Σ_{s'} p(s'|s,a) V(s') ]
6.3 Policy iteration e value iteration a confronto#
| Aspetto | Policy iteration | Value iteration |
|---|---|---|
| Equazione di Bellman usata | aspettativa (valutazione) + greedy (miglioramento) | ottimalità, come unico aggiornamento |
| Struttura del codice | due loop annidati (valutazione dentro il ciclo esterno) | un solo loop |
| Policy esplicita durante l’esecuzione | sì, aggiornata a ogni iterazione esterna | no, estratta solo alla fine |
| Iterate intermedie | : vere value function di policy | : in generale di nessuna policy |
| Costo per iterazione | alto (valutazione completa, molti sweep) | uno sweep, |
| Numero di iterazioni | finito, tipicamente piccolo | asintotico, errore |
| Convergenza | esatta a in un numero finito di giri | a al limite, arresto a soglia |
Nessuno dei due domina l’altro in assoluto: policy iteration fa poche iterazioni costose, value iteration molte iterazioni economiche; quale sia più veloce dipende dal problema. Value iteration ha però il pregio della semplicità e propaga informazione verso l’ottimo a ogni singolo sweep, senza mai “fermarsi a rifinire” la valutazione di una policy provvisoria. Concettualmente, i due algoritmi restano gli estremi dello spettro della generalized policy iteration: valutazione completa a ogni giro da un lato, valutazione troncata a un solo sweep dall’altro, con tutte le vie di mezzo ugualmente legittime.
7. Programmazione dinamica asincrona#
Gli algoritmi visti finora sono sincroni: ogni iterazione esegue uno sweep esaustivo, aggiornando tutti gli stati uno dopo l’altro in un ordine fissato. Su spazi di stati molto grandi questo è un vincolo pesante: un singolo sweep può essere proibitivo, e molti aggiornamenti sono sprecati su stati i cui valori sono già accurati o irrilevanti. La DP asincrona rimuove il vincolo dello sweep: gli stati vengono aggiornati singolarmente, in qualunque ordine, usando ogni volta i valori correnti (aggiornamento in place) degli altri stati. Lo schema generale è:
- si sceglie uno stato (con una qualche strategia di selezione);
- si applica a il backup appropriato (di aspettativa, se si sta valutando una policy; di ottimalità, se si sta facendo value iteration);
- si ripete finché un criterio di convergenza non è soddisfatto.
La convergenza ai valori corretti resta garantita a una condizione: nessuno stato deve essere abbandonato per sempre, cioè ogni stato deve continuare a essere selezionato (tutti gli stati devono essere aggiornati infinite volte, nel limite). All’interno di questo vincolo, la libertà nell’ordine di aggiornamento apre tre opportunità concrete:
- selezione casuale e parallelismo: invece di uno sweep sequenziale si estraggono stati a caso e li si aggiorna; poiché non c’è più un ordine obbligato, più unità di calcolo possono aggiornare in parallelo regioni diverse dello spazio degli stati, il che sposa bene le architetture di calcolo moderne;
- prioritized sweeping: la selezione può essere resa intelligente dando priorità agli stati “più bisognosi”, per esempio quelli con il maggiore errore di Bellman corrente, : si aggiorna lo stato in cima alla coda di priorità, si ricalcola la priorità dei suoi predecessori (che sono quelli il cui valore dipende dal suo) e si procede; l’informazione si propaga così all’indietro lungo le direzioni in cui serve davvero. Anche una conoscenza parziale del problema, come una policy quasi buona già disponibile, può guidare la scelta delle zone da cui partire;
- real-time DP: la guida più naturale per la selezione è l’esperienza dell’agente stesso: si eseguono i backup sugli stati che l’agente visita realmente interagendo con l’ambiente secondo la policy corrente. Il calcolo si concentra così sulle parti dello spazio degli stati che sono effettivamente rilevanti per il comportamento, ignorando a lungo (legittimamente) le regioni mai raggiunte.
La DP asincrona non riduce il costo teorico del problema, ma permette spesso di trovare policy buone con molto meno calcolo di quello richiesto da sweep esaustivi, e di applicare la DP a problemi più grandi di quelli trattabili in forma sincrona.
In parole semplici: non serve rifare tutti i conti su tutta la mappa a ogni giro: si possono aggiornare le caselle una alla volta, in qualsiasi ordine, magari partendo da quelle più sbagliate o da quelle che l’agente incontra davvero. Basta non dimenticarsi per sempre di nessuna casella, e il risultato finale è lo stesso, spesso con molta meno fatica.
8. Efficienza e limiti della programmazione dinamica#
8.1 Complessità computazionale#
Quanto costa la DP? La buona notizia è che trovare una policy ottima con la programmazione dinamica ha costo polinomiale nel numero di stati e di azioni, laddove la ricerca diretta nello spazio delle policy dovrebbe esaminarne , un numero esponenziale: rispetto alla forza bruta, la DP è esponenzialmente più efficiente. Le stime di riferimento:
- value iteration: ogni sweep costa , perché per ciascuno degli stati si valutano azioni, ognuna con una somma su fino a successori;
- policy iteration: la valutazione iterativa di una policy fino a precisione costa dell’ordine di (ogni sweep costa a policy fissata, e il numero di sweep segue dalla contrazione di fattore ); per la fase di miglioramento, il numero di iterazioni necessarie è limitato da una quantità dell’ordine di .
In entrambi i casi il fattore segnala che problemi molto lungimiranti (con vicino a 1) sono intrinsecamente più costosi: la contrazione è più lenta e l’informazione deve propagarsi su orizzonti effettivi più lunghi. Esistono anche approcci alternativi alla DP basati sulla programmazione lineare, che riformulano la ricerca di come problema di ottimizzazione lineare; in teoria sono eleganti, ma in pratica scalano peggio della DP al crescere del problema.
8.2 La maledizione della dimensionalità#
La cattiva notizia è che “polinomiale in ” è una consolazione solo apparente, perché stesso è spesso astronomico. Il fenomeno ha un nome: curse of dimensionality (maledizione della dimensionalità). Se lo stato è descritto da variabili, ciascuna con valori possibili, allora : il numero di stati cresce esponenzialmente con il numero di variabili di stato, non con la loro dimensione fisica. Una scacchiera ha 64 caselle ma circa configurazioni; un robot con una decina di sensori continui discretizzati ha uno spazio di stati che nessuna tabella può contenere.
In pratica:
- la DP classica (sincrona, tabellare) è applicabile fino a qualche milione di stati;
- la DP asincrona, concentrando il calcolo dove serve e prestandosi al parallelismo, arriva a problemi più grandi;
- ma è facile costruire MDP perfettamente ragionevoli per i quali qualunque metodo di DP tabellare è impraticabile.
In parole semplici: il costo della DP cresce “solo” come una potenza del numero di stati, ma il numero di stati esplode come una potenza del numero di variabili che descrivono la situazione. Basta aggiungere qualche sensore o qualche caratteristica allo stato e la tabella dei valori diventa più grande di qualunque memoria: è questo, non l’algoritmo, il vero muro.
8.3 Il limite fondamentale: serve il modello#
C’è però un limite ancora più radicale del costo computazionale, ed è visibile in ogni singola formula di questo capitolo: ogni backup di DP richiede e , cioè la dinamica one-step completa dell’MDP. La DP non è un metodo di apprendimento ma di pianificazione: calcola la soluzione a partire dalla descrizione perfetta del problema. Nei problemi reali questa descrizione spesso non c’è:
- la dinamica può essere ignota: nessuno fornisce la tabella delle probabilità di transizione di un mercato finanziario o di un utente che interagisce con un sistema;
- oppure può essere nota in linea di principio ma proibitiva da modellare: costruire un modello accurato può essere più difficile che risolvere il problema, e un modello sbagliato produce una “soluzione ottima” del problema sbagliato.
Ciò che invece è quasi sempre disponibile, o generabile con un simulatore, è l’esperienza: traiettorie di stati, azioni e reward osservate interagendo con l’ambiente. I metodi dei prossimi capitoli, detti model-free, ripartono esattamente da qui: mantengono l’architettura concettuale costruita in questo capitolo, la generalized policy iteration, ma sostituiscono i backup esatti sul modello con stime ottenute dai campioni. Il primo rappresentante della famiglia, i metodi Monte Carlo, stima le value function mediando i return effettivamente osservati; questa sostituzione, come si vedrà, porta con sé un problema nuovo e centrale, quello dell’esplorazione. Le equazioni di Bellman e lo schema valutazione-miglioramento restano il filo conduttore: cambia solo il modo di calcolare le aspettative quando il modello non c’è.
Idea chiave: la DP risolve gli MDP alla perfezione, ma a due condizioni che il mondo reale raramente concede: uno spazio di stati abbastanza piccolo da essere spazzato, e un modello completo della dinamica. Il reinforcement learning propriamente detto nasce rinunciando alla seconda condizione: stessi obiettivi, stesse equazioni, ma aspettative stimate dall’esperienza invece che calcolate dal modello.
9. Esempio svolto: value iteration sul robot riciclatore#
Per chiudere il cerchio si applica value iteration, passo per passo, al piccolo MDP del robot riciclatore già risolto analiticamente nel capitolo precedente, di cui si conoscono quindi in anticipo la soluzione ottima e la value function ottima: un banco di prova ideale.
9.1 Il modello e le equazioni di aggiornamento#
Richiamo dei dati: stati (batteria alta e bassa), . Nello stato le azioni sono cerca (reward ; resta in con probabilità , scende in con probabilità ) e attendi (reward ; resta in ). Nello stato le azioni sono cerca (reward atteso , perché ; resta in con probabilità , con probabilità la batteria si esaurisce e il robot viene soccorso e riportato in ), attendi (reward ; resta in ) e ricarica (reward ; va in ). La soluzione nota: la policy ottima è , con e .
L’aggiornamento di value iteration, scritto esplicitamente per i due stati:
9.2 Le prime iterazioni a mano#
Si parte da .
Iterazione 1. In : cerca dà , attendi dà : vince cerca, . In : cerca dà , attendi dà , ricarica dà : vince attendi, .
Iterazione 2. In : cerca dà ; attendi dà : vince cerca, . In : cerca dà ; attendi dà ; ricarica dà : vince ancora attendi, per un soffio, .
Iterazione 3. In : cerca dà ; attendi dà : . In : cerca dà ; attendi dà ; ricarica dà : qui avviene il sorpasso, vince ricarica, . Il motivo è leggibile: man mano che cresce, il valore di “tornare in ” cresce con lui, finché il guadagno immediato di attendi () non basta più a compensare la rinuncia a trovarsi in .
La tabella riassume le prime iterazioni e, per ciascuna , la policy greedy che se ne estrarrebbe:
| greedy in | greedy in | |||
|---|---|---|---|---|
| 0 | cerca | attendi | ||
| 1 | cerca | attendi | ||
| 2 | cerca | ricarica | ||
| 3 | cerca | ricarica | ||
| 4 | cerca | ricarica | ||
| 5 | cerca | ricarica | ||
| cerca | ricarica |
9.3 Che cosa insegna l’esempio#
Tre osservazioni condensano i messaggi del capitolo:
- la policy converge molto prima dei valori: la policy greedy estratta da è già quella ottima da in poi, quando i valori ( e ) distano ancora enormemente da quelli ottimi ( e ). Come nel gridworld, per decidere bene serve l’ordinamento corretto tra le alternative, non i valori esatti;
- la velocità di convergenza dei valori è dettata da : la garanzia di contrazione dà . Per portare l’errore sotto servono circa sweep: la coda della convergenza è lunga, coerentemente con il fattore di questo problema;
- il limite coincide con la soluzione analitica: la successione converge esattamente alla calcolata nel capitolo precedente risolvendo le equazioni di ottimalità, e la policy estratta è la certificata allora. Value iteration è a tutti gli effetti un solutore iterativo di quelle equazioni non lineari che non ammettevano forma chiusa.
In parole semplici: l’algoritmo scopre quasi subito “che cosa” conviene fare (cercare con batteria alta, ricaricare con batteria bassa) e impiega molto più tempo a stabilire con precisione “quanto vale” farlo. Se l’obiettivo è la strategia, ci si può fermare presto; se servono i valori esatti, si paga la lentezza della contrazione, tanto più cara quanto più è vicino a 1.
Glossario#
| Termine | Definizione |
|---|---|
| Programmazione dinamica (DP) | Famiglia di metodi che risolve problemi complessi decomponendoli ricorsivamente in sottoproblemi; negli MDP, algoritmi di pianificazione basati sulle equazioni di Bellman con modello noto. |
| Sottostruttura ottima | Proprietà per cui la soluzione ottima si compone dalle soluzioni ottime dei sottoproblemi; negli MDP è espressa dalla ricorsione di Bellman. |
| Sottoproblemi ricorrenti | Proprietà per cui gli stessi sottoproblemi si ripresentano e le soluzioni possono essere memorizzate; negli MDP la value function funge da cache. |
| Prediction | Problema di calcolare dati MDP e policy . |
| Control | Problema di trovare e dato l’MDP. |
| Iterative policy evaluation | Calcolo di applicando ripetutamente l’equazione di aspettativa di Bellman come aggiornamento: ; converge per contrazione da qualunque . |
| Sweep | Applicazione dell’aggiornamento di Bellman a tutti gli stati dello spazio, una volta ciascuno. |
| Backup completo (full-width) | Aggiornamento di un singolo stato che considera tutte le azioni e tutti i successori pesati con il modello e . |
| Aggiornamento in place | Variante con un solo array in cui i valori appena aggiornati sono subito usati nello stesso sweep; converge e di solito accelera. |
| Policy improvement | Costruzione della policy greedy a partire da ; non peggiora mai la policy. |
| Teorema di policy improvement | Se per ogni , allora per ogni : un vantaggio a un passo si estende all’intera traiettoria. |
| Policy iteration | Alternanza di valutazione completa e miglioramento greedy: ; converge esattamente in un numero finito di iterazioni. |
| Generalized policy iteration (GPI) | Cornice generale in cui valutazione e miglioramento interagiscono a qualunque granularità; il punto di equilibrio congiunto è (, ). |
| Value iteration | Iterazione dell’equazione di ottimalità di Bellman come aggiornamento: ; converge a per contrazione, policy estratta alla fine. |
| DP asincrona | DP senza sweep esaustivi: aggiornamenti di singoli stati in qualunque ordine (anche in parallelo); converge purché nessuno stato sia trascurato per sempre. |
| Prioritized sweeping | Selezione asincrona degli stati da aggiornare in base alla priorità, tipicamente il modulo dell’errore di Bellman, con propagazione ai predecessori. |
| Real-time DP | DP asincrona guidata dall’esperienza: si aggiornano gli stati effettivamente visitati dall’agente. |
| Errore di Bellman | Scarto tra il backup e il valore corrente; misura quanto uno stato “ha bisogno” di aggiornamento. |
| Criterio d’arresto (, ) | Arresto delle iterazioni quando la variazione massima in uno sweep scende sotto la soglia ; la distanza residua da o è controllata dalla contrazione. |
| Curse of dimensionality | Crescita esponenziale di con il numero di variabili di stato, che rende impraticabile la DP tabellare sui problemi grandi. |
| Model-based / model-free | Metodi che richiedono la dinamica one-step (, ), come la DP, contro metodi che apprendono solo dall’esperienza campionata, come Monte Carlo. |