В этой статье поговорим о проблеме в модели Q-обучения Vanilla: Катастрофическое забывание. Мы решим эту проблему с помощью воспроизведения опыта и увидим улучшения, которые мы сделали в игре GridWorld.

Добро пожаловать во вторую часть руководств по Deep Q-network. Это продолжение Части 1. Если вы не читали часть 1, я настоятельно рекомендую пройти ее, так как многие коды и пояснения в этой статье будут напрямую связаны с уже объясненными в Часть 1.

До сих пор в части 1!!

  1. Мы начали с понимания того, что такое Q-обучение, и формулы, используемой для обновления Q-обучения.
  2. Позже мы увидели игру GridWorld и определили ее состояние, действия и награды.
  3. Затем мы придумали подход к обучению с подкреплением, чтобы выиграть игру.
  4. Мы научились импортировать среду GridWorld и различные режимы среды
  5. Спроектировал и построил нейронную сеть, которая действует как Q-функция.
  6. Мы обучили и протестировали нашего RL-агента и получили очень хороший результат в решении статического GridWorld. Но нам не удалось решить Random GridWorld.
  7. Разбираемся в чем проблема и обещаем решить ее в этой статье

В чем проблема?

Мы смогли обучить нашу модель в статической среде, где каждый раз, когда модель видела объекты, игрока и цель в одном и том же положении. Но когда агент был обучен более сложной инициализации, когда среда инициализировалась случайным образом каждый раз, когда создается новый эпизод, он не смог обучиться.

Название вышеуказанной проблемы — Катастрофическая забывчивость. Это важная проблема, связанная с обучением на основе градиентного спуска, когда мы выполняем обратное распространение после каждого хода в игре, которую мы называем онлайн-обучением.

Идея катастрофического забывания заключается в том, что когда два игровых состояния очень похожи, но приводят к очень разным результатам, Q-функция «запутается» и не сможет понять, что делать. В приведенном ниже примере катастрофическое забывание происходит потому, что Q-функция учится в игре 1, что движение вправо приводит к награде +1, но в игре 2, которая выглядит очень похожей, она получает награду -1 после перемещения вправо. В результате алгоритм забывает то, что он ранее узнал об игре 1, в результате чего существенного обучения не происходит вообще.

Причина Катастрофического забывания в том, что мы обновляем веса после каждого хода игры. Обычно у нас нет этой проблемы в области контролируемого обучения, потому что мы выполняем рандомизированное пакетное обучение, при котором мы не обновляем наши веса до тех пор, пока не пройдем какое-то случайное подмножество обучающих данных и не вычислим сумму или средний градиент для пакета. . Это усредняет цели и стабилизирует обучение.

Можем ли мы сделать это в DQN?

Да, и это то, что называется воспроизведение опыта. Воспроизведение опыта дает нам пакетное обновление в схеме онлайн-обучения.

На приведенном выше рисунке показан общий обзор воспроизведения опыта, метода смягчения серьезной проблемы с алгоритмами онлайн-обучения: катастрофического забывания. Идея состоит в том, чтобы использовать мини-пакетирование, сохраняя прошлый опыт, а затем используя случайное подмножество этого опыта для обновления Q-сети, а не используя только один самый последний опыт.

Шаги, связанные с воспроизведением опыта, следующие:

  1. В состоянии s выполните действие a и наблюдайте за новым состоянием s(t+1) и вознаграждением r(t+1).
  2. Сохраните это как кортеж (s, a, s(t+1), r(t+1 )) в списке.
  3. Продолжайте хранить каждый опыт в этом списке, пока вы не заполните список до определенной длины (это зависит от вас).
  4. Как только память воспроизведения опыта заполнена, случайным образом выберите подмножество (опять же, вам нужно определить размер подмножества).
  5. Перебрать это подмножество и вычислить обновления значений для каждого подмножества; сохраните их в целевом массиве (например, Y) и сохраните состояние, s, каждой памяти в X.
  6. Используйте X и Y в качестве мини-пакета для пакетного обучения. Для последующих эпох, когда массив заполнен, просто перезапишите старые значения в массиве памяти воспроизведения вашего опыта.

Реализацию воспроизведения опыта можно увидеть ниже.

from collections import deque
epochs = 5000
losses = []
mem_size = 1000        1                                                     
batch_size = 200       2                                                            
replay = deque(maxlen=mem_size)   3                                             
max_moves = 50      4                                                           
h = 0
for i in range(epochs):
    game = Gridworld(size=4, mode='random')
    state1_ = game.board.render_np().reshape(1,64) + np.random.rand(1,64)/100.0
    state1 = torch.from_numpy(state1_).float()
    status = 1
    mov = 0
    while(status == 1): 
        mov += 1
        qval = model(state1)     5                                              
        qval_ = qval.data.numpy()
        if (random.random() < epsilon):         6                               
            action_ = np.random.randint(0,4)
        else:
            action_ = np.argmax(qval_)
        
        action = action_set[action_]
        game.makeMove(action)
        state2_ = game.board.render_np().reshape(1,64) + np.random.rand(1,64)/100.0
        state2 = torch.from_numpy(state2_).float()
        reward = game.reward()
        done = True if reward > 0 else False
        exp =  (state1, action_, reward, state2, done)      7                   
        replay.append(exp)                8                                     
        state1 = state2
        if len(replay) > batch_size:     9                                      
            minibatch = random.sample(replay, batch_size)     10                 
            state1_batch = torch.cat([s1 for (s1,a,r,s2,d) in minibatch])      11
            action_batch = torch.Tensor([a for (s1,a,r,s2,d) in minibatch])
            reward_batch = torch.Tensor([r for (s1,a,r,s2,d) in minibatch])
            state2_batch = torch.cat([s2 for (s1,a,r,s2,d) in minibatch])
            done_batch = torch.Tensor([d for (s1,a,r,s2,d) in minibatch])
            
            Q1 = model(state1_batch)        12                                   
            with torch.no_grad():
                Q2 = model(state2_batch)       13                                
            
            Y = reward_batch + gamma * ((1 - done_batch) * torch.max(Q2,dim=1)[0])      14                                             
            X = \
            Q1.gather(dim=1,index=action_batch.long().unsqueeze(dim=1)).squeeze()
            loss = loss_fn(X, Y.detach())
            optimizer.zero_grad()
            loss.backward()
            losses.append(loss.item())
            optimizer.step()
 
        if reward != -1 or mov > max_moves:         15                           
            status = 0
            mov = 0
losses = np.array(losses)
  • 1 Устанавливает общий размер памяти воспроизведения опыта.
  • 2 Задает размер мини-пакета
  • 3 Создает воспроизведение памяти в виде списка очереди
  • 4 Устанавливает максимальное количество ходов до окончания игры.
  • 5 Выбирает действие, используя эпсилон-жадную стратегию
  • 6 Вычисляет значения Q из состояния ввода, чтобы выбрать действие
  • 7 Создает опыт состояния, вознаграждения, действия и следующего состояния в виде кортежа
  • 8 Добавляет опыт в список повторов опыта.
  • 9 Если длина списка повторов не меньше размера мини-пакета, начинается обучение мини-пакета.
  • 10 Произвольная выборка подмножества списка воспроизведения
  • 11 Компоненты каждого опыта разделяются на отдельные тензоры мини-пакетов.
  • 12 Пересчитывает значения Q для мини-пакета состояний для получения градиентов
  • 13 Вычисляет значения Q для мини-пакета следующих состояний, но не вычисляет градиенты
  • 14 Вычисляет целевые значения Q, которые мы хотим, чтобы DQN изучил
  • 15 Если игра окончена, сбрасывает статус и номер хода

done_batch в Y = reward_batch + gamma * ((1 — done_batch) * torch.max(Q2,dim=1)[0]) — это логическая переменная, которая устанавливает право вознаграждения_batch на ноль, когда игра завершена (конец эпизод)

После обучения модели в случайном режиме в течение 5000 эпох и запуска игры 1000 раз мы смогли выиграть 90% игр, а проигрыш зафиксировался примерно так, как показано ниже.

Из приведенного выше рисунка видно, что потери явно уменьшаются в течение тренировки, а также мы можем выиграть игру в 90% случаев. Мы должны понимать, что могут быть состояния игры, в которых невозможно выиграть. Так что 90% винрейта — это действительно хорошо.

Но все же мы видим, что потери увеличиваются в более поздние эпохи, и тренд очень нестабилен. Это очень часто встречается в задачах глубокого обучения с подкреплением (DRL). Мы называем это нестабильностью обучения. И да, для этого есть решение.

Использование целевой сети решит проблему нестабильности наклона. Мы увидим, как реализовать целевую сеть в Части 3

Код для этой статьи можно получить по этой ссылке GIT

До сих пор!!

  1. Мы узнали, что такое катастрофическое забывание и как оно влияет на агент DQN.
  2. Мы решили катастрофическую забывчивость, реализовав ответ на опыт
  3. ДХО страдают нестабильностью обучения. Мы увидим, как реализовать целевую сеть, чтобы избавиться от нестабильности обучения, в части 3.

Ознакомьтесь с частью 1 этой статьи здесь:



Ознакомьтесь с частью 3 этой статьи здесь:
https://nandakishorej8.medium.com/part-3-building-a-deep-q-network-to-play-gridworld-learning-instability-and- целевые сети-fb399cb42616