Esercizio - MDP con value iteration, policy iteration e Q-learning (laboratorio 9)
In questa pagina 3
Pdi forma(A, S, S):P[a, s, s']è la probabilità di passare dasas'con l'azionea;Rdi forma(S, A):R[s, a]è la ricompensa per eseguireains(qui è un costo dell'azione).
mdptoolbox.util.check(P, R) controlla che gli array siano coerenti (tace se va tutto bene). Gli algoritmi sono mdp.ValueIteration(P, R, sconto), mdp.PolicyIteration(...), mdp.QLearning(...); dopo run() si leggono V (utilità), policy (azione per stato), iter e time.
Esempio guida: la corsia a quattro stati
Testo. Quattro stati in fila, da sinistra a destra. Due azioni: = "Stay" (resta fermo, riesce sempre), = "Right" (sposta a destra con probabilità , resta fermo con probabilità ). Lo stato è assorbente (ci si resta con probabilità ). Lo stato ha ricompensa , qualsiasi azione negli altri stati costa . Sconto . Trovare utilità e politica con value iteration e con policy iteration.
Costruzione degli array. La prima matrice è "Stay" (l'identità), la seconda "Right":
import numpy as np
import mdptoolbox as mt # pip install pymdptoolbox (non installato qui: il codice e' quello del corso)
P1 = np.array([[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], # Stay
[[.2, .8, 0, 0], [0, .2, .8, 0], [0, 0, .2, .8], [0, 0, 0, 1]]]) # Right
R1 = np.array([[-.04, -.04], [-.04, -.04], [-.04, -.04], [1, 1]]) # R[s, a]
mt.util.check(P1, R1)
vi1 = mt.mdp.ValueIteration(P1, R1, 0.9); vi1.run()
print(vi1.V, vi1.policy)
pi1 = mt.mdp.PolicyIteration(P1, R1, 0.9); pi1.run()
print(pi1.V, pi1.policy)Output riportato dal corso:
(2.766226988084275, 3.7438891127976524, 4.857502678650809, 6.12579511) (1, 1, 1, 0)
(6.6402692938291725, 7.6180844735276665, 8.731707317073173, 10.000000000000002) (1, 1, 1, 0)Il corso commenta: "i due metodi non concordano sui valori, ma concordano sulla politica" (Right in , poi Stay). Perché i valori sono diversi? Lo si capisce rifacendo i calcoli.
Value iteration a mano (, sconto ; ):
- iterazione 1: con vale solo la ricompensa: ;
- iterazione 2: stato 3: . Stato 2, Right: ; Stay: . Stati 0 e 1: Stay e Right valgono entrambi . Quindi ;
- iterazione 3: stato 2, Right: ; stato 1, Right: ; stato 3: .
| 1 | ||||
| 2 | ||||
| 3 | ||||
| 4 | ||||
| 5 |
Lo stato 3 è assorbente con ricompensa a ogni passo: , che tende a solo lentamente.
Grafico interattivo: Value iteration sulla corsia: U_n(3) = 10(1 − 0,9^n) tende lentamente al valore esatto 10
Il criterio di arresto della libreria. ValueIteration si ferma quando la variazione scende sotto , ma misura la variazione con lo span (massimo meno minimo) del vettore , non con il massimo. Dopo 9 iterazioni le differenze valgono quasi lo stesso numero in tutti gli stati (tutti crescono insieme, per ), quindi lo span è piccolo anche se i valori sono ancora lontani da quelli esatti: è garantita l'ottimalità della politica, non l'accuratezza dei valori. Ripetendo i calcoli con NumPy si ritrova il vettore del corso, e dopo 9 iterazioni: . Tutte e quattro le utilità sono inferiori di circa rispetto alla policy iteration, come se mancasse una costante. Con il criterio del testo (massimo delle differenze, soglia ) servono 66 iterazioni e si ottiene , vicino ai valori esatti.
Policy iteration a mano. Parte dalla politica "Stay ovunque".
- Valutazione: negli stati si resta fermi a costo per sempre: ; nello stato 3 . Miglioramento: in , : si passa a Right. In e Right e Stay sono pari (): si resta.
- Valutazione con : , cioè , . Miglioramento: : stato 1 passa a Right.
- Valutazione con : , . Miglioramento: .
- Valutazione con : , . Nessun cambio: fine.
Risultato: , coincidente con l'output del corso. Il valore di è esatto perché la policy iteration risolve un sistema lineare, senza errori di arresto.
Esercizio 1 del laboratorio: cosa fare all'aeroporto
Vedi Esercizio - Utilità attesa, maximax e maximin (laboratorio 9).
Esercizio 2: risolvere un MDP con mdptoolbox
Testo. Quattro stati e quattro azioni. Le azioni sono: = Destra, = Sinistra, = Su, = Giù. Gli stati sono disposti così: Il modello di moto prevede probabilità di muoversi nella direzione dell'azione e in ciascuna delle due direzioni perpendicolari. Quindi è sopra , è a destra di , e così via. Il costo di ogni azione (in ogni stato) è . Nel caso di movimenti "non fattibili" (contro il bordo) l'agente resta nello stato corrente con probabilità ; si considerano comunque le direzioni perpendicolari. La ricompensa dello stato è , quella dello stato è , e l'agente non lascia quegli stati. Sconto .
(a) Qual è la politica secondo value iteration? (b) Secondo policy iteration? (c) Secondo il Q-learning? (d) Usare setVerbose() e l'attributo time degli oggetti MDP per confrontare il numero di iterazioni (attributo iter) e il tempo di CPU di value iteration e policy iteration.
Soluzione.
Costruzione di . Per ogni azione, una matrice . Esempio, azione Destra (prima matrice del codice):
- stato 0: a destra c'è lo stato 1 (probabilità ); le direzioni perpendicolari sono Su (stato 2, ) e Giù (il bordo, quindi resta in 0, ). Riga: ;
- stato 2: a destra c'è lo stato 3 (); Su è il bordo (resta in 2, ), Giù porta in 0 (). Riga: ;
- stati 1 e 3: assorbenti, righe e .
Le altre azioni si costruiscono nello stesso modo. Per Sinistra, nello stato 0 "a sinistra" è il bordo: resta in 0 con e va in 2 con (riga ).
Ricompense. : in e , in (ogni azione), in .
transitions = np.array([
[[0.1, 0.8, 0.1, 0], [0, 1, 0, 0], [0.1, 0, 0.1, 0.8], [0, 0, 0, 1]], # 0 Destra
[[0.9, 0, 0.1, 0], [0, 1, 0, 0], [0.1, 0, 0.9, 0], [0, 0, 0, 1]], # 1 Sinistra
[[0.1, 0.1, 0.8, 0], [0, 1, 0, 0], [0, 0, 0.9, 0.1], [0, 0, 0, 1]], # 2 Su
[[0.9, 0.1, 0, 0], [0, 1, 0, 0], [0.8, 0, 0.1, 0.1], [0, 0, 0, 1]]]) # 3 Giu
rewards = np.array([[-0.04] * 4, [-1] * 4, [-0.04] * 4, [1] * 4])
discount_factor = 0.99
vi = mt.mdp.ValueIteration(transitions, rewards, discount_factor); vi.run()
pi = mt.mdp.PolicyIteration(transitions, rewards, discount_factor); pi.run()
ql = mt.mdp.QLearning(transitions, rewards, discount_factor); ql.run()
print("VI:", vi.policy, vi.iter, vi.time)
print("PI:", pi.policy, pi.iter, pi.time)
print("QL:", ql.policy)Output del corso:
Value Iteration policy: (1, 0, 0, 0) iterazioni: 985 CPU time: 0.0384
Policy Iteration policy: (1, 0, 0, 0) iterazioni: 3 CPU time: 0.0188
Q-Learning policy: (2, 3, 0, 0)(a), (b) La politica è : nello stato 0 Sinistra, nello stato 2 Destra (negli stati 1 e 3 l'azione è irrilevante, sono assorbenti). Il caso di Sinistra è il punto interessante: andare a Sinistra dallo stato 0 sembra insensato (a sinistra c'è il bordo), ma serve proprio a non muoversi senza rischi. Con le utilità ottime le sono:
| azione in 0 | |
|---|---|
| Destra | (con finisce nello stato , che vale ) |
| Sinistra | ( resta in 0, va in 2) |
| Su | ( va comunque nello stato 1) |
| Giù |
Da l'unica uscita sicura è passare per ; Su ci arriva con probabilità ma con finisce nel (per la deviazione verso destra), mentre Sinistra aspetta nello stato 0 e con probabilità scivola in , senza mai rischiare lo stato 1. Nello stato l'azione migliore è Destra (, contro Su , Sinistra , Giù ). Le utilità sono molto più grandi di 1 perché lo stato paga a ogni passo per sempre: .
(c) Il Q-learning della libreria dà : in l'azione 0 (Destra) è giusta, ma in sceglie Su. Valutando la politica Su-in-0, Destra-in-2 si ottiene contro della politica ottima: è sbagliata. È un algoritmo che apprende con un numero fisso di campioni ( passi di default), insufficienti con e due stati assorbenti, quindi il risultato cambia da una esecuzione all'altra. Lo stato 1 e lo stato 3 mostrano azioni (3 e 0) senza senso: sono assorbenti e ogni azione vale lo stesso.
(d) Numero di iterazioni e tempo. Value iteration: 985 iterazioni, s. Policy iteration: 3 iterazioni, s. Ciascuna iterazione di policy iteration è più costosa (risolve un sistema lineare ) ma ne servono molte meno: è proprio il confronto della teoria. Per vicino a 1 value iteration ha bisogno di molte iterazioni, dato che l'errore decresce come (con servono centinaia di passi). Ricalcolando con un'implementazione in NumPy dello stesso criterio di arresto della libreria si ottengono 986 iterazioni (il corso riporta 985: differenza di conteggio di uno), politica e utilità per value iteration; per policy iteration (politica identica in 3 iterazioni).
Versione ripasso
Libreria
pymdptoolbox.Pha forma(A, S, S);Rha forma(S, A).util.check(P, R)controlla gli array;ValueIteration,PolicyIteration,QLearning(P, R, sconto), poirun(),V,policy,iter,time.
Corsia (sconto ). Azioni Stay e Right ( avanti, fermo), stato 3 assorbente con ricompensa , costo negli altri.
- Value iteration: ; , ; , , . In generale .
- Policy iteration da "Stay": in e in ; cambia lo stato 2; poi , ; poi ; poi . Fine dopo 4 valutazioni: , politica Right-Right-Right-Stay.
- I valori della value iteration del corso, , sono diversi perché la libreria si ferma quando lo span (massimo meno minimo) di è sotto (dopo 9 iterazioni): garantisce la politica, non i valori. Con il massimo servono 66 iterazioni e si ottiene .
Esercizio 2 (mondo , stati sopra e sotto; azioni 0 Destra, 1 Sinistra, 2 Su, 3 Giù; voluta e laterali, urto = si resta; costo ; stato 3 con , stato 1 con , assorbenti; sconto ).
- Politica di value iteration e di policy iteration: , cioè Sinistra in 0 e Destra in 2.
- Perché Sinistra in 0: , , , . Sinistra urta il bordo ( resta) e con sale in 2 senza mai rischiare lo stato .
- ; perché lo stato 3 paga per sempre.
- Iterazioni e tempo: value iteration 985 iterazioni, s; policy iteration 3 iterazioni, s: iterazioni più pesanti ma molte meno.
- Q-learning: , sbagliata in 0 (Su, con contro ): passi non bastano con .
vi = mt.mdp.ValueIteration(transitions, rewards, 0.99); vi.run()
pi = mt.mdp.PolicyIteration(transitions, rewards, 0.99); pi.run()
print(vi.policy, vi.iter, pi.policy, pi.iter)Errori tipici: confondere la forma di P () con quella di R (); credere che Sinistra contro il bordo sia sempre inutile; fidarsi dei valori di value iteration della libreria (criterio di arresto sullo span); giudicare il Q-learning con troppi pochi passi.