TLDR

  • Nel Reinforcement Learning l'agente impara a compiere azioni ottimali per tentativi ed errori massimizzando le ricompense future.
  • I Processi Decisionali di Markov (MDP) modellano l'ambiente dove il futuro dipende unicamente dallo stato e dall'azione corrente.
  • L'Equazione di Bellman scompone ricorsivamente il valore di un'azione nella ricompensa immediata più il massimo ritorno futuro scontato.
  • Le Deep Q-Networks (DQN) superano la tabella Q con reti neurali stabilizzate da Experience Replay e Target Network.

Dalla Statica Predittiva all'Azione Intelligente

Negli articoli precedenti abbiamo esplorato modelli che analizzano dati passati per formulare previsioni o scoprire cluster. Con il Reinforcement Learning (RL), l'Intelligenza Artificiale compie il passo definitivo: diventa un'entità attiva capace di prendere decisioni sequenziali nel mondo reale per raggiungere un obiettivo complesso.

Dalla guida autonoma dei veicoli alla robotica chirurgica, fino al controllo di reattori a fusione nucleare (Tokamak) e alla vittoria contro i campioni mondiali di scacchi e Go (AlphaGo), il Reinforcement Learning è il paradigma matematico dell'autonomia decisionale.

Ciclo agente-ambiente del Reinforcement Learning
Il ciclo fondamentale del Reinforcement Learning: l'Agente percepisce lo Stato s, compie l'Azione a e riceve la Ricompensa r.
Guarda la video-lezione: Processi di Markov, Equazione di Bellman e atterraggio spaziale autonomo con DQN.

Il Formalismo dei Processi Decisionali di Markov (MDP)

Un problema di Reinforcement Learning viene formalizzato matematicamente come un Processo Decisionale di Markov (MDP), definito dalla tupla $\langle \mathcal{S}, \mathcal{A}, \mathcal{P}, \mathcal{R}, \gamma \rangle$:

  1. Insieme degli Stati ($\mathcal{S}$): Tutte le configurazioni possibili dell'ambiente (es. coordinate $x,y$, velocità $v_x, v_y$, angolo e velocità angolare di un modulo spaziale).
  2. Insieme delle Azioni ($\mathcal{A}$): Le decisioni discrete o continue a disposizione dell'agente (es. accendere propulsore sinistro, destro, centrale o nessun propulsore).
  3. Probabilità di Transizione ($\mathcal{P}(s' \mid s, a)$): La dinamica fisica dell'ambiente.
  4. Funzione di Ricompensa ($\mathcal{R}(s, a, s')$): Il segnale di feedback scalare ($+100$ per atterraggio riuscito, $-100$ per schianto, $-0.3$ per ogni accensione del motore per incentivare il risparmio di carburante).
  5. Fattore di Sconto ($\gamma \in [0, 1)$): Controlla l'orizzonte temporale della pianificazione.

Il Ritorno Cumulativo Scontato ($G_t$)

L'obiettivo dell'agente non è massimizzare la ricompensa immediata, ma la somma scontata delle ricompense future fino al termine dell'episodio:

$$G_t = R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \dots = \sum_{k=0}^{\infty} \gamma^k R_{t+k+1}$$


La Funzione di Valore $Q(s, a)$ e l'Equazione di Bellman

Definiamo la Funzione di Valore Stato-Azione $Q^*(s, a)$ come il ritorno atteso massimo che l'agente può ottenere partendo dallo stato $s$, compiendo l'azione $a$ e seguendo la politica ottima $\pi^*$ successivamente:

$$Q^(s, a) = \mathbb{E} \left[ R_{t+1} + \gamma \max_{a'} Q^(S_{t+1}, a') ;\middle|; S_t = s, A_t = a \right]$$

Questa relazione ricorsiva è la celebre Equazione di Bellman:

$$\mathbf{Q^(s, a) = r(s, a) + \gamma \max_{a'} Q^(s', a')}$$

Intuizione dell'Equazione di Bellman:
Il valore di un'azione compiuta oggi è pari alla ricompensa immediata $r$ più il massimo valore realizzabile nello stato successivo $s'$, scontato del fattore $\gamma$.

Una volta calcolata o approssimata la funzione $Q^(s, a)$, la **Politica Ottima $\pi^(s)$** si ricava semplicemente scegliendo l'azione che massimizza $Q$: $$\pi^(s) = \arg\max_a Q^(s, a)$$


Deep Q-Networks (DQN) per Spazi di Stato Continui

Nei giochi da tavolo semplici (come il Tris), $Q(s, a)$ può essere memorizzata in una tabella bidimensionale. Quando gli stati sono variabili fisiche continue nel tempo reale (es. coordinate e velocità con infiniti valori reali possibili), la tabella è impraticabile.

Le Deep Q-Networks (DQN) (introdotte da DeepMind nel 2015) sostituiscono la tabella con una Rete Neurale Profonda parametrizzata dai pesi $\theta$:

$$Q(s, a; \theta) \approx Q^*(s, a)$$

La rete riceve in input il vettore di stato $s \in \mathbb{R}^n$ e produce in output un vettore contenente il valore $Q$ stimato per ciascuna delle azioni possibili.

       Vettore di Stato s (Coordinate, Velocità, Angoli)
                                │
                                ▼
                   [ Dense Layer 1 (64 ReLU) ]
                                │
                                ▼
                   [ Dense Layer 2 (64 ReLU) ]
                                │
                                ▼
                   [ Output Layer (Lineare) ]
                                │
                                ▼
         Valori Q Stimati: [ Q(s, a0), Q(s, a1), Q(s, a2), Q(s, a3) ]

Le Due Invenzioni Chiave per la Stabilità: Replay Buffer e Target Network

L'addestramento diretto di reti neurali con l'equazione di Bellman fallisce miseramente se non vengono applicati due raffinamenti ingegneristici fondamentali:

1. Experience Replay Buffer ($\mathcal{D}$)

L'agente accumula le sue interazioni in un buffer di memoria circolare ad alta capienza sotto forma di tuple: $$\mathcal{D} = \left{ (s_t, a_t, r_t, s_{t+1}, \text{done}_t) \right}$$ Durante l'addestramento, l'algoritmo non usa i dati consecutivi dell'episodio corrente, ma estrae mini-batch casuali uniformi dal buffer. Questo spezza la forte correlazione temporale tra frame consecutivi e stabilizza la discesa del gradiente.

2. Target Network Separata ($\hat{Q}$ con pesi $\theta^-$)

Se calcolassimo la loss usando la stessa rete sia per la predizione $Q(s, a; \theta)$ sia per il bersaglio $r + \gamma \max_{a'} Q(s', a'; \theta)$, il bersaglio si muoverebbe caoticamente a ogni mini-passo di backprop (come provare a colpire un bersaglio mentre corre).

Si utilizza una seconda rete identica, la Target Network $\hat{Q}(s, a; \theta^-)$, i cui pesi vengono aggiornati molto lentamente (Soft Update con $\tau \ll 1$):

$$\text{Loss}(\theta) = \frac{1}{|B|} \sum_{(s, a, r, s', d) \in B} \left( \left[ r + \gamma (1 - d) \max_{a'} Q\left(s', a'; \theta^-\right) \right] - Q(s, a; \theta) \right)^2$$

$$\theta^- := \tau \theta + (1 - \tau) \theta^- \quad \text{con } \tau \approx 0.001$$


Esplorazione vs Sfruttamento: Politica $\epsilon$-Greedy

Per non rimanere intrappolato in strategie sub-ottimali, l'agente bilancia l'esplorazione e lo sfruttamento tramite la politica $\epsilon$-greedy:

$$a = \begin{cases} \text{Azione casuale scelta uniformemente} & \text{con probabilità } \epsilon \ \arg\max_{a'} Q(s, a'; \theta) & \text{con probabilità } 1 - \epsilon \end{cases}$$

Il valore di $\epsilon$ parte solitamente da $1.0$ (100% esplorazione casuale all'inizio) e decade esponenzialmente ad ogni episodio fino a un valore minimo $\epsilon_{\min} \approx 0.01$.


Laboratorio Pratico: Agente Deep Q-Learning in Python / PyTorch

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import random
from collections import deque

# 1. Definizione Rete Neurale Q-Network
class QNetwork(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(state_dim, 64),
            nn.ReLU(),
            nn.Linear(64, 64),
            nn.ReLU(),
            nn.Linear(64, action_dim)
        )
        
    def forward(self, x):
        return self.net(x)

# 2. Struttura Replay Buffer
class ReplayBuffer:
    def __init__(self, capacity=50000):
        self.buffer = deque(maxlen=capacity)
        
    def push(self, state, action, reward, next_state, done):
        self.buffer.append((state, action, reward, next_state, done))
        
    def sample(self, batch_size):
        batch = random.sample(self.buffer, batch_size)
        s, a, r, ns, d = zip(*batch)
        return (
            torch.FloatTensor(np.array(s)),
            torch.LongTensor(a),
            torch.FloatTensor(r),
            torch.FloatTensor(np.array(ns)),
            torch.FloatTensor(d)
        )
        
    def __len__(self):
        return len(self.buffer)

# 3. Addestramento Mini-Batch DQN
def train_dqn_step(q_net, target_net, buffer, optimizer, batch_size=64, gamma=0.99):
    if len(buffer) < batch_size:
        return 0.0
        
    states, actions, rewards, next_states, dones = buffer.sample(batch_size)
    
    # Valori Q attuali stimati per l'azione eseguita
    q_values = q_net(states).gather(1, actions.unsqueeze(1)).squeeze(1)
    
    # Bersaglio di Bellman calcolato con la Target Network congelata
    with torch.no_grad():
        next_q_values = target_net(next_states).max(1)[0]
        expected_q = rewards + gamma * next_q_values * (1.0 - dones)
        
    loss = nn.MSELoss()(q_values, expected_q)
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    return loss.item()

# 4. Inizializzazione e Soft Update
state_dim, action_dim = 8, 4 # Parametri ambiente tipo Lunar Lander
q_net = QNetwork(state_dim, action_dim)
target_net = QNetwork(state_dim, action_dim)
target_net.load_state_dict(q_net.state_dict())
optimizer = optim.Adam(q_net.parameters(), lr=5e-4)
buffer = ReplayBuffer()

# Riempimento buffer con transizioni di prova
for _ in range(200):
    s = np.random.randn(state_dim)
    a = np.random.randint(0, action_dim)
    r = np.random.randn()
    ns = np.random.randn(state_dim)
    d = float(random.random() > 0.95)
    buffer.push(s, a, r, ns, d)

# Esecuzione ciclo di ottimizzazione
loss_val = train_dqn_step(q_net, target_net, buffer, optimizer)
print(f"DQN Training Step completato con successo: Loss MSE = {loss_val:.4f}")

Sintesi del Percorso di Machine Learning

Con questo articolo si completa il manuale completo di Machine Learning su Able2Code:

  1. Dalla Mappa Concettuale e dalle basi di Regressione Lineare e Logistica;
  2. Alla Tassonomia dei 9 Algoritmi e alla Diagnostica di Bias e Varianza;
  3. Dalle Reti Neurali Profonde ai Modelli Transformer e Fine-Tuning PEFT a 13 parametri;
  4. Fino all'Apprendimento Non Supervisionato, ai Sistemi di Raccomandazione Two-Tower e al Reinforcement Learning con l'Equazione di Bellman.

Un bagaglio teorico, matematico e applicativo completo per comprendere, progettare e scalare sistemi intelligenti di livello industriale.

FAQ

Qual è la differenza fondamentale tra Reinforcement Learning e Supervised Learning?

Nel Supervised Learning il modello viene istruito con esempi corretti noti etichettati dall'uomo. Nel Reinforcement Learning non esiste alcuna risposta corretta predeterminata: l'agente esplora autonomamente l'ambiente e apprende per tentativi ed errori ricevendo ricompense positive o penalità.

Cosa rappresenta il fattore di sconto gamma nell'Equazione di Bellman?

Il fattore di sconto gamma (compreso tra 0 e 1, es. 0.99) quantifica quanto l'agente valuti le ricompense future rispetto a quelle immediate. Se gamma è vicino a 0, l'agente è miope e cerca solo gratificazioni istantanee; se gamma è vicino a 1, l'agente pianifica strategie di lungo termine.

Cos'è il dilemma dell'Esplorazione vs Sfruttamento (Exploration vs Exploitation)?

È il bilanciamento tra compiere l'azione che si ritiene migliore in base all'esperienza attuale (Sfruttamento/Exploitation) e compiere un'azione casuale o nuova per scoprire se conduce a ricompense ancora più elevate (Esplorazione/Exploration). La politica epsilon-greedy modella matematicamente questo equilibrio.

A cosa serve l'Experience Replay Buffer nelle Deep Q-Networks?

Nelle transizioni temporali consecutive (s_t, a_t, s_t+1), gli stati successivi sono fortemente correlati tra loro, rendendo instabile l'addestramento della rete. L'Experience Replay memorizza migliaia di transizioni in una memoria circolare e ne estrae mini-batch casuali, rompendo la correlazione temporale.

Perché è necessaria una Target Network separata in DQN?

Se usassimo la stessa rete sia per predire Q(s,a) sia per calcolare il bersaglio di regressione r + gamma * max Q(s',a'), il bersaglio si muoverebbe caoticamente a ogni aggiornamento dei pesi. La Target Network mantiene i pesi congelati e li aggiorna lentamente (Soft Update), garantendo una convergenza stabile.

Fonti