Pular para o conteúdo principal
InicioTutoriaisAprendizado de máquina

Uma introdução ao Q-Learning: Um tutorial para iniciantes

Saiba mais sobre o algoritmo mais popular de aprendizado por reforço sem modelo com um tutorial em Python.
24 de abr. de 2024  · 16 min leer

Q Cabeçalho de aprendizado

O aprendizado por reforço (RL) é a parte do ecossistema de aprendizado de máquina em que o agente aprende interagindo com o ambiente para obter a estratégia ideal para atingir as metas. Isso é bem diferente dos algoritmos de aprendizado de máquina supervisionados, em que precisamos ingerir e processar esses dados. O aprendizado por reforço não requer dados. Em vez disso, ele aprende com o ambiente e o sistema de recompensas para tomar decisões melhores.

Por exemplo, no videogame Mario, se um personagem realizar uma ação aleatória (por exemplo, mover-se para a esquerda), com base nessa ação, ele poderá receber uma recompensa. Depois de realizar a ação, o agente (Mario) fica em um novo estado, e o processo se repete até que o personagem do jogo chegue ao final da fase ou morra. 

Esse episódio se repetirá várias vezes até que Mario aprenda a navegar pelo ambiente maximizando as recompensas. 

Aprendizagem por reforço

Imagem do autor

Podemos dividir o aprendizado por reforço em cinco etapas simples:

  1. O agente está no estado zero em um ambiente.
  2. Ele tomará uma ação com base em uma estratégia específica.
  3. Ele receberá uma recompensa ou punição com base nessa ação.
  4. Aprendendo com as jogadas anteriores e otimizando a estratégia. 
  5. O processo se repetirá até que seja encontrada uma estratégia ideal. 

Saiba mais lendo nosso tutorial, Introdução ao aprendizado por reforço. Você saberá mais sobre como funciona o aprendizado por reforço com exemplos de código. 

Neste tutorial, aprenderemos sobre Q-learning e entenderemos por que precisamos do Deep Q-learning. Além disso, aprenderemos a criar e treinar algoritmos de aprendizado Q do zero usando o Numpy e o OpenAI Gym.

Observação: Se você é novo no aprendizado de máquina, recomendamos que faça o curso de carreira Cientista de aprendizado de máquina com Python para entender melhor o aprendizado por reforço e o Q-Learning. 

O que é o Q-Learning?

O Q-learning é um algoritmo sem modelo, baseado em valores e fora da política que encontrará a melhor série de ações com base no estado atual do agente. O "Q" significa qualidade. A qualidade representa o valor da ação para maximizar as recompensas futuras.  

Os algoritmos baseados em modelos usam funções de transição e recompensa para estimar a política ideal e criar o modelo. Por outro lado, os algoritmos sem modelo aprendem as consequências de suas ações por meio da experiência sem transição e função de recompensa. 

O método baseado em valor treina a função de valor para saber qual estado é mais valioso e tomar medidas. Por outro lado, os métodos baseados em políticas treinam a política diretamente para aprender qual ação deve ser tomada em um determinado estado.

Na política de desativação, o algoritmo avalia e atualiza uma política que difere da política usada para realizar uma ação. Por outro lado, o algoritmo na política avalia e aprimora a mesma política usada para realizar uma ação.  

Principais terminologias em Q-learning

Antes de falarmos sobre como o Q-learning funciona, precisamos aprender algumas terminologias úteis para entender os fundamentos do Q-learning. 

  • Estado(s): a posição atual do agente no ambiente. 
  • Ação(a): uma etapa realizada pelo agente em um determinado estado. 
  • Recompensas: para cada ação, o agente recebe uma recompensa e uma penalidade. 
  • Episódios: o fim do estágio, onde os agentes não podem realizar novas ações. Isso acontece quando o agente atinge a meta ou falha. 
  • Q(St+1, a): valor Q ideal esperado de realizar a ação em um determinado estado. 
  • Q(St,At): é a estimativa atual de Q(St+1, a).
  • Q-Table: o agente mantém o Q-table de conjuntos de estados e ações.
  • Diferenças temporais (TD): usado para estimar o valor esperado de Q(St+1, a) usando o estado e a ação atuais e o estado e a ação anteriores. 

Como o Q-Learning funciona?

Aprenderemos em detalhes como funciona o Q-learning usando o exemplo de um lago congelado. Nesse ambiente, o agente deve atravessar o lago congelado desde o início até o objetivo, sem cair nos buracos. A melhor estratégia é atingir as metas pelo caminho mais curto. 

Visualização do Q-Learning

Gif por autor

Mesa Q

O agente usará uma tabela Q para tomar a melhor ação possível com base na recompensa esperada para cada estado do ambiente. Em palavras simples, um Q-table é uma estrutura de dados de conjuntos de ações e estados, e usamos o algoritmo de Q-learning para atualizar os valores na tabela. 

Função Q

A função Q usa a equação de Bellman e usa estado(s) e ação(a) como entrada. A equação simplifica os valores de estado e o cálculo do valor da ação de estado. Equação de Bellman

Imagem de freecodecamp.org

Algoritmo de aprendizado Q

Processo de Q-Learning

Imagem do autor

Inicializar o Q-Table

Primeiro, inicializaremos o Q-table. Criaremos a tabela com colunas baseadas no número de ações e linhas baseadas no número de estados.

Em nosso exemplo, o personagem pode se mover para cima, para baixo, para a esquerda e para a direita. Temos quatro ações possíveis e quatro estados (início, ocioso, caminho errado e fim). Você também pode considerar o caminho errado para cair no buraco. Inicializaremos o Q-Table com valores em 0. 


Q-Tabela 1

Imagem do autor

Escolha uma ação

A segunda etapa é bastante simples. No início, o agente escolherá tomar a ação aleatória (para baixo ou para a direita) e, na segunda execução, usará um Q-Table atualizado para selecionar a ação. 

Executar uma ação

A escolha de uma ação e a execução da ação serão repetidas várias vezes até que o loop de treinamento seja interrompido. A primeira ação e o primeiro estado são selecionados usando o Q-Table. Em nosso caso, todos os valores do Q-Table são zero. 

Em seguida, o agente se moverá para baixo e atualizará o Q-Table usando a equação de Bellman. A cada jogada, atualizaremos os valores no Q-Table e também o usaremos para determinar o melhor curso de ação. 

Inicialmente, o agente está no modo de exploração e escolhe uma ação aleatória para explorar o ambiente. A estratégia Epsilon Greedy é um método simples para equilibrar a exploração e o aproveitamento. O epsilon representa a probabilidade de escolher explorar e explora quando há menos chances de explorar. 

No início, a taxa de epsilon é mais alta, o que significa que o agente está no modo de exploração. Ao explorar o ambiente, o epsilon diminui e os agentes começam a explorar o ambiente. Durante a exploração, a cada iteração, o agente se torna mais confiante na estimativa dos valores Q

Q-Table 2

Imagem do autor

No exemplo do lago congelado, o agente não tem conhecimento do ambiente e, portanto, toma uma ação aleatória (mover-se para baixo) para começar. Como podemos ver na imagem acima, o Q-Table é atualizado usando a equação de Bellman.

Medindo as recompensas

Depois de realizar a ação, mediremos o resultado e a recompensa. 

  • A recompensa por atingir a meta é +1
  • A recompensa por seguir o caminho errado (cair no buraco) é 0
  • A recompensa por ficar ocioso ou se mover no lago congelado também é 0. 

Atualizar o Q-Table

Atualizaremos a função Q(St,At) usando a equação. Ele usa os valores Q estimados do episódio anterior, a taxa de aprendizado e o erro de diferenças temporais. O erro de diferenças temporais é calculado usando a recompensa imediata, a recompensa futura máxima esperada descontada e o valor Q da estimativa anterior. 

O processo é repetido várias vezes até que o Q-Table seja atualizado e a função de valor Q seja maximizada. 

Equação de aprendizado Q

Imagem do autor | Equation Visuals de Thomas Simonini

No início, o agente está explorando o ambiente para atualizar o Q-table. E quando o Q-Table estiver pronto, o agente começará a explorar e a tomar decisões melhores. Q-Table 3

Imagem do autor

No caso de um lago congelado, o agente aprenderá a seguir o caminho mais curto para atingir a meta e evitar pular nos buracos. 

Tutorial de Python da Q-Learning 

Nesta seção, criaremos nosso modelo de Q-learning do zero usando o ambiente Gym, Pygame e Numpy. O tutorial de Python é uma versão modificada do Notebook de Thomas Simonini. Inclui a inicialização do ambiente e do Q-Table, a definição da política de ganância, a configuração dos hiperparâmetros, a criação e a execução do loop de treinamento e da avaliação e a visualização dos resultados.   

Se estiver enfrentando problemas para criar e executar o loop de treinamento, verifique o código-fonte com o resultado.   

Configuração

Configurar uma tela virtual

Primeiro, instalaremos todas as dependências para gerar um vídeo de reprodução (Gif). Precisaremos de uma tela virtual (pyvirtualdisplay) para renderizar o ambiente e gravar os quadros. 

Observação: ao usar `%%capture`, estamos suprimindo a saída da célula do Jupyter. 

%%capture
!pip install pyglet==1.5.1
!apt install python-opengl
!apt install ffmpeg
!apt install xvfb
!pip3 install pyvirtualdisplay

# Virtual display
from pyvirtualdisplay import Display

virtual_display = Display(visible=0, size=(1400, 900))
virtual_display.start()

Instalar dependências

Agora, instalaremos as dependências que nos ajudarão a criar, executar e avaliar o loop de treinamento. 

  • academia: Usado para inicializar o ambiente do FrozenLake-v1.
  • pygame: Usado para a interface do usuário do FrozenLake-v1.
  • numPy: Usado para criar e manipular o Q-table.
%%capture
!pip install gym==0.24
!pip install pygame
!pip install numpy

!pip install imageio imageio_ffmpeg

Importar os pacotes

Agora vamos importar as bibliotecas necessárias. 

  • O Imageio é usado para criar a animação. 
  • tqdm é usado para barras de progresso. 
import numpy as np
import gym
import random
import imageio
from tqdm.notebook import trange

Ambiente do ginásio Frozen Lake 

Vamos criar um ambiente 4x4 não escorregadio usando a biblioteca de ginástica Frozen Lake

  • Há duas versões de grade, "4x4" e "8x8".
  • Se `is_slippery=True`, o agente poderá não se mover na direção pretendida devido à natureza escorregadia do lago congelado. 

Depois de inicializar o ambiente, faremos uma análise ambiental. 

env = gym.make("FrozenLake-v1",map_name="4x4",is_slippery=False)

print("Observation Space", env.observation_space)
print("Sample observation", env.observation_space.sample()) # display a random observation

Há 16 espaços exclusivos no ambiente exibidos em posições aleatórias. 

Observation Space Discrete(16)
Sample observation 15

Vamos descobrir o número de ações e exibir a ação aleatória. 

O espaço de ação:

  • 0: mover para a esquerda
  • 1: mover para baixo
  • 2: mover para a direita
  • 3: subir

Função de recompensa:

  • Alcançando a meta: +1
  • Caindo no buraco: 0
  • Ficar no lago congelado: 0
print("Action Space Shape", env.action_space.n)
print("Action Space Sample", env.action_space.sample())
Action Space Shape 4
Action Space Sample 1

Criar e inicializar o Q-table

O Q-Table tem colunas como ações e linhas como estados. Podemos usar o OpenAI Gym para encontrar o espaço de ação e o espaço de estado. Em seguida, usaremos essas informações para criar o Q-Table. 

state_space = env.observation_space.n
print("There are ", state_space, " possible states")

action_space = env.action_space.n
print("There are ", action_space, " possible actions")
There are  16  possible states
There are  4  possible actions

Para inicializar o Q-Table, criaremos uma matriz Numpy de state_space e actions space. Criaremos uma matriz de 16 x 4. 

def initialize_q_table(state_space, action_space):
  Qtable = np.zeros((state_space, action_space))
  return Qtable

Qtable_frozenlake = initialize_q_table(state_space, action_space)

Política de Epsilon-greedy

Na seção anterior, aprendemos sobre a estratégia epsilon greedy que lida com as compensações de exploração e aproveitamento. Com uma probabilidade de 1 - ɛ, fazemos exploitation, e com a probabilidade ɛ, fazemos exploration. 

Na política epsilon_greedy_policy, faremos o seguinte:

  1. Gere o número aleatório entre 0 e 1.
  2. Se o número aleatório for maior que epsilon, faremos a exploração. Isso significa que o agente executará a ação com o valor mais alto em um determinado estado.
  3. Caso contrário, faremos a exploração (tomar ações aleatórias). 
def epsilon_greedy_policy(Qtable, state, epsilon):
  random_int = random.uniform(0,1)
  if random_int > epsilon:
    action = np.argmax(Qtable[state])
  else:
    action = env.action_space.sample()
  return action

Definir a política gananciosa

Como já sabemos, o Q-learning é um algoritmo fora da política, o que significa que a política de tomada de ação e a função de atualização são diferentes. 

Neste exemplo, a política Epsilon Greedy é a política de atuação, e a política Greedy é a política de atualização. 

A política Greedy também será a política final quando o agente for treinado. É usado para selecionar o valor mais alto de estado e ação do Q-Table.

def greedy_policy(Qtable, state):
  action = np.argmax(Qtable[state])
  return action

Hiperparâmetros do modelo

Esses hiperparâmetros são usados no loop de treinamento, e o ajuste fino deles lhe proporcionará melhores resultados. 

O agente precisa explorar um espaço de estado suficiente para aprender uma boa aproximação de valores; precisamos ter um decaimento progressivo do épsilon. Se a taxa de decaimento for alta, o agente poderá ficar preso, pois não explorou espaço de estado suficiente.

  • Há 10.000 episódios de treinamento e 100 de avaliação.
  • A taxa de aprendizado é de 0,7.
  • Estamos usando o "FrozenLake-v1" como um ambiente com 99 etapas máximas por episódio.
  • O gamma (taxa de desconto) é 0,95.
  • eval_seed: semente de avaliação para o ambiente.
  • A probabilidade do épsilon de exploração no início é de 1,0 e a probabilidade mínima será de 0,05.
  • A taxa de decaimento exponencial da probabilidade epsilon é de 0,0005.
# Training parameters
n_training_episodes = 10000
learning_rate = 0.7        

# Evaluation parameters
n_eval_episodes = 100      

# Environment parameters
env_id = "FrozenLake-v1"   
max_steps = 99             
gamma = 0.95               
eval_seed = []             

# Exploration parameters
max_epsilon = 1.0           
min_epsilon = 0.05           
decay_rate = 0.0005           

Treinamento de modelos 

No loop de treinamento, nós o faremos:

  1. Crie um loop para episódios de treinamento.
  2. Primeiro, reduziremos o epsilon. Como precisamos de cada vez menos exploração e mais exploração a cada episódio. 
  3. Redefinir o ambiente.
  4. Crie um loop aninhado para as etapas máximas.
  5. Escolha a ação usando a política epsilon greedy. 
  6. Realize a ação (At) e observe a recompensa esperada (Rt+1) e o estado (St+1).
  7. Realize a ação (a) e observe o estado do resultado (s') e a recompensa (r).
  8. Atualize a função Q usando a fórmula. 
  9. Se `done= True`, finaliza o episódio e interrompe o loop.
  10. Por fim, altere o estado atual para um novo estado. 
  11. Após a conclusão de todos os episódios de treinamento, a função retornará o Q-Table atualizado. 
def train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable):
  for episode in trange(n_training_episodes):
 
    epsilon = min_epsilon + (max_epsilon - min_epsilon)*np.exp(-decay_rate*episode)
    # Reset the environment
    state = env.reset()
    step = 0
    done = False

    # repeat
    for step in range(max_steps):
   
      action = epsilon_greedy_policy(Qtable, state, epsilon)

   
      new_state, reward, done, info = env.step(action)

   
      Qtable[state][action] = Qtable[state][action] + learning_rate * (reward + gamma * np.max(Qtable[new_state]) - Qtable[state][action])

      # If done, finish the episode
      if done:
        break
     
      # Our state is the new state
      state = new_state
  return Qtable

Levamos 3 segundos para concluir 10.000 episódios de treinamento. 

Qtable_frozenlake = train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable_frozenlake)

Episódios de treinamento Resultado

Como podemos ver, o Q-Table treinado tem valores, e o agente agora usará esses valores para navegar pelo ambiente e atingir a meta.  

Qtable_frozenlake
array([[0.73509189, 0.77378094, 0.77378094, 0.73509189],
      [0.73509189, 0.        , 0.81450625, 0.77378094],
      [0.77378094, 0.857375  , 0.77378094, 0.81450625],
      [0.81450625, 0.        , 0.77378094, 0.77378094],
      [0.77378094, 0.81450625, 0.        , 0.73509189],
      [0.        , 0.        , 0.        , 0.        ],
      [0.        , 0.9025    , 0.        , 0.81450625],
      [0.        , 0.        , 0.        , 0.        ],
      [0.81450625, 0.        , 0.857375  , 0.77378094],
      [0.81450625, 0.9025    , 0.9025    , 0.        ],
      [0.857375  , 0.95      , 0.        , 0.857375  ],
      [0.        , 0.        , 0.        , 0.        ],
      [0.        , 0.        , 0.        , 0.        ],
      [0.        , 0.9025    , 0.95      , 0.857375  ],
      [0.9025    , 0.95      , 1.        , 0.9025    ],
      [0.        , 0.        , 0.        , 0.        ]])

Avaliação

O evaluate_agent é executado por `n_eval_episodes` episódios e retorna a média e o desvio padrão da recompensa. 

  1. No loop, primeiro verificaremos se há uma semente de avaliação. Caso contrário, reiniciaremos o ambiente sem a semente. 
  2. O loop aninhado será executado até max_steps.
  3. O agente tomará a ação que tem a recompensa futura máxima esperada em um determinado estado usando o Q-Table. 
  4. Calcule o prêmio.
  5. Alterar o estado.
  6. Se estiver concluído (o agente cair no buraco ou a meta tiver sido atingida), interrompa o loop.
  7. Anexar os resultados.
  8. No final, usaremos esses resultados para calcular a média e o desvio padrão. 
def evaluate_agent(env, max_steps, n_eval_episodes, Q, seed):

  episode_rewards = []
  for episode in range(n_eval_episodes):
    if seed:
      state = env.reset(seed=seed[episode])
    else:
      state = env.reset()
    step = 0
    done = False
    total_rewards_ep = 0
   
    for step in range(max_steps):
      # Take the action (index) that have the maximum reward
      action = np.argmax(Q[state][:])
      new_state, reward, done, info = env.step(action)
      total_rewards_ep += reward
       
      if done:
        break
      state = new_state
    episode_rewards.append(total_rewards_ep)
  mean_reward = np.mean(episode_rewards)
  std_reward = np.std(episode_rewards)

  return mean_reward, std_reward

Como você pode ver, obtivemos a pontuação perfeita com desvio padrão zero. Isso significa que nosso agente atingiu a meta em todos os 100 episódios. 

# Evaluate our Agent
mean_reward, std_reward = evaluate_agent(env, max_steps, n_eval_episodes, Qtable_frozenlake, eval_seed)
print(f"Mean_reward={mean_reward:.2f} +/- {std_reward:.2f}")
Mean_reward=1.00 +/- 0.00

Visualização do resultado

Até agora, estivemos brincando com números e, para fazer a demonstração, precisamos criar um gif animado do agente desde o início até ele atingir a meta. 

  1. Primeiro, criaremos o estado redefinindo o ambiente com um número inteiro aleatório de 0 a 500. 
  2. Renderize o ambiente usando rdb_array para criar uma matriz de imagens. 
  3. Em seguida, anexe a imagem à matriz de imagens. 
  4. No loop, vamos fazer a etapa usando o Q-Table e renderizar a imagem para cada etapa. 
  5. No final, usaremos essa matriz e o imageio para criar um gif de um quadro por segundo. 
def record_video(env, Qtable, out_directory, fps=1):
  images = [] 
  done = False
  state = env.reset(seed=random.randint(0,500))
  img = env.render(mode='rgb_array')
  images.append(img)
  while not done:
    # Take the action (index) that have the maximum expected future reward given that state
    action = np.argmax(Qtable[state][:])
    state, reward, done, info = env.step(action) # We directly put next_state = state for recording logic
    img = env.render(mode='rgb_array')
    images.append(img)
  imageio.mimsave(out_directory, [np.array(img) for i, img in enumerate(images)], fps=fps)

Se você estiver em um notebook Jupyter, poderá exibir o Gif usando a função Image do `IPython.display`. 

video_path="/content/replay.gif"
video_fps=1
record_video(env, Qtable_frozenlake, video_path, video_fps)

from IPython.display import Image
Image('./replay.gif')

Agora você pode compartilhar esses resultados com seus colegas e companheiros de classe ou publicá-los nas mídias sociais.

Perguntas frequentes sobre o Q-Learning

Qual é a desvantagem do Q-learning?

O processo de aprendizado no Q-learning é caro para o agente, especialmente nas etapas iniciais. Por que isso acontece? Para convergir a política ideal, cada par de estado e ação é visitado com frequência.

Por que o aprendizado Q é chamado de aprendizado Q?

No Q-learning, "Q" significa qualidade. Representa a utilidade de uma determinada ação para obter recompensas futuras, que é usada para criar um sistema de mapas de estado e ação para maximizar as recompensas esperadas.

Por que o Q-Learning está fora da política?

No Q-learning, a política atualizada é diferente da política de comportamento (ação), e é por isso que ele é chamado de algoritmo fora da política.

O Q-learning sempre converge?

Sim. Durante o treinamento, o algoritmo sempre converge para a política ideal.

Por que precisamos de Q-learning profundo?

O Q-learning é um algoritmo simples projetado para um ambiente menor e discreto. No caso de um ambiente maior, precisaremos de um Q-table insanamente grande de estados e ações que exigirão mais memória e computação para serem treinados. Por outro lado, o Deep Q-learning substitui o Q-table por uma rede neural para lidar com ambientes grandes que envolvem ações e estados contínuos.

Temas

Cursos de aprendizado de máquina

Course

Designing Machine Learning Workflows in Python

4 hr
10.4K
Learn to build pipelines that stand the test of time.
See DetailsRight Arrow
Start Course
Ver maisRight Arrow
Relacionado

tutorial

Tutorial para entender a regressão logística em Python

Aprenda sobre a regressão logística, suas propriedades básicas e crie um modelo de aprendizado de máquina em um aplicativo do mundo real em Python.
Avinash Navlani's photo

Avinash Navlani

10 min

tutorial

Introdução ao k-Means Clustering com o scikit-learn em Python

Neste tutorial, saiba como aplicar o k-Means Clustering com o scikit-learn em Python

Kevin Babitz

21 min

tutorial

Tutorial de manipulação de dados categóricos de aprendizado de máquina com Python

Aprenda os truques comuns para lidar com dados categóricos e pré-processá-los para criar modelos de aprendizado de máquina!
Moez Ali's photo

Moez Ali

28 min

tutorial

Tutorial de mineração de regras de associação em Python

Descobrindo padrões ocultos em Python com mineração de regras de associação
Moez Ali's photo

Moez Ali

14 min

tutorial

Tutorial de regressão Lasso e Ridge em Python

Saiba mais sobre as técnicas de regressão lasso e ridge. Compare e analise os métodos em detalhes.
DataCamp Team's photo

DataCamp Team

10 min

tutorial

Tutorial de lambda em Python

Aprenda uma maneira mais rápida de escrever funções em tempo real com as funções lambda.
DataCamp Team's photo

DataCamp Team

3 min

See MoreSee More