Implementação do algoritmo Q-Learning no ambiente FrozenLake-v1
1. Configurar o ambiente
Primeiro, instalamos e importamos o gymnasium e as bibliotecas auxiliares.
!pip install gymnasium
import numpy as np
import gymnasium as gym
import random
# Inicializa o ambiente (is_slippery=False facilita a convergência inicial)
env = gym.make('FrozenLake-v1', is_slippery=False)
2. Definir os hiperparâmetros e a Q-table
A Q-table mapeia cada estado (cada quadrado do lago) para o valor de utilidade de cada ação possível.
state_size = env.observation_space.n
action_size = env.action_space.n
# Inicializa a Q-table com zeros
q_table = np.zeros((state_size, action_size))
# Hiperparâmetros
total_episodes = 2000 # Número de episódios de treino
learning_rate = 0.8 # Taxa de aprendizado (alpha)
discount_rate = 0.95 # Fator de desconto (gamma)
# Parâmetros de Exploração (Epsilon-Greedy)
epsilon = 1.0 # Taxa inicial de exploração
max_epsilon = 1.0
min_epsilon = 0.01
decay_rate = 0.005 # Taxa de decaimento do epsilon
3. Treinar o agente com Q-Learning
O agente utiliza a fórmula do Q-Learning para atualizar seus conhecimentos a cada passo, equilibrando exploração (tentar coisas novas) e explotação (usar o que já sabe).
A fórmula matemática de atualização utilizada é:
$$Q(s, a) \leftarrow Q(s, a) + \alpha \left[ r + \gamma \max_{a'} Q(s', a') - Q(s, a) \right]$$
for episode in range(total_episodes):
state, info = env.reset()
done = False
while not done:
# Política Epsilon-Greedy
exp_exp_tradeoff = random.uniform(0, 1)
if exp_exp_tradeoff > epsilon:
# Explotação: escolhe a melhor ação da Q-table
action = np.argmax(q_table[state, :])
else:
# Exploração: escolhe uma ação aleatória
action = env.action_space.sample()
# Executa a ação no ambiente
next_state, reward, terminated, truncated, info = env.step(action)
done = terminated or truncated
# Atualização da Q-table
q_table[state, action] = q_table[state, action] + learning_rate * (
reward + discount_rate * np.max(q_table[next_state, :]) - q_table[state, action]
)
state = next_state
# Reduz a taxa de exploração (epsilon decay)
epsilon = min_epsilon + (max_epsilon - min_epsilon) * np.exp(-decay_rate * episode)
print("Treinamento concluído!")
print("Q-Table Final:")
print(q_table)
4. Avaliar o desempenho
Agora, testamos o agente sem nenhuma exploração ($\epsilon = 0$), medindo sua taxa de sucesso em 100 episódios.
env_eval = gym.make('FrozenLake-v1', is_slippery=False)
total_test_episodes = 100
sucessos = 0
for episode in range(total_test_episodes):
state, info = env_eval.reset()
done = False
while not done:
# Apenas explotação
action = np.argmax(q_table[state, :])
state, reward, terminated, truncated, info = env_eval.step(action)
done = terminated or truncated
if reward == 1.0:
sucessos += 1
print(f"Resultados do teste em {total_test_episodes} episódios:")
print(f"Episódios bem-sucedidos: {sucessos}")
print(f"Taxa de sucesso: {(sucessos / total_test_episodes) * 100}%")
env_eval.close()
env.close()