# Apprendimento per rinforzo (corso uni)

corso universitario tenuto da Maurizio Parton

[https://www.youtube.com/playlist?list=PLMee1hSjLKdAL16E-7EzqHXsGOgzo8iro](https://www.youtube.com/playlist?list=PLMee1hSjLKdAL16E-7EzqHXsGOgzo8iro)

**risorse python:

[https://github.com/dennybritz/reinforcement-learning](https://github.com/dennybritz/reinforcement-learning)

**corso avanzato deep-mind:**

https://www.youtube.com/@googledeepmind/courses

# Introduzione alla probabilità

Prima di procedere con lo studio del RL facciamo una breve introsuzione al calcolo probabilitico. (in particolare la probabilità elementare su insiemi finiti)

> <p class="callout success">Lezione https://www.youtube.com/watch?v=o9Rc1pCYaHo&amp;list=PLMee1hSjLKdAL16E-7EzqHXsGOgzo8iro&amp;index=23</p>

##### Cosa significa aleatorio? (sinonimo di casuale o stocastico)

E' un osservazione di un fenomeno il cui risultato non è determinabile a priori. (es. le previsioni del tempo, o il valore di un titolo azionario, o il lancio di un dado)

Pur non essendo l'esito sicuro dell'informazione si può comunque estrapolare, per es. nel lancio del classico dado otterremo un valore intero da 1 a 6 non 3,8 in virtù della tipologia del fenomeno.

La descrizione matematica che permette di affrontare questa tipologia di problemi si chiama probabilità.

##### Spazio campionario

<span style="white-space: pre-wrap;">Nell'ambito di un esperimento questo "<span style="text-decoration: underline;"><span style="color: rgb(22, 145, 121); text-decoration: underline;">**spazio campionario**</span></span>", rappresntato dal simbolo <span style="color: rgb(186, 55, 42);">Ω (omega)</span>, contiene tutti gli esiti possibili dell'evento che stiamo esaminando. Es. evento lancio di un dado, lo spazio compionario conterrà tutti gli esiti possibili del lancio del dato, quindi l'insime dei numeri possibili da 1 a 6. -&gt; Ω = {1,2,3,4,5,6) </span>

Non sempre però lo spazio campionario è un numero finito, es. il numero di accessi ad un sito web, in questo caso è l'insieme di tutti i numeri naturali, es. Ω = N0 (dove N0 è l'insieme dei numeri naturali)

Se il numero non è discreto nel caso in cui la misurazione è contina allora l'intervallo è omega comprende tutti i valori da zero a infinito, ovvero: Ω = \[0, +∞)

Quindi esistono tre tiologie di spazi campionari:

1. discreto finito
2. discreto inifinito
3. continuo

##### Modello probabilistico

<span style="white-space: pre-wrap;">Rappresenta la </span><u><span style="white-space: pre-wrap;">probabilità </span></u><span style="white-space: pre-wrap;">(o fiducia) che si verifichino i </span><u>valori dello spazio campionario</u>.

Es. quale è la probabilità che il numero ottenuto con il dado sia pari. (2,4,6) o la probabilità che il numero di accessi al sito web sia minore di 100.

Il RL si occupa dello spazio campionario finito. (caso 1)

****Definizione****: la probabilità su tutto lo spazio campionario è sempre 1. (es, quale è la probabilità che lanciando un dado esca 1 o 2 o 3 o 4 o 5 o 6 ? è il 100% ovvero 1) P(Ω) = 1. Invece la probabilità dell'insieme vuoto è zero.

****Definizione****<span style="white-space: pre-wrap;">: I sottoinsimi dello spazio campionario sono detti eventi. es. nel dato il sottoinsieme (evento) 1 potrebbe essere P {1,2} un altro sottoinsieme potrebbe essere P{3,4,5) e così via. Vien da se che Ω contiene tutti gli eventi possibili, NB: tutto questo vale quando gli eventi (sottoinsiemi) sono disgiunti, ovvero </span><u><span style="white-space: pre-wrap;">non </span></u><span style="text-decoration: underline;">si intersecano</span>).

Suggerimento, pensiamo alla probabilità di un insieme come all'area di un cerchio, nel caso di insiemi disgiunti la probabilità dei due sottoinsiemi è semplicemente la somma, se invece i due sottoinsiemi si intersecano allora è la somma delle due probabilità meno la probabilità della loro intersezione.

##### Densità uniforme

<span style="white-space: pre-wrap;">Data una probabilità P su uno spazio finito e numerabile Ω, possiamo associare a P una funzione p detta </span>****densità****<span style="white-space: pre-wrap;">, definita su omega valori \[0,1\]. </span><u>Quindi la densità è definita SOLO sugli elementi di omega.</u>

La probabilità dell'insieme che contiene il singolo elemento è funzione del <span style="text-decoration: underline;">singolo elemento</span>. es. nel lancio del dadi la probabilità dell'insieme P({1,2,3}) è la somma delle probabilità dei <span style="text-decoration: underline;">singoli </span>elementi che indicheremo con p minuscola ovvero: P({1,2,3})= p{(1)} +p{(2) }+ p{(3)}

ATTENZIONE: con P maiuscola ci indica la <span style="text-decoration: underline;">probabilità </span>mentre con la p minuscola si indica la <span style="text-decoration: underline;">funzione </span>che resituisce la probabilità. Per es. la densità definita sullo spazio campionario del lancio del dado, P: {<span style="white-space: pre-wrap;">Ω} -&gt; \[0,1\] mentre la densità di ogni elemento di Ω è p(1) = 1/6... fino a p(6)= 1/6</span>

<span style="white-space: pre-wrap;">Altro esempio</span>

##### <span style="white-space: pre-wrap;">Esperimento Bernulliano</span>

<span style="white-space: pre-wrap;">un esperimento bernulliano è una variabile che può indicare successo o non successo, è una varibile booleana. La variabile che indica la proabilità di successo è P mentre quella che indica l'insuccesso è (1-P), insieme omega è quindi Ω = {successo, insuccesso} o Ω = {1,0}</span>

<span style="white-space: pre-wrap;">Esempio: qual'è la probabilità di ottenere un successo alla K-esima volta che facciamo un esperimento. (es. alla 10a volta) </span>

<span style="white-space: pre-wrap;">ciò significa che per i primi 9 lanci non deve verificarsi il successo (1-P) e al decimo deve valere P. Per i primi 9 lanci le probabiltià si devono moltiplicare (1-P)\*(1-P)\*(1-P)\*(1-P)\*(1-P)\*(1-P)\*(1-P)\*(1-P)\*(1-P)\*P = exp((1-P),K-1)\*P</span>

##### Densità non uniforme a preferenze (SoftMax)

<span style="text-decoration: underline;">Esistono casi in cui gli elementi dello spazio capionario hanno delle **preferenze** (o dei **pesi**) che ne alternano in qualche modo le probabilità.</span>

**NB**: L'intento è quello di trasformare queste preferenze (o pesi) in probabilità. Però ci sono dei pesi negativi.

Nel caso in cui questi "pesi" abbiano valori <span style="text-decoration: underline;">negativi</span>, come si calcola il <span style="text-decoration: underline;">peso in termini probabiliststici di ciascuno elemento</span> di omega rispetto agli altri?

Il caso viene illustrato nell'immagine sotto riportata dove vediamo ciascuno preferenza H definita per ciascuna delle 6 facce delle dado. Si può notare che esistono delle preferenze negative che se dovessimo calcolare semplicemente come peso della singola preferenza fratto sommatoria di tutti i pesi, ne risulterebbe una probabilità negativa.

Quindi per es. se volessimo calcolare la probabilità di P(H1) sarebbe -&gt; 100 / (somma di tutti i pesi) . Però non funzionerebbe in quanto abbiamo dei pesi negativi, e nel caso per es. di P(H3) verrebbe una probabilità negativa, il che sarebbe sbagliato.

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2024-10/scaled-1680-/6QjP8ghzfqi3wsEW-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2024-10/6QjP8ghzfqi3wsEW-image.png)

<p class="callout success">Per nornalizzare questi valori si applica semplicemente la **<span style="text-decoration: underline;">funzione esponenete</span>** per ciascuna preferenza che rende tutti i numeri &gt; 0. (anche con esponente negativo i valori sono sempre &gt; 0) quindi diventa. (non considerare la variabile beta)</p>

Q quindi diventa:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2024-12/scaled-1680-/YZARPvPEoiaXEPFM-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2024-12/YZARPvPEoiaXEPFM-image.png)

Questa tecnica per normalizzare i pesi è detta <span style="color: rgb(186, 55, 42);">**softmax**</span>. E' importante perchè la somma delle probabilità di tutti i valori "pesati" da 1.

Nel caso di insiemi discreti non finiti si applicata la formula Poisson. (che in questo momento non ci interessa)



##### Contare le combinazioni di eventi complessi

Supponiamo di poter filtrare un insieme per determinare caratteristiche che si sommano in successione.

Utilizziamo degli esempi:

1\) voglio determinare le carte pari di cuori e picche da un mazzo di carte di poker:

Applico la regola delle caratteristiche che si sommano,

In questo abbiamo 2 caratteristiche, ovvero:

caratteristica 1) le carte pari -&gt;5 su 13

caratteristica 2) i semi di carte -&gt; 2 su 4

quindi sommiamo la caratteristica 1 e 2 che matematicamente significa moltiplicare, ovvero: 5\*2 = 10

2\) sempre la mazzo di poker voglio trovare tutte le combinazioni di full possibili. (3 carte dello stesso valore + 2 dello stesso, esclusi vicendevolmente es. 3 carte di assi + 2 carte di jack)

In questo abbiamo 4 caratteristiche, ovvero:

caratteristica 1) 3 carte uguali -&gt; 13

caratteristica 2) 2 carte uguali (in quanto vado ad escludere il tris) -&gt; 12 (in quanto non possono esistere 5 carte con lo stesso valore)

caratteristica 3) 3 carte che hanno 3 semi su 4 -&gt; 4 presi in combinazione di 3 (combinazioni semplici senza dipetizione C(4,3)

caratteristica 4) 2 carte che hanno 2 semi su 4-&gt; 4 presi in combinazione semplice senza ripetizione C(4,2)

= 13\*C(4,3)\*<span style="color: rgb(241, 196, 15);">12\*C(4,2)</span> = 3744

#### Calcolo combinatorio

Di seguito un breve ripasso del calcolo combinatorio

##### Disposizioni semplici

Le disposizioni prese da un insieme di N elementi in K modi (es. da un insieme di 10 numeri (N) presi a 2 (K) ) sono un sottoinsieme di numeri ordinati, dove l'<span style="text-decoration: underline;">ordine del numero <span style="color: rgb(186, 55, 42); text-decoration: underline;">**conta**</span></span>, allora la formula diventa <span style="color: rgb(22, 145, 121);">N! / ( N-K)!</span>

##### Combinazioni

Se invece l'ordine dei <span style="text-decoration: underline;"><span style="color: rgb(186, 55, 42); text-decoration: underline;">**non** </span>conta</span> allora il numero di casi dimunuisce quindi la formula diventa <span style="color: rgb(22, 145, 121);">N! / K! \* (N-K)! </span>

##### Probabilità condizionata

**<span style="color: rgb(186, 55, 42);">Premessa</span>**: l'informazione cambia le probabilità.

*Premessa bis*: La proababilità ovviamente si calcola come casi favorevoli fratto casi possibili.

*Es*, qual'è la probabilità che lanciando un dado esca il numero sei? ovviamente 1/6. Supponiamo invece che dopo aver lanciato il dado qualcuno ci dica che è uscito un numero pari, ora come cambia la probabilità? in questo caso lo spazio campionario (omega) cambia e passa da sei numeri a tre tutti pari, a questo punto la proabilità diventa 1/3.

Sia un evento A condizionato a B -&gt; P (A **<span style="color: rgb(186, 55, 42);">|</span>** B) il calcolo diventa P(A|B) = **P(A <span style="color: rgb(186, 55, 42);">∩</span> B) / P (B)**

##### Indipendenza di eventi

Premessa: In genere sapere il verificarsi di un certo evento ci da informazioni sulla probabibilità di un altro evento.

Ci sono però casi che l'informazione non modifica che la probabilità che modifichi l'evento.

Quindi P(A|B) = P(A) significa che se la probabilità di A condizionata all'evento B è invariata allora i due eventi sono indipendenti.

L'intersezione dei due eventi rende la probabilità una funzione moltiplicazione, ovvero: **P(A <span style="color: rgb(186, 55, 42);">∩</span> B) = P(A) \* P(B)**

# Sessione 1

Nell'apprendimento per rinforzo (d'ora in poi verrà indicato con RL) si basa sul <span style="color: rgb(224, 62, 45);">**processo decisionale di Markov**</span> aka MDP attrraverso un task di controllo dove un set di possibili <span style="text-decoration: underline;">stati </span>e <span style="text-decoration: underline;">azioni </span>ritornano un <span style="text-decoration: underline;">reward </span>e una <span style="text-decoration: underline;">probabilità </span>di passaggio ad uno stato all'altro. Il task nella pratica è un "compito" o una simulazione che per essere svolta (risolta) implica l'utilizzo dell'MDP.

**NB**: Il processo decisionale di Markov (MDP) asserisce che il passaggio allo stato successivo T+1, dipende esclusivamente dallo <span style="text-decoration: underline;">stato attuale T e non dagli stati precedenti</span>. Quindi il processo **NON** ha memoria, in questo caso si dice che il processo è<span style="color: rgb(224, 62, 45);"> "Markoviano".</span>

##### Tipologie di processi decisionali di Markov (MDP)

Esistono due tipologie di MPD, il processo a stati <span style="color: rgb(224, 62, 45);">finiti </span>e quello a stati <span style="color: rgb(224, 62, 45);">infiniti</span>.

Nel<span style="text-decoration: underline;"> <span style="color: rgb(224, 62, 45); text-decoration: underline;">MDP finiti</span></span> gli stati finiti hanno un numero finiti di stati definiti dall'ambiente, es. l'uscita da un labirinto di 5 caselle x 5. In questo caso abbiamo 25 stati e 4 azioni (su, giù, dx e sx)

Nel <span style="color: rgb(224, 62, 45);"><span style="text-decoration: underline;">MDP a stati infiniti,</span> <span style="color: rgb(22, 145, 121);">invece</span></span>, l'ambiente appunto può restituire infiniti stati a fronte di infinite azioni, pensiamo per es. il sistema di guida automatica di una macchina dove l'azione es. girare il volante, è un valore continuo così come la scelta della velocità dell'auto.

##### Episodi

MDP definisce anche degli "episodi" in particolare:

Nel <span style="color: rgb(224, 62, 45);">M<span style="text-decoration: underline;">DP episodico</span></span> un episodio termina a determinate condizioni. Es. nel gioco degli scacchi quando la giocare da scacco matto.

<span style="text-decoration: underline;">Nel <span style="color: rgb(224, 62, 45); text-decoration: underline;">MDP continuo</span>,</span> il processo non ha fine, semplicemente continua ad esistere all'infinito in quanto non esiste uno stato fine.

##### Traiettoria ed episodio

La <span style="text-decoration: underline; color: rgb(224, 62, 45);">traiettoria </span>è il movimento che l'agente compie per muoversi da uno stato all'altro. La <span style="text-decoration: underline;">traiettoria è definita dal simbolo greco</span> <span style="color: rgb(224, 62, 45);">𝜏</span> "tau". Un esempio può essere:

<span style="color: rgb(224, 62, 45);">𝜏</span> = S0, A0, R1, S1,.A1, R2, S2, A2, R3, S3 che indica la partenza dallo stato zero, dove viene effettuata l'azione A0 che porta la reward R1 e il posizionamento nello stato S1, alla quale segue l'azione A1 e così via. L'ultimo stato della traiettoria sarà (nel caso specifico) S3.

La *treittoria* può essere <span style="text-decoration: underline;">finita o infinita</span>, se è finita si chiama <span style="text-decoration: underline; color: rgb(224, 62, 45);">episodio </span>è semplicemente una traiettoria che inizia in uno stato e finisce nello stato finale oltre quale non si torna indietro. es:

![\tau ](https://wikimedia.org/api/rest_v1/media/math/render/svg/38a7dcde9730ef0853809fefc18d88771f95206c)= S0, A0, R1, S1,.A1, R2, S2, A2, R3, S3, ..... **<span style="color: rgb(224, 62, 45);">RT,ST</span>**.

[![Screenshot 2023-06-25 090815.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-06/scaled-1680-/MacBQFXk2qoHPQ9O-screenshot-2023-06-25-090815.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-06/MacBQFXk2qoHPQ9O-screenshot-2023-06-25-090815.png)

di cui deriva il concetto di storia, ovvero la somatoria delle osservazioni, ricompense e azioni fino all'azione finale.

[![Screenshot 2023-06-25 091029.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-06/scaled-1680-/tbRyUHL29ohkSngz-screenshot-2023-06-25-091029.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-06/tbRyUHL29ohkSngz-screenshot-2023-06-25-091029.png)

##### Ricompensa vs Ritorno

La <span style="color: rgb(224, 62, 45);">**ricompensa** </span>(*reward*) viene restituita a fronte di un'azione, quindi per risolvere un task, dobbiamo massimizzare le ricompense ottenute. La ricompensa è quindi un risultato <span style="text-decoration: underline;">**immediato**</span>. (Rt)

Invece il <span style="color: rgb(224, 62, 45);">**ritorno** </span>è la <span style="text-decoration: underline;">somma </span>di tutte le <span style="text-decoration: underline;">ricompense </span>ad un determinato momento nel tempo es: **<span style="color: rgb(224, 62, 45);">G(t) </span>**= R(t+1) + R(t+2) + ... R(T) finchè il task è stato completato.

##### Predizione, miglioramento e Controllo

La <span style="text-decoration: underline;">*predizione* </span>significa calcolore il valore di una certa policy fissata, il <span style="text-decoration: underline;">*miglioramento*</span>, come dice la parola serve per migliorare (anche solo di poco, non la miglioare in assoluto) la policy attuale, mentre il <span style="text-decoration: underline;">*controllo* </span>serve per trovare la migliore di tutte.

Da qui il ciclo utile per trovare la policy migliore: pi(s) -&gt; Vpi(s) -&gt; pi'&gt;= pi che inserire in un loop fino a quando converge. (teorema banach caccioppoli)

##### Fattore di sconto **γ** (gamma)

Il fattore di sconto è un incentivo per completare l'episodio nel miglior modo (più efficiente) possibile. Per ottenere questo la ricompensa dovrà essere moltiplicata per il fattore di sconto che <span style="text-decoration: underline;">diminuirà nel tempo</span> all'aumentare delle azioni intraprese, rendendo le ricompense sempre più basse e quindi disincentivando le traiettorie lunghe.

Il fattore è un valore compreso tra zero e uno e viene elevato ad un esponente corrispondente dall'iesima azione fino alla fine dell'episodio.

Se **γ** *(*gamma) vale zero l'agente cercherà di prendere una ricompensa immediata, il che denota una strategia miope che non ottimizza l'apprendimento. Al contrario invece, un fattore **γ** gamma pari a uno, rende l'agente più "paziente" e quindi <span style="text-decoration: underline;">non</span> prono ad ottimizzare gli step dell'episodio. In genere il fattore gamma viene settato a 0,99 che forza l'agente ad avere una ricompensa immediata ma allo stesso tempo lo forza ad avere una visione "a lungo termine".

In conclusione il fattore gamma indica all'agente quanto può valutare in maniera ottimali le azioni future.

**NB**: se il task è *episodico* allora è possibile utilizzare un fattore di sconto pari a 1, diversamente se il task è *continuo* (infinito senza stati assorbenti terminali) allora il tasso di sconto è meglio che sia &lt;1.

##### Policy

La <span style="text-decoration: underline;">policy </span>dell'agente è una <span style="text-decoration: underline;">funzione </span>che prende in <span style="text-decoration: underline;">input uno stato</span> e ritorna <span style="text-decoration: underline;">l'azione </span>che va presa in quello stato. E' rappresenta dalla lettere greca pigreco <span style="color: rgb(236, 240, 241);">**<span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span>**</span>

[![Screenshot 2022-11-28 222728.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/861YiH69FKsiyAIg-screenshot-2022-11-28-222728.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/861YiH69FKsiyAIg-screenshot-2022-11-28-222728.png)

La <span style="text-decoration: underline;"><span style="color: rgb(224, 62, 45); text-decoration: underline;">probabilità </span></span>di eseguire un'azione (a) nello stato (s) si può rappresentare come:<span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span>(a|s)

L<span style="text-decoration: underline;"><span style="color: rgb(224, 62, 45); text-decoration: underline;">'azione</span></span><span style="color: rgb(0, 0, 0);"> <span style="color: rgb(236, 240, 241);">che la policy sceglie</span> </span>nello stato (s) viene descritta dalla formula: <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span>(s)

Dipende quindi dal contesto, in alcuni casi si uitilzza il primo <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span>(a|S) in altri il secondo <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span>(s).

La policy può essere di due tipi: **<span style="color: rgb(224, 62, 45);">stocastica </span>**o **<span style="color: rgb(224, 62, 45);">deterministica</span>**.

Si dice che la policy è <span style="background-color: rgb(224, 62, 45); color: rgb(236, 240, 241);">deterministica </span>quando viene scelta <span style="color: rgb(224, 62, 45);">sempre </span>la<span style="text-decoration: underline;"> stessa azione in un determinato stato</span> quindi stiamo parlando del caso <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span>(S).

Si dice invece <span style="background-color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">stocastica</span> </span>quando l'azione viene scelta sulla <span style="text-decoration: underline;">base delle probabilità</span> es. : <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span>(S) = \[0.3, 0.2, 0.5\] ovvero la probabilità di effettuare una azione nello stato S, è del 30% nel primo caso, 20% nel secondo e 50% nel terzo. Quindi siamo in presenza del caso <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π </span></span></span></span></span></span></span></span>(a|S)

Quindi bisogna trovare la policy ottimale rappresentata come <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span><span style="color: rgb(224, 62, 45);"><span style="background-color: rgb(255, 255, 255);">\*</span> </span>(pigreco - asterisco) che sceglie le azioni che <span style="text-decoration: underline;">massimizzano la somma dei fattori di sconto per le </span><span style="color: rgb(224, 62, 45);"><span style="text-decoration: underline;">ricompense</span> </span>alla lunga.

La policy <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span> è una distribuzione di probabilità che deciamo noi dato lo stato con la quale scegliamo le azioni e prendendo quindi una decisione, si differenzia dalla probabilità che NON decidiamo noi che si rappresenta con **P** che invece rappresenta il modello la cui prabobilità non possiamo modificare. (es. P(s',r|s,a) )

<p class="callout success">Il valore della policy V in genere indica la ricompensa totale media che si ottiene applicando la policy</p>

##### Controllo Ottimale

Nel RL è fondamentale determinare la Policy Ottimale <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π<span style="color: rgb(224, 62, 45);">\*</span> </span></span></span></span></span></span></span></span>*indispensabile per la gestione dell'ambiente. La griglia di centro (visibile in figura) è la rappresentazione del valore di ciascuno stato. (dove per stato si intende ogni casella della griglia) Per valore ottimale* V\* si intende il valore della policy ottimale, ovvero quello che si può ottenere facendo le azioni migliori possibili. Per migliore azione si intende determinare lo scopo, ovvero massimizzare le somma delle ricompense (dette *ritorno*) ottenibili con le azioni future.

La policy ottimale quindi, si ottiene valutando di volta in volta il valore ottimale. Le policy ottimali sono tante, anche su un unico stato, vedi per es. che nella casella in fondo a sx il cui valore è 14,4 ha due policy ottimali in quanto i valori ottimali in questo specifico caso sono due.

[![Screenshot 2023-08-05 181817.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/jEX4kRIuCJNCHQVh-screenshot-2023-08-05-181817.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/jEX4kRIuCJNCHQVh-screenshot-2023-08-05-181817.png)

##### Pianificazione e Apprendimento

L'apprendimento nel RL si basa sulla pianificazione.

La <span style="color: rgb(45, 194, 107);">*pianficazione* </span>implica la conoscenza del modello associato all'ambiente, es. il lancio di un dado che implica che il <span style="color: rgb(45, 194, 107);">*valore medio detto anche ritorno medio*</span> dell'azione è 3,5 ovvero 1\*1/6+2\*1/6+3\*1/6+4\*1/6+5\*1/6+6\*1/6.

**NB**: il <span style="color: rgb(224, 62, 45);">modello </span>è l'ambiente e normalmente NON lo conosciamo.

L'apprendimento, è la fase successiva alla pianificazione e implica l<span style="text-decoration: underline;">'iterazione con l'ambiente</span> e prevede il calcolo della <span style="text-decoration: underline; color: rgb(45, 194, 107);">media empirica</span> ovvero la media dei valori ottenuti dall'iterazione con l'ambiente.

Quindi con la pianficazione e l'apprendimento, l'agente migliora la policy.

Entrambi guardano avanti nel futuro calcolando i valori cercando il miglioramento della policy.


##### Tipologie di algoritmi applicabili al RL

Di seguito viene rappresentata la tassonomia (categorizzazione) delle varie tipologie di algoritmi applicabili nell'ambito del RL.

[![Screenshot 2023-08-05 181817.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/peun6Td4yIm70rWz-screenshot-2023-08-05-181817.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/peun6Td4yIm70rWz-screenshot-2023-08-05-181817.png)

##### Esplorazione vs Sfruttamento

E' l'eterno dilemma, ovvero provo sempre nuove soluzioni o sfrutto sempre quelle che già conosco. Entrambi vanno utilizzati per "allenare" la rete rete neurale. (vedremo più avanti)


##### Processi decisionali di Markov (MDP)

I processi decisionali di Markov si basano sulla gestione degli stati. Gli stati vengono rappresentati come dei cerchi dove all'interno è presente una lettera che lo rappresenta. Il pallino nero invece è l'azione.

Nello schema sotto rappresentato vediamo che, partendo dallo stato "u", la risposta dell'ambiente a fronte dell'azione "a" di <span style="text-decoration: underline;">tipo probabilistico (aleatoria) e quindi non deterministico</span>, è di 0,7 con un reward di +3 che ci porta di v, oppure 0,3 con reward -1 che ci porta in "w". <span style="text-decoration: underline;">Se invece a fronte di una azione (pallino) ci fosse stato una unica determinazone della riposta dello stato T+1 anzichè due o piu, allora la risposta sarebbe stata derministica.</span>

Es. leggendo la risposta dell'ambiente a fronte dell'azione a (nel caso dello 0,7 - 70%) è: la probabilità di arrivare in "v" con una ricompensa di +3, dato che sono partito dallo stato iniziale "u" e ho fatto l'azione "a".

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/CBONlOh3cKHYN1g8-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/CBONlOh3cKHYN1g8-screenshot-2023-08-06-105538.png)

Sempre rimandendo nel diagramma sopra riportato, qual'è la probabilità di andare in "w" con una reward di 42? (vedi figura sotto)

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/fYp9S8GLa0xcJPYC-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/fYp9S8GLa0xcJPYC-screenshot-2023-08-06-105538.png)

La risposta è zero in quando deve verificarsi la combinazione stato + reward che in questo caso non esistendo è quindi pari zero.

NOTA: lo **stato terminale si indica con un quadrato**.

Ora semplifichiamo un attimo lo schema per renderlo più leggibile come sotto riportato:

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/m4aqiIrgbyI3KzVp-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/m4aqiIrgbyI3KzVp-screenshot-2023-08-06-105538.png)

Nello specifico la differenza tra S0 e S1 indica la situazione dello stato "S" al tempo T. Ovvero S0 è lo stato iniziale, mentre S1 è sempre lo stato S ma al tempo T+1 e può valere "w" o "v" a seconda della probabilità. Se ci fosse uno stato successivo S2 dovremmo considerare le probabilità di transizione da S0 a S1 e da S1 a S2.

<span style="color: rgb(45, 194, 107);">**La rappresentazione**</span> è quindi un **g**<span style="text-decoration: underline;">**rafo orientato**</span> in quanto unidirezionale. i tondi sono le azioni e gli archi i risultati probabilistici delle azioni.

Ho quindi un insieme di stati S e di azioni A e di rewards R. Dopo ogni azione ho quindi una distribuzione di probabilità su SxR. Per ogni coppia di stato azione ho una distribuzione di probabilità. Conoscere il modello significa quindi conoscere la distribuzione di probabilità. Introduciamo anche il fattore di sconto gamma che vale sempre di meno all'allungarsi della distanza di tempo in modo che l'agente sia incentivato a trovare la soluzione migliore più velocemente.

La funzione p rappresenta quindi il modello, è quindi la probabilità di transizione dallo stato al tempo T-1 allo stato al tempo T. (a fronte di una certa azioen e relativa ricompensa)

Generalizzando quanto sinora detto:

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/z6qe3aFMeRyopre3-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/z6qe3aFMeRyopre3-screenshot-2023-08-06-105538.png)

> dove il simbolo **<span style="color: rgb(224, 62, 45);">｜</span>** (pipe) indica che un elmento "a" è condizionato **da** "b", es. "a | b". Occhio che per es. P(a,b) è la probabilità dato in input "a" e "b" mentre invece P(a|b) significa la probabilità dato "a" e condizionato a "b" <span style="text-decoration: underline;">MA </span>"a" puà assumere più valori in B.
> 
> dove il simbolo **<span style="color: rgb(224, 62, 45);">~</span>** (tilde) indica che uno stato S è preso da una certa distribuzione di probabibilità P, es. S ~ P(...)

Esercizio:

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/7Jgs7CO0F5XrMrvi-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/7Jgs7CO0F5XrMrvi-screenshot-2023-08-06-105538.png)

nota: ricordare che il simbolo <span style="color: rgb(224, 62, 45);">𝔼</span> rappresenta il ritorno atteso ovvero il valor medio dei ritorni.

In pratica <span style="color: rgb(224, 62, 45);">𝔼</span> rappresenta il <span style="text-decoration: underline;">valore medio</span> (<span style="color: rgb(241, 196, 15);">**media dei valori pesati**</span>) delle ricompense che posso ottenere in un determinato stato S. Questo perchè in uno stato protrei avere una distribuzione di probabilità che per es. a fronte di una azione possono scaturire più azioni con associata una proababilità e un ricompensa ciascuna. es: [![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/scaled-1680-/3i4xk2Qw7p6xnalW-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/3i4xk2Qw7p6xnalW-image.png)

1\)

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/dum07P5Hu1H17p7K-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/dum07P5Hu1H17p7K-screenshot-2023-08-06-105538.png)

La prima riga si legge così: la probabilità che un stato S al tempo T sia s' condizionato al fatto che lo stato precedente fosse s e che io abbia fatto precendetemente una derminazione azione a. Quindi si vuole sapere la probabilità di essere nello stato s' nel caso in cui nello stato precedente s sia stata eseguita l'azione a.

Per ricavare questa probabilità bisogna partire la formula generica MDP che tiene conto delle rewards, ovvero:

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/F1MTVaLRW6WJ3dLC-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/F1MTVaLRW6WJ3dLC-screenshot-2023-08-06-105538.png)

quindi per rispondere al prima quesito dobbiamo sommare tutte le rewards in modo che rimanga la sola probabilità che ci porta allo stato s', <span style="text-decoration: underline;">in quanto non vogliamo la probabilità che esca <span style="color: rgb(22, 145, 121); text-decoration: underline;">s' e r</span></span>, ma vogliamo solo la probabilità che esca <span style="color: rgb(22, 145, 121);">s'</span>, oovero:

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/Iu0EBNEKNv6MbeG6-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/Iu0EBNEKNv6MbeG6-screenshot-2023-08-06-105538.png)

perchè sommando <span style="text-decoration: underline;">**tutte** </span>le rewards ho la certezza di finire nello stato s'. Sommare tutti gli "r" si dice anche <span style="text-decoration: underline;">saturare </span>tutti gli indici r.

2\)

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/eTQueLACsuiwp203-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/eTQueLACsuiwp203-screenshot-2023-08-06-105538.png)

In questo caso invece si desiderata la ricompensa media (variabile aletoria) al tempo "t" condizionata dal fatto che al tempo t-1 partissi dallo stato "s" e facessi l'azione "a".

Quindi il valore medio della ricompensa sarà la sommatoria di tutte le ricompense ciascuna di esse moltiplicate per la propria probabilità di uscita, ovvero:

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/hx0RkIYRgYL4hsW1-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/hx0RkIYRgYL4hsW1-screenshot-2023-08-06-105538.png)

dato che in questo caso vogliamo la reward media al tempo t, come nel caso 1) dobbiamo "saturare" un fattore, in questo caso sono gli stati. Quindi per tutti gli stati s' moltiplichiamo la probabilità ritornata dall'azione a nello stato "s" a t-1 per tutte le reward. La prima sommatoria estrare tutte le reward che vanno a moltiplicare le corrispittive probabilità. Moltiplicando reward per la probabilità si ottinene la reward media. (vedi esempio del valotre medio del lancio del dado, dato dalla sommatoria del valore di ciacuna faccia del dado per 1/6 per un totale di 3,5)

3\) per ora non viene spiegato.

##### Dinamica del MDP: rappresentazione tabbellare

Una delle tecniche più basiche di rappresentazione delle transizioni da uno stato all'altro fa uso di matrici di valori che indicano la probabilità di transizione da uno stato all'altro. Se per esempio un sistema ha 4 stati, la tabella sarò composta da una mtrice di 4x4. Ovviamente questo metodo funziona con sistemi i cui stati sono molto limitati, non per funziona con sistemi complessi come per es. gli scacchi o la dama.

Facciamo un esempio, calcoliamo su questo MDP delle quantità:

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/BhNOCEtvvLgqiw8M-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/BhNOCEtvvLgqiw8M-screenshot-2023-08-06-105538.png)

Iniziamo con il calcolo di una matrice di transizione detta <span style="text-decoration: underline;">matrice stocastica</span>, in queso caso avendo due stati la matrice è 2x2, nelle celle della matrice andremo ad inserire le probabilità di transizione da uno stato all'altro. Nell'esempio sotto riportato andremo a calcolare la matrice associata all'azione 1. La peculiarità di questa matrice è che la somma di ciascuna riga da sempre 1 - 100%.

<table border="1" id="bkmrk-p-%3D-1-%28azione-1%29-a-b" style="border-collapse: collapse; width: 61.2346%; height: 89px;"><colgroup><col style="width: 33.3148%;"></col><col style="width: 33.3148%;"></col><col style="width: 33.3148%;"></col></colgroup><tbody><tr><td>P = 1 (azione 1)</td><td>A</td><td>B</td></tr><tr><td>A</td><td>0,8</td><td>0,2</td></tr><tr><td>B</td><td>0,9</td><td>0,1</td></tr></tbody></table>

Calcoliamo ora il vattore ricompensa associata all'azione 1.

<table border="1" id="bkmrk-r-%3D-1-%28azione-1%29-10%2A" style="border-collapse: collapse; width: 61.1111%; height: 47px;"><colgroup><col style="width: 33.4081%;"></col><col style="width: 33.4081%;"></col><col style="width: 33.4081%;"></col></colgroup><tbody><tr><td>R = 1 (azione 1)</td><td>10\*0,8 + 3\*0,2 = **8,6**</td><td>0,9\*42+0,1\*39 = **41,7**</td></tr></tbody></table>

ora creiamo che tabella che rappresenta l'intero modello:

<table border="1" id="bkmrk-s-%28stato-partenza%29-a" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 20%;"></col><col style="width: 20%;"></col><col style="width: 20%;"></col><col style="width: 20%;"></col></colgroup><tbody><tr><td>s (stato partenza)</td><td>a (azione)</td><td>s' (stato di arrivo)</td><td>r (ricompensa)</td><td>p(s',r | s,a) probabilità</td></tr><tr><td>A</td><td>1</td><td>B</td><td>3</td><td>0,2</td></tr><tr><td>...</td><td>  
</td><td>  
</td><td>  
</td><td>  
</td></tr><tr><td>  
</td><td>  
</td><td>  
</td><td>  
</td><td>  
</td></tr></tbody></table>

La tabella conterrà un totale di righe dato dalle azioni x numero di probabilità di accedere allo stato, questo caso 8.

##### La proprietà di "Markovianità"

La proprità di markov indica che il valore dello stato St dipende esclusivamente dallo St-1 ma <span style="text-decoration: underline;">**non** </span>dipende dagli stati precedenti a St-1. (es. St-2, St-3 etc etc)

##### Episodi MDP

Se ho uno stato terminale tra gli stati possibili allora il mio task si chiama *episodico*. Attenzione che però dipende dalla policy, ovvero se ho delle azioni che mi consentono di evitare lo stato terminali posso entrare in loop. E' compito dell'algoritmo evitare questi loop. Nel caso in cui non esista lo stato terminale si tratta di un *MDP continuing.*

Esiston anche task a *orizzonte temporale definito* se esistono dei limiti temporali.

Un episodio quindi è una sequenza di stati, azioni, rewards che terminano con lo stato terminale.

Simuliamo un episodio:

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/AND4uKXJ8oX0gXae-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/AND4uKXJ8oX0gXae-screenshot-2023-08-06-105538.png)

EPISODIO: A, 1,10, A, 2, -3, B, 2, 0,9, B , 1, 1, C

PROBABILITA': dipende da:

- probabilità di scegliere (1|A)
- probabilità di scegliere (2|A)
- probabilità di scegliere (1|B)
- probabilità di scegliere (2|B)

Per calcolare un episodio bisogna capire quindi come viene definita la policy.

Un esempio di policy <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span> che per esempio può essere scegliere sempre l'azione 1. <span style="text-decoration: underline;">Quindi la policy "pi" è fondamentalmente una strategia che può (e spesso deve) variare per massimizzare il ritorno.</span>

##### Ritorno

Il ritorno (G = gain) è la somma delle ricompense di un episodio ed è una variabile aleatoria.

[![Screenshot 2023-08-06 105538.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/Eab1YaJoGnYxe9sM-screenshot-2023-08-06-105538.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/Eab1YaJoGnYxe9sM-screenshot-2023-08-06-105538.png)

NB: L'ipotesi è che i ritorni R abbiamo un limite superiore finito che consente al fattore di sconto far convergere il ritorno totale.

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/FOtvNxaUYGK0pHNu-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/FOtvNxaUYGK0pHNu-screenshot.png)

Ricordo la notazione che si ripeterà spesso nel corso, [![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/xet13VLuicjep4qu-screenshot.png) ](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/xet13VLuicjep4qu-screenshot.png)ovvero la probabilità che facendo un'azione "a" nello stato "s" l'ambiente mi porti nello stato s'. Il mio comportamento è rappresentato da una distribuzione di probabilità negli stati S. La strategia di scelta delle azioni - **che sia chiama polocy** - è una distribuzione di probabilità neglis stati.

Le policy ottimali possono essere deterministiche o non deterministiche. Un esempio di policy determinisca è il lancio de dado in quanto ho una sola possibile azione, appunto il lancio del dato, invece un esempio di non deterministica è per es. sasso-carta-forbice.

##### Funzione stato-valore

La funzione stato valore per un MDP è il numero che ci indica quale azione intraprendere. Si rappresenta come:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/XoAqHNNKDRKMYbpe-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/XoAqHNNKDRKMYbpe-screenshot.png)

dove V è il valore indicizzato dalla lettera pi (policy) indicizzato dallo stato S.

Mentre "<span style="color: rgb(224, 62, 45);">**E"**</span> è il **<span style="text-decoration: underline;">valore atteso/valore medio</span>**, è il valore dello stato, è il numero teorico che se lo conoscessimo aprioristicamente ci "renderebbe la vita più semplice" in quanto significherebbe che conosceremmo l'ambiente, cosa ovviamente non possibile. (<span style="text-decoration: underline;">spesso il valore E è la media ponderata dei valori attesi</span>)

"**<span style="color: rgb(224, 62, 45);">E</span>**" il è il valore che voglio massimizzare, viene quindi indicato con la lettera "**V**" che sta per valore indicizzato a pi-greco ovvero la "policy" cioè quello che facciamo noi espresso in probabilità di effettuare un'azione, dello stato "S" (notazione funzionale) uguale al valore medio atteso di Gt -&gt; <span style="text-decoration: underline;">ritorno</span> al tempo "t" condizionato al stato "s" che è l'argomento della funzione <span style="color: rgb(0, 0, 0); background-color: rgb(236, 240, 241);">Vπ</span>**<span style="color: rgb(224, 62, 45);"><span style="background-color: rgb(255, 255, 255);"><span style="background-color: rgb(236, 240, 241);">(</span> s)</span></span>**

##### Q-learning

E ora veniamo ad un concetto molto importante, il concetto del <span style="color: rgb(224, 62, 45);">**Q-learning,** </span>ovvero action value function che sta per qualità dell'azione.

**<span style="color: rgb(236, 240, 241);">Qπ</span><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">(s,a)</span></span></span></span> =** rappresenta la <span style="text-decoration: underline;">**qualità di una azione**</span> -&gt; partedo dalla prima azione (<span style="color: rgb(224, 62, 45);">**fissata**</span>) e dallo stato (**<span style="color: rgb(224, 62, 45);">fissato</span>**) eseguo tutte le azioni che la policy mi dice di eseguire. Tenendo ovviamente in conto che il modello (P) mi dice quale sarà il nuovo stato e la ricompensa e la policy π deciderà quale sarà la nuova azione da eseguire.

<span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">**Vπ(s)** = </span></span></span></span>rappresenta il **<span style="text-decoration: underline;">valore dello stato</span>** "s" (stato di partenza) che si ottiene seguendo le azioni dettate dalla policy <span style="color: rgb(236, 240, 241);">**π**</span> tenendo conto che la scelta delle azioni è di tipo probabilitstico quindi in teoria sarebbe <span style="color: rgb(236, 240, 241);">**π**</span>P. ("P" si omette) Questo guardagno è una variabile aleatoria. L'intenzione è quello il avere il valor medio (la quantità) più grande possibile

**<span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">V\*(s) </span></span></span></span></span></span></span></span></span></span></span></span>**= è il <span style="text-decoration: underline;">valore medio massimo ottimale </span>che si può ottenere su tutti i <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">Vπ(s) </span></span></span></span> applicando tutte le policy possibili. -&gt; max<span style="color: rgb(236, 240, 241);">π</span> <span style="color: rgb(236, 240, 241);">Vπ(s) </span>

<span style="color: rgb(236, 240, 241);">**Q\*(s,a)**</span> =è la funzione valore ottimale <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">-&gt; </span></span></span></span></span></span></span></span></span></span></span></span>max<span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(186, 55, 42);"><span style="color: rgb(236, 240, 241);">π</span></span> <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">qπ(s,a)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

In fine definiamo la <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(186, 55, 42);">**policy ottimale <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>**</span><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">\* </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>in grado di massimizzare il valori (sia l'azione valore che la stato valore)

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2024-10/scaled-1680-/c3WWCsWR3H6EIllv-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2024-10/c3WWCsWR3H6EIllv-image.png)

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2024-10/scaled-1680-/PujqXDaPhJgjOwjt-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2024-10/PujqXDaPhJgjOwjt-image.png)

Ora facciamo un esempio:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/kUfichqOZJ8txNKu-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/kUfichqOZJ8txNKu-screenshot.png)

 Esercizio: calcolare il q-values applicando la policy pi nello stato B e compiendo l'azione 1 in un caso e l'azione 2 nell'altro; e calcolare il valore atteso nello stato B applicando la policy uniforme <span style="color: rgb(236, 240, 241);">**π**</span>.

**Soluzione q<span style="color: rgb(236, 240, 241);">π</span>(B,1)**

q<span style="color: rgb(236, 240, 241);">**π**</span>i(B,1) = gamma\*0,1\*(39+ V\_pi(B)) + gamma\*0,9\*(42+V\_pi(A))

dove:

V\_pi(B) = 0,5\*q\_pi(B,1)+0,5\*q\_pi(B,2)

V\_pi(A) = 0,5\*q\_pi(A,1)+0,5\*q\_pi(A,2)

*spiegone:*

Per determinare la funzione q (valore azione) relativa alla policy <span style="color: rgb(236, 240, 241);">**π** </span>che nel caso di partenza da B, è necessario applicare la "policy di partenza" ovvero al 50% di probabilità di scegliere un'azione. Quindi la q<span style="color: rgb(236, 240, 241);">**π**</span>(B,1) è calcolata come la probabilità di scegliere l'azione 1 (che in questo caso è del 100% in quanto viene impostato come richiesta iniziale) che moltiplica la probabilità del 10% di ottenere 39 sommato al valore-<span style="color: rgb(236, 240, 241);">**π**</span> dello stato di arrivo ovvero "B", più la probabilità del 90% di andare nello stato A ottenedo 42 sommato al valore-pi di A.

Il valore-pi di A è a sua volta la probabilità di scegliere l'azione 1 sommata alla probabilità di scegliere l'azione 2 ovvero: V\_pi(A) = 0,5\*q\_pi(A,1)+0,5\*q\_pi(A,2). (dove la probabilità per questa policy di scegliere l'azione è del 50%)

Analogamente il valore-pi di B è probabilità di scegliere l'azione 1 sommata alla probabilità di scegliere l'azione 2 ovvero: V\_pi(B) = 0,5\*q\_pi(B,1)+0,5\*q\_pi(B,2). (dove la provabilità per questa policy di scegliere l'azione è del 50%)

Da notare che questa non è la policy ottimale in quanto è la policy di partenza che ci da il 50%, l'apprendimento sta**<span style="text-decoration: underline;"> nell'iterare</span>** il processo a fine di variare la % della policy per farla convergere a quella ottimale.

Bisogna quindi calcolare 4 equazioni con 4 incognite che sono: q<span style="color: rgb(236, 240, 241);">**π**</span>(A,1) q<span style="color: rgb(236, 240, 241);">**π**</span>(A,2) q<span style="color: rgb(236, 240, 241);">**π**</span>(B,1) e q<span style="color: rgb(236, 240, 241);">**π**</span>(B,2)

Per farla convergere però, bisogna utilizzare un fattore di sconto gamma, altrimenti tende a infinito... (di qui l'introduzione di gamma)

Questo ciclo (iterazione) viene anche detto <span style="text-decoration: underline;">**controllo**</span>.

In conclusione questo sistema è una versione dell'equazione di Bellman.

<span style="color: rgb(224, 62, 45);">**NB**</span>: per r<span style="text-decoration: underline;">icompensa si intede la somma dei valori che il modello ci da quando da uno stato passa ad un altro</span>. Quindi la ricompensa è composta da uno a più valori con relativa percentuale di ottenimento. (es. mi da valore 20 al 10%, valore 50 al 60% e così via) Una volta ottenuti tutti i valori dello stato si calcola il valore medio che appunto rappresnta la ricompensa.

#### Equazioni di Bellman

Ed eccoci ad uno dei capisaldi dell'apprendimento per riforzo, le equazioni di Bellman che si basano sui concetti sinora appresi, ovvero ritorno (somma delle ricompense), ricompensa, valore dello stato, funzione valore-azione.

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/x256JEYKqdWMY3Qy-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/x256JEYKqdWMY3Qy-screenshot.png)

Il ritorno Gt può essere formulato (descritto) in maniera **<span style="text-decoration: underline;">ricorsiva </span>**in quanto è la somma delle ricompense.

*Ovvero il ritorno al tempo t è la somma della ricompensa al tempo t+1 sommato al ritorno del tempo t+1, dove il ritorno al tempo t+1 è rispetto a t+1 (quindi es. t=2 scontato di gamma ovviamente)*

*dimostrazione:*

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/UGpW358nyFyGjRJK-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/UGpW358nyFyGjRJK-screenshot.png)

quindi

Gt = R(t+1) + gamma\*G(t+1)

cvd

da qui ne deriva l'equazione di Bellman:

##### Funzione valore dello stato 

La **prima** equazione <span style="text-decoration: underline;">ricorsiva </span>di Bellman

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/J5VqVK7QVazPNRiQ-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/J5VqVK7QVazPNRiQ-screenshot.png)

innanzitutto bisogna osservare che è un'equazione **ricorsiva,** in quanto all'interno della funzione è riproposta la funzione stessa.

Come si legge l'equazione di Bellman:

Partiamo dal presupposto che a questo livello stiamo <span style="text-decoration: underline;">**pianificando**</span>, ovvero cerchiamo di capire cosa potrebbe accadere se faccessimo l'azione a1 piuttosto che l'a2. In futuro vedremo come apprendere...

Quindi:

Partiamo dallo stato "s", abbiamo una policy <span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span> che ci fa scegliere ogni azione tra le azioni disponibili, con una certa probabilità, ovvero -&gt; [![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/iwKWIFJuC2FCpHWO-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/iwKWIFJuC2FCpHWO-screenshot.png)

e quindi vediamo cosa succede, ovvero -&gt; [![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/cjgk38mhhmGY5Z9f-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/cjgk38mhhmGY5Z9f-screenshot.png)

*che significa:*

*la <span style="text-decoration: underline;">ricompensa media</span> (è un singolo numero) ottenuta dallo stato "s" facendo l'azione "a"* [![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/zpTc4mY3tuxjPxaF-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/zpTc4mY3tuxjPxaF-screenshot.png) sommata al valore dello stato s', [![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/xSitMtPa1lVIWp9a-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/xSitMtPa1lVIWp9a-screenshot.png) la cui probabilità di arrivarci è data da [![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/cSK56JDK5tuZop3a-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/cSK56JDK5tuZop3a-screenshot.png) che rappresenta quindi la probabilità di passare dallo stato s a s', ed è una matrice di valori detta anche *matrice di transizione.*

*dimostrazione*:

partiamo dall'assunto:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/kGeQgMQeuUebRv6M-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/kGeQgMQeuUebRv6M-screenshot.png)

che ci dice che il valore-pi allo stato S è pari al valore atteso dato dal ritorno al tempo t subordinato allo stato "s".

V<span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);"><span style="color: rgb(224, 62, 45);"><span style="color: rgb(236, 240, 241);">π</span></span></span></span></span></span></span></span>(S) =

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/coIue61YwUAtlTHS-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/coIue61YwUAtlTHS-screenshot.png)

**+**

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/aTEN3akLTZnWHmzk-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/aTEN3akLTZnWHmzk-screenshot.png)

ovvero:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/H4uZ4pVBiueMuqDL-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/H4uZ4pVBiueMuqDL-screenshot.png)

##### Funzione valore stato-azione

La seconda equazione <span style="text-decoration: underline;">ricorsiva </span>di Bellman

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/dWeElASYC5XVcbSe-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/dWeElASYC5XVcbSe-screenshot.png)

##### Valori migliori possibili delle stati e delle azioni (policy ottimali V\* e Q\*)

Per migliorare la policy devo cercare il "meglio possibile" sia degli stati-valore che degli stati-valore-azione nello stato s per tutte le policy possibili, e quindi sarà il valore più alto (max) ottenibile. Questi valori saranno indicati come V\*(s) e Q\*(s,a)

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/jLD3JCt0yIysyGbm-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/jLD3JCt0yIysyGbm-screenshot.png)

<span style="text-decoration: underline;">Però </span>bisogna dire che le policy potrebbero essere infinite, quindi trovare il valore massimo di queste è un problema...

##### Tipologie di policy

Le policy possono essere:

1\) dipendenti dalla storia si chiama -&gt; HD (history dependent)

2\) dipendenti dal tempo e non dalla storia, si chiama -&gt; MARKOV

3\) se non dipende da nulla si dice "stazionaria" e si indica con pigrego (<span style="color: rgb(236, 240, 241);">**π**</span>)

Quindi nonostante l'insieme delle policy è un insieme infinito e quindi non è possibile trovare il massimo, allora come faccio? Bisogna quindi prendere un sottoinsieme di policy e in particolare quelle <span style="text-decoration: underline;">stazionarie </span>e <span style="text-decoration: underline;">deterministiche</span>, ma in che modo?

Possiamo farlo se agiamo su stati e azioni <span style="text-decoration: underline;">**finiti**</span>. Le policy <span style="text-decoration: underline;">stazionarie </span>e <span style="text-decoration: underline;">deterministiche</span> sono tutte le possibili azioni associate agli stati. (che si rappressanta com A elevato alla S, dove A sono le azioni e le S sono gli stati)

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/uzx69hoEBLGjA20r-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/uzx69hoEBLGjA20r-screenshot.png)

Se esiste una policy "ottimale", cioè il valore di tutti gli stati è il valore V\*/ Q\* (massimo) di quello stato.

La policy ottimale è deterministica in quanto sceglie sempre l'azione (una) che massimizza il ritorno, come si trova? si trova agendo "greedy" sulle azioni.

quindi:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/kYD4OlETu7GQNZcv-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/kYD4OlETu7GQNZcv-screenshot.png)

##### Equazione di ottimabilità per funzione stato valore ottimale V\* di Bellman 

A questo punto troviamo l'equazione ottimale di Bellman per la policy <span style="color: rgb(236, 240, 241);">**π**</span>\*

Partiamo dalla "classica" equazione di Bellman che agisce su tutte le policy, ovvero:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/MV7hSinVvDAbeVJ3-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/MV7hSinVvDAbeVJ3-screenshot.png)

Modifichiamola facendola agire solo sulla policy ottimale:

V\* = [![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/G8FCsvy7aEyPcBGU-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/G8FCsvy7aEyPcBGU-screenshot.png)

ma la policy valore ottimale sceglie le azioni in maniera greedy, quindi:

V\* = [![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/SLnuIjGeV3Iz2DTx-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/SLnuIjGeV3Iz2DTx-screenshot.png)

da notare che la V\* è ricorsiva in quanto compare all'interno della formula.

##### Equazione di ottimabilità per funzione azione-valore ottimale Q\* di Bellman 

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/kpsL94Q3AEObXLTg-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/kpsL94Q3AEObXLTg-screenshot.png)


Ricapitolando, le equazioni di Bellman ottimali e non sono:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/1uh2JrRNSe2LpGAT-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/1uh2JrRNSe2LpGAT-screenshot.png)

#### Risoluzione dell'equazione di Bellman

Partiamo dal presupposto che l'MDP è un processo finito, ciò significa che gli stati sono definiti e numerati. I metodi per risolvere l'equazione sono di tipo "iterativo".

**NB**: In questa fase non stiamo facendo ancora apprendimento, stiamo facendo quella che viene chiamata "pianificazione" in quanto conosciamo il modello. Per implementare la pianificazione, vengono utilizzate tecniche di <span style="text-decoration: underline;">programmazione dinamica</span>.

La programmazione dinamica è una tecnica di risoluzione dei problemi, si applica in due fasi:

- il problema complesso viene scomposto in sotto-problemi più semplici
- i sotto-problemi vengono poi ricomposti per risolvere il problema originale

Ci sono però dei requisiti, ovvero:

- il problema deve poter essere scomposto, si dice in questo caso che deve avere "una sotto-struttura ottimale"
- i sotto-problemi devono essere sovrapponibili, ovvero alcuni calcoli si possono ripetere in quanto l'algoritmo riceve in input gli stessi valori, per cui in questi è possibile implementare delle ottimizzazioni per evitare l'utilizzo di computazionale, come per es. l'utilizzo di cache, o altro.

Per calcolare la funzione valore di un policy dobbiamo quindi applicare l'equazione di Bellman iterativamente

##### Programmazione dinamica parte 2 (fase di pianificazione non apprendimento)

Stiamo quindi cercando di risolvere la fantomatica equazione di Bellman per determinare il valore dello stato e/o dello stato ottimale. La tipologia di casi che stiamo affrontando vengono detti "tabellari" in quanto, avendo a che fare con stati finiti, possono essere rapprentati in una tabella con valori finiti.

Per casi più complicati si utilizzano i casi "non tabellari" utilizzando gli<span style="text-decoration: underline;"> approssimatori, ovvero le rete neurali</span>.

Veniamo al pseudo algoritmo che utilizza l'equazione di Bellman.

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/2C29eq0bNSu7hqrc-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/2C29eq0bNSu7hqrc-screenshot.png)

spiegone:

L'algoritmo inizializza il vettore V con dei valori casuali tranne l'ultimo stato che deve essere inizializzato a zero, Questo perchè l'algorimo è di tipo "<span style="text-decoration: underline;">bootstrap</span>" ovvero utilizza i valori del vettore al tempo t1 per deteterminare i valori degli stati al tempo t2. Lo stato "finale" deve essere **<span style="text-decoration: underline;">assorbente</span>**, ovvero dallo stato finale o si esce o fa ripartire il loop di convergenza.

Ma questa versione non si usa, di seguito la versione migliorata, che in pratica utilizza l'ultimo valore per aggiornare V in quanto l'assegnazione di V svviene nel ciclo più interno, vedi sotto:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/tIFJDmqfNSCUJmnk-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/tIFJDmqfNSCUJmnk-screenshot.png)

in questo modo tutti gli stati succesivi al primo beneficiano di valori aggiornati degli stati precedenti.

 Esercizio:

Di seguito abbiamo un "mondo griglia" con due stati finali.

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/PI7pZ6iJczefk9Gn-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/PI7pZ6iJczefk9Gn-screenshot.png)

Analisi:

gli stati sono 15, le azioni sono 4, un esempio di policy potrebbe essere: al 70% vado giù, e all'30% vado a destra.

Invece un esempio di policy ottimale:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/kiE7Y3MVHkYDOQBc-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/kiE7Y3MVHkYDOQBc-screenshot.png)

Vedendo il modello possiamo pianificazione l'azione, per questo stiamo in modalità "pianificazione".

Ora proviamo con la policy: al 70% vado giù, e all'30% vado a destra.

Applicatione pratica dell'equazione di Bellman valore-stato (con policy non ottimale)

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/WhNDtR3pZTRDHJOX-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/WhNDtR3pZTRDHJOX-screenshot.png)

##### Policy Evaluetion

<div class="style-scope ytd-watch-metadata" id="bkmrk--61"><div class="item style-scope ytd-watch-metadata" id="bkmrk--62"></div></div>Ora veniamo al secondo passaggio, che va anche a spiegare il primo (rappresentato qui sopra)

Il secondo passaggio (v2) dopo che il primo passaggio ha settatto il valore V degli stati a -1. (ad eccezione ovviamente degli stati finali T che valgono zero)

Il passaggio logico è:

La prima parte dell'espressizione è relatvia alla policy, che nel caso specifico è al 70% andare giù e al 30% andare a destra. (si legge come probabilità di raggiungere lo stato successivo s' facendo l'azione in s, dove s in questo caso vale 1 in quanto è lo stato 1)[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/ET5MJcyD5EAW0Rob-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/ET5MJcyD5EAW0Rob-screenshot.png)

Quindi per prima cosa inseriamo nell'espressione le due probabilità 0.7 e 0.3 che moltiplicano una certa quantità.

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/AfxsPBOcK7OOQmCm-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/AfxsPBOcK7OOQmCm-screenshot.png)

 (questa quantità in formula si legge come la <span style="text-decoration: underline;">ricompensa media</span> dell'andare nello stato s' sommato alla probabilità dell'azione "a" di andare nello stato s' motiplicata (la probabilità) per la reward dello stato s'. Attenzione che la probabilità di anadare nello stato s' da s, in questo particolare caso, è 100% quindi 1. Da cui ne deriva che:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/ZUjcYCsIhtaiGn3P-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/ZUjcYCsIhtaiGn3P-screenshot.png)

Il tutto va iterato per tutti gli stati dell'ambiente fino a che i valori degli stati "convergono", il che si significa che variano di poco.

Il metodo consente di propagare in modalità "backward" dagli stati finali (quelli più vicini allo stato T) verso quegli iniziali i valori.

Alla fine ciascuno stato del modello avrà un valore che indicherà quanti "passi" sono necessari per arrivare alla meta, dandoci quindi un'indicazione sul comportametno della policy.

##### Conclusioni dell'esercizio

Con una policy che assegna il 25% per ogni azione gli stati valori ottenuti sono:

\[\[ 0. -14. -20. -22.\]  
 \[-14. -18. -20. -20.\]  
 \[-20. -20. -18. -14.\]  
 \[-22. -20. -14. 0.\]\]

che indicano la ricompensa totale media che si otterrebbe partendo dallo stato. per es. se parto dallo stato "1" (quello vicino all'uscita) otterrei mediamente, con la policy al 25% una ricompensa media di circa -14.

ATTENZIONE! stiamo parlando di una ricompensa media in quanto ci potrebbero essere casi in cui arrivo subito all'uscita andando per es. subito a sx oppure casi in cui inizio a va girare per la griglia, esistono quindi <span style="text-decoration: underline;">**traiettorie** </span>lunghissime.

Ecco l'esempio di codice:

allego a questa pagina le classi di ambiente utilizzate per simulare il "mondo griglia"

```python
from envs.gridworld import GridworldEnv
import  numpy as np

# 0 su 1 dx 2 giù 3 sx
# instanzio l'ambiente griglia
env = GridworldEnv()


print (env.nS)
print (env.nA)
env.reset()
env._render()
env.step(1)
print()
env._render()
env.step(1)

def policy_evaluation(policy, env, discount_factor=1.0, theta=0.00000001):
    """

    :param policy: [A,S] matrice di shape (rango = 29  a due domensioni che rappresenta la policy, dove sulle riche ci sono gli stati e sulle colonne le azioni
    :param env: rappresentazione dell'ambiente
    :param discount_factor: fattore di sconto gamma
    :param theta: valore che termina la valutazione della policy una volta che la funzione stato valore è sotto questa soglia
    :return:
    """

    # inizializzamo la funzione stato valore V, per semplificare la vita li portiamo a zero
    # dove il valore è il valore di OGNI STATO
    V = np.zeros(env.nS)

    # il ciclo deve fermarsi solo quanto la qta delta calcolata è minuore o uguale a theta
    passaggi = 0
    while True:
        delta = 0
        passaggi += 1

        # per ciscuno stato effettuo un "full backup"
        # questo primo ciclo fa passare tutti gli stati
        for s in range(env.nS):
            v = 0

            # questo il ciclo fa la sommatoria delle azioni
            # ovvero esegue tutte le azioni possibili nello stato s
            for a, action_prob in enumerate(policy[s]):

                # per ciascuna azione chiedo all'ambiente in quale stato finisco, la probabilità di finirci, la ricompensa e se eventualmente è lo stato finale
                # NB: la situazione NON è vera in quanto stiamo facendo "esperienza" senza fare un passo, questo non è vero RL è pianificazione
                for prob, next_state, reward, done in env.P[s][a]:

                    # equazione di Bellman
                    # probabilità dell'azione per la probabilità della transizione
                    v += action_prob * prob * (reward + discount_factor * V[next_state])

            # quanto del valore stato funzione è variatto tra tutti gli stati
            delta = max(delta, np.abs(v - V[s]))
            V[s] = v

        # finiamo la valutazione una volta che il valore è sotto la soglia theta
        if delta < theta:
            break

    return np.array(V), passaggi

# definiamo una polcy generica, in pratica per ogni stato del mondo griglia associo 4 probabilità di eseguire una azione, le probabilità sono tutte al 25%
random_policy = np.ones( [env.nS, env.nA])/env.nA

v,passaggi = policy_evaluation(random_policy, env)

v = v.reshape(4,4)
print(v,passaggi)
```

##### Migliorare la policy (policy improvement-iteration)

Il metodo per migliorare la policy è quello di compiere tutte le azioni possibili e scegliere quella che restituisce il valore maggiore agendo in maniera "greedy", ovvero:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/VzzLCb8hk9g7qD7K-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/VzzLCb8hk9g7qD7K-screenshot.png)

<p class="callout success">Come faccio a calcolare pi' (primo) ? be faccio <span style="text-decoration: underline;">tutte le azioni <span style="color: rgb(224, 62, 45); text-decoration: underline;">**"a"**</span> possibili</span>, faccio "**<span style="text-decoration: underline;">one step looking forward</span>**", ovvero faccio un passo avanti compiendo un'azione sola, guardo cosa succede al passo successivo chiedento all'ambiente cosa può succedere con quale probabilità. Facendo queste azioni prendo quella che massimizza il ritorno.</p>

*Ma quando una policy è migliore di un'altra? beh quando per ogni stato s, applicando la nuova policy <span style="color: rgb(236, 240, 241);">**π'**</span>, il valore dello stato è maggiore-uguale al valore della vecchia policy. Nella pratica faccio N iterazioni compiendo N traiettorie fino a quando i valori convergano, a questo punto confronto tutti gli stati valori con quelli precedenti, se sono migliori allora faccio un altro giro, loppando fino a quando gli stati valori sono uguali al precedente, il che identifica la policy migliore.*

Ma cosa vuol dire nella pratica?

Supponiamo di avare uno stato "s" e un'azione "a1" che porta in tre stati (s',s2, s3), dove per ognuno dei tre stati avviamo una probabilità di entrare in ciascuno stato con una relativa reward, abbiamo anche il <span style="text-decoration: underline;">valor medio totale dello stato</span> <span style="color: rgb(255, 255, 255);">**V**</span>*<span style="color: rgb(236, 240, 241);">**π**</span>* di ciascun stato che era stato precedentemente calcolato applicando la policy. (vedi schema sotto riportato)

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2024-11/scaled-1680-/e1QOvMl5ike2Fqje-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2024-11/e1QOvMl5ike2Fqje-image.png)

Ora per ogni azione (es. a1 e a2) voglio <span style="text-decoration: underline;">calcolare il valore medio dell'azione</span> stessa che significa calcolare il valore delle "cose/fatti" che possono accadere pesati per le probabilità. Nell'esempio sopra riportato significa prendere la probabilità che accada s' con la relativa reward r dato lo stato s con l'azione a1, ovvero:

p(s',r | s, a1)\*(r+Vπ(s')) -&gt; probabilità di andare in s' con l'azione a1 che moltiplica la somma della reward ottenuta per andare nello stato s' + il valore medio totale dello stato s'.

Questa operazione va ripetuta per ogni stato raggiunto dall'azione **a**1, ovvero nel nostro caso s',s2, s3 e sommata per questi tre stati quindi:

**Qπ(s,a) = Σ (**xx**) p(s**xx**,r | s, a**xx**)\*(r+Vπ(s**xx**))** dove **xx** è **s',s2,s3**

Poi analogamente calcoliamo il **Qπ(s,<span style="color: rgb(224, 62, 45);">a2</span>)** e ne calcoliamo il massimo tra *argmax* (**Qπ(s,a),Qπ(s,<span style="color: rgb(224, 62, 45);">a2</span>**)) e scegliamo <span style="color: rgb(224, 62, 45);">**l'azione** </span>associata al **Qπ massimo**. In questo modo andiamo a miglioare la policy in maniera "**greedy**" ovvero cercando di massimizzare il valore. Il nome di questo algoritmo di chiama "policy iteration". Il cui pseudo codice è sotto riportato:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2024-11/scaled-1680-/1NsL1E2c7IUqDzW9-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2024-11/1NsL1E2c7IUqDzW9-image.png)

L'algoritmo alterna la valutazione (evaluation) della policy al improvement fino a che non ottengo la policy.

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/kDnCgz7zp7hbd2qY-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/kDnCgz7zp7hbd2qY-screenshot.png)

dove:

1\) inzializza i valori randomicamente e seleziona una policy casuale

2\) applica la valutazione delle policy, ovvero calcola V\_pi

3\) miglioramento, ovvero:

- facciamo un ciclo sugli stati S (detta anche "*sweep*") -&gt; NB essendo pianificazione di un MDP a stati finiti rende la cosa fattibile, in reatà in giochi come "go" non è possibile in quanto gli stati sono un numero enorme, ma questa è un'altra storia)
- ciclo su tutte le azioni dello stato che sto valutando 
    - salvo la vecchia azione (V(sxx)
    - effettuo la nuova azione e vedo quale valore V(sxx) otttengo
    - confronto vecchia e "nuova funzione valore" V(S) se il valore della nuova azione è miglioare allora l'agoritmo non ha ancora trovato la policy migliore e quindi aggiorno la policy con l'azione miglioare e continuo a looppare
- fatti passare tutti gli stati se la policy non è stabile riparto dal punto 2
- in generale il tutto looppa finchè i valori non convergono il che significa che tra uno sweep e l'altro non ci sono grandi variazioni

Ricordo che la pianficazione si può applicare solo quando disponiamo del modello, che è il caso più facile e poco probabile che accada nel RL.

Di seguito l'algoritmo completo

```python
from envs.gridworld import GridworldEnv
import  numpy as np


def policy_evaluation(policy, env, discount_factor=1.0, theta=0.001):
    """

    :param policy: [A,S] matrice di shape (rango = 29  a due domensioni che rappresenta la policy, dove sulle riche ci sono gli
                   stati e sulle colonne le azioni
    :param env: rappresentazione dell'ambiente
    :param discount_factor: fattore di sconto gamma
    :param theta: valore che termina la valutazione della policy una volta che la funzione stato valore è sotto questa soglia
    :return: ritarna la tabella stato valore (V) contenente i valori ottimali per arrivare allo più efficacemente allo stato terminale
             in pratica l'algoritmo incentiva ad andare verso lo stato il cui valore è più alto, es. tra due stati che valgono
             rispettivamente- 14 e -20 si va verso il valore pià grande ovvero -14.

    NOTA: - le azioni sono: 0 = su, 1 = dx, 2 = giù, 3 sx
          - la reward è sempre -1 tranne negli stati terminali
          - negli stati terminali le azioni non effettuano spostamento di stato.
    """

    # inizializzamo la funzione stato valore V, per semplificare la vita li portiamo a zero
    # dove il valore è il valore di OGNI STATO
    V = np.zeros(env.nS)

    # il ciclo deve fermarsi solo quanto la qta delta calcolata è minuore o uguale a theta
    passaggi = 0
    while True:
        delta = 0
        passaggi += 1


        # per ciscuno stato effettuo un "full backup"
        # questo primo ciclo fa passare tutti gli stati
        for stato in range(env.nS):
            v_appo = 0

            # questo il ciclo fa la sommatoria delle azioni
            # ovvero esegue tutte le azioni possibili nello stato s
            azioni_stato = enumerate(policy[stato])
            for azione , policy_prob in azioni_stato:

                # per ciascuna azione chiedo all'ambiente in quale stato finisco, la probabilità di finirci, la ricompensa
                # e se eventualmente è lo stato finale
                # NB: la situazione NON è vera in quanto stiamo facendo "esperienza" senza fare un passo, questo non è
                # vero RL è pianificazione
                # Da notare che questo ciclo è utile solo nel caso in cui a fronte di una azione ci possono essere diversi
                # stati destinazione con diverse probabilità, nel nostro caso ci sarà sempre e solo uno stato destinazione
                # con probabilità (env_prob) pari a 1
                for env_prob, next_state, reward, done in env.P[stato][azione]:

                    # equazione di Bellman
                    # probabilità dell'azione per la probabilità della transizione
                    v_appo = v_appo + policy_prob * env_prob * (reward + discount_factor * V[next_state])

            # delta misura l'errore su tutti gli stati, ovvero misura la differenza tra tutti gli
            # nella passata precedente N-1 e l'attuale N.
            # Nella pratica significa che per ogni stato il delta massimo trovato è quello indicato nella varibile
            # e quindi potrà poi essere comparato con theta per terminare la valutazione della policy
            delta = max(delta, np.abs(v_appo - V[stato]))
            V[stato] = v_appo

            # stampo la tabella degli stati
            # vr = V.reshape(env.shape).round(3)
            # print(vr,stato,passaggi,'%5.15f' % delta)
            # input()

        # finiamo la valutazione una volta che il valore è sotto la soglia theta
        if delta < theta:
            break

    return np.array(V), passaggi


def policy_improvment (env, policy,  policy_evaluetion_fn, discount_factor=1.0):
    """
    Funzione che migliora la policy iterativamente

    :param env: ambiente openAI
    :param random_policy: passiamo una policy iniziale
    :param policy_evaluetion_fn: funzione che valuta la policy e restituisce gli stati funzione valore V
    :param discount_factor: fattore di sconto gamma
    :return: ritorna una tupla che che tiene la nuova policy ottimale, gli stati valori e il totale passaggi effettuati
    """
    def one_step_lookahead(state, V):
        """
        funzione helper che calcola il valore di tutte le azioni dato uno stato

        :param state:
        :param V:
        :return: Q-value -> un vettore di lunghezza env.nA ovvero tutte le azioni possibili nello stato che contiene il valore funzione stato per ogni azione.
        """
        A = np.zeros(env.nA)
        # prendo tutte le azioni possibili nello stato passato in input alla funzione
        for a in range(env.nA):

            # come reagisce l'ambiente in quello stato
            # per ogni azione ottengo il valore totale medio
            # NB: interrogo l'ambiente e sarà lui a dirmi con quella azione in quali stati andrò e con quale probabilità e reward
            for prob, next_state, reward, done in env.P[state][a]:
                # calcolo il valore medio di tutti gli stati raggiungibili effettuando l'azione "a".
                A[a] += prob * (reward + discount_factor * V[next_state])
        return A

    passaggi = 0
    # ciclo di controllo.
    while True:

        passaggi += 1

        # valutiamo la policy
        V, psg = policy_evaluation_fn(policy, env, discount_factor)

        # setto il flag che mi interromperà il loop while
        policy_stable = True

        # estraggi tutti glistati
        # SWEEP
        for s in range(env.nS):

            # effetuo lo "one step ahead" per capire quali valori mi restituisce l'azione che ho deciso di
            action_values = one_step_lookahead(s, V)

            ############# calcolo l'azione migliore
            # IMPROVMENT
            #############
            best_a = np.argmax(action_values)

            # sceglo l'azione con probabilità maggiore tra quelle presente nella VECCHIA (attuale) policy
            # per quello stato, nella pratica estrae l'indice
            prev_policy_action = np.argmax(policy[s])

            # confronto l'azione delle vecchia policy con quella trovata dall'improvment e verifico se coincidoni
            # se non coincidono allora la policy non è ancora stabile e quindi non ottimale.
            if prev_policy_action != best_a:
                policy_stable = False

            # setto l'indice dell'azione che massimizza il valore calcolato a 1 per cambiare la policy ottimizzandola
            policy[s] = np.zeros(env.nA)
            policy[s][best_a] = 1

        # se la policy è stabile allora abbiamo trovato quella ottimale, quindi interrompo il ciclo principale ed esco
        if policy_stable:
            break


    return policy, V, passaggi


# 0 su 1 dx 2 giù 3 sx
# instanzio l'ambiente griglia
env = GridworldEnv([4,4])

print (env.nS)
print (env.nA)
env.reset()
env._render()
env.step(1)
print()
env._render()
env.step(1)

# definiamo una polcy generica, in pratica per ogni stato del mondo griglia associo 4 probabilità di eseguire una azione, le probabilità sono tutte al 25%
random_policy = np.ones( [env.nS, env.nA])/env.nA
print(random_policy)

policy_ottimale, V, passaggi = policy_improvment (env, random_policy, policy_evaluation)
#V,passaggi = policy_evaluation(random_policy, env)



v = V.reshape(env.shape).round(0)
print(v,passaggi)
#
print()
print(policy_ottimale)









```

([https://www.youtube.com/watch?v=QY3yxYyK4wM&amp;list=PLMee1hSjLKdAL16E-7EzqHXsGOgzo8iro&amp;index=13)](https://www.youtube.com/watch?v=QY3yxYyK4wM&list=PLMee1hSjLKdAL16E-7EzqHXsGOgzo8iro&index=13))

##### Iterazione di valore 

Con queste tipologie di algoritmi vogliamo **<span style="text-decoration: underline;">ottimizzare </span>**le policy combianando la policy evaluation e la policy improvement.

Nel <span style="text-decoration: underline;">iterazione della policy</span> ricordiamo che l'algoritmo è diviso in due parti, la prima che riguarda la valutazione della policy (evaluation) e la seconda che la migliora agendo in maniera "greedy" ovvero scegliendo l'azione che massimizza il valore medio atteso prendendo la argmax dei valori restituiti dal "one step look ahead".

Nella iterazione di valore invece l'alogoritmo di semplica e indirettamente si ottimizza combianando i due step secondo lo pseudo codice sotto riportato:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/scaled-1680-/cm8jcWDDzKMFXy7C-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/cm8jcWDDzKMFXy7C-image.png)

che in pratica applica l'equazione di Bellman sostituendo direttamente il valore medio atteso della funziona stato valore.:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/scaled-1680-/XeT0wzWY6TeNbQZy-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/XeT0wzWY6TeNbQZy-image.png)

 di seguito l'algorirmo rivisto, la differenza in termini di performace rispetto al precedente è notevole.

```python
from envs.gridworld import GridworldEnv
import numpy as np

import time

# funzione per misurare il tempo di esecuzione di una funzione tramite un decorator
#  basterà1:
#  1) importare la funzione -> from objs.TimerDecorator import timing_decorator
#  2) decorare la funzione da misurare con @timing_decorator
def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        original_return_val = func(*args, **kwargs)
        end = time.time()
        print("time elapsed in ", func.__name__, ": ", end - start, sep='')
        return original_return_val

    return wrapper

from envs.gridworld import GridworldEnv
import numpy as np

from utils.TimerDecorator import timing_decorator


@timing_decorator
def value_itaration(env, theta = 0.00001, discount_factor=1.0):
    """
    Funzione che migliora la policy policy_improvment

    :param env: ambiente openAI
    :param theta: valore che termina la valutazione della policy una volta che la funzione stato valore è sotto questa soglia
    :param discount_factor: fattore di sconto gamma
    :return: ritorna una tupla che che tiene la nuova policy ottimale, gli stati valori e il totale passaggi effettuati
    """

    def one_step_lookahead(state, V):
        """
        funzione helper che calcola il q-value (valore) di tutte le azioni dato uno stato

        :param state:
        :param V:
        :return: Q-value -> un vettore di lunghezza env.nA ovvero tutte le azioni possibili nello stato che contiene il valore funzione stato per ogni azione.
        """
        A = np.zeros(env.nA)
        # prendo tutte le azioni possibili nello stato passato in input alla funzione
        for a in range(env.nA):

            # come reagisce l'ambiente in quello stato
            # per ogni azione ottengo il valore totale medio
            # NB: interrogo l'ambiente e sarà lui a dirmi con quella azione in quali stati andrò e con quale probabilità e reward
            for prob, next_state, reward, done in env.P[state][a]:
                # calcolo il valore medio di tutti gli stati raggiungibili effettuando l'azione "a".
                # equazione di "punto fisso"
                A[a] += prob * (reward + discount_factor * V[next_state])
        return A

    # inizializziamo gli stati con dei valori casuali a piacere (array di N stati)
    V = np.zeros(env.nS)
    while True:
        # inizializzo la variabile che condizione lo stop del loop
        delta = 0

        # aggiornare di stati
        for s in range(env.nS):
            # guardo uno step avanti restituendo la funzione stato valore di ogni azioni che può essere fettuata nello stato
            best_action_value = np.max(one_step_lookahead(s,V))

            # confronto l'azione con i valore dello stato nell'itezione precedente
            delta = max(delta, np.abs (best_action_value - V[s]))

            # salvo lo stato valore
            V[s] = best_action_value

        # se il delta è sotto theta allora i valori sono prossimi alla convergenza desiderata
        if delta < theta:
            break

        # ora dagli stati valore ricavo la policu V*(s) -> Q*(s,a)
        # inizilizzo la policy
        policy = np.zeros([env.nS,env.nA])
        for s in range (env.nS):
            azione = np.argmax(one_step_lookahead(s,V))
            policy[s][azione] = 1.0

        return policy, V


# 0 su 1 dx 2 giù 3 sx
# instanzio l'ambiente griglia
env = GridworldEnv([4, 4])

# print(env.nS)
# print(env.nA)
env.reset()
# env._render()
# env.step(1)
# print()

policy_ottimale, V, = value_itaration(env)
# V,passaggi = policy_evaluation(random_policy, env)

print(V)
#
# print()
print(policy_ottimale)

```

Esercizio 2

Abbiamo un certo capitale inferiore a 100 (es. 99 o 1 o 44) e lo scopo è arrivare esattamente a 100. (valori oltre il 100 non sono considerati, il goal è esattamente a 100) Possiamo scommetere solo il capitale a nostra disposizione lanciando una monetina scommettendo quello che vogliamo sulla base di quello che abbiamo. (es. ho 70 lancio la monetina e scommetto per es. 30 per arrivare a 100, se perdo vado a 40 se vinco vado a 100 e ho terminato il gioco vnicendo. Ovviamente se arrivo a zero ho perso.

<p class="callout info">Il problema può essere modellato come un MDP, senza 1) fattore di sconto, 2) episodico, ovvero da traiettorie (successione di azioni, rewards e stati) di lunghezza finita che si concludono in uno (o più) stato/i terminale/i raggiungible/i e 3) finito ovvero che stati e azioni sono finiti.</p>

<p class="callout danger"><span style="color: rgb(236, 240, 241);">In generale quando le ricompense sono tutte zero, tranne che nella transizione dallo stato precedente allo stato terminale e lo stato terminale stesso, dove in questo caso vale 1, allora la funzione stato valore indica la probabilità di vittoria in quello stato.</span></p>

<p class="callout danger"><span style="color: rgb(236, 240, 241);">Ricodiamo che: il valore dello stato è media con la probabilità di tutte le traiettorie possibili della ricompensa totale.</span></p>

```python
import numpy as np

"""
Abbiamo un certo capitale inferiore a 100 (es. 99 o 1 o 44) e lo scopo è arrivare esattamente a 100. 
(valori oltre il 100 non sono considerati, il goal è esattamente a 100) Possiamo scommettere solo 
il capitale a nostra disposizione lanciando una monetina scommettendo quello che vogliamo sulla 
base di quello che abbiamo. (es. ho 70 lancio la monetina e scommetto per es. 30 per arrivare 
a 100, se perdo vado a 40 se vinco vado a 100 e ho terminato il gioco vincendo. 
Ovviamente se arrivo a zero ho perso.

Il problema può essere modellato come un MDP, senza 1) fattore di sconto, 2) episodico, 
ovvero da traiettorie (successione di azioni, rewards e stati) di lunghezza finita che 
si concludono in uno (o più) stato/i terminale/i raggiungible/i e 3) finito ovvero che 
stati e azioni sono finiti.

In pratica lo stato rappresenta il capitale posseduto, e in base a quello la policy dovrebbe
cercare di assumere il comportamento ottimale.

In prima battuta va definito il modello. Il modello restituisce sempre ricompensa 0 tranne
quando arrivo nello stato terminale 100. Notare che la ricompensa non è quanto stiamo guadagnando in 
quanto l'obiettivo è arrivare a 100 e non accumulare più soldi possibili.

"""

def values_iteration_for_gamblers(probab_monetina = 0.5 , theta=0.0001, discount_factor=1.0):
    """

    :param probab_monetina: probabilità che esca testa
    :param theta: valore delta di convergenza
    :param discount_factor: fattore di sconto

    :return: policy e funzione stato valore
    """


    def one_step_look_ahead(in_capital, V, rewards, probab_monetina, discount_factor):
        """
        In base allo stato in cui mi trovo, ovvero il capitale a mia disposizione, effettuo una possibile
        giocata per tutte le possibili giocate a mia disposizione. Ovvero se ho un capitale di 40, farò
        una giocata partendo dalla somma 1 fino al massimo a mia dispisizione. (ovvero 40)

        La funziona ci dice nella pratica per ogni azione fatta con il capitale passato quanto vale quella azione.

        :param capitale: capitale del giocatore (rappresentato dallo stato)
        :param V: stati valore
        :param rewars: ricompense

        :return: ritorna l'elenco dei valori medi ottenibili effettuato tutte le azioni nello stato ovvero
                 del capitale passato in input
        """

        # inizializzo le azioni possibili in ogni stato
        A = np.zeros(101)

        # passato il capitale a disposizione, calcolo tutte le possibili giocate da quella minima (1) al massimo
        # che posso giocare con il capitale a disposizione passato in input.
        # il min(capital, (100-capital)) serve per calcolare il capitale giocabile considerando che
        # non posso andare oltre 100 anche se il capitale a mia disposizione lo consetirebbe
        capitale_giocabile = min(in_capital, (100 - in_capital))

        # effettuo tutte le giocate possibili
        for giocata_in_soldi in range(1,capitale_giocabile+1):
            # a questo punto per ogni giocata vedo il valore medeio di quello che può succedere effettuando
            # tutte le giocate possibili.
            A[giocata_in_soldi] =      probab_monetina  * (rewards[in_capital + giocata_in_soldi] + V[in_capital + giocata_in_soldi] * pow(discount_factor, giocata_in_soldi)) \
                                + (1 - probab_monetina) * (rewards[in_capital - giocata_in_soldi] + V[in_capital - giocata_in_soldi] * pow(discount_factor, giocata_in_soldi))

        # array che indica per ogni azione fatta con il capitale a mia disposizione, quanto vale ciascuna azione.
        return A

    ######################
    ######## INIZIO ######
    ######################

    # creo un array di 101 elementi che rappresenta le rewards dove:
    # - l'elemento zero è lo stato di perdita del gioco -> stato terminale
    # - l'elemento 101  è lo stato di vincita del gioco -> stato terminale
    # tutti gli stati avranno una rewards pari a zero tranne l'ultimo (100) che avrà reward = 1
    rewards = np.zeros(101)

    # ricordo che è zero based, quindi l'elemento 100 è il 101
    rewards[100] = 1

    # inzializzo la funzione stato valore con dei valori a "caso" facciamo zero per facilitare
    V = np.zeros(101)

    # creo la policy ottimale
    policy = np.zeros(101)

    # ciclo principale
    while True:

        # inizializzo la variabile che verrà utilizzata per interrompere i ciclo di valutazione della policy
        # fino alla sua convergenza.
        delta = 0

        # simulo tutti le possibili giocate con tutti i possibili capitali a mia disposizione
        # fa passare tutti gli stati
        for giocata in range (1,100):

            # verifico quanto valgono tutte le giocate con il capitale simulato
            # faccio tutte le azioni possibili
            A = one_step_look_ahead(giocata, V, rewards, probab_monetina, discount_factor)

            # determino il valore della giocata più alto
            best_action_value = np.max(A)

            # verifico se la giocata è migliore della precedente
            delta = max(delta, np.abs(best_action_value-V[giocata]))

            # salvo il valore migliore nella funzione stato valore
            V[giocata] = best_action_value

        # verifico se interrompere il loop perchè la funzione stato valore sta converendo
        if delta < theta:
            break

    # questo ciclo indica come giocare in ogni stato, dove lo stato rappresenta il capitale posseduto
    # serve solo per identificare l'azione megliore da intraprendere basandosi sulle stati valori ottimali precedentemente
    # calcolatir
    for giocata in range (1,100):
        A = one_step_look_ahead(giocata, V, rewards, probab_monetina, discount_factor)
        best_action_value = np.argmax(A)
        policy [giocata] = best_action_value

    return policy,V

policy, V = values_iteration_for_gamblers(discount_factor=1)

# tampo la funzione valore
for i in range(101):
    if i % 10 == 0:
        print()
    print (" %i-%s"%(i,V[i]), end='')

print ()

# stampo la policy
for i in range(101):
    if i % 10 == 0:
        print()
    #print (" %i-%s"%(i,policy[i]), end='')
    print(" %i-%s" % (i,policy[i]), end='')
# print (policy)
# print (np.reshape(policy,(10,10)))
```

# Sessione 2

#### Metodi Model free

Nel capitolo precedente abbiamo svolto un lavoro di **<span style="text-decoration: underline; color: rgb(224, 62, 45);">*pianificazione* </span>**e <span style="text-decoration: underline;">**non** di </span>*<span style="text-decoration: underline;">appredimento per rinforzo</span>* in quanto avevamo il modello (ambiente) che ci diceva con quale probabilità svolgeva le azioni. La policy (pi) era in qualche modo nota, questo però non rappresenta la realtà in quanto il modello, nella natura delle cose, non ci viene dato a priori, dobbiamo quindi trovare un modo per ricavarlo, come fare? Bene bisogna quindi interrogare l'ambiete e con le risposte ottenute ricavare in quale modo il modello. Abbiamo quindi a che fare un metodi **<span style="color: rgb(186, 55, 42);"><span style="text-decoration: underline;">"model free" </span></span><span style="text-decoration: underline;">in quanto il modello</span><span style="color: rgb(186, 55, 42);"><span style="text-decoration: underline;"> NON </span></span><span style="text-decoration: underline;">è noto a prior</span><span style="text-decoration: underline;">i</span>.**

Da notare che possiamo comunque interagire con l'ambiente tramite esperienza, ovvero:

1. parto da uno stato che posso scegliere in maniera casuale
2. scelgo l'azione tramite la mia policy e vedo cosa succede
3. torno al punto 1 e così via fino alla fine dell'episodio

**SPIEGONE**: Tutto questo fino a quando otterremo la "policy ottimale", ovvero facendo la media di tutti i ritorni Gt. Quindi per via delle <span style="text-decoration: underline;"><span style="color: rgb(224, 62, 45); text-decoration: underline;">l*egge dei grandi numeri*</span></span> possiamo approssimare il <span style="text-decoration: underline;"><span style="color: rgb(22, 145, 121); text-decoration: underline;">valore medio atteso</span></span> ([![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-04/scaled-1680-/Icj36K8XriPTKO3p-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-04/Icj36K8XriPTKO3p-image.png)) con la semplice <span style="text-decoration: underline;"><span style="color: rgb(22, 145, 121); text-decoration: underline;">media empirica</span></span>. Ricordo che il valore atteso (**E**) è quello che si calcola con le <span style="text-decoration: underline;">probabilità</span> di transizione, mentre la media empirica è la semplice somma di tutti i valori diviso il numero totale dei valori. Quindi quando il numero di valori tende a <span style="text-decoration: underline;">infinito </span>allora il valore <span style="text-decoration: underline;">converge al valore atteso</span>.

##### Predizione

E' model free perchè non abbiamo a priori il modello, cosa che invece avevamo all'inizio del corso con la *pianificazione*.

Dovremo quindi far uso di "stimatori" in grado di ricostruire nella maniera più federe possibile il modello.

Dobbiamo quindi fare un lavoro di predizione, per fare questo abbiamo due metodi, il primo detto "<span style="color: rgb(22, 145, 121);">Monte Carlo</span>" mentre il secondo detto "<span style="color: rgb(22, 145, 121);">Temporal Difference</span>"

<span style="color: rgb(22, 145, 121);">**<span style="text-decoration: underline;">Metodo Monte Carlo </span>**</span>

Il metodo <span style="text-decoration: underline;">**Monte Carlo (MC)**</span>, nella pratica voglio "**imparare**" il valore delle mie azioni iteragendo con l'ambiente. *Banalmente compio azioni "a caso" e poi tengo traccia delle media aritmetica degli episodi che faccio.* Svolgo quindi un episodio partendo dallo stato k e raccolgo tutti i valori, e relative reward, degli stati fino allo stato terminale. Terminato un episodio G(T) ne faccio altri N, poi, per ottnere il valore V(Sxx) faccio la media aritmetica di tutti i G(T) ottenuiti partendo dal quello stato "S" e salvo il valore ottenuto nello stato s. Svolgo questo lavoro per N volte per tutti gli M stati, in questo modo a tendere, sempre per la legge dei grandi numeri, mi avvicino al valore reale dello stato. (da notere che con questo metodo non devo inizializzare gli stati in quanto interrogo subito l'ambiente)

**NB**: MC è un metodo "off line" ovvero che impare dopo aver finito l'episodio.

Questo metodo impara il valore della policy dall'esperienza.

Da qui deriva il concetto di "<span style="color: rgb(22, 145, 121);">**boostrapping**</span>", ovvero quando calcolo il valore Vk applicando la funzione "one step looking ahead" andando ad esplorare gli stati successivi s', utilizzo i valori Vk calcolati in precedenza per ricalcolare l'attuale valore Vk.

Da notare che nei metodi con bootstrapping bisogna stimare i valori di **tutti** gli stati altrimenti perde efficacia.

Di qui la versione più semplice dell'algoritmo in pseudo-codice:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/scaled-1680-/EnMYIzULTO5BiNjZ-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/EnMYIzULTO5BiNjZ-image.png)

da notare la formula sottolineata che rappresenta la ***<span style="color: rgb(22, 145, 121);">forma incrementale della media aritmetica</span>***, ovvero come aggiungere un valore ad una media considerando il suo peso rispetto alla media stessa. In pratica si tratta di sommare la media a (valore meno la media)/numero totale dei valori.

come funziona:

- inzializza la funzione valore con dei valori a caso (anche *zeros*)
- facciamo <span style="color: rgb(22, 145, 121);">**un episodio**</span>, ovvero memorizzare: 
    - tutti gli stati
    - tutte le azioni
    - tutte le ricompense
    - fino alla fine
- partiamo dalla fine dell'episodio (stato Rt) e inzializziamo il valore Gt a zero
- procedo <span style="color: rgb(22, 145, 121);">**risalendo**</span> gli stati partendo da quello terminale che vale zero, vado a T-1 del quale prendo la **<span style="color: rgb(22, 145, 121);">ricompensa </span>**e la <span style="color: rgb(22, 145, 121);">**sommo** </span>a quella dello stato se segue (in questo caso quello finale)
- procedo risalendo in questo modo (sommando) fino allo stato iniziale
- calcolo il valore V(St) come la media dei ritorni di tutti gli stati precendenti (da quello terminale a quello in elaborazione)

Di seguito il codice che implementa l'algoritmo:

```python
import io
from collections import defaultdict

import numpy as np
import sys
import gym
import matplotlib as plot

"""
Il BJ è un gioco a due o più giocatori, si tratta di uno o più giocatori contro il banco.
Il banco mostra una carta e poi ci da 2 carte, noi sommiamo queste due carte e possiamo decidere
se prendere una carta o rimanere fermo (stick)
Quando mi fermo faccio la somma delle mie carte, se ho più vi 21 punti allora ho perso, se invece meno
tocca al banco e lui continua a prendere carte fino a quando arriva ad avere più o uguale 17 punti.
A quel punto si ferma anche lui e chi ha di più vince.
NB: Il banco non è interessato a quello che facciamo noi.

POLICY: continuiamo a prendere fino a quanto arrivo a 20 o 21, la reward è +1 se ho vinto, -1 se perdo o zero se pareggio.
Il valore dello stato non è più la probabilità della vittoria

"""

env = gym.make("Blackjack-v1", sab=True)


def mc_prediction (policy, env, num_episodies, discont_factor =1.0):
    """
    Algoritmo di predizione Monte Carlo, calcola la funzione valore per una data policy utilizzando il metodo "sampling"

    :param policy: una funzione che mappa un'osservazione ad una azione probabile
    :param env:  openAI gym
    :param num_episodies:  numero di epidosi che compongo il sample
    :param discont_factor: solito

    :return: un dizionaio che mappa lo stato nel valore valore, è una tupla il cui valore è float
    """

    # preparo il dizionario di ritorno delle funzione
    # tiene traccia e conta i ritorni di ciascuno stato per calcolarne la media
    # NOTA: tale metodo è inefficiente
    returns_sum = defaultdict(float)
    returns_count = defaultdict(float)

    # funzone valore finale
    V = defaultdict(float)

    for i_episode in range (1,num_episodies+1):
        # stampo a quale episodio mi trovo (utile per il debug)
        if i_episode % 1000 == 0:
            print("\repisode {}/{}.".format(i_episode,num_episodies), end="")
            sys.stdout.flush()

        # genera un epidosodio rappresentato da un array di tuple composte da (stati, azionie e ricompendse)
        episode = []
        state, info = env.reset() # resetto il gioco ovvero la carta che viene mostrata dal banco + le 2 carte che abbiam
        while True:
            probs = policy(state) # probabilità della policy
            # scelgo un'azione a caso dalle prob. della policy
            action = np.random.choice(np.arange(len(probs)), p= probs)
            next_state, reward, done , truncated, info = env.step(action)
            episode.append((state, action, reward))
            if done:
                break
            state = next_state

        # scorro tuti gli stati visitati nell'episodio e calcola il valore medio per ogni stato
        states_in_episode = set ([tuple(x[0]) for x in episode])
        for state in states_in_episode:

            first_occurence_idx = next(i for i,x in enumerate(episode) if x[0] == state)

            G = sum ([x[2]*(discont_factor**i) for i,x in enumerate(episode[first_occurence_idx:])])
            returns_sum[state] += G
            returns_count[state] += 1.0

            # media aritmetica
            V[state] = returns_sum[state] / returns_count[state]

    return V

def sample_policy(observation):
    """
    la policy che "sticks" ovvero si ferma se il punteggio del giocare è >= 20, altrimente prende una carta
    :param observation:
    :return:
    """
    score, dealer_score, usable_ace = observation
    return [1,0] if score >= 20 else [0,1]

V_10k = mc_prediction (sample_policy, env, num_episodies=10000)

```

**<span style="text-decoration: underline; color: rgb(22, 145, 121);">Metodo Temporal Difference</span>**

Il mtetodo **<span style="text-decoration: underline;">Temporal difference (TD)</span>**. E' un metodo iterativo, per prima cosa devi inizializzare tutti gli stati con dei valori che potrebbero anche essere random. Partendo dallo stato s faccio<span style="color: rgb(241, 196, 15);"> <span style="text-decoration: underline;">**una sola azione**</span></span> per arrivare nello stato s+1 e raccolgo il valore dello stato e la rimpensa corrispondente all'azione. Torno quindi allo stato in cui ero parito allo step (s) e aggiorno il valore. Come aggiorno il valore di S? <span style="color: rgb(224, 62, 45);">V(s) = V(s) + <span style="color: rgb(241, 196, 15);">α</span>(R + <span style="color: rgb(22, 145, 121);">ɣ</span>V(s+1) - Vs)</span> dove <span style="color: rgb(22, 145, 121);"><span style="color: rgb(241, 196, 15);">α</span> </span>è il fattore di apprendimento, più è grande più do importanza al valore restituito dallo stato s+1. Il che significa sommare il valore dello stato attuale alla somma data della reward più la differenza tra il valore dello stato successivo e il valore dello stato attuale, il tutto *moltiplicato per il tasso di<span style="text-decoration: underline;"> apprendimento alpha</span>*. Da notare che la differenza tra <span style="color: rgb(224, 62, 45);">V(s)</span> e <span style="color: rgb(22, 145, 121);">α</span><span style="color: rgb(224, 62, 45);">(R + <span style="color: rgb(22, 145, 121);">ɣ</span>V(s+1) - Vs)</span> è detta errore, che posso <span style="text-decoration: underline;">variare </span>con il tasso di apprendimento alpha. Poi si continua passando allo stato successvo e faccio la stessa cosa aggiornando V(s+1) con i valori ricavati da V(s+2). Anche quindi come con il MC faccio passare tutti gli stati S e lo faccio per N volte, anche in questo modo i valori convergeranno, dopo un numero considerevole di volte, al valore reale.

Esempio.

1. setto dei valori a caso per tutti gli stati (es, zero per tutti)
2. ad ogni passo sapendo che ho una stima per ogni stato mi metto nello stato di partenza S
3. nello stato V(S) faccio l'azione arrivando nello stato S' ottenendo 14 di ricompensa
4. la mia nuova stima di V(S) sarà quindi la ricompensana + il valore di S' -&gt; R+V(S') che essendo all'inizio V(S') varrà zero però..
5. la stima nuova non voglio utilizzarla completamente per inserirla nello stato S cerco quindi di "poderarla" in qualche modo, quindi sottrarò dalla stima il valore dello stato S ovvero V(S) che in gergo si chiama errore e lo sommo al valore di S.
6. Riassumendo V(S) = V(S) + <span style="color: rgb(22, 145, 121);">α</span>(errore) dove *l'errore* è (R(S') + V(S') - V(S))
7. faccio così per tutti gli stati

dove <span style="color: rgb(22, 145, 121);">α</span> è un iperparametro (numero) che rappresenta quanto viene valutata affidabile la stima

Nella pratica cerco di pesare il valore di V(S') tramite l'iperparametro <span style="color: rgb(22, 145, 121);">α</span> in considerazione del valore V(S')

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/scaled-1680-/iNEx5gGB9hbpRVSm-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/iNEx5gGB9hbpRVSm-image.png)

<span style="color: rgb(22, 145, 121);">**NB**</span>: qui faccio del **<span style="color: rgb(22, 145, 121);">boostrapping</span>**, ovvero ad ogni passo aggiorno le stime utilizzando le stime del passo precedente.

Di seguito lo pseudo-codice per la **<span style="color: rgb(22, 145, 121);">predizione</span>**.

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/scaled-1680-/KJUa6XOTxEIcblXv-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/KJUa6XOTxEIcblXv-image.png)

Dove ad ogni passo aggiorno il valore della funzione valore.


Differenze e analogie tra MC e TD

- MC funziona solo quando il task è <span style="color: rgb(241, 196, 15);">episodico</span>. (quando l'episodio finisce, in realtà esistono task infiniti) TD funziona anche con task continuativi. Nel metodo MC bisogna vedere i ritorni di tutti gli episodi, nel TD invece stiamo stimando il valore di uno stato usando la stima che avevamo prima. Ovvero, al passo <span style="color: rgb(22, 145, 121);">K+1</span> si stimano i valori degli stati usando i valori del passo <span style="color: rgb(22, 145, 121);">K</span> e per questo motivo si parla di "differenza temporale". TD apprende ad ogni passo, MC invece deve finire l'episodio. TD è un metodo <span style="color: rgb(241, 196, 15);">**ON-LINE**</span> ovvero che impara ad ogni passo, mentre MC è un metodo <span style="color: rgb(241, 196, 15);">**OFF-LINE**</span> perchè ha bisogno di finire l'episodio aggiornare le sue stime.
- Il MC sommando tutti i ritorni rischia di avere una <span style="text-decoration: underline;">varianza molto alta</span> in quanto i ritorni potrebbero variare inducendo un ampliamento totale dell'errore, per contro il TD non sommando tutti i ritorni, in quanto si ferma al solo stato successivo, r<span style="text-decoration: underline;">iduce la varianza dell'errore</span> quindi converge prima.
- TD è *distorto*, mentre MC non lo è.. un punto a favore di MC

Curiosità: diffrenze tra MC , TD e programmazione dinamica (vista a inizio corso)

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/scaled-1680-/v7BitcuvG1yD8A2d-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-01/v7BitcuvG1yD8A2d-image.png)

##### Model free -&gt; miglioramento e controllo

Nella predizione, viene sempre applicata la stessa policy, ovviamente anche la policy deve migliorare nel tempo, ecco che quindi dopo il ciclo di predizione deve seguire il ciclo di miglioramento e controllo della policy. Questo significa che i valori degli stati migliorerano nella fase di predizione e che la scelta degli stati stessi, conseguenza del miglioramento della policy, cambia in quanto le azioni cambiano (in genere) con il cambio della policy per via del miglioramento della stessa.

Esistono due famiglie di metodi per fare miglioramento e controllo, e sono:

1. On-policy MC control (controllo = iterazione del miglioramento con la predizione)
2. On-policy TD control (controllo = iterazione del miglioramento con la predizione)
3. Off-policy prediction
4. Off-policy control

Che differenza c'è tra i metodi on-policy e off-policy?

##### On-policy

Questi metodi nella pratica utilizzano la stessa policy migliorandola. Ovvero agendo "greedy" vengono scelte le azioni che massimizzano il risultato e che ne migliorarno la policy, ma, la policy seppur migliorata è sempre la stessa.

##### Off-policy

Con i metodi off-policy viene introdotto un fattore di "<span style="color: rgb(241, 196, 15);">**esplorazione**</span>" che in qualche modo crea delle policy nuove "*parallele*" a quella che stiamo migliorando, per poi metterle in qualche modo a confronto ed eventualmente cambiare la policy con quella nuova trovata tramite esplorazione.

##### General Policy Iteration

Come miglioro la policy? **<span style="text-decoration: underline;">Basta fare il calcolo della funzione valore stato-azione <span style="color: rgb(224, 62, 45); text-decoration: underline;">Q(s,a)</span> anzichè il valore della stato azione V(s)</span>** in modo da ottenere la probabilità dell'azione. Ok, ma questo non serve realmente per migliorare la policy in quanto agisce sempre in manidera greedy sulla stessa policy. Per migliorare la policy quindi è necessario scegliere "ogni tanto" delle azioni che non sono greedy in modo da effettuare **<span style="color: rgb(22, 145, 121);">l'esplorazione</span>**. Ricordo che per miglioramento della policy si intende: "**<span style="text-decoration: underline; color: rgb(22, 145, 121);">il valore della nuova policy è migliore della precedente in tutti gli stati</span>**".

##### Dilemma dell'esplorazione vs sfruttamento

Di qui il metodo "<span style="color: rgb(186, 55, 42);">**<span style="text-decoration: underline;">epsisodio greedy</span>**</span>" (**<span style="color: rgb(22, 145, 121);">ε</span>-greedy**) , dove epsilon è la <span style="text-decoration: underline;"><span style="color: rgb(22, 145, 121);">percentuale di scelta di una azione casuale</span></span>. (in genere un valore piccolo es. 10%)

Bisogna quindi lavorare con policy stato-azione con probabilità &gt; 0 in particolare la percentuale deve essere maggiore di <span style="color: rgb(22, 145, 121);">**ε**</span>. (questo concetto non mi è chiaro)

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/eRA9eWRjqnztGb43-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/eRA9eWRjqnztGb43-screenshot.png)

##### GL-IE (teorema generale)

Come deve funzionare l'algoritmo epsilon greedy? L'algoritmo da utilizzare è il GLIE che, per definizione, converge alla policy ottimale, ma cosa significa GLIE e come funziona?

<span style="color: rgb(224, 62, 45);">**GL**</span>= *greedy in the limit*: si richiede che nella policy iteration (valutazione della policy e miglioramento) che il miglioramento <span style="text-decoration: underline;">**tenda** </span>ad una policy greedy. Che significa che la policy a cui si converge è greedy.

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/3TRvqtsOPoHBIh6F-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/3TRvqtsOPoHBIh6F-screenshot.png)

**<span style="color: rgb(224, 62, 45);">IE</span>**= infinite exploration: tutte le coppie stato-azione siano visitate dall'algoritmo infinite volte. (richiesto dalla legge dei numeri)

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/dePn57Qp6TDci55h-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/dePn57Qp6TDci55h-screenshot.png)

Se <span style="color: rgb(224, 62, 45);">GL</span> e <span style="color: rgb(224, 62, 45);">IE </span>sono confermati ed implementati allora l'algoritmo è **ottimale**.

Ma come fare? La risposta è implementare l'algoritmo espisolon-greedy facendo in modo che epsilon decresca al crescere degli episodi k. Il che significa che ad un certo punto epsilon tenderà a zero.

##### On-policy MC (Monte Carlo)

Per calcolare la policy e migliorarla va usato il Q-Value.

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/21nqG3fL7yfT6Vz5-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/21nqG3fL7yfT6Vz5-screenshot.png)

##### Partenze esplorative (exploring starts)

Un altro algorino GLIE è per es. quello che implementa le "partenze esplorative" <span style="text-decoration: underline;">ovvero la scelta causale di uno stato di partenza.</span>

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/UkfnSvUzZK4tCFB1-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/UkfnSvUzZK4tCFB1-screenshot.png)

##### On-policy TD (temporal difference)

Anche per il TD dovremmo utilizzare il Q-Vaue, l'algoritmo da utilzzare si chiama "*Sarsa*".

Si chiama così perchè parte dalla coppia Stato-Azione vede ricompensa abbiamo ottenuto, vede lo stato successivo ottenuto, prende una nuova azione (quindi va in un nuovo nodo Stato-Azione) e si ferma. Ricordo che il concetto di stato stato nel "model free" è sempre riferito allo Stato-Azione. (vedi diagramma di backup sotto riportata)

[![Cattura.PNG](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/3oTaR5yQ4my7RsTL-cattura.PNG)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/3oTaR5yQ4my7RsTL-cattura.PNG)

*Predizione*

Per la fase di predizione TD, quando arrivo nel nuovo nodo vedo il valore Q-Value associato allo stato-azione di arrivo. Anche qui vale la formula classica di calcolo del valore stato per TD con la differenza che, essendo model free, dovremo utilizzare il Q-Value e quindi la combianazine <span style="color: rgb(241, 196, 15);">Stato-Azione</span>. Anche qui alpha rappresenta il fattore di apprendimento, la tabella dei q-value va anche qui va inizializzata con valori a piacimento, alla fine dei vari episodi il tutto dovrebbe convergere.

[![Cattura.PNG](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/0xAOGcXHhaxcFvAy-cattura.PNG)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/0xAOGcXHhaxcFvAy-cattura.PNG)

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-05/scaled-1680-/TZfJ1GxqfJHUDuNg-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-05/TZfJ1GxqfJHUDuNg-image.png)

e quindi il diagramma di convergenza

[![Cattura.PNG](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/U3x9POyYk0HBnoES-cattura.PNG)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/U3x9POyYk0HBnoES-cattura.PNG)

e lo psudo-codice:

Scegliamo il tasso di apprendimento (alpha), inizializziamo la tabella degli stati-azioni facendo attenzione a impostare il valore dello stato terminale a *zero*. (altrimenti avremo una distorsione nel valore iniziale che non verrà mai corretta)

*Controllo epsilon-greedy*

Per migliorare la policy utilizzo il metodo epsiolo-greedy ovvero partendo dalla matrice dove ogni cella contine il valori stato-azione...

Scegliamo la partenza, scegliamo un'azione dallo stato S utilizzando una policy epsilon-greedy. Quando lo stato è terminale riconciamo.

[![Cattura.PNG](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/1K4y8Fj70LPftzo3-cattura.PNG)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/1K4y8Fj70LPftzo3-cattura.PNG)

Funziona? si purchè siano soddisfatte delle ipotesi (teoriche) che sono:

1\) la successione di policy che ottengo devono tutte darmi tutte esplorazini infinite (soft) e devono essere greedy-in-limit, ovvero con espilon-greedy non costante, cioè che deve tendere - all'aumentare di k - al valore zero

2\) il tasso di apprendimento alpha che tende allo zero velocemente ma non troppo..

Però queste due condizioni teoriche non vengono quasi mai rispettate, quindi in genere si tengono come costanti

Esiste anche al versione a N step di Sarsa:

[![Cattura.PNG](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/0yPTcJlLwGu3isWX-cattura.PNG)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/0yPTcJlLwGu3isWX-cattura.PNG)

e questo lo pseudo codice:

[![Cattura.PNG](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/5i0mu5BZtNujhh67-cattura.PNG)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/5i0mu5BZtNujhh67-cattura.PNG)

#### Metodi off-policy

Con il metodo off-policy usiamo una policy "<span style="color: rgb(224, 62, 45);">**u**</span>" (mu) detta di "esplorazione" per fare un'esperienza (traiettoria) che ci dice come è fatto l'ambiente, uso questa esperienza per valutarne un'altra detta policy "target" "**<span style="color: rgb(224, 62, 45);">pi</span>**" (di miglioramento) e le confronto. Quindi nella pratica c'è <span style="color: rgb(241, 196, 15);">una policy che </span>**<span style="text-decoration: underline;"><span style="color: rgb(241, 196, 15); text-decoration: underline;">impara</span> </span>**<span style="color: rgb(224, 62, 45);">e</span> <span style="color: rgb(241, 196, 15);">una che fa **<span style="text-decoration: underline;">esperienza</span>**</span>. (esperinza detta anche policy comportamento)

*Difetti*

- questi metodi hanno una varianza molto alta e quindi convergenza molto lenta
- quando utilizzati + metodi non tabellari (rete neurali) + bootstrapping = non funziona

*Vantaggi*

- risolve il dilemma esplorazione-sfruttamento molto bene
- l'esperienza pregressa può essere acquisita (importata) dall'esterno ed essere sfruttata
- posso riusare quando voglio le esperienza generata nelle policy precedenti
- posso <span style="text-decoration: underline;">imparare policy multiple</span> ovvero seguo una policy da questa ne derivo N che possono essere tutte <span style="text-decoration: underline;">ottimali</span>

*Prerequisito di utilizzo*

Se un'azione ha probabilità positiva di essere scelta allora deve essere positiva anche la probabilità di scelta di un'azione della policy di comportamento, ovvero: <span style="color: rgb(224, 62, 45);">pi(s,a) &gt; 0 -&gt; u(s,a) &gt; 0</span>

*Quindi la policy che impariamo può/deve essere deterministica, mentre la policy di comportamento deve essere stocastica.*

*Predizione: Regole di update dei metodi di predizione off-policy:*

[![Cattura.PNG](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/MZ1fAH1k4uSCxNmh-cattura.PNG)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/MZ1fAH1k4uSCxNmh-cattura.PNG)

Viene suggerito di non considerare il metodo off-policy con MC in quanto, per via dei troppi stati da esplorare nell'episodio, viene generata troppa varianza dei valori, il che rende la formula molto complicata.

Invece il metodo off-polcy funziona bene con il temporal difference, in quanto il rapporto tra u (mu) e pi risulta essere un rapporto tra probabilità il che non presenta il difetto della varianza.

#### Predizine + miglioramento dei metodi off-policy

##### Controllo MC

Nonostante MC non sia forse il metodo migliore nell'ambito degli off-policy, l'algoritmo cmq esiste, ne riporto lo pseudo codice sotto:

[![Cattura.PNG](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/scaled-1680-/s12Zqvem7tLCNNdn-cattura.PNG)](https://cms.marcocucchi.it/uploads/images/gallery/2023-08/s12Zqvem7tLCNNdn-cattura.PNG)

Questo algoritmo nel 2019 ancora non era stato ben esplorato, per cui per in questo corso non verrà approfondito.

#### Controllo TD

Quando si lavora con i metodi *on-policy*, viene utilizzata la stessa policy per esplorare gli stati e la si faceva migliorare e tende ad essere la policy ottimale. Si era poi deciso che per mantere una policy che sia in grado, da un lato di migliorare in maniera greedy e che nel contempo possa anche eplorare, di utilizzare le epsilon-greedy ovvero che facesse anche dell'esplorazione mentre migliora.

A questo punto <span style="text-decoration: underline;">separiamo </span>le due policy, ovvero scegliamo una poloicy che esplora e usiamo l'esperienza fatta con questa per aggiornare un'altra policy, che è quella che piano piano diventa migliore e che a questo punto può essere totalmente greedy.

Il rapporto tra le due policy si chiama "rapporto di verosimilianza". Quando il rapporto tra i due è grande (pi/u)

##### Controllo Q-learning

I Q-learning sono una famiglia di algoritmi, dove l'azione nel target la scelgo con la policy pi di improvement.

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/scaled-1680-/Ar1tJndfpsS4zrYp-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/Ar1tJndfpsS4zrYp-screenshot.png)

che migliorata si può scrivere:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/scaled-1680-/C2ZG0d6YKfbwZLwq-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/C2ZG0d6YKfbwZLwq-screenshot.png)

dove la policy pi è scelta come max di Q ovvero in maniera greedy, mentre le altre azioni sono scelte con la policy "mu" esplorativa.

Nella pratica l'azione A viene scelta in maniera epsilo-greedy con la policu "mu" [![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-05/scaled-1680-/TVaa9YodW23eLhg8-image.png) ](https://cms.marcocucchi.it/uploads/images/gallery/2025-05/TVaa9YodW23eLhg8-image.png) mentre l'azione dello stato di arrivo St+1 è scelta con la polict greedy [![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2025-05/scaled-1680-/CuGjbNm7SA7HVpeW-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2025-05/CuGjbNm7SA7HVpeW-image.png)

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/scaled-1680-/y4Kat0RoWQp8vLem-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/y4Kat0RoWQp8vLem-screenshot.png)

Ippotizziamo ora questo esercizio, ovvero un mondo griglia con un burrone come sotto riportato:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/scaled-1680-/W2ehxBfw9WOKkUw0-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/W2ehxBfw9WOKkUw0-screenshot.png)

<div class="style-scope ytd-watch-metadata" id="bkmrk--34"><div class="item style-scope ytd-watch-metadata" id="bkmrk--35"></div></div>Vogliamo applicare l'algoritmo Sarsa e l'algoritmo Q-Learning. Sarsa è epsilo-greedy mentre Q-Learning è greedy. Quanto emerge viene riportato sotto:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/scaled-1680-/NavP9ZcxuiOHz30b-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/NavP9ZcxuiOHz30b-screenshot.png)

ovvero che Sarsa (blu) trova un percorso sub-ottimale, questo perchè essendo epsilong-greedy, tende a "rischiare" di meno e quindi sbagliare di meno. Mentre invece Q-learning è si ottimale, ma tende a rischiare di più. Q-Learning è quindi meglio? Dipende, se abbiamo a che fare con delle simultazioni, allora è sicuramente meglio, se invece abbiamo a che fare con il mondo reale dove i rischi sono reali allora è meglio scegliere una soluzione più "safe" come quella di Sarsa.

Se quindi misuro la somma delle ricompense il Q-learning ne riceve meno in quanto appunto rischia di più in quanto, nell'esempio tende a cadere maggiormente nel burrone. (vedi gradico sotto riportato)

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/scaled-1680-/apZxVfeO9mFqoL8w-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/apZxVfeO9mFqoL8w-screenshot.png)

##### Miglioramento della policy target pi Q-Learning (detto Sarsa Atteso o Expeted)

Target Q-Learning (predizione ovvero fissato pi) -&gt; R + gamma\*Q(S',A') dove A' è campionata di pi di S' che si scrive (A=pi(.|S')

ovvero:

[![Screenshot.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/scaled-1680-/4JYFNki6VKNCMlj0-screenshot.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-09/4JYFNki6VKNCMlj0-screenshot.png)

questo algoritmo migliora il Sarsa On-policy e il Q-Learning Off-policy.

Questo è un metodo che stima il modello, lo impara e lo usa man mano che lo imparano, sono detti "model based".

<div class="style-scope ytd-watch-metadata" id="bkmrk--41"><div class="item style-scope ytd-watch-metadata" id="bkmrk--42"></div></div>

# Sessione 1 (v2)

Premessa

In questa seconda versione del corso ho deciso di soffermarmi sui concetti che non avevo colto nella prima versione del corso stesso.

Le nozioni del primo corso rimangono valide e sono da utilizzare come integrazione di questa seconda versione.

La V2 quindi sintetizza i concetti che reputo più importanti.