Deep Q Network не учится

Я пытался написать код Deep Q Network, чтобы играть в игры Atari, используя Tensorflow и OpenAI Gym. Вот мой код:

import tensorflow as tf
import gym
import numpy as np
import os

env_name = 'Breakout-v0'
env = gym.make(env_name)
num_episodes = 100
input_data = tf.placeholder(tf.float32,(None,)+env.observation_space.shape)
output_labels = tf.placeholder(tf.float32,(None,env.action_space.n))

def convnet(data):
    layer1 = tf.layers.conv2d(data,32,5,activation=tf.nn.relu)
    layer1_dropout = tf.nn.dropout(layer1,0.8)
    layer2 = tf.layers.conv2d(layer1_dropout,64,5,activation=tf.nn.relu)
    layer2_dropout = tf.nn.dropout(layer2,0.8)
    layer3 = tf.layers.conv2d(layer2_dropout,128,5,activation=tf.nn.relu)
    layer3_dropout = tf.nn.dropout(layer3,0.8)
    layer4 = tf.layers.dense(layer3_dropout,units=128,activation=tf.nn.softmax,kernel_initializer=tf.zeros_initializer)
    layer5 = tf.layers.flatten(layer4)
    layer5_dropout = tf.nn.dropout(layer5,0.8)
    layer6 = tf.layers.dense(layer5_dropout,units=env.action_space.n,activation=tf.nn.softmax,kernel_initializer=tf.zeros_initializer)
    return layer6

logits = convnet(input_data)
loss = tf.losses.sigmoid_cross_entropy(output_labels,logits)
train = tf.train.GradientDescentOptimizer(0.001).minimize(loss)
saver = tf.train.Saver()
init = tf.global_variables_initializer()
discount_factor = 0.5

with tf.Session() as sess:
    sess.run(init)
    for episode in range(num_episodes):
        x = []
        y = []
        state = env.reset()
        feed = {input_data:np.array([state])}
        print('episode:', episode+1)
        while True:
            x.append(state)
            if (episode+1)/num_episodes > np.random.uniform():
                Q = sess.run(logits,feed_dict=feed)[0]
                action = np.argmax(Q)
            else:
                action = env.action_space.sample()
            state,reward,done,info = env.step(action)
            Q = sess.run(logits,feed_dict=feed)[0]
            new_Q = np.zeros(Q.shape)
            new_Q[action] = reward+np.amax(Q)*discount_factor
            y.append(new_Q)
            if done:
                break

        for sample in range(len(x)):
            _,l = sess.run([train,loss],feed_dict={input_data:[x[sample]],output_labels:[y[sample]]})
            print('training loss on sample '+str(sample+1)+': '+str(l))
    saver.save(sess,os.getcwd()+'/'+env_name+'-DQN.ckpt')

Проблема в том, что:

  1. Потери не уменьшаются во время тренировки и всегда составляют где-то около 0,7 или 0,8
  2. Когда я тестирую сеть в среде Breakout, даже после того, как обучил ее 1000 эпизодов, действия все равно кажутся случайными и редко попадают в цель.

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

Может кто-нибудь сказать мне, как это исправить?

2 ответа

Вот некоторые вещи, на которые стоит обратить внимание (в таких случаях всегда трудно сказать наверняка, не пытаясь точно определить, какие проблемы являются наиболее важными):

  • 100 эпизодов вроде не много. На изображении ниже вы видите кривые обучения некоторых вариантов Double DQN (немного более продвинутых, чем DQN) на Breakout ( источник). Время обучения на x- Ось там измеряется миллионами кадров, а не эпизодами. Я не знаю точно, где 100 эпизодов будет на этом x- Ось, но я не думаю, что это будет далеко. Может быть просто не разумно ожидать какой-либо достойной производительности после 100 эпизодов.

https://blog.openai.com/content/images/2017/05/Pasted-image-at-2017_05_23-02_11-PM-3.png

  • Похоже, вы используете Dropout в своих сетях. Я бы порекомендовал избавиться от отсева. Я не знаю на 100% наверняка, что это плохое использование отсева в Deep Reinforcement Learning, но 1) это, конечно, не распространено, и 2) интуитивно это не кажется необходимым. Выпадение используется для борьбы с переобучением в контролируемом обучении, но переоснащение на самом деле не представляет большого риска в обучении подкреплению (по крайней мере, если вы просто пытаетесь тренироваться для одной игры за раз, как вы здесь).

  • discount_factor = 0.5 кажется крайне низким, это сделает невозможным распространение долгосрочных вознаграждений на более чем несколько действий. Нечто подобное discount_factor = 0.99 было бы гораздо более распространенным.

  • if (episode+1)/num_episodes > np.random.uniform():этот код выглядит так epsilon от 1.0 - 1 / num_episodes в первом эпизоде 1.0 - num_episodes / num_episodes = 0.0 в последнем эпизоде. С вашим текущим num_episodes = 100это означает, что он разлагается от 0.99 в 0.0 над 100 эпизоды. Мне кажется, что он разлагается слишком быстро. Для справки, в оригинальной статье DQN, epsilon медленно распадается линейно от 1.0 в 0.1 более 1 миллиона кадров, и после этого оставались неизменными.

  • Вы не используете Experience Replay и не используете отдельную целевую сеть, как описано в оригинальном документе DQN. Все вышеперечисленные пункты значительно легче рассмотреть и исправить, поэтому я бы порекомендовал это в первую очередь. Этого уже может быть достаточно, чтобы действительно начать видеть некоторые результаты, превосходящие случайные, после обучения, но, вероятно, все равно будет работать хуже, чем с этими двумя дополнениями.

Сначала давайте подробно опишем явления. Функция ошибки нейронной сети может иметь значение от 1,0 (максимальная ошибка) до 0,0 (цель). Идея алгоритма обучения состоит в том, чтобы снизить функцию ошибок до нуля, что означает, что агент играет в игру идеально. В начале обучение работает хорошо, значение ошибки уменьшается, но затем кривая параллельна на определенном уровне. Это означает, что процессор вычисляет огромное количество данных, процессор потребляет энергию, но значение ошибки больше не уменьшается.

Хорошей новостью является то, что это не имеет никакого отношения к вашему исходному коду. Ваша реализация сети Deep Q великолепна, я бы даже предположил, что ваш исходный код выглядит лучше, чем код среднего программиста. Проблема связана со сложностью среды в тренажерном зале OpenAI. Это означает, что в простых играх, таких как "приведение игрока в целевую позицию", сеть хорошо учится, в то время как в таких сложных задачах, как "Месть Монтесумы", возникает описанная выше проблема с функцией постоянной ошибки. Преодолеть проблему не так просто, как кажется. Проблема не в тонкой настройке нейронной сети, а в изобретении нового способа обработки сложных игр. В литературе для преодоления проблемы используются стратегии, такие как решение иерархических проблем, обоснование естественного языка и предметные онтологии.