Double DQN

Глубокое обучение с подкреплением на Python

Timothée Carayol

Principal Machine Learning Engineer, Komment

Двойное Q-обучение

  • Q-обучение завышает Q-значения, снижая эффективность обучения
  • Причина — смещение максимизации
  • Двойное Q-обучение устраняет смещение, разделяя выбор действия и оценку значения

Две Q-таблицы (иллюстрация из курса «Обучение с подкреплением с Gymnasium на Python»); в двойном Q-обучении они используются поочерёдно

Глубокое обучение с подкреплением на Python

Идея DDQN

  • Отправная точка — полный DQN (с фиксированными Q-целями)
  • TD-цель в DQN:
    • Выбор действия: целевая сеть
    • Оценка значения: целевая сеть
  • TD-цель в DDQN:
    • Выбор действия: онлайн-сеть
    • Оценка значения: целевая сеть
  • Не совсем двойное Q-обучение (Q-сети не чередуются)
  • Большинство преимуществ при минимальных изменениях

Ошибка Беллмана (DQN с фиксированными Q-целями): Q_online(s_t, a_t) - (r_t+1 + gamma max(Q_target(s_t+1, a)))

Ошибка Беллмана (DDQN с фиксированными Q-целями): Q_online(s_t, a_t) - (r_t+1 + gamma Q_target(s_t+1, tilde a)) с tilde a = argmax_a(Q_online(s_t+1, a))

Глубокое обучение с подкреплением на Python

Реализация Double DQN

DQN:

... # instantiate online and target networks
q_values = (online_network(states)
            .gather(1, actions).squeeze(1))

with torch.no_grad():
# # next_q_values = (target_network(next_states) .amax(1))
target_q_values = (rewards + gamma * next_q_values * (1 - dones))
loss = torch.nn.MSELoss()(q_values, target_q_values) ... # gradient descent ... # target network update

DDQN:

... # instantiate online and target networks
q_values = (online_network(states)
            .gather(1, actions).squeeze(1))

with torch.no_grad():

target_q_values = (rewards + gamma * next_q_values * (1 - dones))
loss = torch.nn.MSELoss()(q_values, target_q_values) ... # gradient descent ... # target network update
Глубокое обучение с подкреплением на Python

Реализация Double DQN

DQN:

... # instantiate online and target networks
q_values = (online_network(states)
            .gather(1, actions).squeeze(1))

with torch.no_grad():
next_actions = (target_network(next_states) .argmax(1).unsqueeze(1))
next_q_values = (target_network(next_states) .gather(1, next_actions).squeeze(1))
target_q_values = (rewards + gamma * next_q_values * (1 - dones))
loss = torch.nn.MSELoss()(q_values, target_q_values) ... # gradient descent ... # target network update

DDQN:

... # instantiate online and target networks
q_values = (online_network(states)
            .gather(1, actions).squeeze(1))

with torch.no_grad():
next_actions = (online_network(next_states) .argmax(1).unsqueeze(1))
next_q_values = (target_network(next_states) .gather(1, next_actions).squeeze(1))
target_q_values = (rewards + gamma * next_q_values * (1 - dones))
loss = torch.nn.MSELoss()(q_values, target_q_values) ... # gradient descent ... # target network update
Глубокое обучение с подкреплением на Python

Производительность DDQN

 

  • Сравнение результатов DDQN, DQN и игроков-людей на играх Atari
  • DDQN: более высокие результаты, чем у обычного DQN
  • Не всегда верно — стоит проверить оба варианта

Столбчатая диаграмма: DQN почти достигает уровня человека по медиане и превосходит его в среднем; DDQN превосходит и человека, и DQN как по медиане, так и в среднем.

1 https://arxiv.org/abs/2303.11634
Глубокое обучение с подкреплением на Python

Давайте потренируемся!

Глубокое обучение с подкреплением на Python

Preparing Video For Download...