L’Apprendimento per rinforzo: il bastone e la carota in versione algoritmica.

L’Apprendimento per rinforzo: il bastone e la carota in versione algoritmica.

Condividi con i tuoi amici...

Le ricompense e le punizioni hanno un ruolo fondamentale nell’apprendimento umano e non solo, e questa è una scoperta che risale ai tempi antichi. Fin dagli albori della civiltà, abbiamo capito che premiare un comportamento desiderato o punire un comportamento indesiderato può essere un potente strumento per influenzare il comportamento di una persona. Questo principio si applica anche all’addestramento degli animali e all’educazione dei bambini.

Nel mondo animale, le tecniche di addestramento basate su ricompense e punizioni sono state utilizzate per secoli. Un esempio noto è l’addestramento dei cani, in cui si utilizza spesso un sistema di premi come biscotti o giocattoli per rinforzare un comportamento desiderato e sanzioni come il ritiro dell’attenzione o un suono sgradevole per scoraggiare comportamenti indesiderati.

Nel contesto dell’educazione umana, l’uso di ricompense e punizioni ha giocato un ruolo importante nella formazione dei bambini. Ad esempio, i genitori spesso elargiscono dolci come premio per un buon comportamento o ritirano un privilegio come una gita al parco per un comportamento indesiderato. Questo ha lo scopo di associare una reazione positiva o negativa a un determinato comportamento e, quindi, favorire la sua ripetizione o scoraggiarla.

Ma cosa dice la scienza su questo argomento? Negli ultimi decenni, numerosi studi hanno dimostrato l’efficacia delle ricompense e delle punizioni nell’apprendimento umano. Uno degli esperimenti classici in questo campo è stato condotto dallo psicologo americano Edward L. Thorndike alla fine del XIX secolo.

Thorndike ha condotto studi sull’apprendimento negli animali, in particolare nei gatti. Nei suoi esperimenti, ha posto i gatti in una scatola speciale da cui potevano fuggire solo attraverso una serie di azioni specifiche come tirare una corda o premere un pulsante. All’inizio, i gatti si trovavano a scartare diverse azioni sbagliate prima di arrivare alla soluzione corretta. Ma col passare del tempo, grazie al principio delle ricompense (come un pezzetto di cibo all’esterno della scatola) e delle punizioni (come la mancanza di cibo se non si riusciva a fuggire), i gatti imparavano a raggiungere l’obiettivo più rapidamente.

Questi esperimenti supportarono la teoria di Thorndike sull’apprendimento degli animali, conosciuta come “legge dell’effetto”.

Secondo la teoria nota come “legge dell’effetto”, un comportamento che porta a conseguenze piacevoli tende ad essere ripetuto, mentre un comportamento che porta a conseguenze spiacevoli tende a essere evitato.

Il lavoro di Thorndike ha avuto un impatto significativo sulla psicologia dell’apprendimento e ha fornito una base solida per ulteriori scoperte nel campo. Studi successivi hanno confermato che il principio delle ricompense e delle punizioni è valido anche per l’apprendimento umano. Ad esempio, la pratica dell’economia comportamentale si basa sulla teoria dell’apprendimento attraverso incentivi e disincentivi, dimostrando come le persone possano essere influenzate nel prendere decisioni economiche in base a ricompense e punizioni.

L’intelligenza artificiale e l’apprendimento per rinforzo

Il metodo di apprendimento appena descritto può essere riprodotto per addestrare i modelli di intelligenza artificiale. In pratica, ciò significa creare degli algoritmi che applicano il concetto di apprendimento per rinforzo.

L’apprendimento per rinforzo è un tipo di apprendimento automatico in cui un agente impara a compiere azioni in un ambiente al fine di massimizzare un segnale di ricompensa.

L’agente esplora l’ambiente, compie azioni e riceve ricompense o penalità, imparando così una strategia che associa alle situazioni (stati) le azioni da compiere che ottimizzano la ricompensa totale nel tempo.

Definiamo gli elementi in gioco:

L’Agente è l’entità che compie azioni.
L’Ambiente è il contesto in cui l’agente opera.
Lo stato è una rappresentazione dell’ambiente in un dato momento.
L’azione è un’operazione compiuta dall’agente sul ambiente.
La ricompensa è un segnale ricevuto dall’agente dopo aver compiuto un’azione, che indica il successo o il fallimento dell’azione.
La strategia è uno schema che l’agente usa per decidere quale azione compiere in un dato stato.

Ecco uno schema semplificato del processo:

-L’agente osserva lo stato corrente dell’ambiente.
-In base alla strategia, l’agente sceglie un’azione da compiere.
-L’agente compie l’azione scelta e riceve una ricompensa dall’ambiente.
-L’agente usa la ricompensa per aggiornare la sua strategia, migliorando la sua capacità di scegliere azioni future.
-Il processo si ripete, con l’agente che continua ad apprendere e ad aggiornare la sua strategia.

La strategia può essere deterministica o stocastica. Una politica deterministica associa uno stato specifico ad una specifica azione, mentre una strategia stocastica associa ad ogni stato una probabilità per ciascuna azione.

A livello algoritmico, una strategia può essere rappresentata in diversi modi. Un esempio semplice è una tabella (tavola Q) che associa a ciascun stato-azione un valore. L’agente sceglie l’azione che massimizza questo valore, possibilmente con qualche meccanismo di esplorazione come la strategia ε-greedy, che sceglie occasionalmente un’azione casuale per esplorare l’ambiente.

In casi più complessi, la strategia può essere rappresentata da un modello parametrico, come una rete neurale, che prende uno stato come input e produce le probabilità delle azioni come output. L’apprendimento consiste nell’aggiornare i parametri del modello (i pesi della rete neurale, per esempio) per migliorare la strategia.

Esempio: l’algoritmo Q-learning

Un esempio classico di apprendimento per rinforzo è l’algoritmo Q-learning, un tipo di apprendimento TD (Temporal Difference). In Q-learning, la funzione di valore azione, Q(s,a), rappresenta il valore atteso di eseguire un’azione a in uno stato s.

La formula di aggiornamento per Q-learning è:

Q'(s,a) = (1−α)⋅Q(s,a)+α⋅(r+γ⋅max⁡aQ(s′,a))Q(s,a)

Dove:

s è lo stato attuale.
a è l’azione compiuta.
s′ è lo stato successivo.
r è la ricompensa ricevuta.
α è il tasso di apprendimento, che controlla quanto l’aggiornamento incide sul valore corrente di Q.
γ è il fattore di sconto, che determina l’importanza delle ricompense future rispetto a quelle immediate.
max⁡aQ(s′,a) rappresenta il massimo valore di Q per lo stato successivo s′, tenendo conto di tutte le possibili azioni.

Per scegliere un’azione, si può utilizzare una strategia ε-greedy. Con probabilità 1−ϵ, si sceglie l’azione che massimizza Q(s,a) per lo stato corrente s, e con probabilità ϵ, si sceglie un’azione casuale. Questo bilancia tra l’esplorazione di nuove azioni e i risultati ottenuti dalle azioni già conosciute.

Matematicamente, la scelta ε-greedy si può esprimere come:

  • argmaxaQ(st,a) con probabilita 1−ϵ
  • un’azione casuale con probabilita ϵ

Dove at è l’azione scelta al tempo t e st è lo stato al tempo t.

Esempio di codice Python

L’obiettivo del seguente codice è quello di insegnare a un “agente” come muoversi in una griglia 3×3 per trovare la posizione con la ricompensa migliore.

Pensa alla griglia come a un piccolo tabellone da gioco. In alcune caselle ci sono delle ricompense (un premio o una penalità). L’agente inizia da una posizione casuale e può muoversi su, giù, a sinistra o a destra. Vuole imparare quale sequenza di mosse gli darà la migliore ricompensa nel minor tempo possibile.

Per farlo, l’agente gioca molte partite (o “episodi”) sulla griglia. In ogni partita:

A volte prova una mossa casuale, per esplorare nuovi percorsi. Altre volte, si basa su ciò che ha imparato finora per fare la mossa che pensa gli darà la migliore ricompensa. Dopo ogni mossa, aggiorna la sua “memoria” (chiamata Q) sulla bontà della mossa effettuata.

Dopo aver giocato molte partite, l’agente ha una buona idea di quale sequenza di mosse gli darà la migliore ricompensa. Il codice poi stampa questa “memoria” alla fine, mostrandoci quanto l’agente valuta ogni possibile mossa a partire da ogni casella della griglia.

CODICE

import numpy as np
import random

# Parametri
alpha = 0.5  # tasso di apprendimento
gamma = 0.9  # fattore di sconto
epsilon = 0.1  # probabilità di esplorazione
num_episodes = 1000  # numero di episodi

# Ambiente: Griglia 3x3 con ricompensa +1 in (2,2) e -1 in (2,0)
states = [(i, j) for i in range(3) for j in range(3)]
actions = ["up", "down", "left", "right"]
rewards = {(2, 2): 1, (2, 0): -1}

# Inizializzazione della funzione Q
Q = {(s, a): 0 for s in states for a in actions}

# Funzione per eseguire un'azione e ricevere la ricompensa e lo stato successivo
def step(s, a):
    x, y = s
    if a == "up": x = max(0, x-1)
    if a == "down": x = min(2, x+1)
    if a == "left": y = max(0, y-1)
    if a == "right": y = min(2, y+1)
    s_prime = (x, y)
    return s_prime, rewards.get(s_prime, 0)

# Training
for episode in range(num_episodes):
    s = random.choice(states)  # stato iniziale casuale
    done = False
    while not done:
        # Politica epsilon-greedy
        if random.uniform(0, 1) < epsilon:
            a = random.choice(actions)
        else:
            a = max(actions, key=lambda a: Q[s, a])

        s_prime, reward = step(s, a)
        done = s_prime in rewards  # episodio termina quando si riceve una ricompensa

        # Aggiornamento Q
        Q_max = max(Q[s_prime, a_prime] for a_prime in actions)
        Q[s, a] = (1 - alpha) * Q[s, a] + alpha * (reward + gamma * Q_max)

        s = s_prime  # passa al prossimo stato

# Stampa la funzione Q appresa
for s in states:
    print(s, {a: Q[s, a] for a in actions})


CLICCA SULL'IMMAGINE PER INGRANDIRLA

OUTPUT (per ogni stato (i,j) vengono stampati valori di Q(s,a) associati ad ogni azione possibile a partire da quello stato. Un’azione verso il margine equivale a star fermi)

(0, 0) {‘up’: 3.450276507610707, ‘down’: 3.087092510059749, ‘left’: 3.4771199658278418, ‘right’: 4.307415916766567}
(0, 1) {‘up’: 3.8363380746269717, ‘down’: 4.251257415858595, ‘left’: 3.5825612334650376, ‘right’: 4.955227011316431}
(0, 2) {‘up’: 4.338274017880813, ‘down’: 5.686649005642511, ‘left’: 3.8309626317422847, ‘right’: 4.260080129893787}
(1, 0) {‘up’: 3.452699496150789, ‘down’: 1.0652998471671893, ‘left’: 2.652610791285514, ‘right’: 4.379794045367323}
(1, 1) {‘up’: 3.5625936651429457, ‘down’: 3.7367037986259555, ‘left’: 3.094092707587938, ‘right’: 5.553821243976246}
(1, 2) {‘up’: 4.37073699199273, ‘down’: 6.456295964553847, ‘left’: 4.262789823532971, ‘right’: 4.922963784936339}
(2, 0) {‘up’: 2.7616172749494963, ‘down’: 1.6700247149455065, ‘left’: 1.220727396335836, ‘right’: 4.822277144323348}
(2, 1) {‘up’: 4.2620986608047975, ‘down’: 4.1307052381913, ‘left’: 2.742059424271321, ‘right’: 6.102222662806238}
(2, 2) {‘up’: 4.736697667522829, ‘down’: 6.1142138645824895, ‘left’: 3.899735790582084, ‘right’: 3.9305523252083576}

Valutiamo la ragionevolezza del risultato

(0, 0): Andare a destra ha il valore più alto. Ancora una volta, muovendosi verso destra (o in basso) ci si avvicina alla posizione (2, 2) dove c’è la ricompensa principale.

(0, 1): Andare a destra ha il valore più alto. L’agente percepisce che muovendosi a destra da questa posizione è la mossa che porta alla maggior parte delle ricompense.

(0, 2): Andare in basso ha il valore più alto, portando l’agente direttamente verso la ricompensa in (2, 2).

(1, 0): Muoversi in alto o a destra ha valori elevati, con una leggera preferenza per il movimento verso destra.

(1, 1): La mossa migliore qui è andare a destra. Muovendosi a destra, l’agente si avvicina alla ricompensa.

(1, 2): Ancora una volta, andare in basso ha il valore più alto, che è la mossa ottimale per arrivare direttamente alla ricompensa.

(2, 0): Andare a destra ha il valore più alto. Questa mossa porta l’agente verso la ricompensa in (2, 2), allontanandolo dalla penalità.

(2, 1): Andare a destra ha il valore più alto. Ancora una volta, questo avvicina l’agente alla ricompensa.

(2, 2): Questo è lo stato con la ricompensa principale. L’azione di muoversi in alto ha il valore più alto, il che indica che l’agente ha imparato che, anche se ha raggiunto la ricompensa, muovendosi in alto potrebbe ancora accumulare ulteriori ricompense in episodi futuri.

Note sui parametri

I parametri specificati sono comuni nelle implementazioni di Q-learning, ma è sempre possibile fare delle considerazioni e dei suggerimenti sulla base di questi valori:

alpha (tasso di apprendimento): alpha=0.5 significa che l’agente considera il 50% del nuovo valore Q e il 50% del vecchio valore Q durante l’aggiornamento.

gamma (fattore di sconto): Con gamma=0.9, si sta dando un’alta considerazione alle ricompense future. Questo dovrebbe andare bene per la maggior parte dei problemi, ma se si ritiene che l’agente debba focalizzarsi di più sulle ricompense immediate, si potrebbe ridurre questo valore.

epsilon (probabilità di esplorazione): epsilon=0.1 significa che l’agente sceglie un’azione casuale il 10% delle volte. Se si ritiene che l’agente non stia esplorando abbastanza, potresti considerare di aumentare questo valore. Un’alternativa potrebbe essere l’implementazione di un “epsilon-decrescente”, dove epsilon inizia alto (es. 0.9) e diminuisce gradualmente nel tempo, permettendo all’agente di esplorare molto all’inizio e sfruttare di più man mano che apprende.

num_episodes (numero di episodi): num_episodes=1000 potrebbe essere sufficiente, ma dipende dalla complessità dell’ambiente. Se dopo 1000 episodi l’agente non ha ancora appreso una strategia efficace, si potrebbe considerare di aumentare il numero di episodi.