Algoritmo Q-Learning
Definições e conceitos chave
Nesta aula vamos utilizar os slides abaixo:
Implementação
Depois de uma breve conversa sobre os principais conceitos, vamos implementar o primeiro agente utilizando aprendizado por reforço. Por favor, siga as instruções abaixo:
-
copie o arquivo TaxiDriverGym.py para a sua máquina local. Este arquivo faz uso do ambiente
Taxi-v3
da biblioteca Gymanasium e do algoritmo Q-Learning. -
copie o arquivo QLearning.py para a sua máquina local. Esta implementação está incompleta. Você terá que preencher o método
train
para que o algoritmo Q-Learning funcione corretamente. Mas antes disso, vamos entender a estrutura desta classe.
Arquivo QLearning.py
Este arquivo implementa o algoritmo Q-Learning. A classe implementada neste arquivo possui 4 métodos:
-
__init__
(construtor): que recebe todos os hiperparâmetros do algoritmo Q-Learning e inicializa a Q-table com base no número de ações e estados informados pelo parâmetro env. Alguns destes hiperparâmetros não serão utilizados neste momento, mas vamos mantê-los. -
select_action
: dado um estado, este método seleciona uma ação que deve ser executada. -
train
: método responsável por executar as simulações e popular a Q-table. Este método retorna uma q-table, mas também atualiza um arquivo CSV com os dados da q-table e uma imagem que é um plot da quantidade de ações executadas em cada episódio. -
plotactions
: é um método que cria uma imagem com o plot da quantidade de ações executadas em cada episódio.
Atualizando os valores da Q-table
Dentro do método train
tem-se o seguinte trecho de código:
for i in range(1, self.episodes+1):
(state, _) = self.env.reset()
rewards = 0
done = False
actions = 0
while not done:
#
# escolher uma ação $a$ para um estado $s$
# executar a ação $a$
# observar a recompensa $r$ e o novo estado $s'$
# Q(s,a) \leftarrow Q(s,a) + \alpha[r + \gamma \max_{A'}Q(s',A') - Q(s,a)]
# s recebe s'
#
que é responsável por execurtar N episódios e atualizar a variável self.q_table
.
Este método é chamado pelo arquivo TaxiDriverGym.py
nas linhas 11 e 12:
qlearn = QLearning(env, alpha=0.1, gamma=0.6, epsilon=0.7, epsilon_min=0.05, epsilon_dec=0.99, episodes=100000)
q_table = qlearn.train('data/q-table-taxi-driver.csv', 'results/actions_taxidriver')
#q_table = loadtxt('data/q-table-taxi-driver.csv', delimiter=',')
Atividades:
-
Complete o código do método
train
emQLearning.py
. -
Execute o arquivo
TaxiDriverGym.py
com o comando:
python TaxiDriverGym.py
Lembre-se que nesta execução o programa irá criar toda a Q-table e armazenar no arquivo data/q-table-taxi-driver.csv
. Depois de calcular os valores para a Q-table o programa irá resolver um dos possíveis cenários considerando um estado inicial qualquer. Além disso, o programa irá gerar um plot no diretório results que descreve a quantidade de ações executadas em cada época.
-
Abra o arquivo
results/action_taxidriver.jpg
e faça uma análise do mesmo. O que este gráfico representa? -
Agora faça o algoritmo
TaxiDriverGym.py
ler a Q-table a partir do arquivo gerado anteriormente e veja qual é o comportamento. Execute diversas vezes. -
Qual é o comportamento do agente? Ele sempre consegue encontrar uma solução? As soluções parecem ser ótimas?
Considerando os valores informados nos parâmetros do método train
, se a sua implementação do Q-learning
estiver correta então o agente TaxiDriverGym.py
deve encontrar a solução para todos os casos apresentados. Se por algum motivo a sua solução não estiver convergindo então significa que tem algum bug na atualização da q-table.
Uma vez que você confirmou que a sua implementação não tem bugs então você pode ajustar alguns dos hiperparâmetros. Por exemplo, diminuindo a quantidade de episódios e analisando a Q-table gerada.
- O arquivo
results/action_taxidriver.jpg
é um plot da quantidade de episódios versus a quantidade de atividades. Teria alguma outra forma de visualizar a evolução do agente? E se usarmosrewards
ao invés da quantidade de atividades? A visualização fica melhor?
Q-table pronta
Como resultado da etapa de treinamento, o agente terá uma Q-table que mostra a melhor ação que ele pode tomar em cada estado. A maneira de usar essas informações é muito simples:
(state, _) = env.reset()
done = False
while not done:
print(state)
action = np.argmax(q_table[state])
state, reward, done, truncated, info = env.step(action)
Aqui, o agente seleciona a ação com o maior valor em cada estado. Nós não temos nenhum comportamento aleatório.