从零使用强化学习训练AI玩儿游戏(4)——使用DQN

        上一篇我们使用了Sarsa-lambda和Sarsa玩一个寻宝的游戏,这一篇我们要使用DQN(Deep Q Network)来玩儿真正的游戏了,也就是DeepMind前几年用来玩儿电动使得比人类还厉害,然后被谷歌收购的原因之一,想想还有些小激动呐。

        还是先po上莫烦大神关于DQN的讲解视频,在这个视频之前你首先的有一点神经网络的知识,和TensorFlow的基础知识,需要先把大神的TensorFlow教程看完,但其实也不用完全看完,因为有点长,你只需要了解一点TensorFlow的基础操作知识就好了,以后的教程是会用Keras搭建神经网络的,Keras搭建神经网络就比TensorFlow简单很多了,只需要几个视频、几行代码就学会额。

        首先我们来说说为什么需要DQN,因为在现实生活中的状态值是无数的,如果使用之前的Q-learning或者是Sarsa,需要维护一个Q表,那个Q表会变得无限的大,在之前的Q-learning教程里面我就讨论过这个问题,并且用一个简单的游戏来证明了。在现实生活中根本不可能维护这么大的Q表。

         使用DQN的核心,就是使用神经网络来代替Q表,输入一个新的状态值,输出他所对应的估计值,就如下图所示,有两种方法,第一种是输入状态值加动作值输出对应的Q值,第二种是输入状态值输入对应动作的Q值,有多少个动作就对应多少个Q值。

        这篇我们主要讨论第二种算法,我们知道神经网络是需要训练的,训练是需要对应的标签量的,我们就用Q表中的Q现实来作为对于的标量,Q估计作为当前的输出值,他们的error就能用来更新神经网络。

下面这张图书DQN的算法简单流程图

这是主函数,跟之前的Q-learning、Sarsa一样是用来交互的。

def run_maze():
    step = 0    # 用来控制什么时候学习
    for episode in range(300):
        # 初始化环境
        observation = env.reset()

        while True:
            # 刷新环境
            env.render()

            # DQN 根据观测值选择行为
            action = RL.choose_action(observation)

            # 环境根据行为给出下一个 state, reward, 是否终止
            observation_, reward, done = env.step(action)

            # DQN 存储记忆
            RL.store_transition(observation, action, reward, observation_)

            # 控制学习起始时间和频率 (先累积一些记忆再开始学习)
            if (step > 200) and (step % 5 == 0):
                RL.learn()

            # 将下一个 state_ 变为 下次循环的 state
            observation = observation_

            # 如果终止, 就跳出循环
            if done:
                break
            step += 1   # 总步数

    # end of game
    print('game over')
    env.destroy()


if __name__ == "__main__":
    env = Maze()
    RL = DeepQNetwork(env.n_actions, env.n_features,
                      learning_rate=0.01,
                      reward_decay=0.9,
                      e_greedy=0.9,
                      replace_target_iter=200,  # 每 200 步替换一次 target_net 的参数
                      memory_size=2000, # 记忆上限
                      # output_graph=True   # 是否输出 tensorboard 文件
                      )
    env.after(100, run_maze)
    env.mainloop()
    RL.plot_cost()  # 观看神经网络的误差曲线

接下来就是最主要的搭建神经网络,代码中运用了两个神经网络先看一个搭建好后的图。

左边的eval_net,和右边的target_net是具有一模一样的结构,但是只有eval_net是需要反向训练的,训练需要一个误差值error也可以叫做loss损失函数,所以多了一个输入Q_target,Q_target其实是target_net的输出,他和eval_net的输出组成了一个平方差的损失函数。这样就能使用优化器对神经网络的参数进行优化了。

下面是创建神经网络的代码,这里使用了TensorFlow来创建,以后我们会使用Keras

    def _build_net(self):
        # ------------------ 建立评估神经网络 ------------------
        self.s = tf.placeholder(tf.float32, [None, self.n_features], name='s')  #输入状态值
        self.q_target = tf.placeholder(tf.float32, [None, self.n_actions], name='Q_target')  # 用来接收 q_target 的值, 这个之后会通过计算得到
        with tf.variable_scope('eval_net'):
            # c_names非常重要,是用来储存神经网络参数的,在后面的学习中会把整个参数全部复制给目标神经网络
            c_names, n_l1, w_initializer, b_initializer = \
                ['eval_net_params', tf.GraphKeys.GLOBAL_VARIABLES], 10, \
                tf.random_normal_initializer(0., 0.3), tf.constant_initializer(0.1)  # 建立神经网络的参数

            # 第一层,一个非常简单的神经元,y = relu(w1*x + b1) 输入进去的是状态值 输入给第二层神经网络的值
            with tf.variable_scope('l1'):
                w1 = tf.get_variable('w1', [self.n_features, n_l1], initializer=w_initializer, collections=c_names)
                b1 = tf.get_variable('b1', [1, n_l1], initializer=b_initializer, collections=c_names)
                l1 = tf.nn.relu(tf.matmul(self.s, w1) + b1)

            # 第二层, 还是一个简单的神经元,y = w2*x + b2 输入是上一层的值,输出的是估计值,也就是Q估计
            with tf.variable_scope('l2'):
                w2 = tf.get_variable('w2', [n_l1, self.n_actions], initializer=w_initializer, collections=c_names)
                b2 = tf.get_variable('b2', [1, self.n_actions], initializer=b_initializer, collections=c_names)
                self.q_eval = tf.matmul(l1, w2) + b2

        # 建立损失函数这里就是q_target - q_eval 来计算error q_target是目标神经网络的输出值,这里输入进来做期望
        with tf.variable_scope('loss'):
            self.loss = tf.reduce_mean(tf.squared_difference(self.q_target, self.q_eval))
        # 训练优化器
        with tf.variable_scope('train'):
            self._train_op = tf.train.RMSPropOptimizer(self.lr).minimize(self.loss)

        # 建立目标神经网络,目标神经网络的结构必须要跟估计神经网络一模一样,因为会做整个参数的赋值
        self.s_ = tf.placeholder(tf.float32, [None, self.n_features], name='s_')    # 输入 这里只有一个输入 因为他不需要做训练 
        with tf.variable_scope('target_net'):
            c_names = ['target_net_params', tf.GraphKeys.GLOBAL_VARIABLES]

            with tf.variable_scope('l1'):
                w1 = tf.get_variable('w1', [self.n_features, n_l1], initializer=w_initializer, collections=c_names)
                b1 = tf.get_variable('b1', [1, n_l1], initializer=b_initializer, collections=c_names)
                l1 = tf.nn.relu(tf.matmul(self.s_, w1) + b1)

            with tf.variable_scope('l2'):
                w2 = tf.get_variable('w2', [n_l1, self.n_actions], initializer=w_initializer, collections=c_names)
                b2 = tf.get_variable('b2', [1, self.n_actions], initializer=b_initializer, collections=c_names)
                self.q_next = tf.matmul(l1, w2) + b2

这一篇有点长了我准备把他分成两篇吧,下一篇 从零使用强化学习训练AI玩儿游戏(5)——使用DQN

猜你喜欢

转载自blog.csdn.net/u012465304/article/details/80952083
今日推荐