Aprendizado por Reforço (RL) é um dos três principais paradigmas de aprendizado de máquina, os outros dois sendo o aprendizado supervisionado e não supervisionado. No RL, um agente aprende a interagir com seu ambiente para maximizar as recompensas cumulativas. Ele aprende a ação ótima sob diferentes condições ambientais por tentativa e erro. Aprendizado por Reforço com Feedback Humano (RLHF) permite que o agente modifique o comportamento com base em entradas humanas a cada passo.
O 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, é chamado de Aprendizado por Reforço Profundo.
Neste tutorial, vou te 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 é o Gymnasium?
Gymnasium é uma biblioteca Python de código aberto projetada para suportar 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.
Gym da OpenAI versus Ginásio da Farama
A OpenAI não comprometeu recursos significativos para desenvolver o Gym porque não era uma prioridade comercial para a empresa. T a Fundação Farama foi criada para padronizar e manter bibliotecas de RL a longo prazo. O Ginásio é o fork da Fundação Farama do Gym da OpenAI. O Ginásio 0.26.2 é uma substituição direta para o Gym 0.26.2. Com o fork, a Farama pretende adicionar métodos funcionais (além dos baseados em classes) para todas as chamadas da API, suportar ambientes vetoriais e melhorar os wrappers. O objetivo geral é tornar o framework mais limpo e eficiente.
Configurando o Ginásio
O ginásio precisa de versões específicas (não as mais recentes) 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 Ginásio e executar programas de RL.
Você pode usar este caderno DataLab para seguir o tutorial.
Instalando o Ginásio
Para instalar o Ginásio 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, utilize 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 Gymnasium. A coluna da esquerda possui links para todos os ambientes. A página da 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 em livros didáticos. Eles oferecem a mistura certa de complexidade e simplicidade para testar e avaliar novos algoritmos de RL. Os ambientes de controle clássico no Gymnasium incluem:
- Acrobot
- Cart Pole
- Mountain Car Discreto
- Mountain Car Contínuo
- Pêndulo
- Box2D: O Box2D é um Motor de Física 2D para Jogos. Ambientes baseados nesse motor incluem jogos simples como:
- Lunar Lander
- Corrida de Carros
- ToyText: Esses são ambientes pequenos e simples frequentemente usados para depurar algoritmos de RL. Muitos desses ambientes são baseados no modelo de mundo em grade pequena e jogos de cartas simples. Exemplos incluem:
- Blackjack
- Táxi
- Frozen Lake
- MuJoCo: Dinâmica Multiarticulada com Contato (MuJoCo) é um motor de física de código aberto que simula ambientes para aplicações como robótica, biomecânica, ML, etc. Ambientes MuJoCo no Gymnasium incluem:
- Formiga
- Pulador
- Humanoide
- Nadador
- E mais
Além dos ambientes integrados, o Gymnasium pode ser usado com muitos ambientes externos usando a mesma API.
Nós 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 um argumento. Por exemplo, para criar um novo ambiente baseado em 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 fornece uma recompensa (ou penalidade) em 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 de 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 diversas 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 rende ao agente uma recompensa.
- 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 dos próximos passos. 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 (aleatorizado) 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ô, poderia 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 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 em que 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 observation_space
método:
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 CartPole-v1
o espaço de observação tem 4 dimensões. Os 4 elementos do array de observação são:
- Posição do carrinho – varia entre -4.8 e +4.8
- Velocidade do carrinho – varia entre – e +
- Ângulo do pêndulo – varia entre -0,4189 e +0,4189
- Velocidade angular do polo – varia entre – e +
Para ver um exemplo de um array 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 poste, velocidade angular do poste), como explicado anteriormente.
Espaço de ação
O espaço de ação inclui todas as ações possíveis que o agente pode tomar. O espaço de ação também define o formato no qual 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 realizar:
- 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 modificam 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 toda vez que o programa é 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 semear os 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 passo de um processo de Markov, o agente pode escolher aleatoriamente uma ação 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 acumuladas 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 baseadas 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. Em RL, o processo de treinamento também é chamado de otimização de política.
Existem 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 Proximal de Política (PPO).
Implementando um Agente Simples de Gradiente de Política
Para construir um agente RL que usa 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
Nós 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 estados observados para ações. Dada 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
Conforme mencionado, em cada etapa do processo de Markov, o ambiente fornece uma recompensa com base na ação e no estado do agente. O objetivo no 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 atinge um estado terminal).
Na prática, ao acumular recompensas, é comum:
- Ajustar as recompensas futuras usando um fator de desconto.
- Normalizar o array 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 direta consiste em executar o agente com base na política atual até que ele alcance um estado terminal e colete as recompensas por etapa e as probabilidades de ação. Os passos abaixo explicam como implementar a passagem direta:
- Redefina o ambiente para um estado inicial.
- Inicialize os buffers para armazenar as probabilidades de ação, as recompensas e o retorno cumulativo
- Use a função
.step()
para executar iterativamente o agente no ambiente até que ele termine: - Obtenha a observação do estado do ambiente.
- Obtenha a ação prevista pela política com base na observação.
- Utilize 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 da distribuição simulada.
- Adicione o logaritmo da probabilidade das ações e das recompensas de cada etapa aos seus respectivos 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
Atualização da política com base nas recompensas
A perda representa a quantidade sobre a qual aplicamos a descida do gradiente. O objetivo em RL é maximizar os retornos. Portanto, usamos o valor de retorno esperado como um proxy para a perda. O valor de retorno esperado é calculado como o produto dos retornos esperados passo a passo e do logaritmo da probabilidade das ações passo a passo. 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 update_policy()
método abaixo invoca o calculate_loss()
método. Em seguida, executa a 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 de gradiente de política.
Treinamento da 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 etapas de tempo futuras. 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 da etapa 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 aleatoriamente zerada. 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 para frente 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 logarítmicas 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
ultrapassa 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 workbook DataLab para executar o algoritmo acima diretamente e resolver o ambiente CartPole usando RL.
Técnicas Avançadas em Ginásio
Depois de demonstrar como implementar um algoritmo de RL, agora discutimos algumas técnicas avançadas comumente usadas na prática.
Usando arquiteturas pré-construídas
Implementar 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 umsoftware 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 plotar gráficos e gravar vídeos.
Ray RLib é outra ferramenta popular para RL. O RLib é projetado como uma solução escalável, facilitando a implementação de algoritmos de RL em sistemas multi-GPU. Ele também suporta RL multi-agente, o que abre novas possibilidades como:
- Aprendizado independente de múltiplos agentes: Cada agente trata outros agentes como parte do ambiente.
- Treinamento colaborativo multiagente: 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 entre si em ambientes competitivos semelhantes a jogos.
Com o RLib e o Stable Baselines3, você pode importar e utilizar ambientes do OpenAI Gymnasium.
Ambientes personalizados
Ambientes embalados 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 funcionar 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 das quais o agente pode escolher.
- Como inicializar o ambiente (quando a função
reset()
é chamada). - Como o ambiente decide o próximo estado dadas 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.
Práticas recomendadas 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 que você aplique 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. É composto por uma única entrada representada como uma variável contínua – o torque (magnitude e direção) aplicado ao pêndulo em qualquer estado dado. Esse torque pode assumir qualquer valor entre -2 e +2.
Experimentar com diferentes algoritmos em diversos ambientes ajuda a compreender melhor 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 ao inicializar o ambiente. Por exemplo:
env = gym.make(‘CartPole-v1’, render_mode=’human’)
Para realizar a renderização, envolva o método .render()
após cada ação realizada pelo agente (por meio da chamada do método .step()
). O pseudo-código abaixo ilustra como fazer isso:
while not done: … step, reward, terminated, truncated, info = env.step(action.item()) env.render() …
Resolução de erros comuns
O Gymnasium facilita a interface com ambientes de RL complexos. No entanto, é um software continuamente atualizado com muitas dependências. Portanto, ficar atento a alguns tipos comuns de erros é essencial.
Discrepâncias de versão
- Desajuste 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 significativas entre as versões antigas do Gym e as novas versões do Gymnasium. Muitas implementações disponíveis publicamente são baseadas nas versões antigas do Gym e podem não funcionar diretamente com a versão mais recente. Nesses casos, é necessário fazer o downgrade da instalação para uma versão mais antiga ou adaptar o código para funcionar com a versão mais recente.
- 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 o comprimento 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. - Incompatibilidade de versão das dependências: O Gymnasium depende de bibliotecas como NumPy e PyTorch. Em dezembro de 2024, as versões mais recentes dessas dependências são
numpy 2.1.3
etorch 2.5.1
. No entanto, o 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 usando 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 braços: explorar o ambiente para descobrir novos caminhos e adotar uma abordagem gananciosa para maximizar as recompensas com base nos caminhos conhecidos até agora. Se ele explorar demais, a política não converge. Por outro lado, nunca tentará o caminho ideal 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 altas: Se a taxa de aprendizado for muito alta, os parâmetros da política sofrem grandes atualizações em cada etapa. Isso pode levar a perder 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 etapas subsequentes. Para ter um processo de treinamento estável e convergente, equilibre exploração com exploração.
- Escolha errada de algoritmo: Algoritmos simples como o gradiente de política podem levar a um treinamento instável em ambientes complexos com grandes espaços de ações e estados. Nesses casos, recomendamos o uso de algoritmos mais robustos como PPO e Otimização de Política de Região de Confiança (TRPO). Esses algoritmos evitam grandes atualizações de política a 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 está instável, às vezes pode ser estabilizada usando uma semente aleatória diferente ou reinitializando a política.
Conclusão
Neste tutorial, exploramos os princípios básicos do 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 de RL simples e aplicá-lo em um ambiente do Gymnasium.
Depois de entender os conceitos básicos neste tutorial, recomendo usar os ambientes do Gymnasium para aplicar os conceitos de RL na resolução de 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