Deep Q Network没有学习

时间:2018-04-15 10:27:46

标签: tensorflow neural-network artificial-intelligence reinforcement-learning q-learning

我尝试使用Tensorflow和OpenAI的健身房编写Deep Q网络来玩Atari游戏。 这是我的代码:

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集之后,这些动作看起来仍然是随机的,而且很少能够击球。
  3. 我已经尝试使用不同的丢失函数(softmax crossentropy和均方误差),使用另一个优化器(Adam)并提高学习率但没有任何改变。

    有人可以告诉我如何解决这个问题吗?

2 个答案:

答案 0 :(得分:7)

以下是您可以研究的一些突出的事情(在这些情况下,如果不确切地确定哪个(哪些)是最重要的问题,则总是很难确定):

  • 100集似乎不是很多。在下图中,您可以看到Breakout(source)上Double DQN的某些变体(略高于DQN)的学习曲线。 x轴上的训练时间以百万帧为单位进行测量,而不是以剧集为单位。我不确切知道在x轴上有哪100集,但我认为它不会很远。在100集之后期待任何一种不错的表现可能是不合理的

OpenAI Baselines DQN Learning Curves Breakout

  • 您的网络中似乎正在使用dropout。我建议摆脱辍学。我不确定100%肯定在深度强化学习中使用辍学是不好的,但1)它肯定不常见,2)直观地说它似乎没有必要。辍学用于对抗监督学习中的过度拟合,但过度拟合在强化学习中并没有太大的风险(至少,如果你只是想像你在这里一样训练单个游戏)。

  • discount_factor = 0.5似乎非常低,这使得无法将长期奖励传播回到少数几个行动之上。 discount_factor = 0.99的某些内容会更加常见。

  • if (episode+1)/num_episodes > np.random.uniform():,此代码看起来在第一集中epsilon1.0 - 1 / num_episodes到最后一集中的1.0 - num_episodes / num_episodes = 0.0衰减了num_episodes = 100。对于您当前的0.99,这意味着它会在0.0100期间从epsilon衰减到1.0。在我看来,它似乎太快了。作为参考,在original DQN paper中,0.1在{strong> 100万帧之后从const fetch = require('node-fetch') const SEN_URL = "http://www.sentiment140.com/api/bulkClassifyJson" // URL of sentiment analysis app.get('/api/sentimenttest', async (req, res) => { try{ var sentiments = await fetch(SEN_URL, {method: "POST", body: {"data": [{"text": "I love you"}, {"text": "I hate you"}]}}) console.log(sentiments) res.send(sentiments) }catch(error){ console.log(error) } }) {"size":0,"timeout":0} 线性缓慢衰减,并在之后永久固定。

  • 您没有使用体验重播,也没有使用单独的目标网络,如the original DQN paper中所述。以上所有要点显着更容易查看和修复,所以我建议先这样做。这可能已经足够让他们在学习之后真正开始看到一些比随机性更好的表现,但可能仍会比这两个新成绩更差。

答案 1 :(得分:1)

首先让我们详细描述这些现象。神经网络的误差函数可以具有1.0(最大误差)和0.0(目标)之间的值。学习算法背后的想法是将误差函数降低到零,这意味着代理人完美地玩游戏。一开始学习效果很好,误差值正在减小,但曲线在某个水平上是平行的。这意味着CPU正在计算大量数据,CPU消耗能量,但错误值不再减少。

好消息是,它与您的源代码无关。您甚至可以假设您的DeepQ网络的实现很好,您的源代码看起来比普通程序员的代码更好。问题与OpenAI健身房的环境困难有关。这意味着,在诸如“将玩家带到目标位置”之类的简单游戏中,网络学习良好,而在诸如“Montezuma's Revenge”之类的困难问题上,上述具有恒定错误功能的问题正在发生。克服这个问题并不像看起来那么容易。这不是微调神经网络的问题,而是发明一种处理复杂游戏的新方法。在分层问题解决等文献策略中,使用自然语言基础和领域特定本体来克服这个问题。