Apprendimento per rinforzo con Gymnasium: Una guida pratica

Apprendimento per Rinforzo (RL) è uno dei tre principali paradigmi di apprendimento automatico, gli altri due sono l’apprendimento supervisionato e l’apprendimento non supervisionato. Nell’RL, un agente impara a interagire con il proprio ambiente per massimizzare i premi cumulativi. Impara l’azione ottimale sotto diverse condizioni ambientali attraverso tentativi ed errori. Apprendimento per Rinforzo con Feedback Umano (RLHF) consente all’agente di modificare il comportamento in base agli input umani a ogni passo.

RL risolve problemi come le auto a guida autonoma, il trading automatizzato, i giocatori computerizzati nei videogiochi, la formazione di robot e altro ancora. Quando le reti neurali profonde vengono utilizzate per applicare algoritmi RL, si parla di Apprendimento per Rinforzo Profondo.

In questo tutorial, ti mostrerò come iniziare con Gymnasium, una libreria Python open-source per sviluppare e confrontare algoritmi di apprendimento per rinforzo. Dimostrerò come configurarlo, esplorare vari ambienti RL e utilizzare Python per costruire un semplice agente per implementare un algoritmo RL.

Cosa è Gymnasium?

Gymnasium è una libreria Python open-source progettata per supportare lo sviluppo di algoritmi di RL. Per facilitare la ricerca e lo sviluppo nel RL, Gymnasium offre:

  • Una vasta gamma di ambienti, da semplici giochi a problemi che imitano scenari della vita reale.
  • API e wrapper semplificati per interfacciarsi con gli ambienti.
  • La possibilità di creare ambienti personalizzati e sfruttare il framework API.

Gli sviluppatori possono costruire algoritmi di RL e utilizzare chiamate API per attività come:

  • Passare l’azione scelta dall’agente all’ambiente.
  • Conoscere lo stato dell’ambiente e il premio dopo ogni azione.
  • Addestrare il modello.
  • Testare le prestazioni del modello.

OpenAI’s Gym versus Farama’s Gymnasium

OpenAI non ha dedicato risorse significative allo sviluppo di Gym perché non era una priorità commerciale per l’azienda. La Fondazione Farama è stata creata per standardizzare e mantenere le librerie RL a lungo termine. Gymnasium è il fork della Fondazione Farama di Gym di OpenAI. Gymnasium 0.26.2 è un sostituto diretto di Gym 0.26.2. Con il fork, Farama mira ad aggiungere metodi funzionali (oltre a quelli basati su classi) per tutte le chiamate API, supportare gli ambienti vettoriali e migliorare i wrapper. L’obiettivo generale è rendere il framework più pulito e efficiente.

Configurazione di Gymnasium

Gymnasium necessita versioni specifiche (non le ultime versioni) di vari programmi di dipendenza come NumPy e PyTorch. Pertanto, raccomandiamo di creare un nuovo ambiente Conda o venv o un nuovo notebook per installare, utilizzare Gymnasium e eseguire programmi RL.

Puoi utilizzare questo quaderno DataLab per seguire il tutorial.

Installazione di Gymnasium

Per installare Gymnasium su un server o su una macchina locale, eseguire:

$ pip install gymnasium

Per installare utilizzando un Notebook come Google Colab o DataLab di DataCamp, utilizzare:

!pip install gymnasium

Il comando sopra installa Gymnasium e le versioni corrette delle dipendenze.

Esplorare gli ambienti di Gymnasium

Da novembre 2024, Gymnasium include oltre 60 ambienti integrati. Per visualizzare gli ambienti integrati disponibili, utilizzare la funzione gym.envs.registry.all(), come illustrato nell’esempio seguente:

import gymnasium as gym for i in gym.envs.registry.keys(): print(i)

Puoi anche visitare la homepage di Gymnasium. La colonna sinistra ha link a tutti gli ambienti. La pagina web di ogni ambiente include dettagli su di esso, come azioni, stati, ecc. 

Gli ambienti sono organizzati in categorie come Classic Control, Box2D e altro. Di seguito, elenco alcuni degli ambienti comuni in ogni gruppo:

  • Classic Control: Questi sono ambienti canonici utilizzati nello sviluppo di RL; formano la base di molti esempi da manuale. Offrono il giusto mix di complessità e semplicità per testare e valutare nuovi algoritmi RL. Gli ambienti di controllo classico in Gymnasium includono: 
    • Acrobot
    • Cart Pole
    • Mountain Car Discreto
    • Mountain Car Continuo
    • Pendolo
  • Box2D: Box2D è un motore fisico 2D per giochi. Gli ambienti basati su questo motore includono giochi semplici come:
    • Lunar Lander
    • Car Racing
  • ToyText: Questi sono ambienti piccoli e semplici spesso usati per il debug degli algoritmi RL. Molti di questi ambienti sono basati sul modello del piccolo mondo a griglia e su semplici giochi di carte. Esempi includono: 
    • Blackjack
    • Taxi
    • Frozen Lake
  • MuJoCo: Multi-Joint dynamics with Contact (MuJoCo) è un motore fisico open-source che simula ambienti per applicazioni come robotica, biomeccanica, ML, ecc. Gli ambienti MuJoCo in Gymnasium includono:
    • Ant
    • Hopper
    • Humanoid
    • Swimmer
    • E altro ancora

Oltre agli ambienti integrati, Gymnasium può essere usato con molti ambienti esterni utilizzando la stessa API.

Utilizzeremo uno degli ambienti di controllo classici canonici in questo tutorial. Per importare un ambiente specifico, utilizzare il comando .make() e passare il nome dell’ambiente come argomento. Ad esempio, per creare un nuovo ambiente basato su CartPole (versione 1), utilizzare il comando qui sotto:

import gymnasium as gym env = gym.make("CartPole-v1")

Comprensione dei Concetti di Apprendimento per Rinforzo in Palestra

In poche parole, l’Apprendimento per Rinforzo consiste in un agente (come un robot) che interagisce con il suo ambiente. Una policy decide le azioni dell’agente. A seconda delle azioni dell’agente, l’ambiente fornisce una ricompensa (o una penalità) ad ogni passaggio temporale. L’agente utilizza l’RL per capire la policy ottimale che massimizza le ricompense totali guadagnate dall’agente.

Componenti di un ambiente di RL

I seguenti sono i componenti chiave di un ambiente di RL:

  • Ambiente: Il sistema esterno, il mondo o il contesto. L’agente interagisce con l’ambiente in una serie di passaggi temporali. In ciascun passaggio temporale, in base all’azione dell’agente, l’ambiente:
    • Fornisce una ricompensa (o penalità)
    • Decide il prossimo stato
  • Stato: Una rappresentazione matematica della configurazione attuale dell’ambiente.
    • Ad esempio, lo stato di un ambiente a pendolo può includere la posizione del pendolo e la velocità angolare in ciascun passaggio temporale.
    • Stato terminale: Uno stato che non porta a nuovi/altri stati.
  • Agente: L’algoritmo che osserva l’ambiente e compie varie azioni basate su quest’osservazione. L’obiettivo dell’agente è massimizzare i suoi premi.
    • Ad esempio, l’agente decide quanto duramente e in che direzione spingere il pendolo.
  • Osservazione: Rappresentazione matematica della visione dell’agente dell’ambiente, acquisita, ad esempio, utilizzando sensori.
  • Azione: La decisione presa dall’agente prima di procedere al passo successivo. L’azione influisce sullo stato successivo dell’ambiente e guadagna all’agente una ricompensa.
  • Ricompensa: Il feedback dall’ambiente all’agente. Può essere positivo o negativo, a seconda dell’azione e dello stato dell’ambiente.
  • Ritorno:Il ritorno cumulativo previsto nei prossimi passaggi. Le ricompense dai prossimi passaggi possono essere scontate utilizzando un fattore di sconto.
  • Politica:La strategia dell’agente su quale azione intraprendere in vari stati. È tipicamente rappresentata come una matrice di probabilità, P, che mappa gli stati alle azioni.
    • Data un insieme finito di m stati possibili e n azioni possibili, l’elemento Pmn nella matrice denota la probabilità di intraprendere l’azione an nello stato sm.  
  • Episodio: La serie di passaggi temporali dallo stato iniziale (casuale) fino a quando l’agente raggiunge uno stato terminale.

Spazio di osservazione e spazio di azione

L’osservazione è l’informazione che l’agente raccoglie sull’ambiente. Un agente, ad esempio un robot, potrebbe raccogliere informazioni ambientali utilizzando sensori. Idealmente, l’agente dovrebbe essere in grado di osservare lo stato completo, che descrive tutti gli aspetti dell’ambiente. In pratica, l’agente utilizza le sue osservazioni come proxy per lo stato. Quindi, le osservazioni determinano le azioni dell’agente.

Uno spazio è analogo a un insieme matematico. Lo spazio degli elementi X include tutte le possibili istanze di X. Lo spazio di X definisce anche la struttura (sintassi e formato) di tutti gli elementi di tipo X. Ogni ambiente Gymnasium ha due spazi, lo spazio azione, action_space, e lo spazio osservazione, observation_space. Sia lo spazio azione che lo spazio osservazione derivano dalla superclasse genitore gymnasium.spaces.Space

Spazio di osservazione

Lo spazio di osservazione è lo spazio che include tutte le osservazioni possibili. Definisce anche il formato in cui le osservazioni sono memorizzate. Lo spazio di osservazione è tipicamente rappresentato come un oggetto di tipo Box. Questo è un ndarray che descrive i parametri delle osservazioni. La scatola specifica i limiti di ciascuna dimensione. Puoi visualizzare lo spazio di osservazione per un ambiente utilizzando il metodo observation_space:

print("observation space: ", env.observation_space)

Nel caso dell’ambiente CartPole-v1, l’output appare come nell’esempio sottostante:

observation space: Box([-4.8 -inf -0.41887903 -inf], [4.8 inf 0.41887903 inf], (4,), float32)

In questo esempio, lo spazio delle osservazioni di CartPole-v1 ha 4 dimensioni. Gli 4 elementi dell’array di osservazioni sono:

  • Posizione del carrello – varia tra -4.8 e +4.8
  • Velocità del carrello – varia tra e +
  • Angolo del palo – varia tra -0.4189 e +0.4189
  • Velocità angolare del polo – varia tra e +

Per vedere un esempio di un array di osservazione individuale, utilizza il comando .reset()

observation, info = env.reset() print("observation: ", observation)

Nel caso dell’ambiente CartPole-v1, l’output appare come nell’esempio qui sotto:

[ 0.03481963 -0.0277232 0.01703267 -0.04870504]

Gli elementi di questo array corrispondono alle quattro quantità osservate (posizione del carrello, velocità del carrello, angolo del palo, velocità angolare del palo), come spiegato in precedenza.

Spazio azioni

Lo spazio azioni include tutte le azioni possibili che l’agente può intraprendere. Lo spazio azioni definisce anche il formato in cui le azioni sono rappresentate. Puoi visualizzare lo spazio azioni per un ambiente utilizzando il metodo action_space:

print("action space: ", env.action_space)

Nel caso dell’ambiente CartPole-v1, l’output appare come nell’esempio seguente:

action space: Discrete(2)

Nel caso dell’ambiente CartPole-v1, lo spazio delle azioni è discreto. Ci sono un totale di due azioni che l’agente può compiere:

  • 0: Spingere il carrello verso sinistra
  • 1: Spingere il carrello verso destra

Costruzione del tuo primo agente di RL con Gymnasium

Nelle sezioni precedenti, abbiamo esplorato i concetti di base del RL e del Gymnasium. Questa sezione ti mostra come utilizzare il Gymnasium per costruire un agente RL.

Creare e ripristinare l’ambiente

Il primo passo è creare un’istanza dell’ambiente. Per creare nuovi ambienti, utilizza il metodo .make().

env = gym.make('CartPole-v1')

Le interazioni dell’agente cambiano lo stato dell’ambiente. Il metodo .reset() ripristina l’ambiente a uno stato iniziale. Per impostazione predefinita, l’ambiente viene inizializzato a uno stato casuale. Puoi utilizzare un parametro SEED con il metodo .reset() per inizializzare l’ambiente nello stesso stato ogni volta che il programma viene eseguito. Il codice qui sotto mostra come farlo:

SEED = 1111 env.reset(seed=SEED)

Il campionamento delle azioni comporta anche casualità. Per controllare questa casualità e ottenere un percorso di addestramento completamente riproducibile, possiamo impostare i generatori casuali di NumPy e PyTorch:

np.random.seed(SEED) torch.manual_seed(SEED)

Azioni casuali contro azioni intelligenti

In ogni passo di un processo di Markov, l’agente può scegliere casualmente un’azione ed esplorare l’ambiente fino a raggiungere uno stato terminale. Scegliendo azioni a caso:

  • Ci può volere molto tempo per raggiungere lo stato terminale.
  • Le ricompense cumulative sono molto inferiori a quelle che avrebbero potuto essere.

Addestrare l’agente per ottimizzare la selezione delle azioni basandosi su esperienze precedenti (di interazione con l’ambiente) è più efficiente per massimizzare le ricompense a lungo termine.

L’agente non addestrato inizia con azioni casuali basate su una politica inizializzata casualmente. Questa politica è tipicamente rappresentata come una rete neurale. Durante l’addestramento, l’agente apprende la politica ottimale che massimizza i premi. In RL, il processo di addestramento è anche chiamato ottimizzazione della politica.

Esistono vari metodi di ottimizzazione della politica. Le equazioni di Bellman descrivono come calcolare il valore delle politiche di RL e determinare la politica ottimale. In questo tutorial, useremo una tecnica semplice chiamata policy gradients. Esistono altri metodi, come Proximal Policy Optimization (PPO).

Implementazione di un semplice agente di gradienti di politica

Per costruire un agente RL che utilizza i gradienti di policy, creiamo una rete neurale per implementare la policy, scriviamo funzioni per calcolare i rendimenti e la perdita dai premi passo dopo passo e le probabilità di azione, e aggiorniamo iterativamente la policy utilizzando tecniche standard di backpropagation.

Configurare la rete di policy

Utilizziamo una rete neurale per implementare la policy. Poiché CartPole-v1 è un ambiente semplice, utilizziamo una rete neurale con:

  • Dimensioni di input uguali alla dimensionalità dello spazio di osservazione dell’ambiente.
  • Un singolo strato nascosto con 64 neuroni.
  • Le dimensioni di output sono uguali alla dimensionalità dello spazio delle azioni dell’ambiente.

Pertanto, la funzione della rete di policy è mappare gli stati osservati alle azioni. Date le osservazioni in input, prevede l’azione corretta. Il codice sottostante implementa la rete di policy:

class PolicyNetwork(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim, dropout): super().__init__() self.layer1 = nn.Linear(input_dim, hidden_dim) self.layer2 = nn.Linear(hidden_dim, output_dim) self.dropout = nn.Dropout(dropout) def forward(self, x): x = self.layer1(x) x = self.dropout(x) x = F.relu(x) x = self.layer2(x) return x

Raccolta delle ricompense e passaggio in avanti

Come accennato, in ogni passo del processo di Markov, l’ambiente fornisce una ricompensa basata sull’azione e sullo stato dell’agente. L’obiettivo in RL è massimizzare il ritorno totale.

  • Il ritorno ad ogni passo è la somma cumulativa delle ricompense ottenute dall’inizio fino a quel passo.
  • Il rendimento totale in ciascun episodio è ottenuto accumulando tutti i premi passo dopo passo di quell’episodio. Pertanto, il rendimento totale è il rendimento all’ultimo passo temporale (quando l’agente raggiunge uno stato terminale).

Nella pratica, durante l’accumulo dei premi, è comune:

  • Regolare i premi futuri utilizzando un fattore di sconto.
  • Normalizzare l’array dei rendimenti passo dopo passo per garantire un addestramento regolare e stabile.

Il codice seguente mostra come fare ciò:

def calculate_stepwise_returns(rewards, discount_factor): returns = [] R = 0 for r in reversed(rewards): R = r + R * discount_factor returns.insert(0, R) returns = torch.tensor(returns) normalized_returns = (returns - returns.mean()) / returns.std() return normalized_returns

Il passaggio in avanti consiste nel far funzionare l’agente in base alla policy corrente fino a quando raggiunge uno stato terminale e nel raccogliere le ricompense passo dopo passo e le probabilità delle azioni. I passaggi seguenti spiegano come implementare il passaggio in avanti:

  • Reimposta l’ambiente a uno stato iniziale.
  • Inizializza i buffer per memorizzare le probabilità delle azioni, le ricompense e il rendimento cumulativo
  • Utilizza la funzione .step() per eseguire in modo iterativo l’agente nell’ambiente fino alla terminazione:
    • Ottieni l’osservazione dello stato dell’ambiente.
    • Ottenere l’azione prevista dalla policy in base all’osservazione.
    • Utilizzare la funzione Softmax per stimare la probabilità di eseguire l’azione prevista.
    • Simulare una distribuzione di probabilità categorica basata su queste probabilità stimat.
    • Estrarre un campione da questa distribuzione per ottenere l’azione dell’agente.
    • Stimare il logaritmo della probabilità dell’azione campionata dalla distribuzione simulata.
  • Aggiungere il logaritmo della probabilità delle azioni e le ricompense di ciascun passaggio ai rispettivi buffer.
  • Stimare i valori normalizzati e scontati dei rendimenti ad ogni passaggio in base alle ricompense.
def forward_pass(env, policy, discount_factor): log_prob_actions = [] rewards = [] done = False episode_return = 0 policy.train() observation, info = env.reset() while not done: observation = torch.FloatTensor(observation).unsqueeze(0) action_pred = policy(observation) action_prob = F.softmax(action_pred, dim = -1) dist = distributions.Categorical(action_prob) action = dist.sample() log_prob_action = dist.log_prob(action) observation, reward, terminated, truncated, info = env.step(action.item()) done = terminated or truncated log_prob_actions.append(log_prob_action) rewards.append(reward) episode_return += reward log_prob_actions = torch.cat(log_prob_actions) stepwise_returns = calculate_stepwise_returns(rewards, discount_factor) return episode_return, stepwise_returns, log_prob_actions

Aggiornamento della policy basato sulle ricompense

La perdita rappresenta la quantità su cui applichiamo la discesa del gradiente. L’obiettivo in RL è massimizzare i rendimenti. Quindi, utilizziamo il valore di ritorno atteso come surrogato della perdita. Il valore di ritorno atteso è calcolato come il prodotto dei rendimenti attesi passo dopo passo e il logaritmo della probabilità delle azioni passo dopo passo. Il codice seguente calcola la perdita:

def calculate_loss(stepwise_returns, log_prob_actions): loss = -(stepwise_returns * log_prob_actions).sum() return loss

Per aggiornare la policy, si esegue backpropagation rispetto alla funzione di perdita. Il metodo update_policy() di seguito invoca il metodo calculate_loss(). Viene quindi eseguita la backpropagation su questa perdita per aggiornare i parametri della policy, cioè i pesi del modello della rete policy.

def update_policy(stepwise_returns, log_prob_actions, optimizer): stepwise_returns = stepwise_returns.detach() loss = calculate_loss(stepwise_returns, log_prob_actions) optimizer.zero_grad() loss.backward() optimizer.step() return loss.item()

Aggiornare la policy basandosi sul gradiente dei ritorni è chiamato il metodo del gradiente della policy

Allenare la policy

Ora abbiamo tutti i componenti necessari per allenare e valutare la policy. Implementiamo il ciclo di allenamento come spiegato nei seguenti passaggi:  

Prima di iniziare, dichiariamo gli iperparametri, istanziamo una policy e creiamo un ottimizzatore:

  • Dichiara gli iperparametri come costanti Python:
    • MAX_EPOCHS è il numero massimo di iterazioni che siamo disposti a eseguire per addestrare la policy.
    • DISCOUNT_FACTOR decide la rilevanza relativa delle ricompense dai passaggi temporali futuri. Un fattore di sconto di 1 significa che tutte le ricompense sono ugualmente importanti, mentre un valore di 0 significa che è importante solo la ricompensa del passaggio temporale attuale.
    • N_TRIALS è il numero di episodi su cui mediamosi i ritorni per valutare le prestazioni dell’agente. Decidiamo che l’addestramento è riuscito se il ritorno medio su N_TRIALS episodi è superiore alla soglia.
    • REWARD_THRESHOLD: Se la politica può ottenere un ritorno superiore alla soglia, è considerata un successo.
    • DROPOUT decide la frazione dei pesi che devono essere azzerati casualmente. La funzione di dropout imposta casualmente una frazione dei pesi del modello a zero. Questo riduce la dipendenza da neuroni specifici e previene l’overfitting, rendendo la rete più robusta.
    • LEARNING_RATE determina quanto possono essere modificati i parametri della politica ad ogni passo. L’aggiornamento dei parametri in ogni iterazione è il prodotto del gradiente e del tasso di apprendimento.
  • Definisci la politica come un’istanza della classe PolicyNetwork (implementata in precedenza).
  • Crea un ottimizzatore utilizzando l’algoritmo Adam e il tasso di apprendimento.

Per addestrare la politica, eseguiamo iterativamente i passaggi di addestramento fino a quando il ritorno medio (su N_TRIALS) è maggiore della soglia di ricompensa:

  • Per ogni episodio, esegui una volta il passaggio in avanti. Raccogli la probabilità logaritmica delle azioni, i ritorni passo passo e il ritorno totale da quell’episodio. Accumula i ritorni episodici in un array.
  • Calcolare la perdita utilizzando le log probabilità e i rendimenti passo dopo passo. Eseguire la retropropagazione sulla perdita. Utilizzare l’ottimizzatore per aggiornare i parametri della policy.
  • Verificare se il rendimento medio su N_TRIALS supera la soglia di ricompensa.

Il codice seguente implementa questi passaggi:

def main(): MAX_EPOCHS = 500 DISCOUNT_FACTOR = 0.99 N_TRIALS = 25 REWARD_THRESHOLD = 475 PRINT_INTERVAL = 10 INPUT_DIM = env.observation_space.shape[0] HIDDEN_DIM = 128 OUTPUT_DIM = env.action_space.n DROPOUT = 0.5 episode_returns = [] policy = PolicyNetwork(INPUT_DIM, HIDDEN_DIM, OUTPUT_DIM, DROPOUT) LEARNING_RATE = 0.01 optimizer = optim.Adam(policy.parameters(), lr = LEARNING_RATE) for episode in range(1, MAX_EPOCHS+1): episode_return, stepwise_returns, log_prob_actions = forward_pass(env, policy, DISCOUNT_FACTOR) _ = update_policy(stepwise_returns, log_prob_actions, optimizer) episode_returns.append(episode_return) mean_episode_return = np.mean(episode_returns[-N_TRIALS:]) if episode % PRINT_INTERVAL == 0: print(f'| Episode: {episode:3} | Mean Rewards: {mean_episode_return:5.1f} |') if mean_episode_return >= REWARD_THRESHOLD: print(f'Reached reward threshold in {episode} episodes') break

Infine, invocare la funzione main() per addestrare la policy:

main()

Usa questo DataLab workbook per eseguire ll’algoritmo sopra direttamente e risolvere l’ambiente CartPole utilizzando RL.

Tecniche avanzate in Gymnasium

Dopo aver dimostrato come implementare un algoritmo RL, ora discutiamo alcune tecniche avanzate comunemente utilizzate nella pratica.

Utilizzando architetture predefinite

Implementare algoritmi RL da zero è un processo lungo e difficile, specialmente per ambienti complessi e politiche all’avanguardia.

Un’alternativa più pratica è utilizzare software come Stable Baselines3. Include implementazioni collaudate di algoritmi di RL. Comprende agenti pre-addestrati, script di addestramento, strumenti di valutazione e moduli per tracciare grafici e registrare video.

Ray RLib è un altro strumento popolare per RL. RLib è progettato come una soluzione scalabile, rendendo facile implementare algoritmi di RL su sistemi multi-GPU. Supporta anche il RL multi-agente, il che apre nuove possibilità come:

  • Apprendimento multi-agente indipendente: Ogni agente considera gli altri agenti come parte dell’ambiente.
  • Addestramento collaborativo multi-agente: Un gruppo di agenti condividono la stessa politica e funzioni di valore e imparano dalle esperienze reciproche in parallelo.
  • Addestramento avversario: Gli agenti (o gruppi di agenti) competono tra loro in ambienti simili a giochi competitivi.

Con entrambi RLib e Stable Baselines3, puoi importare e utilizzare ambienti da OpenAI Gymnasium.

Ambienti personalizzati

Gli ambienti confezionati con Gymnasium sono la scelta giusta per testare nuove strategie di RL e addestrare politiche. Tuttavia, per la maggior parte delle applicazioni pratiche, è necessario creare e utilizzare un ambiente che rifletta accuratamente il problema che si desidera risolvere. È possibile utilizzare Gymnasium per creare un ambiente personalizzato. Il vantaggio nell’utilizzare gli ambienti personalizzati di Gymnasium è che molti strumenti esterni come RLib e Stable Baselines3 sono già configurati per funzionare con la struttura dell’API di Gymnasium.

Per creare un ambiente personalizzato in Gymnasium, è necessario definire:

  • Lo spazio delle osservazioni.
  • Le condizioni terminali.
  • Il set di azioni che l’agente può scegliere.
  • Come inizializzare l’ambiente (quando la funzione reset() viene chiamata).
  • Come l’ambiente decide lo stato successivo date le azioni dell’agente (quando la funzione step() viene chiamata).

Per saperne di più, segui la guida sulla creazione di ambienti personalizzati di Gymnasium.

Linee guida per l’utilizzo di Gymnasium

Sperimenta con ambienti diversi

Il codice in questo tutorial ha mostrato come implementare l’algoritmo del gradiente della politica nell’ambiente CartPole. Si tratta di un ambiente semplice con uno spazio delle azioni discrete. Per comprendere meglio RL, ti consigliamo di applicare lo stesso algoritmo del gradiente della politica (e altri algoritmi, come PPO) in altri ambienti.

Ad esempio, l’ambiente Pendulum ha uno spazio di azione continuo. È costituito da un’unica variabile di input rappresentata come una variabile continua – il momento (magnitude e direzione del) applicato al pendolo in uno stato qualsiasi. Questo momento può assumere qualsiasi valore tra -2 e +2.

Sperimentare con diversi algoritmi in vari ambienti ti aiuta a comprendere meglio diversi tipi di soluzioni di RL e le loro sfide.

Monitorare il progresso dell’addestramento

Gli ambienti RL sono spesso composti da robot, pendoli, auto da montagna, videogiochi, ecc. Visualizzare le azioni dell’agente all’interno dell’ambiente offre una migliore comprensione intuitiva delle prestazioni della policy.

In Gymnasium, il metodo env.render() visualizza le interazioni dell’agente con l’ambiente. Visualizza graficamente lo stato attuale dell’ambiente – schermate di gioco, la posizione del pendolo o del palo del carrello, ecc. Il feedback visivo sulle azioni dell’agente e sulle risposte dell’ambiente aiuta a monitorare le prestazioni dell’agente e il progresso nel processo di addestramento.

Ci sono quattro modalità di rendering: “human”, “rgb_array”, “ansi” e “rgb_array_list”. Per visualizzare le prestazioni dell’agente, utilizzare la modalità di rendering “human”. La modalità di rendering viene specificata durante l’inizializzazione dell’ambiente. Ad esempio:

env = gym.make(‘CartPole-v1’, render_mode=’human’)

Per eseguire il rendering, coinvolgi il .render() metodo dopo ogni azione eseguita dall’agente (attraverso la chiamata al .step() metodo). Il pseudo-codice qui sotto illustra come farlo:

while not done: … step, reward, terminated, truncated, info = env.step(action.item()) env.render()

Risoluzione dei problemi comuni

Gymnasium facilita l’interfacciamento con ambienti RL complessi. Tuttavia, è un software continuamente aggiornato con molte dipendenze. Quindi, è essenziale prestare attenzione a alcuni tipi comuni di errori.

Incongruenze di versione

  • Discrepanza di versione della palestra: Il pacchetto software Gymnasium di Farama è stato derivato da OpenAI’s Gym dalla versione 0.26.2. Ci sono state alcune modifiche sostanziali tra le vecchie versioni di Gym e le nuove versioni di Gymnasium. Molte implementazioni pubblicamente disponibili si basano sulle vecchie versioni di Gym e potrebbero non funzionare direttamente con l’ultima versione. In tali casi, è necessario o tornare all’installazione di una versione più vecchia o adattare il codice per farlo funzionare con la nuova release.
  • Discrepanza di versione dell’ambiente: Molti ambienti di palestra hanno versioni diverse. Ad esempio, ci sono due ambienti CartPole – CartPole-v1 e CartPole-v0. Anche se il comportamento dell’ambiente è lo stesso in entrambe le versioni, alcuni parametri, come la lunghezza dell’episodio, la soglia di ricompensa, ecc., possono essere diversi. Una policy addestrata su una versione potrebbe non funzionare altrettanto bene su un’altra versione dello stesso ambiente. È necessario aggiornare i parametri di addestramento e riformare la policy per ciascuna versione dell’ambiente. 
  • Incompatibilità delle versioni delle dipendenze: Gymnasium dipende da dipendenze come NumPy e PyTorch. A partire da dicembre 2024, le versioni più recenti di queste dipendenze sono numpy 2.1.3 e torch 2.5.1. Tuttavia, Gymnasium funziona meglio con torch 1.13.0 e numpy 1.23.3. Potresti riscontrare problemi se installi Gymnasium in un ambiente con queste dipendenze già installate. Ti consigliamo di installare e lavorare con Gymnasium in un nuovo ambiente Conda. 

Problemi di convergenza

  • Iperparametri:Come altri algoritmi di apprendimento automatico, le politiche RL sono sensibili agli iperparametri come il tasso di apprendimento, il fattore di sconto, ecc. Consigliamo di sperimentare e regolare gli iperparametri manualmente o utilizzando tecniche automatizzate come la ricerca a griglia e la ricerca casuale.
  • Esplorazione versus sfruttamento:Per alcune classi di politiche (come PPO), l’agente adotta una strategia a due punte: esplorare l’ambiente per scoprire nuovi percorsi e adottare un approccio avido per massimizzare i premi basati sui percorsi conosciuti finora. Se esplora troppo, la politica non converge. Al contrario, non prova mai il percorso ottimale se non esplora abbastanza. Quindi, trovare il giusto equilibrio tra esplorazione e sfruttamento è essenziale. È anche comune privilegiare l’esplorazione negli episodi precedenti e lo sfruttamento negli episodi successivi durante l’addestramento.

Instabilità dell’addestramento

  • Grandi tassi di apprendimento: Se il tasso di apprendimento è troppo alto, i parametri della politica subiscono grandi aggiornamenti ad ogni passo. Questo potrebbe portare a perdere l’insieme ottimale di valori. Una soluzione comune è quella di ridurre gradualmente il tasso di apprendimento, garantendo aggiornamenti più piccoli e stabili man mano che l’addestramento converge. 
  • Esplorazione eccessiva: Troppa casualità (entropia) nella selezione delle azioni impedisce la convergenza e porta a grandi variazioni nella funzione di perdita tra i passaggi successivi. Per avere un processo di addestramento stabile e convergente, bilanciare esplorazione ed sfruttamento. 
  • Scelta errata dell’algoritmo: Algoritmi semplici come il gradiente della politica possono portare a un addestramento instabile in ambienti complessi con ampi spazi di azione e stati. In tali casi, raccomandiamo di utilizzare algoritmi più robusti come PPO e Trust Region Policy Optimization (TRPO). Questi algoritmi evitano grandi aggiornamenti della politica ad ogni passo e possono essere più stabili.
  • Casualità: Gli algoritmi di RL sono notoriamente sensibili agli stati iniziali e alla casualità intrinseca alla selezione delle azioni. Quando un ciclo di addestramento è instabile, talvolta può essere stabilizzato utilizzando un diverso seed casuale o riinizializzando la politica.

Conclusione

In questo tutorial, abbiamo esplorato i principi di base di RL, discusso di Gymnasium come un pacchetto software con un’API pulita per interfacciarsi con vari ambienti RL, e mostrato come scrivere un programma Python per implementare un semplice algoritmo RL e applicarlo in un ambiente Gymnasium.

Dopo aver compreso le basi in questo tutorial, consiglio di utilizzare gli ambienti Gymnasium per applicare i concetti di RL per risolvere problemi pratici come ottimizzazione del percorso del taxi e simulazioni di trading di azioni.

Source:
https://www.datacamp.com/tutorial/reinforcement-learning-with-gymnasium