Aprendizado por Reforço (RL) é um dos três principais paradigmas de aprendizado de máquina, sendo os outros dois o aprendizado supervisionado e o aprendizado não supervisionado. No RL, um agente aprende a interagir com seu ambiente para maximizar as recompensas acumuladas. Ele aprende a ação ideal sob diferentes condições ambientais por meio de tentativa e erro. Aprendizado por Reforço com Feedback Humano (RLHF) permite que o agente modifique seu comportamento com base nas entradas humanas a cada passo.
RL resolve problemas como carros autônomos, negociação automatizada, jogadores de computador em videogames, treinamento de robôs e muito mais. Quando redes neurais profundas são usadas para aplicar algoritmos de RL, isso é chamado de Aprendizado por Reforço Profundo.
Neste tutorial, vou mostrar como começar com o Gymnasium, uma biblioteca Python de código aberto para desenvolver e comparar algoritmos de aprendizado por reforço. Vou demonstrar como configurá-lo, explorar vários ambientes de RL e usar Python para construir um agente simples para implementar um algoritmo de RL.
O que é Gymnasium?
Gymnasium é uma biblioteca Python de código aberto projetada para apoiar o desenvolvimento de algoritmos de RL. Para facilitar a pesquisa e o desenvolvimento em RL, o Gymnasium oferece:
- Uma ampla variedade de ambientes, desde jogos simples até problemas que imitam cenários da vida real.
- APIs e wrappers simplificados para interagir com os ambientes.
- A capacidade de criar ambientes personalizados e aproveitar a estrutura da API.
Os desenvolvedores podem construir algoritmos de RL e usar chamadas de API para tarefas como:
- Passar a ação escolhida pelo agente para o ambiente.
- Conhecendo o estado do ambiente e a recompensa após cada ação.
- Treinando o modelo.
- Testando o desempenho do modelo.
OpenAI’s Gym versus Gymnasium da Farama
A OpenAI não dedicou recursos significativos ao desenvolvimento do Gym, pois não era uma prioridade comercial para a empresa. A Fundação Farama foi criada para padronizar e manter bibliotecas de RL a longo prazo. O Gymnasium é o fork da Fundação Farama do Gym da OpenAI. O Gymnasium 0.26.2 é um substituto direto para o Gym 0.26.2. Com o fork, a Farama tem como objetivo adicionar métodos funcionais (além dos baseados em classe) para todas as chamadas de API, suportar ambientes vetoriais e aprimorar os wrappers. O objetivo geral é tornar o framework mais limpo e eficiente.
Configurando o Gymnasium
O Gymnasium precisa de versões específicas (não as últimas lançamentos) de vários programas de dependência como NumPy e PyTorch. Assim, recomendamos criar um novo ambiente Conda ou venv ou um novo notebook para instalar, usar o Gymnasium e executar programas de RL.
Você pode usar este caderno DataLab para seguir o tutorial.
Instalando o Gymnasium
Para instalar o Gymnasium em um servidor ou máquina local, execute:
$ pip install gymnasium
Para instalar usando um Notebook como o Colab do Google ou o DataLab do DataCamp, use:
!pip install gymnasium
O comando acima instala o Gymnasium e as versões corretas das dependências.
Explorando os ambientes do Gymnasium
A partir de novembro de 2024, o Gymnasium inclui mais de 60 ambientes integrados. Para navegar pelos ambientes integrados disponíveis, use a função gym.envs.registry.all()
, conforme ilustrado no exemplo abaixo:
import gymnasium as gym for i in gym.envs.registry.keys(): print(i)
Você também pode visitar a página inicial do Ginásio. A coluna esquerda tem links para todos os ambientes. A página web de cada ambiente inclui detalhes sobre ele, como ações, estados, etc.
Os ambientes são organizados em categorias como Controle Clássico, Box2D, e mais. Abaixo, listo alguns dos ambientes comuns em cada grupo:
- Controle Clássico: Estes são ambientes canônicos usados no desenvolvimento de RL; eles formam a base de muitos exemplos de livros didáticos. Eles oferecem a mistura certa de complexidade e simplicidade para testar e comparar novos algoritmos de RL. Os ambientes de controle clássico no Ginásio incluem:
- Acrobata
- Pêndulo
- Carro Pendurado
- Carro na Montanha Discreto
- Carro na Montanha Contínuo
- Box2D: Box2D é um Motor de Física 2D para Jogos. Ambientes baseados nesse motor incluem jogos simples como:
- Lunar Lander
- Car Racing
- ToyText: Esses são ambientes pequenos e simples frequentemente usados para depurar algoritmos de RL. Muitos desses ambientes são baseados no modelo do pequeno mundo de grade e em jogos simples de cartas. Exemplos incluem:
- Blackjack
- Taxi
- Frozen Lake
- MuJoCo: Multi-Joint dynamics with Contact (MuJoCo) é um motor de física de código aberto que simula ambientes para aplicações como robótica, biomecânica, ML, etc. Os ambientes MuJoCo no Gymnasium incluem:
- Ant
- Hopper
- Humanoid
- Swimmer
- E mais
Além dos ambientes integrados, o Gymnasium pode ser usado com muitos ambientes externos usando a mesma API.
Usaremos um dos ambientes clássicos canônicos de Controle neste tutorial. Para importar um ambiente específico, use o comando .make()
e passe o nome do ambiente como argumento. Por exemplo, para criar um novo ambiente baseado no CartPole (versão 1), use o comando abaixo:
import gymnasium as gym env = gym.make("CartPole-v1")
Entendendo os Conceitos de Aprendizado por Reforço no Gymnasium
Em resumo, Aprendizado por Reforço consiste em um agente (como um robô) que interage com seu ambiente. Uma política decide as ações do agente. Dependendo das ações do agente, o ambiente oferece uma recompensa (ou penalidade) a cada passo de tempo. O agente usa RL para descobrir a política ótima que maximiza as recompensas totais que o agente ganha.
Componentes de um ambiente RL
Os seguintes são os principais componentes de um ambiente de RL:
- Ambiente: O sistema externo, mundo ou contexto. O agente interage com o ambiente em uma série de passos de tempo. Em cada passo de tempo, com base na ação do agente, o ambiente:
- Dá uma recompensa (ou penalidade)
- Decide o próximo estado
- Estado: Uma representação matemática da configuração atual do ambiente.
- Por exemplo, o estado de um ambiente de pêndulo pode incluir a posição do pêndulo e a velocidade angular em cada passo de tempo.
- Estado terminal: Um estado que não leva a novos/outros estados.
- Agente: O algoritmo que observa o ambiente e toma várias ações com base nessa observação. O objetivo do agente é maximizar suas recompensas.
- Por exemplo, o agente decide com que força e em que direção empurrar o pêndulo.
- Observação: Uma representação matemática da visão do agente sobre o ambiente, adquirida, por exemplo, usando sensores.
- Ação: A decisão tomada pelo agente antes de prosseguir para o próximo passo. A ação afeta o próximo estado do ambiente e proporciona uma recompensa ao agente.
- Recompensa: O feedback do ambiente para o agente. Pode ser positivo ou negativo, dependendo da ação e do estado do ambiente.
- Retorno: O retorno cumulativo esperado ao longo de passos futuros. Recompensas de passos futuros podem ser descontadas usando um fator de desconto.
- Política: A estratégia do agente sobre qual ação tomar em vários estados. Geralmente é representada como uma matriz de probabilidade, P, que mapeia estados para ações.
- Dado um conjunto finito de m estados possíveis e n ações possíveis, o elemento Pmn na matriz denota a probabilidade de tomar a ação an no estado sm.
- Episódio: A série de etapas a partir do estado inicial (aleatório) até que o agente alcance um estado terminal.
Espaço de observação e espaço de ação
A observação é a informação que o agente coleta sobre o ambiente. Um agente, por exemplo, um robô, pode coletar informações ambientais usando sensores. Idealmente, o agente deveria ser capaz de observar o estado completo, que descreve todos os aspectos do ambiente. Na prática, o agente usa suas observações como um substituto para o estado. Assim, as observações determinam as ações do agente.
Um espaço é análogo a um conjunto matemático. O espaço de itens X inclui todas as instâncias possíveis de X. O espaço de X também define a estrutura (sintaxe e formato) de todos os itens do tipo X. Cada ambiente de Ginásio tem dois espaços, o espaço de ação, action_space
, e o espaço de observação, observation_space
. Tanto os espaços de ação quanto de observação derivam da superclasse pai gymnasium.spaces.Space
.
Espaço de observação
O espaço de observação é o espaço que inclui todas as observações possíveis. Ele também define o formato no qual as observações são armazenadas. O espaço de observação é tipicamente representado como um objeto do tipo Box. Este é um ndarray que descreve os parâmetros das observações. A caixa especifica os limites de cada dimensão. Você pode visualizar o espaço de observação para um ambiente usando o método observation_space
:
print("observation space: ", env.observation_space)
No caso do ambiente CartPole-v1
, a saída se parece com o exemplo abaixo:
observation space: Box([-4.8 -inf -0.41887903 -inf], [4.8 inf 0.41887903 inf], (4,), float32)
Neste exemplo, o espaço de observação CartPole-v1
tem 4 dimensões. Os 4 elementos da matriz de observação são:
- Posição do carrinho – varia entre -4.8 e +4.8
- Velocidade do carrinho – varia entre – e +
- Ângulo do poste – varia entre -0,4189 e +0,4189
- Velocidade angular do polo – varia entre – e +
Para ver um exemplo de uma matriz de observação individual, use o comando .reset()
.
observation, info = env.reset() print("observation: ", observation)
No caso do ambiente CartPole-v1
, a saída se parece com o exemplo abaixo:
[ 0.03481963 -0.0277232 0.01703267 -0.04870504]
Os quatro elementos deste array correspondem às quatro quantidades observadas (posição do carrinho, velocidade do carrinho, ângulo do pólo, velocidade angular do pólo), conforme explicado anteriormente.
Espaço de ação
O espaço de ação inclui todas as ações possíveis que o agente pode realizar. O espaço de ação também define o formato em que as ações são representadas. Você pode visualizar o espaço de ação para um ambiente usando o método action_space
:
print("action space: ", env.action_space)
No caso do ambiente CartPole-v1
, a saída se parece com o exemplo abaixo:
action space: Discrete(2)
No caso do ambiente CartPole-v1
, o espaço de ação é discreto. Há um total de duas ações que o agente pode tomar:
- 0: Empurrar o carrinho para a esquerda
- 1: Empurrar o carrinho para a direita
Construindo Seu Primeiro Agente de RL com Gymnasium
Nas seções anteriores, exploramos os conceitos básicos de RL e Gymnasium. Esta seção mostra como usar o Gymnasium para construir um agente de RL.
Criando e redefinindo o ambiente
O primeiro passo é criar uma instância do ambiente. Para criar novos ambientes, use o método .make()
.
env = gym.make('CartPole-v1')
As interações do agente alteram o estado do ambiente. O método .reset()
redefine o ambiente para um estado inicial. Por padrão, o ambiente é inicializado em um estado aleatório. Você pode usar um parâmetro SEED
com o método .reset()
para inicializar o ambiente no mesmo estado sempre que o programa for executado. O código abaixo mostra como fazer isso:
SEED = 1111 env.reset(seed=SEED)
A amostragem de ações também envolve aleatoriedade. Para controlar essa aleatoriedade e obter um caminho de treinamento totalmente reproduzível, podemos definir as sementes dos geradores aleatórios do NumPy e do PyTorch:
np.random.seed(SEED) torch.manual_seed(SEED)
Ações aleatórias versus ações inteligentes
Em cada etapa de um processo de Markov, o agente pode escolher uma ação aleatoriamente e explorar o ambiente até chegar a um estado terminal. Ao escolher ações aleatoriamente:
- Pode levar muito tempo para alcançar o estado terminal.
- As recompensas cumulativas são muito menores do que poderiam ter sido.
Treinar o agente para otimizar a seleção de ações com base em experiências anteriores (de interação com o ambiente) é mais eficiente para maximizar recompensas a longo prazo.
O agente não treinado começa com ações aleatórias com base em uma política inicializada aleatoriamente. Essa política é tipicamente representada como uma rede neural. Durante o treinamento, o agente aprende a política ótima que maximiza as recompensas. No RL, o processo de treinamento também é chamado de otimização de política.
Há vários métodos de otimização de política. As equações de Bellman descrevem como calcular o valor das políticas de RL e determinar a política ótima. Neste tutorial, usaremos uma técnica simples chamada gradientes de política. Outros métodos existem, como Otimização de Política Proximal (PPO).
Implementando um Agente de Gradiente de Política Simples
Para construir um agente de RL que utiliza gradientes de política, criamos uma rede neural para implementar a política, escrevemos funções para calcular os retornos e a perda a partir das recompensas passo a passo e das probabilidades de ação, e atualizamos iterativamente a política usando técnicas padrão de retropropagação.
Configurando a rede de política
Usamos uma rede neural para implementar a política. Como o CartPole-v1
é um ambiente simples, usamos uma rede neural com:
- Dimensões de entrada iguais à dimensionalidade do espaço de observação do ambiente.
- Uma única camada oculta com 64 neurônios.
- As dimensões de saída são iguais à dimensionalidade do espaço de ação do ambiente.
Assim, a função da rede de política é mapear os estados observados para ações. Dado uma observação de entrada, ela prevê a ação correta. O código abaixo implementa a rede de política:
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
Coleta de recompensas e passagem direta
Como mencionado, em cada etapa do processo de Markov, o ambiente fornece uma recompensa com base na ação e estado do agente. O objetivo em RL é maximizar o retorno total.
- O retorno em cada passo de tempo é a soma cumulativa das recompensas obtidas desde o início até esse passo.
- O retorno total em cada episódio é obtido acumulando todas as recompensas passo a passo daquele episódio. Assim, o retorno total é o retorno no último passo de tempo (quando o agente alcança um estado terminal).
Na prática, ao acumular recompensas, é comum:
- Ajustar recompensas futuras usando um fator de desconto.
- Normalizar o conjunto de retornos passo a passo para garantir um treinamento suave e estável.
O código abaixo mostra como fazer isso:
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
A passagem para a frente consiste em executar o agente com base na política atual até que ele alcance um estado terminal e coletar as recompensas passo a passo e as probabilidades de ação. Os passos abaixo explicam como implementar a passagem para a frente:
- Redefinir o ambiente para um estado inicial.
- Inicializar buffers para armazenar as probabilidades de ação, as recompensas e o retorno cumulativo
- Usar a função
.step()
para executar iterativamente o agente no ambiente até que ele termine: - Obter a observação do estado do ambiente.
- Obtenha a ação prevista pela política com base na observação.
- Use a função
Softmax
para estimar a probabilidade de tomar a ação prevista. - Simule uma distribuição de probabilidade categórica com base nessas probabilidades estimadas.
- Amostra essa distribuição para obter a ação do agente.
- Estime o logaritmo da probabilidade da ação amostrada a partir da distribuição simulada.
- Acrescente o logaritmo da probabilidade das ações e as recompensas de cada etapa aos respetivos buffers.
- Estime os valores normalizados e descontados dos retornos em cada etapa com base nas recompensas.
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
Atualizando a política com base nas recompensas
A perda representa a quantidade na qual aplicamos a descida do gradiente. O objetivo em RL é maximizar os retornos. Assim, usamos o valor de retorno esperado como um proxy para a perda. O valor de retorno esperado é calculado como o produto dos retornos esperados em cada etapa e o logaritmo da probabilidade das ações em cada etapa. O código abaixo calcula a perda:
def calculate_loss(stepwise_returns, log_prob_actions): loss = -(stepwise_returns * log_prob_actions).sum() return loss
Para atualizar a política, você executa retropropagação em relação à função de perda. O método update_policy()
abaixo invoca o método calculate_loss()
. Em seguida, executa retropropagação nessa perda para atualizar os parâmetros da política, ou seja, os pesos do modelo da rede de política.
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()
Atualizar a política com base no gradiente dos retornos é chamado de método do gradiente da política.
Treinando a política
Agora temos todos os componentes necessários para treinar e avaliar a política. Implementamos o loop de treinamento conforme explicado nos seguintes passos:
Antes de começar, declaramos os hiperparâmetros, instanciamos uma política e criamos um otimizador:
- Declare os hiperparâmetros como constantes Python:
MAX_EPOCHS
é o número máximo de iterações que estamos preparados para executar para treinar a política.DISCOUNT_FACTOR
decide a importância relativa das recompensas de passos de tempo futuros. Um fator de desconto de 1 significa que todas as recompensas são igualmente importantes, enquanto um valor de 0 significa que apenas a recompensa do passo de tempo atual é importante.N_TRIALS
é o número de episódios sobre os quais calculamos a média dos retornos para avaliar o desempenho do agente. Decidimos que o treinamento é bem-sucedido se o retorno médio emN_TRIALS
episódios estiver acima do limite.REWARD_THRESHOLD
: Se a política conseguir um retorno maior que o limite, é considerada bem-sucedida.DROPOUT
decide a fração dos pesos que deve ser zerada aleatoriamente. A função de dropout zera aleatoriamente uma fração dos pesos do modelo. Isso reduz a dependência de neurônios específicos e previne o overfitting, tornando a rede mais robusta.LEARNING_RATE
decide quanto os parâmetros da política podem ser modificados em cada passo. A atualização dos parâmetros em cada iteração é o produto do gradiente e da taxa de aprendizado.- Defina a política como uma instância da classe
PolicyNetwork
(implementada anteriormente). - Crie um otimizador usando o algoritmo Adam e a taxa de aprendizado.
Para treinar a política, executamos iterativamente os passos de treinamento até que o retorno médio (sobre N_TRIALS
) seja maior que o limite de recompensa:
- Para cada episódio, execute a passagem direta uma vez. Colete a probabilidade logarítmica das ações, os retornos passo a passo e o retorno total daquele episódio. Acumule os retornos episódicos em um array.
- Calcule a perda usando as probabilidades de log e os retornos passo a passo. Execute a retropropagação na perda. Use o otimizador para atualizar os parâmetros da política.
- Verifique se o retorno médio ao longo de
N_TRIALS
excede o limite de recompensa.
O código abaixo implementa essas etapas:
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
Por fim, invoque a função main()
para treinar a política:
main()
Use este caderno DataLab para executar o algoritmo acima diretamente e resolver o ambiente CartPole usando RL.
Técnicas Avançadas em Gymnasium
Depois de demonstrar como implementar um algoritmo de RL, agora discutimos algumas técnicas avançadas comumente utilizadas na prática.
Usando arquiteturas pré-construídas
A implementação de algoritmos de RL do zero é um processo longo e difícil, especialmente para ambientes complexos e políticas de ponta.
Uma alternativa mais prática é usar software como Stable Baselines3. Ele vem com implementações testadas e comprovadas de algoritmos de RL. Inclui agentes pré-treinados, scripts de treinamento, ferramentas de avaliação e módulos para traçar gráficos e gravar vídeos.
Ray RLib é outra ferramenta popular para RL. RLib é projetado como uma solução escalável, facilitando a implementação de algoritmos de RL em sistemas multi-GPU. Também suporta RL multi-agente, o que abre novas possibilidades como:
- Aprendizagem multi-agente independente: Cada agente trata outros agentes como parte do ambiente.
- Treinamento colaborativo de múltiplos agentes: Um grupo de agentes compartilha a mesma política e funções de valor e aprende com as experiências uns dos outros em paralelo.
- Treinamento adversarial: Agentes (ou grupos de agentes) competem uns contra os outros em ambientes competitivos semelhantes a jogos.
Com tanto RLib quanto Stable Baselines3, você pode importar e usar ambientes do OpenAI Gymnasium.
Ambientes personalizados
Os ambientes empacotados com o Gymnasium são a escolha certa para testar novas estratégias de RL e treinar políticas. No entanto, para a maioria das aplicações práticas, você precisa criar e usar um ambiente que reflita com precisão o problema que deseja resolver. Você pode usar o Gymnasium para criar um ambiente personalizado. A vantagem de usar ambientes personalizados do Gymnasium é que muitas ferramentas externas, como RLib e Stable Baselines3, já estão configuradas para trabalhar com a estrutura da API do Gymnasium.
Para criar um ambiente personalizado no Gymnasium, você precisa definir:
- O espaço de observação.
- As condições terminais.
- O conjunto de ações que o agente pode escolher.
- Como inicializar o ambiente (quando a função
reset()
é chamada). - Como o ambiente decide o próximo estado dado as ações do agente (quando a função
step()
é chamada).
Para saber mais, siga o guia do Gymnasium sobre a criação de ambientes personalizados.
Boas práticas para usar o Gymnasium
Experimente com diferentes ambientes
O código neste tutorial mostrou como implementar o algoritmo de gradiente de política no ambiente CartPole. Este é um ambiente simples com um espaço de ação discreto. Para entender melhor o RL, aconselhamos você a aplicar o mesmo algoritmo de gradiente de política (e outros algoritmos, como PPO) em outros ambientes.
Por exemplo, o ambiente Pendulum possui um espaço de ação contínuo. Ele consiste em uma única entrada representada como uma variável contínua – o (magnitude e direção do) torque aplicado ao pêndulo em um determinado estado. Esse torque pode assumir qualquer valor entre -2 e +2.
Experimentar com diferentes algoritmos em vários ambientes ajuda você a entender melhor os diferentes tipos de soluções de RL e seus desafios.
Monitorar o progresso do treinamento
Os ambientes de RL frequentemente consistem em robôs, pêndulos, carros de montanha, videogames, etc. Visualizar as ações do agente dentro do ambiente proporciona uma melhor compreensão intuitiva do desempenho da política.
No Gymnasium, o método env.render()
visualiza as interações do agente com o ambiente. Ele exibe graficamente o estado atual do ambiente – telas de jogos, a posição do pêndulo ou do carrinho, etc. O feedback visual das ações do agente e das respostas do ambiente ajuda a monitorar o desempenho do agente e o progresso durante o processo de treinamento.
Há quatro modos de renderização: “humano”, “rgb_array”, “ansi” e “rgb_array_list”. Para visualizar o desempenho do agente, utilize o modo de renderização “humano”. O modo de renderização é especificado durante a inicialização do ambiente. Por exemplo:
env = gym.make(‘CartPole-v1’, render_mode=’human’)
Para realizar a renderização, envolva o .render()
método após cada ação executada pelo agente (através da chamada ao .step()
método). O pseudo-código abaixo ilustra como fazer isso:
while not done: … step, reward, terminated, truncated, info = env.step(action.item()) env.render() …
Soluções para erros comuns
O Gymnasium facilita a interface com ambientes RL complexos. No entanto, é um software em constante atualização com muitas dependências. Portanto, é essencial ficar atento a alguns tipos comuns de erros.
Incompatibilidades de versão
- Discrepância de versão do Gymnasium: O pacote de software do Gymnasium da Farama foi bifurcado do Gym da OpenAI a partir da versão 0.26.2. Houve algumas mudanças incompatíveis entre versões antigas do Gym e as novas versões do Gymnasium. Muitas implementações publicamente disponíveis são baseadas em versões antigas do Gym e podem não funcionar diretamente com a última versão. Nestes casos, é necessário ou reverter a instalação para uma versão anterior ou adaptar o código para funcionar com a nova versão.
- Incompatibilidade de versão do ambiente: Muitos ambientes do Gymnasium têm versões diferentes. Por exemplo, existem dois ambientes CartPole –
CartPole-v1
eCartPole-v0
. Embora o comportamento do ambiente seja o mesmo em ambas as versões, alguns dos parâmetros, como a duração do episódio, o limite de recompensa, etc., podem ser diferentes. Uma política treinada em uma versão pode não ter um desempenho tão bom em outra versão do mesmo ambiente. Você precisa atualizar os parâmetros de treinamento e re-treinar a política para cada versão do ambiente. - Problemas de convergência: Gymnasium depende de dependências como NumPy e PyTorch. A partir de dezembro de 2024, as versões mais recentes dessas dependências são
numpy 2.1.3
etorch 2.5.1
. No entanto, Gymnasium funciona melhor comtorch 1.13.0
enumpy 1.23.3
. Você pode encontrar problemas se instalar o Gymnasium em um ambiente com essas dependências pré-instaladas. Recomendamos instalar e trabalhar com o Gymnasium em um novo ambiente Conda.
Problemas de convergência
- Hiperparâmetros: Assim como outros algoritmos de aprendizado de máquina, as políticas de RL são sensíveis a hiperparâmetros como taxa de aprendizado, fator de desconto, etc. Recomendamos experimentar e ajustar os hiperparâmetros manualmente ou usar técnicas automatizadas como busca em grade e busca aleatória.
- Exploração versus exploração: Para algumas classes de políticas (como PPO), o agente adota uma estratégia de dois lados: explorar o ambiente para descobrir novos caminhos e adotar uma abordagem gananciosa para maximizar as recompensas com base nos caminhos conhecidos até agora. Se explorar demais, a política não converge. Por outro lado, nunca tenta o caminho ótimo se não explorar o suficiente. Portanto, encontrar o equilíbrio certo entre exploração e exploração é essencial. Também é comum priorizar a exploração nos episódios iniciais e a exploração nos episódios posteriores durante o treinamento.
Instabilidade no treinamento
- Taxas de aprendizado elevadas: Se a taxa de aprendizado for muito alta, os parâmetros de política sofrem grandes atualizações a cada passo. Isso poderia levar potencialmente a não atingir o conjunto ótimo de valores. Uma solução comum é decair gradualmente a taxa de aprendizado, garantindo atualizações menores e mais estáveis à medida que o treinamento converge.
- Exploração excessiva: Muita aleatoriedade (entropia) na seleção de ações impede a convergência e leva a grandes variações na função de perda entre os passos subsequentes. Para ter um processo de treinamento estável e convergente, equilibre a exploração com a exploração.
- Escolha errada de algoritmo: Algoritmos simples como gradientes de política podem levar a treinamentos instáveis em ambientes complexos com espaços de ação e estado grandes. Nesses casos, recomendamos o uso de algoritmos mais robustos como PPO e Otimização de Política por Região de Confiança (TRPO). Esses algoritmos evitam grandes atualizações de política em cada passo e podem ser mais estáveis.
- Aleatoriedade: Algoritmos de RL são notoriamente sensíveis a estados iniciais e à aleatoriedade inerente à seleção de ações. Quando uma execução de treinamento é instável, às vezes pode ser estabilizada usando uma semente aleatória diferente ou reinicializando a política.
Conclusão
Neste tutorial, exploramos os princípios básicos de RL, discutimos o Gymnasium como um pacote de software com uma API limpa para interagir com vários ambientes de RL e mostramos como escrever um programa em Python para implementar um algoritmo simples de RL e aplicá-lo em um ambiente Gymnasium.
Após entender os conceitos básicos neste tutorial, recomendo usar ambientes Gymnasium para aplicar os conceitos de RL para resolver problemas práticos, como otimização de rotas de táxi e simulações de negociação de ações.
Source:
https://www.datacamp.com/tutorial/reinforcement-learning-with-gymnasium