Vai al contenuto
Apprendimento per Rinforzo

Le equazioni di Bellman dimostrate: contrazione, iterazione dei valori e della policy

Equazione di Bellman per una policy e di ottimalità, l'operatore di Bellman è una contrazione (con dimostrazione), esistenza e unicità del valore ottimo, teorema di miglioramento della policy, codice Python sul gridworld.

Le equazioni di Bellman sono il cuore matematico dell’apprendimento per rinforzo: trasformano la definizione del valore, una media su infiniti futuri possibili, in un’equazione che lega il valore di uno stato a quello degli stati successivi. Da esse nascono tutti gli algoritmi, da quelli esatti (iterazione dei valori e della policy) a quelli che imparano dall’esperienza (Q-learning, DQN, actor-critic). Questa lezione le ricava, dimostra che hanno una e una sola soluzione e che gli algoritmi convergono, e le applica al gridworld della lezione precedente con il codice Python.

L’equazione di Bellman per una policy

Teorema. Per ogni policy \pi e ogni stato s:

    \[ V^\pi(s) = \sum_a\pi(a \mid s)\Big[R(s, a) + \gamma\sum_{s'}P(s' \mid s, a)\,V^\pi(s')\Big] \]

Dimostrazione. Si parte dalla relazione ricorsiva del ritorno, G_t = r_{t+1} + \gamma G_{t+1}, e si prende la media condizionata a s_t = s:

    \[ V^\pi(s) = \mathbb E_\pi[r_{t+1} \mid s_t = s] + \gamma\,\mathbb E_\pi[G_{t+1} \mid s_t = s] \]

Il primo termine è la ricompensa media: si sceglie a con probabilità \pi(a \mid s) e si riceve in media R(s, a). Nel secondo si condiziona anche sullo stato successivo: per la proprietà di Markov, una volta noto s_{t+1} = s', il futuro non dipende da come ci si è arrivati, quindi \mathbb E_\pi[G_{t+1} \mid s_t = s, a_t = a, s_{t+1} = s'] = V^\pi(s'). Pesando con le probabilità \pi(a \mid s)P(s' \mid s, a) si ottiene l’equazione. ∎

È un sistema lineare di |\mathcal S| equazioni in |\mathcal S| incognite: in forma vettoriale V^\pi = R^\pi + \gamma P^\pi V^\pi, con soluzione V^\pi = (I - \gamma P^\pi)^{-1}R^\pi (la matrice è invertibile per \gamma \lt  1, perché \gamma P^\pi ha norma minore di 1). Per il gridworld con la policy casuale si ottengono i valori −14, −20, −22 della lezione precedente.

L’equazione di ottimalità

Per la policy ottima la media sulle azioni diventa un massimo:

    \[ V^*(s) = \max_a\Big[R(s, a) + \gamma\sum_{s'}P(s' \mid s, a)\,V^*(s')\Big],\qquad Q^*(s, a) = R(s, a) + \gamma\sum_{s'}P(s' \mid s, a)\max_{a'}Q^*(s', a') \]

Non è più lineare (per il massimo), quindi non si risolve invertendo una matrice: si risolve per iterazione. Il risultato che lo rende possibile è il seguente.

La contrazione di Bellman

Si definisce l’operatore di Bellman ottimo T, che trasforma una funzione V in un’altra: (TV)(s) = \max_a\big[R(s, a) + \gamma\sum_{s'}P(s' \mid s, a)V(s')\big]. L’equazione di ottimalità dice che V^* è un punto fisso: TV^* = V^*.

Teorema. T è una contrazione di fattore \gamma nella norma del massimo: per ogni U, V, \|TU - TV\|_\infty \le \gamma\|U - V\|_\infty.

Dimostrazione. Si usa una disuguaglianza elementare: per due funzioni f, g di a, |\max_af(a) - \max_ag(a)| \le \max_a|f(a) - g(a)| (se il massimo di f è in a_1, \max f - \max g \le f(a_1) - g(a_1), e simmetricamente). Allora, per ogni s:

    \[ |(TU)(s) - (TV)(s)| \le \max_a\gamma\Big|\sum_{s'}P(s' \mid s, a)\big(U(s') - V(s')\big)\Big| \le \gamma\max_a\sum_{s'}P(s' \mid s, a)\,\|U - V\|_\infty = \gamma\|U - V\|_\infty \]

perché le probabilità P(s' \mid s, a) sommano a 1. ∎

Conseguenze (teorema del punto fisso di Banach):

  • il punto fisso esiste ed è unico: V^* è ben definito;
  • partendo da qualunque V_0, la successione V_{k+1} = TV_k converge a V^*, e l’errore si riduce almeno del fattore \gamma a ogni passo: \|V_k - V^*\|_\infty \le \gamma^k\|V_0 - V^*\|_\infty.

È l’iterazione dei valori. Sul gridworld con \gamma = 0{,}9 e una stima iniziale volutamente sbagliata (50 in ogni casella) l’errore massimo scende da 46,7 a 41,3, 36,5, 32,1, …: rapporti tra 0,87 e 0,88, sempre sotto 0,9 come garantito dal teorema.

Convergenza dell'iterazione dei valori
L’errore massimo, in scala logaritmica, scende in linea retta: a ogni passata si riduce di circa 0,88, un po’ più del fattore 0,9 garantito dal teorema, la retta grigia tratteggiata.

Il miglioramento della policy

Teorema (miglioramento della policy). Data una policy \pi, sia \pi' la policy greedy rispetto a Q^\pi: \pi'(s) = \arg\max_aQ^\pi(s, a). Allora V^{\pi'}(s) \ge V^\pi(s) per ogni s.

Dimostrazione. Per costruzione Q^\pi(s, \pi'(s)) \ge \sum_a\pi(a \mid s)Q^\pi(s, a) = V^\pi(s). Si espande Q^\pi(s, \pi'(s)) = \mathbb E[r_{t+1} + \gamma V^\pi(s_{t+1})] facendo \pi' al primo passo, e si applica la stessa disuguaglianza a V^\pi(s_{t+1}):

    \[ V^\pi(s) \le \mathbb E_{\pi'}[r_{t+1} + \gamma V^\pi(s_{t+1})] \le \mathbb E_{\pi'}[r_{t+1} + \gamma r_{t+2} + \gamma^2V^\pi(s_{t+2})] \le \dots \le V^{\pi'}(s) \]

ripetendo all’infinito (i termini residui \gamma^kV^\pi tendono a zero). ∎

Alternando valutazione (calcolare V^\pi con l’equazione lineare) e miglioramento (rendere la policy greedy) si ottiene l’iterazione della policy: ogni passo migliora o lascia uguale la policy, le policy deterministiche sono in numero finito, quindi in un numero finito di passi si arriva a una policy che non migliora più, cioè che soddisfa l’equazione di ottimalità. Questo dimostra anche che una policy ottima deterministica esiste sempre. Lo schema “valuta, poi migliora” ritorna in tutti gli algoritmi moderni: in actor-critic il critico valuta e l’attore migliora.

Il codice

import numpy as np

N = 4                                         # gridworld 4x4, uscite in 0 e 15, -1 a ogni passo
MOSSE = [(-1, 0), (1, 0), (0, -1), (0, 1)]    # su, giù, sinistra, destra
USCITE = {0, 15}

def passo(s, a):
    if s in USCITE:
        return s, 0.0
    r, c = divmod(s, N)
    r = min(max(r + MOSSE[a][0], 0), N - 1)
    c = min(max(c + MOSSE[a][1], 0), N - 1)
    return r * N + c, -1.0

def bellman_ottimo(V, gamma):
    """Operatore di Bellman ottimo T: (TV)(s) = max_a [ r + gamma V(s') ]."""
    return np.array([0.0 if s in USCITE else
                     max(r + gamma * V[s2] for s2, r in (passo(s, a) for a in range(4)))
                     for s in range(N * N)])

# iterazione dei valori con gamma = 1
V = np.zeros(N * N)
for k in range(100):
    V_nuovo = bellman_ottimo(V, 1.0)
    if np.max(abs(V_nuovo - V)) < 1e-10:
        break
    V = V_nuovo
print("V* dopo", k, "passate:\n", V.reshape(N, N))

# valutazione della policy casuale: media sulle quattro azioni invece del massimo
Vc = np.zeros(N * N)
for _ in range(5000):
    Vc = np.array([0.0 if s in USCITE else
                   np.mean([r + Vc[s2] for s2, r in (passo(s, a) for a in range(4))])
                   for s in range(N * N)])
print("policy casuale:\n", np.round(Vc.reshape(N, N), 1))

# policy greedy rispetto a V*: la freccia migliore in ogni casella
FRECCE = "↑↓←→"
pol = [" " if s in USCITE else FRECCE[int(np.argmax([r + V[s2] for s2, r in (passo(s, a) for a in range(4))]))]
       for s in range(N * N)]
print("\n".join(" ".join(pol[i * N:(i + 1) * N]) for i in range(N)))

# contrazione: con gamma = 0,9 l'errore si riduce almeno di 0,9 a ogni passata
Vs = np.zeros(N * N)
for _ in range(200):
    Vs = bellman_ottimo(Vs, 0.9)
U = np.where(np.isin(np.arange(N * N), list(USCITE)), 0.0, 50.0)
errori = []
for _ in range(6):
    U = bellman_ottimo(U, 0.9)
    errori.append(np.max(abs(U - Vs)))
print("errori:", np.round(errori, 2), "rapporti:", np.round(np.array(errori[1:]) / np.array(errori[:-1]), 3))

L’esecuzione stampa V^* dopo 3 passate più quella di verifica (i valori 0, −1, −2, −3), i valori della policy casuale (−14, −18, −20, −22), la griglia delle frecce verso l’uscita più vicina e gli errori 46,71, 41,31, 36,45, … con rapporti 0,884, 0,882, 0,880, … Su problemi grandi la tabella V(s) non entra in memoria e P non è noto: le lezioni successive sostituiscono la somma su s' con l’esperienza (Q-learning) e la tabella con una rete neurale (DQN).

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x
()
x