Введение в Deep Q-Learning Network

Автор: | 14.01.2022

Введение 
Пример DQN программы
Алгоритм обучения нейросети в методе DQN
Полезные ссылки

Введение

Прежде, чем переходить к освоению Deep Q-learning Network (DQN) ознакомьтесь с методом Q-Learning.

Разницу между методами Q-Learning и DQN можно проиллюстрировать следующим образом:

Заменив таблицу значений Q table на нейронную сеть (Neural network, NN), мы получаем метод DQN. В DQN на вход нейросети подается текущее состояние (state, s), а на выходе нейросеть предсказывает  ценность Q всех возможных действий (actions, a) для этого состояния. Такую NN называют функциональным аппроксиматором.

Архитектура NN (слева) с одним Q на выходе (и  указанием конкретного действия на входе)  вместо NN (справа) c множеством Q для конкретного состояния s  также могла бы быть применена в методе DQN.

Но она очень неэффективна, поскольку потребуются несколько прогнозов сети для каждого Q. 

Перейдем сразу к примеру программы, а потом  рассмотрим реализованный в ней алгоритм Deep Q-learning Network.

Пример DQN программы

Ниже приводится программа, в которой Q-таблица (см. реализацию методом Q-Learning) заменена на нейронную сеть (реализация методом DQN).

Нейронная сеть состоит из 3 слоев:

  • Входной слой с 9 узлами (соответствует количеству состояний в среде).
  • Скрытый слой из 20 узлов
  • Выходной слой из 4-х узлов (соответствуют количеству действий в среде).
'''  
      (0,0)(0,1)(0,2)
       ___________
      |   |   |   |
 (0,0)|_S_|___|___|
      |   |   |   |
 (1,0)|___|___|XXX|
      |   |   |   |
 (2,0)|___|___|_G_| 
      Actions - 1:UP
                2:DOWN
                3:RIGHT
                4:LEFT
      ___________
     |   |   |   |
     |_0_|_1_|_2_|
     |   |   |   |
     |_3_|_4_|_5_| 
     |   |   |   |
     |_6_|_7_|_8_| 

0 -> [100000000]
2 -> [001000000]
8 -> [000000001]
'''
import random
import numpy as np
from keras.models import Sequential
from keras.layers import InputLayer
from keras.layers import Dense

def game(state,action):
    #Awarding 10 for reaching the goal
    if state[0]==2 and state[1]==1 and action==3:
            return [10,[2,2]]
    # -10 for bumping into the blocked state
    elif state[0]==1 and state[1]==1 and action==3:
            return [-10,[1,1]]
    # -10 for bumping into the blocked state
    elif state[0]==0 and state[1]==2 and action==2:
            return [-10,[0,2]]
    #For all other actions -1 reward
    else:
        if action==1:
            x=state[0]-1
            y=state[1]
            if x<0:
                x=0
            return [-1,[x,y]]
        elif action == 2:
            x=state[0]+1
            y=state[1]
            if x>2:
                x=2
            return [-1,[x,y]]
        elif action ==3:
            x=state[0]
            y=state[1]+1
            if y>2:
                y=2
            return [-1,[x,y]]
        else:
            x=state[0]
            y=state[1]-1
            if y<0:
                y=0
            return [-1,[x,y]]

def nstate (state):
    x=state[0]
    y=state[1]
    return 3*x+y

def main():

    model = Sequential()
    model.add(InputLayer(batch_input_shape=(1, 9)))
    model.add(Dense(20, activation='relu'))
    model.add(Dense(4, activation='linear'))
    model.compile(loss='mse', optimizer='adam', metrics=['mae'])
 
    actions_n=4
    space_n=9
    matrix1 = np.identity(space_n)
    epsilon=0.2
    discount=0.9
 
    print("TRAINING GAMES")
    numgames=30
    for i in range(numgames):
       state=[0,0]
       while state!=[2,2]:
          stn = nstate (state) 
          input = matrix1[stn:stn + 1]

          # PREDICTION NETWORK
          output = model.predict(input)
          target_vector = output[0]
 
          randomnum= random.uniform(0,1)
          if randomnum>=epsilon:
             action = np.argmax(output)+1 
          else:
             action=random.randint(1,4)
 
          reward,new_state = game(state,action)
          new_stn = nstate (new_state)
          new_input = matrix1[new_stn:new_stn + 1]
          #print("input:",new_input)
          new_output = model.predict(new_input)

          # TARGET NETWORK
          target = reward + discount * np.max(new_output) 
          target_vector[action-1] = target
          output = target_vector.reshape(-1, actions_n)
          model.fit(input, output, epochs=1, verbose=0)

          state = new_state
       print("END_GAME",i+1)

    print("TESTING GAME")
    state=[0,0]
    totalreward=0
    while state!=[2,2]:
         stn = nstate (state) 
         input = matrix1[stn:stn + 1]
         # PREDICTION NETWORK
         output = model.predict(input)
         action = np.argmax(output)+1 
         reward,new_state = game(state,action)
         totalreward=totalreward+reward
         state=new_state
         print("State[",state[0],",",state[1],"] --->",end=" ")
 
    print("Total reward = ",totalreward)

if __name__=='__main__':
 main()

Алгоритм обучения нейросети в методе DQN

При обучении НС с учителем (Supervised) данные на входе должны функционально соответствовать данным на выходе. Но в методе DQN нет явно выраженных данных на выходе НС. Возникает вопрос, какие использовать значения Qvalue на выходе из DQN чтобы они соответствовали состоянию s на входе? Если мы не даем алгоритму явного указания как поступать правильно, то чему же алгоритм научится? Как алгоритм будет обучаться не зная куда ему корректировать свои внутренние параметры, чтобы поступать правильно и в конечном итоге решить задачу так как нам бы хотелось.

В то время как обучение с учителем связано с прогнозированием значений или классов на основе помеченных данных (данных на выходе), а обучение без учителя связано с кластеризацией и поиском отношений в неразмеченных данных, обучение с подкреплением имеет дело с тем, как Агент должен действовать и вести себя в данной среде.

Обучение с подкреплением находится между контролируемым обучением (когда у нас есть помеченные данные) и неконтролируемым обучением (где у нас нет помеченных данных). Он имеет редкую и отложенную во времени метку, которая является вознаграждением, и цель этого типа обучения состоит в том, чтобы максимизировать вознаграждение, выполняя набор действий.

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

В игре, где Агент пытается дойти от начального положения (S) до цели (G), минуя заблокированную ячейку (XXX),  мы не говорим алгоритму в какой конкретно момент времени куда нужно двигаться. Мы скажем алгоритму только результат его действий — заработал он призовые или штрафные очки.

Алгоритм обучения нейросети методом DQN для наглядности представим так, как будто в нем задействованы две отдельные сети с одинаковой архитектурой.

На самом деле создается только одна модель сети (см. пример программы ).

Одна сеть (Prediction Network) используется для оценки текущего результата. Другая сеть (Target Network) используется для обучения (обновления весов сети).  Данные на выходе Prediction Network, полученные на предыдущей итерации обрабатываются и используются в качестве данных на выходе Target Network. Обновленные веса  копируются в Prediction Network для следующей итерации.

Q обозначается как Q(s,a;θ ), где θ представляет обучаемые веса сети.

Функция потерь (Loss ) — это квадрат разницы между прогнозируемым  и фактическим значениями Q. Поскольку фактическое значение Q неизвестно, то в качестве такого используется обновленное для следующего шага Q (см. правило обновления значения Q) .

Loss — это функция среднеквадратичной ошибки (MSE). Предыдущее значение Q — это прогноз (y), а текущее  Q — это цель (y’).

В MSE мы сопоставили y и y’  с  Q(s,a;θ ). Но MSE сравнивает прогнозы y с истинными метками y’, а истинные метки остаются постоянными на протяжении всей процедуры обучения. В DQN это не так: y и y’ предсказываются самой сетью и, следовательно, меняются на каждой итерации.

Полезные ссылки:

 

Автор: Николай Свирневский