Salta al contenuto
Note per Studenti Esercizio - Value iteration sul mondo 4x3 (slide del corso)

Esercizio - Value iteration sul mondo 4x3 (slide del corso)

Teoria: Processi decisionali di Markov - utilità, equazione di Bellman, value e policy iterationUn MDP (processo decisionale di Markov) modella un problema decisionale sequenziale in ambiente stocastico e completamente osservabile con stati S, azioni A(s), modello di transizione P(s'|s,a) e ricompensa R(s,a,s'). La soluzione è una politica pi(s). L'utilità U(s) è il ritorno scontato atteso e soddisfa l'equazione di Bellman U(s)=max_a sum_s' P(s'|s,a)[R(s,a,s')+gamma U(s')]; la quantità tra parentesi quadre sommata su s' è la funzione azione-utilità Q(s,a). Value iteration parte da U=0, applica Bellman a tutti gli stati insieme e si ferma quando delta <= eps(1-gamma)/gamma; la politica è argmax_a Q(s,a). Policy iteration alterna valutazione (sistema lineare, senza max) e miglioramento greedy, e termina quando la politica non cambia. Nei POMDP lo stato è nascosto: si lavora sullo stato di credenza b aggiornato come nel filtraggio, b'(s')=alpha P(e|s') sum_s P(s'|s,a)b(s).Processi decisionali di Markov - utilità, equazione di Bellman, value e policy iteration →, sezioni 3-6.

Testo (dalle slide). Un robot si muove in una griglia con 4 colonne e 3 righe. Le celle sono indicate con (colonna, riga), partendo da (1,1)(1,1) in basso a sinistra. La cella (2,2)(2,2) è un muro. Le celle (4,3)(4,3) e (4,2)(4,2) sono terminali: entrare in (4,3)(4,3) ha ricompensa +1+1, entrare in (4,2)(4,2) ha ricompensa −1-1. Ogni altra transizione ha ricompensa r=−0,04r=-0{,}04. L'azione voluta (Su, Giù, Sinistra, Destra) riesce con probabilità 0,80{,}8; con probabilità 0,10{,}1 per parte il robot si muove perpendicolarmente. Un urto contro un muro o il bordo lascia il robot fermo. Fattore di sconto γ=1\gamma=1.

(a) Calcolare a mano U1U_1 e U2U_2 di value iteration partendo da U0=0U_0=0. (b) Scrivere il programma, trovare le utilità finali e il numero di iterazioni. (c) Ricavare la politica ottima e verificare la scelta in (1,1)(1,1). (d) Che cosa cambia con r=−2r=-2 e con r=−0,01r=-0{,}01?

Soluzione

Regole di calcolo. Per ogni stato non terminale ss e azione aa: Qk(s,a)=∑s′P(s′∣s,a)[R(s,a,s′)+γUk(s′)],Uk+1(s)=max⁡aQk(s,a),Q_k(s,a)=\sum_{s'}P(s'\mid s,a)\big[R(s,a,s')+\gamma U_k(s')\big],\qquad U_{k+1}(s)=\max_aQ_k(s,a), con ricompensa +1+1 o −1-1 quando s′s' è un terminale (e Uk(terminale)=0U_k(\text{terminale})=0: la ricompensa si incassa entrando, poi il gioco finisce) e r+Uk(s′)r+U_k(s') altrimenti. Un esito che urta un muro o il bordo ha s′=ss'=s.

(a) Iterazioni a mano

Iterazione 1 (U0=0U_0=0): Q0(s,a)Q_0(s,a) è solo la ricompensa attesa del passo. Quasi ovunque =r=−0,04=r=-0{,}04. Fanno eccezione le celle da cui si può entrare in un terminale:

  • (3,3)(3,3), Destra: 0,8⋅(+1)+0,1 (r+0)+0,1 (r+0)=0,8−0,008=0,7920{,}8\cdot(+1)+0{,}1\,(r+0)+0{,}1\,(r+0)=0{,}8-0{,}008=\mathbf{0{,}792} (Su e Giù non entrano nel +1+1 con probabilità 0,80{,}8, la deviazione a destra sì ma con 0,10{,}1: valgono meno, per esempio Su: 0,1⋅1+0,9⋅r=0,0640{,}1\cdot1+0{,}9\cdot r=0{,}064);
  • (3,2)(3,2), Su: 0,8 (r+0)+0,1 (r+0)+0,1⋅(−1)=−0,04⋅0,9−0,1=−0,1360{,}8\,(r+0)+0{,}1\,(r+0)+0{,}1\cdot(-1)=-0{,}04\cdot0{,}9-0{,}1=-0{,}136; Giù: 0,8r+0,1r+0,1(−1)0{,}8r+0{,}1r+0{,}1(-1) è uguale, e Sinistra (0,80{,}8 muro: resta; 0,10{,}1 su; 0,10{,}1 giù) vale −0,04-0{,}04. Il massimo è −0,04-0{,}04 (Sinistra, che non rischia il −1-1);
  • (4,1)(4,1) e tutte le altre: −0,04-0{,}04.

Quindi U1(3,3)=0,792U_1(3,3)=0{,}792 e tutti gli altri stati non terminali valgono −0,04-0{,}04.

Iterazione 2 (si usa U1U_1):

  • (3,3)(3,3), Destra: 0,8⋅1+0,1 (r+U1(3,3))+0,1 (r+U1(3,2))=0,8+0,1⋅0,752+0,1⋅(−0,08)=0,86720{,}8\cdot1+0{,}1\,(r+U_1(3,3))+0{,}1\,(r+U_1(3,2))=0{,}8+0{,}1\cdot0{,}752+0{,}1\cdot(-0{,}08)=\mathbf{0{,}8672};
  • (2,3)(2,3), Destra: 0,8 (r+U1(3,3))+0,1 (r+U1(2,3))0{,}8\,(r+U_1(3,3))+0{,}1\,(r+U_1(2,3)) (su: bordo, resta) + 0,1 (r+U1(2,3))+\,0{,}1\,(r+U_1(2,3)) (giù: muro, resta) =0,8⋅0,752+0,2⋅(−0,08)=0,5856=0{,}8\cdot0{,}752+0{,}2\cdot(-0{,}08)=\mathbf{0{,}5856};
  • (3,2)(3,2), Su: 0,8 (r+U1(3,3))+0,1 (r+U1(3,2))0{,}8\,(r+U_1(3,3))+0{,}1\,(r+U_1(3,2)) (sinistra: muro) + 0,1⋅(−1)=0,6016−0,008−0,1=0,4936+\,0{,}1\cdot(-1)=0{,}6016-0{,}008-0{,}1=\mathbf{0{,}4936};
  • tutte le altre celle hanno vicini non ancora "informati" (valgono −0,04-0{,}04) e la miglior azione non tocca i terminali: U2=−0,04+(−0,04)=−0,08U_2=-0{,}04+(-0{,}04)=-0{,}08.
col. 1 col. 2 col. 3 col. 4
riga 3, U1U_1 −0,04-0{,}04 −0,04-0{,}04 0,7920{,}792 terminale
riga 2, U1U_1 −0,04-0{,}04 muro −0,04-0{,}04 terminale
riga 1, U1U_1 −0,04-0{,}04 −0,04-0{,}04 −0,04-0{,}04 −0,04-0{,}04
riga 3, U2U_2 −0,08-0{,}08 0,58560{,}5856 0,86720{,}8672 terminale
riga 2, U2U_2 −0,08-0{,}08 muro 0,49360{,}4936 terminale
riga 1, U2U_2 −0,08-0{,}08 −0,08-0{,}08 −0,08-0{,}08 −0,08-0{,}08

(b) Il programma

python
import numpy as np

MURI = {(2, 2)}
TERMINALI = {(4, 3): +1.0, (4, 2): -1.0}                 # ricompensa per l'ingresso
STATI = [(x, y) for y in (1, 2, 3) for x in (1, 2, 3, 4) if (x, y) not in MURI]
IDX = {s: i for i, s in enumerate(STATI)}
AZIONI = {"Su": (0, 1), "Giu": (0, -1), "Sx": (-1, 0), "Dx": (1, 0)}
LATERALI = {"Su": ("Sx", "Dx"), "Giu": ("Sx", "Dx"), "Sx": ("Su", "Giu"), "Dx": ("Su", "Giu")}
NOMI = list(AZIONI)

def passo(s, a):
    t = (s[0] + AZIONI[a][0], s[1] + AZIONI[a][1])
    return s if (t in MURI or not (1 <= t[0] <= 4 and 1 <= t[1] <= 3)) else t

def costruisci_mdp(r):
    n = len(STATI)
    P = np.zeros((4, n, n)); R = np.zeros((n, 4))        # P[a,s,s'], R[s,a] = ricompensa attesa
    for ai, a in enumerate(NOMI):
        for s in STATI:
            if s in TERMINALI:
                P[ai, IDX[s], IDX[s]] = 1                 # terminale: assorbente, nessuna ricompensa
                continue
            for b, p in ((a, .8), (LATERALI[a][0], .1), (LATERALI[a][1], .1)):
                t = passo(s, b)
                P[ai, IDX[s], IDX[t]] += p
                R[IDX[s], ai] += p * TERMINALI.get(t, r)  # +1 / -1 se entra in un terminale, altrimenti r
    return P, R

def stampa(V):
    for y in (3, 2, 1):
        print("  ".join("  muro " if (x, y) in MURI else f"{V[IDX[(x, y)]]:7.4f}" for x in (1, 2, 3, 4)))

def value_iteration(P, R, gamma, tol=1e-10):
    V = np.zeros(P.shape[1]); storia = [V]
    while True:
        Q = R.T + gamma * P @ V
        V_new = Q.max(axis=0); storia.append(V_new)
        if np.abs(V_new - V).max() < tol:
            return V_new, Q.argmax(axis=0), storia
        V = V_new

P, R = costruisci_mdp(-0.04)
V, pol, storia = value_iteration(P, R, 1.0)
print("iterazioni:", len(storia) - 1)
for k in (1, 2):
    print("U_%d" % k); stampa(storia[k])

Output atteso (i terminali compaiono con 0 nelle tabelle di UkU_k, perché la loro ricompensa è incassata nell'ingresso):

iterazioni: 40
U_1
-0.0400  -0.0400   0.7920   0.0000
-0.0400    muro   -0.0400   0.0000
-0.0400  -0.0400  -0.0400  -0.0400
U_2
-0.0800   0.5856   0.8672   0.0000
-0.0800    muro    0.4936   0.0000
-0.0800  -0.0800  -0.0800  -0.0800

Gli stessi valori che si sono ricavati a mano. Dopo 40 iterazioni (tolleranza 10−1010^{-10}; con γ=1\gamma=1 la soglia ε(1−γ)/γ\varepsilon(1-\gamma)/\gamma non si può usare) le utilità sono quelle delle slide:

col. 1 col. 2 col. 3 col. 4
riga 3 0,85160{,}8516 0,90780{,}9078 0,95780{,}9578 +1+1
riga 2 0,80160{,}8016 muro 0,70030{,}7003 −1-1
riga 1 0,74530{,}7453 0,69530{,}6953 0,65140{,}6514 0,42790{,}4279

(c) Politica

La politica è π∗(s)=arg⁡max⁡aQ(s,a)\pi^*(s)=\arg\max_aQ(s,a). In (1,1)(1,1), con U(1,2)=0,8016U(1,2)=0{,}8016, U(2,1)=0,6953U(2,1)=0{,}6953, U(1,1)=0,7453U(1,1)=0{,}7453:

  • Su: 0,8⋅0,7616+0,1⋅0,6553+0,1⋅0,7053=0,74530{,}8\cdot0{,}7616+0{,}1\cdot0{,}6553+0{,}1\cdot0{,}7053=0{,}7453;
  • Sinistra: 0,9⋅0,7053+0,1⋅0,7616=0,71090{,}9\cdot0{,}7053+0{,}1\cdot0{,}7616=0{,}7109;
  • Giù: 0,9⋅0,7053+0,1⋅0,6553=0,70030{,}9\cdot0{,}7053+0{,}1\cdot0{,}6553=0{,}7003;
  • Destra: 0,8⋅0,6553+0,1⋅0,7616+0,1⋅0,7053=0,67090{,}8\cdot0{,}6553+0{,}1\cdot0{,}7616+0{,}1\cdot0{,}7053=0{,}6709.

Vince Su, e 0,7453=U(1,1)0{,}7453=U(1,1) (equazione di Bellman soddisfatta). Politica completa:

col. 1 col. 2 col. 3 col. 4
riga 3 Dx Dx Dx terminale
riga 2 Su muro Su terminale
riga 1 Su Sx Sx Sx

È una politica prudente: dalle celle in basso (2,1)(2,1), (3,1)(3,1), (4,1)(4,1) si va a sinistra e si sale lungo la colonna 1 (il giro lungo), perché la strada breve passa da (3,2)(3,2), che confina con il −1-1: una deviazione a destra costerebbe 0,1⋅(−1)0{,}1\cdot(-1). Nel codice la politica si legge con NOMI[pol[IDX[(x, y)]]].

(d) Altri valori di rr

Cambiando solo costruisci_mdp(r):

  • r=−2r=-2 (33 iterazioni): ogni passo costa moltissimo, conviene finire subito. Riga 3: Dx Dx Dx; riga 2: Su, muro, Dx; riga 1: Dx Dx Dx e Su in (4,1)(4,1): dall'angolo in basso a destra si va dritti nel −1-1, perché restare in gioco costa più di −1-1. È la politica "sotto −1,6497-1{,}6497" delle slide.
  • r=−0,01r=-0{,}01 (200 iterazioni: con un costo così basso l'informazione si stabilizza lentamente): il costo del passo è basso, si evita il −1-1 a ogni costo. Riga 3: Dx Dx Dx; riga 2: Su, muro, Sx; riga 1: Su, Sx, Sx e Giù in (4,1)(4,1): in (3,2)(3,2) si va a sinistra (urtando il muro) per non rischiare lo scivolamento in (4,2)(4,2), e in (4,1)(4,1) si urta il bordo inferiore (Giù). È la politica "tra −0,0274-0{,}0274 e 00" delle slide.
  • Con r=−0,6r=-0{,}6 (intervallo −0,7311<r<−0,4526-0{,}7311<r<-0{,}4526 delle slide) si ottiene la politica Dx Dx Dx / Su, muro, Su / Su, Dx, Su, Su, uguale a quella del corso.

Confermato per i tre valori con lo stesso programma.

Versione ripasso

Teoria: Processi decisionali di Markov - utilità, equazione di Bellman, value e policy iterationUn MDP (processo decisionale di Markov) modella un problema decisionale sequenziale in ambiente stocastico e completamente osservabile con stati S, azioni A(s), modello di transizione P(s'|s,a) e ricompensa R(s,a,s'). La soluzione è una politica pi(s). L'utilità U(s) è il ritorno scontato atteso e soddisfa l'equazione di Bellman U(s)=max_a sum_s' P(s'|s,a)[R(s,a,s')+gamma U(s')]; la quantità tra parentesi quadre sommata su s' è la funzione azione-utilità Q(s,a). Value iteration parte da U=0, applica Bellman a tutti gli stati insieme e si ferma quando delta <= eps(1-gamma)/gamma; la politica è argmax_a Q(s,a). Policy iteration alterna valutazione (sistema lineare, senza max) e miglioramento greedy, e termina quando la politica non cambia. Nei POMDP lo stato è nascosto: si lavora sullo stato di credenza b aggiornato come nel filtraggio, b'(s')=alpha P(e|s') sum_s P(s'|s,a)b(s).Processi decisionali di Markov - utilità, equazione di Bellman, value e policy iteration →.

Setup. Griglia 4×34\times3, muro in (2,2)(2,2), terminali (4,3)(4,3) con +1+1 e (4,2)(4,2) con −1-1, altrimenti r=−0,04r=-0{,}04; azione voluta con 0,80{,}8, laterali 0,1+0,10{,}1+0{,}1; urto = si resta; γ=1\gamma=1. Aggiornamento: Uk+1(s)=max⁡a∑s′P(s′∣s,a)[R+γUk(s′)]U_{k+1}(s)=\max_a\sum_{s'}P(s'\mid s,a)[R+\gamma U_k(s')], simultaneo, con U(terminale)=0U(\text{terminale})=0 e ricompensa incassata all'ingresso.

Passaggi.

  • U1(3,3)=0,8⋅1+0,1(−0,04)+0,1(−0,04)=0,792U_1(3,3)=0{,}8\cdot1+0{,}1(-0{,}04)+0{,}1(-0{,}04)=0{,}792; gli altri stati valgono −0,04-0{,}04.
  • U2(3,3)=0,8+0,1⋅0,752+0,1⋅(−0,08)=0,8672U_2(3,3)=0{,}8+0{,}1\cdot0{,}752+0{,}1\cdot(-0{,}08)=0{,}8672.
  • U2(2,3)=0,8⋅0,752+0,2⋅(−0,08)=0,5856U_2(2,3)=0{,}8\cdot0{,}752+0{,}2\cdot(-0{,}08)=0{,}5856.
  • U2(3,2)=0,8⋅0,752+0,1⋅(−0,08)+0,1⋅(−1)=0,4936U_2(3,2)=0{,}8\cdot0{,}752+0{,}1\cdot(-0{,}08)+0{,}1\cdot(-1)=0{,}4936.
  • Le altre celle: −0,08-0{,}08.
  • Dopo 40 iterazioni (tolleranza 10−1010^{-10}): riga 3 0,8516; 0,9078; 0,95780{,}8516;\ 0{,}9078;\ 0{,}9578; riga 2 0,80160{,}8016 e 0,70030{,}7003; riga 1 0,7453; 0,6953; 0,6514; 0,42790{,}7453;\ 0{,}6953;\ 0{,}6514;\ 0{,}4279.

Politica. In (1,1)(1,1): Su 0,74530{,}7453 (massimo), Sinistra 0,71090{,}7109, Giù 0,70030{,}7003, Destra 0,67090{,}6709. Politica completa: riga 3 Dx Dx Dx; riga 2 Su, muro, Su; riga 1 Su, Sx, Sx, Sx.

Altri rr. r=−2r=-2: da (4,1)(4,1) Su dritto nel −1-1, riga 1 Dx Dx Dx; r=−0,01r=-0{,}01: (3,2)(3,2) Sx, (4,1)(4,1) Giù, riga 1 Su Sx Sx.

Costruzione di PP e RR. Per ogni stato non terminale e azione aa si considerano tre direzioni: aa con 0,80{,}8 e le due laterali con 0,10{,}1; passo(s, b) restituisce la cella di arrivo (se muro o bordo, resta in ss). P[a,s,s'] accumula le probabilità; R[s,a] accumula p⋅(±1)p\cdot(\pm1) se l'arrivo è un terminale, altrimenti p⋅rp\cdot r. I terminali sono assorbenti (P[a,t,t]=1, ricompensa nulla). Stati: 11 non-muro, di cui 2 terminali.

Tabella finale. (1,3) 0,8516(1,3)\ 0{,}8516, (2,3) 0,9078(2,3)\ 0{,}9078, (3,3) 0,9578(3,3)\ 0{,}9578, (1,2) 0,8016(1,2)\ 0{,}8016, (3,2) 0,7003(3,2)\ 0{,}7003, (1,1) 0,7453(1,1)\ 0{,}7453, (2,1) 0,6953(2,1)\ 0{,}6953, (3,1) 0,6514(3,1)\ 0{,}6514, (4,1) 0,4279(4,1)\ 0{,}4279. Con γ=1\gamma=1 non si può usare la soglia ε(1−γ)/γ\varepsilon(1-\gamma)/\gamma: si usa una tolleranza sul massimo delle differenze (10−1010^{-10}).

Altri rr: r=−2r=-2 (33 iterazioni) riga 1 Dx Dx Dx Su; r=−0,6r=-0{,}6 riga 2 Su, muro, Su e riga 1 Su, Dx, Su, Su; r=−0,01r=-0{,}01 (200 iterazioni) riga 2 Su, muro, Sx e riga 1 Su, Sx, Sx, Giù.

python
V, pol, storia = value_iteration(*costruisci_mdp(-0.04), 1.0)

Errori tipici: aggiornare in sequenza; contare un urto come "resta senza costo"; usare U(terminale)=±1U(\text{terminale})=\pm1 e la ricompensa ±1\pm1 insieme (si conta due volte).

Esercizi su questo argomento

Teoria collegata