Introdução: Aprender com Recompensas
O Reinforcement Learning (RL) é um paradigma de aprendizado fundamentalmente diferente do supervised e unsupervised learning. Em vez de aprender com dados rotulados, um agente interage com um ambiente, executa ações e recebe recompensas. O objetivo é aprender uma policy (estratégia) que maximize a recompensa acumulada ao longo do tempo.
Do jogo de xadrez (AlphaZero) à robótica (manipulação de objetos), do trading algorítmico à condução autônoma, o reinforcement learning está na base de algumas das aplicações de IA mais impressionantes. Neste artigo exploraremos os conceitos fundamentais, do Q-Learning clássico aos algoritmos modernos de deep RL como DQN e PPO.
O Que Você Aprenderá
- Markov Decision Process (MDP): estado, ação, recompensa, transição
- Q-Learning: a tabela de valores ação-estado
- Deep Q-Network (DQN): aproximar Q com redes neurais
- Policy Gradient: otimizar diretamente a policy
- Proximal Policy Optimization (PPO): estabilidade e desempenho
- Exploration vs exploitation: equilibrar descoberta e aproveitamento
- Implementação prática com Gymnasium (OpenAI)
Markov Decision Process (MDP)
O framework formal do RL é o Markov Decision Process, definido por quatro componentes:
- Estados (S): as situações possíveis em que o agente pode se encontrar (ex.: posição em uma grade, frame de um jogo)
- Ações (A): os movimentos disponíveis em cada estado (ex.: cima, baixo, esquerda, direita)
- Recompensas (R): o feedback numérico recebido após cada ação (ex.: +1 por vencer, -1 por perder)
- Transições (P): a probabilidade de passar para um estado seguinte dada uma ação. A propriedade de Markov estabelece que o futuro depende apenas do estado atual, não do histórico
O agente busca uma policy ótima que maximize a soma descontada das recompensas futuras. O discount factor gamma (entre 0 e 1) equilibra recompensas imediatas vs futuras: gamma próximo de 0 torna o agente míope, próximo de 1 o torna previsor.
Q-Learning: Valores Ação-Estado
O Q-Learning é um algoritmo off-policy que aprende a função Q(s, a): o valor esperado da recompensa acumulada ao escolher a ação a no estado s e seguindo a policy ótima a partir desse momento. A regra de atualização é:
Q(s, a) = Q(s, a) + alpha * [R + gamma * max_a'(Q(s', a')) - Q(s, a)]
import numpy as np
import gymnasium as gym
class QLearningAgent:
def __init__(self, n_states, n_actions, lr=0.1, gamma=0.99, epsilon=1.0):
self.q_table = np.zeros((n_states, n_actions))
self.lr = lr
self.gamma = gamma
self.epsilon = epsilon
self.epsilon_min = 0.01
self.epsilon_decay = 0.995
def choose_action(self, state):
"""Epsilon-greedy: explora com prob epsilon, explota caso contrário"""
if np.random.random() < self.epsilon:
return np.random.randint(self.q_table.shape[1])
return np.argmax(self.q_table[state])
def learn(self, state, action, reward, next_state, done):
"""Atualização da Q-table"""
target = reward
if not done:
target += self.gamma * np.max(self.q_table[next_state])
self.q_table[state, action] += self.lr * (target - self.q_table[state, action])
self.epsilon = max(self.epsilon_min, self.epsilon * self.epsilon_decay)
# Treinamento em FrozenLake
env = gym.make('FrozenLake-v1', is_slippery=False)
agent = QLearningAgent(n_states=16, n_actions=4)
for episode in range(5000):
state, _ = env.reset()
total_reward = 0
done = False
while not done:
action = agent.choose_action(state)
next_state, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
agent.learn(state, action, reward, next_state, done)
state = next_state
total_reward += reward
if episode % 1000 == 0:
print(f"Episódio {episode}, Recompensa: {total_reward}, "
f"Epsilon: {agent.epsilon:.3f}")
Exploration vs Exploitation
O dilema fundamental do RL: o agente deve explorar (tentar ações novas para descobrir melhores recompensas) e explotar (usar o conhecimento atual para maximizar a recompensa). A estratégia epsilon-greedy equilibra ambos os aspectos: com probabilidade epsilon escolhe uma ação aleatória, caso contrário a melhor ação conhecida. Epsilon é reduzido gradualmente durante o treinamento.
Deep Q-Network (DQN)
O Q-Learning com tabelas funciona apenas para espaços de estados pequenos e discretos. Para ambientes complexos (imagens, estados contínuos), a Deep Q-Network (DQN) substitui a Q-table por uma rede neural que aproxima a função Q. Duas inovações-chave estabilizam o treinamento:
- Experience Replay: as transições são armazenadas em um buffer e amostradas aleatoriamente para o treinamento, quebrando a correlação temporal entre amostras consecutivas
- Target Network: uma cópia separada da rede, atualizada periodicamente, calcula os Q-values alvo, estabilizando o aprendizado
import torch
import torch.nn as nn
from collections import deque
import random
class DQN(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.net = nn.Sequential(
nn.Linear(state_dim, 128),
nn.ReLU(),
nn.Linear(128, 128),
nn.ReLU(),
nn.Linear(128, action_dim)
)
def forward(self, x):
return self.net(x)
class DQNAgent:
def __init__(self, state_dim, action_dim, lr=1e-3, gamma=0.99):
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
self.q_net = DQN(state_dim, action_dim).to(self.device)
self.target_net = DQN(state_dim, action_dim).to(self.device)
self.target_net.load_state_dict(self.q_net.state_dict())
self.optimizer = torch.optim.Adam(self.q_net.parameters(), lr=lr)
self.memory = deque(maxlen=100000)
self.gamma = gamma
self.batch_size = 64
def store(self, state, action, reward, next_state, done):
self.memory.append((state, action, reward, next_state, done))
def learn(self):
if len(self.memory) < self.batch_size:
return
batch = random.sample(self.memory, self.batch_size)
states, actions, rewards, next_states, dones = zip(*batch)
states = torch.FloatTensor(states).to(self.device)
actions = torch.LongTensor(actions).to(self.device)
rewards = torch.FloatTensor(rewards).to(self.device)
next_states = torch.FloatTensor(next_states).to(self.device)
dones = torch.FloatTensor(dones).to(self.device)
q_values = self.q_net(states).gather(1, actions.unsqueeze(1))
with torch.no_grad():
next_q = self.target_net(next_states).max(1)[0]
targets = rewards + (1 - dones) * self.gamma * next_q
loss = nn.functional.mse_loss(q_values.squeeze(), targets)
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()
def update_target(self):
self.target_net.load_state_dict(self.q_net.state_dict())
Policy Gradient e Actor-Critic
Os métodos Policy Gradient otimizam diretamente a policy sem passar pela função Q. O teorema do policy gradient estabelece que o gradiente da recompensa esperada em relação aos parâmetros da policy é proporcional à recompensa ponderada pela log-probabilidade das ações.
Actor-Critic
A arquitetura Actor-Critic combina ambas as abordagens: o Actor (policy network) escolhe as ações, o Critic (value network) estima quão bom é o estado atual. O Critic reduz a variância das atualizações do Actor, tornando o treinamento mais estável.
PPO: O Padrão Industrial
Proximal Policy Optimization (PPO), desenvolvido pela OpenAI, é o algoritmo de RL mais usado na prática. Sua inovação-chave é o objetivo clipado: limita o quanto a nova policy pode se distanciar da antiga em cada atualização, prevenindo mudanças muito drásticas que desestabilizariam o treinamento.
PPO está na base de muitos sucessos: InstructGPT e RLHF (alinhamento de LLMs), OpenAI Five (Dota 2), treinamento de agentes robóticos e muitos outros.
Próximos Passos na Série
- No próximo artigo exploraremos o Transfer Learning Avançado com BERT, GPT e Hugging Face
- Veremos fine-tuning, prompt engineering e RAG (Retrieval-Augmented Generation)
- Compararemos modelos open-source: Llama, Mistral, Falcon







