前期回顾

强化学习经典算法笔记(零):贝尔曼方程的推导
强化学习经典算法笔记(一):价值迭代算法Value Iteration
强化学习经典算法笔记(二):策略迭代算法Policy Iteration
强化学习经典算法笔记(三):蒙特卡罗方法Monte Calo Method
强化学习经典算法笔记(四):时间差分算法Temporal Difference(Q-Learning算法)
强化学习经典算法笔记(五):时间差分算法Temporal Difference(SARSA算法)

强化学习经典算法笔记——深度Q值网络

  到这里,我们终于来到了深度强化学习的领域了,之前的算法都是经典RL算法,它们和DRL的关系好比是机器学习和深度学习的关系。深度神经网络的引入极大地提升了强化学习算法的效率和能力,使强化学习的研究进入了新的阶段。

简介

  深度强化学习的经典之作是2015年DeepMind发表在Nature的DQN论文《Human-Level Control Through Deep Reinforcement Learning》。本篇博客就讲一讲DQN的基本框架思想,并用代码实现它。

  DQN属于Q-Learning算法,也是一种Value-Based算法,并不直接学习一个Policy,而是学习Critic,也就是学习如何评价当前状态的好坏,进而根据Q值选取最佳的action。因此可以将DQN中的神经网络看做是一个复杂的Q-function,本质上,它和前几篇中提到的Q-table干的事是一样的,只不过神经网络的函数拟合能力很强,它能胜任更复杂的RL任务。

  我个人观点,深度强化学习的框架大致可以分为两部分,一部分是感知(Sensoring),另一部分是决策(Decision Making)。

  DRL往往需要学习一个感知算法,感知真实环境的各种信息。有的感知器输出一个标量,反映当前环境或状态动作对的好坏;有的感知器则是对真实环境进行建模,将当前状态抽象成一个隐层特征,用于后续的决策算法使用,这类算法有DeepMind的World Model和PlaNet系列,我们以后都会讲到。

  感知算法是对真实环境的总结和特征提取,要想做出决策,还需要一个决策算法。比如DQN中的ϵ−greedy\epsilon-greedyϵ−greedy算法,虽然是一个比较简单的policy算法,直接采取具有最大Q值的动作作为当前策略,但是我们也可以看做是一个决策算法,它利用了上一步的感知器对环境的感知信息。

  再比如,AlphaGo系列算法中,CNN负责对当前棋盘状态提取特征,给出当前胜算(也就是评估当前状态好坏),接着蒙特卡洛树搜索算法根据CNN输出的Q值计算子结点的U值,进行棋盘搜索,完成决策。

  从感知和决策的角度审视深度强化学习,深度神经网络的引入提升了感知和决策两方面的效果。我们在这一篇主要讲神经网络对感知能力的提升,而将神经网络用于决策的内容放到后面去讲。但是,将神经网络用于强化学习早已有之,不过效果一直不好,直到DQN引入了几个核心技术,才将性能大大提升,即

  • 卷积神经网络 CNN
  • 目标网络 Target Network
  • 经验回放 Experience Replay

  DQN应该是第一个采用原始图像作为CNN输入进行训练的,也应该是第一个将CNN在RL发挥巨大威力的算法。DQN中的CNN采用和AlexNet类似的结构。

  目标网络是DQN的一大贡献。我们知道,与环境交互具有极大的随机性,XXXXXXXXXXXXXXXXX

  经验回放是DQN的另一贡献。我们知道,一个episode是一个时间关联性很强的(状态-动作-回报)序列,如果直接拿若干个episode的序列数据来训练CNN,XXXXXXXXXXXXXXXXXXXXXXX

现在让我们看看DQN完整的算法

以下操作执行N个Episode:

  • 将游戏画面sss进行预处理,送入CNN,输出每个动作的Q值
  • 根据ϵ−greedy\epsilon-greedyϵ−greedy算法计算应该采取的动作a=argmax(Q(s,a,θ))a=argmax(Q(s,a,\theta))a=argmax(Q(s,a,θ))
  • 执行动作aaa,转移到下一状态s′s's′,收到环境给出的回报
  • 将序列&lt;s,a,r,s′&gt;&lt;s,a,r,s'&gt;<s,a,r,s′>存入经验池
  • 从经验池采样一个batch的数据,训练Q Network,实际上是一个由输入预测输出的回归问题
    loss=(r+γmaxa′Q(s′,a′;θ′)−Q(s,a;θ))2loss=(r+\gamma max_{a'}Q(s',a';\theta')-Q(s,a;\theta))^2 loss=(r+γmaxa′​Q(s′,a′;θ′)−Q(s,a;θ))2
  • CNN(当前网络)训练若干代之后,将其参数拷贝给目标网络。

DQN实验

  本次实验采用的游戏环境是MrPacman-v0。这个游戏很简单,控制小人吃掉路上的小长方块,同时躲避怪物的接触。每吃一个小块得10分,碰到怪物就会丢掉命,一局游戏有三条命,每条命的得分是累加的。算法的目标就是取得尽可能高的分数

导入必要的环境依赖。

import numpy as np
import gym
import tensorflow as tf
from tensorflow.contrib.layers import flatten, conv2d, fully_connected
from collections import deque, Counter
import random
import matplotlib.pyplot as plt
%matplotlib inline

  游戏环境给出的observation210x160x3的彩色图像,如下图。

env = gym.make('MsPacman-v0')
env.render()
# env.close()


  游戏的动作有九个——等待、右转、左转、向上、向下、向左移动、向右移动、向上移动和向下移动,所以我们之后要搭建的神经网络的输出也有9个。

n_outputs = env.action_space.n
# n_outputs = 9

  我们首先对图像进行预处理。具体包括裁剪、降采样、灰度化和提高对比度。

# color后面用于图像的锐化
color = np.array([210, 164, 74]).mean()def preprocess_observation(obs):'''处理210x160x3图像'''# 以2为步长,截取1-176行的像素,共取88行# 同样地,每两列取1列像素,共取80列# img.shape = (88,80,3)img = obs[1:176:2, ::2]# 彩图转灰度图,即对三通道像素值取平均img = img.mean(axis=2)# 提高图像对比度img[img==color] = 0# 像素值归一化(-1,1)img = (img - 128) / 128 - 1return img.reshape(88,80,1)

处理过后的图像

  下面来搭建DQN的核心——CNN。根据Q function的定义,Q值是评估一个状态动作对的好坏的,但是在实现算法时,状态(一个矩阵)非常适合作为CNN的输入,但是动作是一个标量,和状态同时输入CNN不好实现,所以我们实际做的是输入一个游戏状态的图像,输出所有动作的Q值。

tf.reset_default_graph()def q_network(X, name_scope):# Initialize layersinitializer = tf.contrib.layers.variance_scaling_initializer()with tf.variable_scope(name_scope) as scope: # 定义卷积操作layer_1 = conv2d(X, num_outputs=32, kernel_size=(8,8), stride=4, padding='SAME', weights_initializer=initializer) # summary.histogram的作用是在tensorboard中以直方图的形式可视化这个变量tf.summary.histogram('layer_1',layer_1)layer_2 = conv2d(layer_1, num_outputs=64, kernel_size=(4,4), stride=2, padding='SAME', weights_initializer=initializer)tf.summary.histogram('layer_2',layer_2)layer_3 = conv2d(layer_2, num_outputs=64, kernel_size=(3,3), stride=1, padding='SAME', weights_initializer=initializer)tf.summary.histogram('layer_3',layer_3)# 将2维feature map拉成向量,送入全连接层flat = flatten(layer_3)fc = fully_connected(flat, num_outputs=128, weights_initializer=initializer)tf.summary.histogram('fc',fc)# 最后一层全连接的输出是9个可能动作的Q值,注意这里没有经过激活函数,可以试一下softmax函数的效果output = fully_connected(fc, num_outputs=n_outputs, activation_fn=None, weights_initializer=initializer)tf.summary.histogram('output',output)# 将网络的权重保存起来,以便拷贝给Target Networkvars = {v.name[len(scope.name):]: v for v in tf.get_collection(key=tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope.name)} return vars, output

  下面创建ϵ−greedy\epsilon-greedyϵ−greedy 策略,与之前不同,算法的ϵ\epsilonϵ是随着训练代数的增加而线性递减的。训练初期,策略更接近随机探索,训练后期,策略倾向于选择具有最优Q值的动作。请注意,当训练的episode数改变后,eps_decay_steps的值也要相应改变,使epsilon随着整个训练过程合理地减小。这一点在代码中也有说明。

eps_min = 0.05
eps_max = 1.0
# 每个episode约持续600-700个step
# 因此eps_decay_steps要随着num_episodes的变化而变化
eps_decay_steps = 500000def epsilon_greedy(action, step):'''step = 0,epsilon=1step = 500000,epsilon = 0.05线性衰减'''epsilon = max(eps_min, eps_max - (eps_max-eps_min) * step/eps_decay_steps)if np.random.rand() < epsilon:# 输出随机动作epsilon_greedyreturn np.random.randint(n_outputs)else:# 输出最优动作return action

  现在感知算法和决策算法都具备了,还差数据集。我们需要将(s,a,r,s′)(s,a,r,s')(s,a,r,s′)这样的数据存入经验池(experience replay buffer)。buffer不能用简单的list来充当,否则随着训练代数的增加,有可能内存会溢出。我们希望buffer具有线性表的各种特点,支持入队、出对,能设置最大长度。这个功能Python已经帮我们实现了,就是deque

# from collections import deque, Counter
buffer_len = 20000
exp_buffer = deque(maxlen=buffer_len)

  有了经验池,下一步就需要从经验池中取出数据,用于训练CNN。所以还要写一个sample_memories函数。

def sample_memories(batch_size):# permutation的作用:# 将[0, len(exp_buffer)-1] 的整数乱序排列# [:batch_size]取打乱顺序的buffer中1个batch的数据 perm_batch = np.random.permutation(len(exp_buffer))[:batch_size]mem = np.array(exp_buffer)[perm_batch]# 一条数据中包括(s,a,s',r,done) 5个数据return mem[:,0], mem[:,1], mem[:,2], mem[:,3], mem[:,4]

  下面我们需要配置网络训练相关的超参数。

num_episodes = 800              # 一共玩800盘游戏
batch_size = 48                 # 每次从经验池拿出48个样本训练CNN
input_shape = (None, 88, 80, 1) # 网络输入尺寸,第1维是batch
learning_rate = 0.001
X_shape = (None, 88, 80, 1)
discount_factor = 0.97          # 折扣率,表示未来回报对现在的重要程度global_step = 0                 # 将每局游戏走的步数相累加,就是全局步数
copy_steps = 100                # 每100代,当前网络向Target Network拷贝参数
steps_train = 4                 # 设定游戏中每走4步,就训练CNN一次
start_steps = 2000              # 训练初期,经验池不满,所以前2000代先收集数据,不进行训练# 在当前目录下新建logs文件夹,记录训练数据
logdir = 'logs'
tf.reset_default_graph()# 定义送入CNN数据的接口
X = tf.placeholder(tf.float32, shape=X_shape)# 用一个布尔值控制训练/非训练状态
in_training_mode = tf.placeholder(tf.bool)

  创建2个CNN,一个Main CNN,一个Target CNN。

# main Q network
mainQ, mainQ_outputs = q_network(X, 'mainQ')# target Q network
targetQ, targetQ_outputs = q_network(X, 'targetQ')

  计算Q值。前面讲到,网络输入s,输出9个动作分别的Q值,也就是1个9维向量,但实际上我们希望的是输入(s,a),输出Q(s,a),所以需要在9维向量中取出我们真正想要的那个值,也就是数据(s,a,r,s′)(s,a,r,s')(s,a,r,s′)中真正的a对应的Q值。

  为此我们定义X_action接口,对应的是exp buffer中的action,当然其长度是batch_size,因为我们在训练中一次取batch_size个样本,每1个元素都表示当时采取的动作(0-8)。将action从0-8转换成one-hot码,如(0,0,0,1,0,0,0,0,0)(0,0,0,1,0,0,0,0,0)(0,0,0,1,0,0,0,0,0),然后将CNN输出的9维向量,比如(1,2,3,4,5,6,7,8,9)(1,2,3,4,5,6,7,8,9)(1,2,3,4,5,6,7,8,9)与one-hot相乘,就得(0,0,0,4,0,0,0,0,0)(0,0,0,4,0,0,0,0,0)(0,0,0,4,0,0,0,0,0),再求和得到4。到这里,我们算出了数据样本(s,a,r,s′)(s,a,r,s')(s,a,r,s′)中(s,a)(s,a)(s,a)的CNN估值。将这个值记为Q_action

# X_action 长度 = batch_size(48), 每1个元素都表示当时采取的动作0-8
X_action = tf.placeholder(tf.int32, shape=(None,))
# Q_action 长度 = batch_size
# Q_action计算的是样本中(s,a)的CNN估计的Q值
# (0,0,0,1,0,0,0,0,0)        *     (1,2,3,4,5,6,7,8,9)   =   (0,0,0,4,0,0,0,0,0) ==sum==> 4
# one_hot(X_action,9)    *       targetQ_outputs    ======  tf.reduce_sum ======>Q_action
Q_action = tf.reduce_sum(targetQ_outputs * tf.one_hot(X_action, n_outputs), axis=-1, keep_dims=True)

  定义拷贝参数的操作

copy_op = [tf.assign(main_name, targetQ[var_name]) for var_name, main_name in mainQ.items()]
copy_target_to_main = tf.group(*copy_op)

  定义优化算法和loss function

# y相当于r+γ*max(Q(s,a))
y = tf.placeholder(tf.float32, shape=(None,1))# 训练任务相当于一个回归问题,让CNN计算出来的值Q_action越来越接近r+γ*max(Q(s,a))
loss = tf.reduce_mean(tf.square(y - Q_action))# Adam算法用于优化
optimizer = tf.train.AdamOptimizer(learning_rate)
training_op = optimizer.minimize(loss)# 全局参数的初始化器
init = tf.global_variables_initializer()loss_summary = tf.summary.scalar('LOSS', loss)# summary.merge_all()可以将几乎所有数据放在tensorboard上显示
merge_summary = tf.summary.merge_all()# 写入训练记录文件
file_writer = tf.summary.FileWriter(logdir, tf.get_default_graph())

  下面就是正式开始训练的时候了。

with tf.Session() as sess:init.run() # 参数初始化# for循环持续num_episode盘游戏for i in range(num_episodes):done = False # 该局游戏是否结束的标志obs = env.reset() # 初始化游戏环境epoch = 0 # 在游戏中每走1步  = 一个global_step = 一个epochepisodic_reward = 0 # 每局游戏的总回报actions_counter = Counter()  # 一局游戏中0-8共9种动作分别执行的次数episodic_loss = [] # 记录一局游戏中每次训练CNN时的loss# 进入循环,直到游戏结束while not done:# 可视化游戏界面env.render()# 对游戏界面做图像预处理,obs.shape=(88,80,1)obs = preprocess_observation(obs)# 将当前obs送入CNN得到每个动作的Q值actions = mainQ_outputs.eval(feed_dict={X:[obs], in_training_mode:False})# 选Q值最大的actionaction = np.argmax(actions, axis=-1)# 记录当前选择的actionactions_counter[str(action)] += 1 # 利用epsilon-greedy策略选择动作action = epsilon_greedy(action, global_step)# 执行动作,得到下一个状态、回报、是否结束的标志next_obs, reward, done, _ = env.step(action)# 将(s,a,r,s',done)作为一条exp存入经验池exp_buffer.append([obs, action, preprocess_observation(next_obs), reward, done])# 前start_steps(2000)次迭代只搜集数据,不训练CNN# 每4次迭代训练一次CNN,steps_train=4if global_step % steps_train == 0 and global_step > start_steps:# 从经验池中采样batch_size条数据o_obs, o_act, o_next_obs, o_rew, o_done = sample_memories(batch_size)# 当前状态,shape=(batch_size, 88, 80, 1)o_obs = [x for x in o_obs]# 下一状态o_next_obs = [x for x in o_next_obs]# 由o_next_obs计算的下一状态时,9个动作的Q值,shape=(batch_size, 9)next_act = mainQ_outputs.eval(feed_dict={X:o_next_obs, in_training_mode:False})# 利用时间差分算法计算当前真实回报,当游戏结束时刻,只有第1项o_rew,而无未来收益discount_factor * np.max(next_act, axis=-1)y_batch = o_rew + discount_factor * np.max(next_act, axis=-1) * (1-o_done) # 保存所有训练过程中数据mrg_summary = merge_summary.eval(feed_dict={X:o_obs, y:np.expand_dims(y_batch, axis=-1), X_action:o_act, in_training_mode:False})file_writer.add_summary(mrg_summary, global_step)# 计算loss,训练CNNtrain_loss, _ = sess.run([loss, training_op], feed_dict={X:o_obs, y:np.expand_dims(y_batch, axis=-1), X_action:o_act, in_training_mode:True})episodic_loss.append(train_loss)# print(sess.run(X_action,feed_dict={X_action:o_act}))# print(sess.run(Q_action,feed_dict={X_action:o_act,targetQ_outputs:next_act}))# 经过100次迭代,将main Q network权重拷贝给target Q networkif (global_step+1) % copy_steps == 0 and global_step > start_steps:copy_target_to_main.run()obs = next_obsepoch += 1global_step += 1episodic_reward += rewardprint('Episode',i,'Epoch', epoch, 'Reward', episodic_reward,'Buffer len',len(exp_buffer))

  代码完整版

import numpy as np
import gym
import tensorflow as tf
from tensorflow.contrib.layers import flatten, conv2d, fully_connected
from collections import deque, Counter
import random
import matplotlib.pyplot as plt
%matplotlib inlineenv = gym.make('MsPacman-v0')n_outputs = env.action_space.n
# n_outputs = 9# color后面用于图像的锐化
color = np.array([210, 164, 74]).mean()def preprocess_observation(obs):'''处理210x160x3图像'''# 以2为步长,截取1-176行的像素,共取88行# 同样地,每两列取1列像素,共取80列# img.shape = (88,80,3)img = obs[1:176:2, ::2]# 彩图转灰度图,即对三通道像素值取平均img = img.mean(axis=2)# 提高图像对比度img[img==color] = 0# 像素值归一化(-1,1)img = (img - 128) / 128 - 1return img.reshape(88,80,1)tf.reset_default_graph()def q_network(X, name_scope):# Initialize layersinitializer = tf.contrib.layers.variance_scaling_initializer()with tf.variable_scope(name_scope) as scope: # 定义卷积操作layer_1 = conv2d(X, num_outputs=32, kernel_size=(8,8), stride=4, padding='SAME', weights_initializer=initializer) # summary.histogram的作用是在tensorboard中以直方图的形式可视化这个变量tf.summary.histogram('layer_1',layer_1)layer_2 = conv2d(layer_1, num_outputs=64, kernel_size=(4,4), stride=2, padding='SAME', weights_initializer=initializer)tf.summary.histogram('layer_2',layer_2)layer_3 = conv2d(layer_2, num_outputs=64, kernel_size=(3,3), stride=1, padding='SAME', weights_initializer=initializer)tf.summary.histogram('layer_3',layer_3)# 将2维feature map拉成向量,送入全连接层flat = flatten(layer_3)fc = fully_connected(flat, num_outputs=128, weights_initializer=initializer)tf.summary.histogram('fc',fc)# 最后一层全连接的输出是9个可能动作的Q值,注意这里没有经过激活函数,可以试一下softmax函数的效果output = fully_connected(fc, num_outputs=n_outputs, activation_fn=None, weights_initializer=initializer)tf.summary.histogram('output',output)# 将网络的权重保存起来,以便拷贝给Target Networkvars = {v.name[len(scope.name):]: v for v in tf.get_collection(key=tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope.name)} return vars, outputeps_min = 0.05
eps_max = 1.0
# 每个episode约持续600-700个step
# 因此eps_decay_steps要随着num_episodes的变化而变化
eps_decay_steps = 500000def epsilon_greedy(action, step):'''step = 0,epsilon=1step = 500000,epsilon = 0.05线性衰减'''epsilon = max(eps_min, eps_max - (eps_max-eps_min) * step/eps_decay_steps)if np.random.rand() < epsilon:# 输出随机动作epsilon_greedyreturn np.random.randint(n_outputs)else:# 输出最优动作return action# from collections import deque, Counter
buffer_len = 20000
exp_buffer = deque(maxlen=buffer_len)def sample_memories(batch_size):# permutation的作用:# 将[0, len(exp_buffer)-1] 的整数乱序排列# [:batch_size]取打乱顺序的buffer中1个batch的数据 perm_batch = np.random.permutation(len(exp_buffer))[:batch_size]mem = np.array(exp_buffer)[perm_batch]# 一条数据中包括(s,a,s',r,done) 5个数据return mem[:,0], mem[:,1], mem[:,2], mem[:,3], mem[:,4]num_episodes = 800              # 一共玩800盘游戏
batch_size = 48                 # 每次从经验池拿出48个样本训练CNN
input_shape = (None, 88, 80, 1) # 网络输入尺寸,第1维是batch
learning_rate = 0.001
X_shape = (None, 88, 80, 1)
discount_factor = 0.97          # 折扣率,表示未来回报对现在的重要程度global_step = 0                 # 将每局游戏走的步数相累加,就是全局步数
copy_steps = 100                # 每100代,当前网络向Target Network拷贝参数
steps_train = 4                 # 设定游戏中每走4步,就训练CNN一次
start_steps = 2000              # 训练初期,经验池不满,所以前2000代先收集数据,不进行训练# 在当前目录下新建logs文件夹,记录训练数据
logdir = 'logs'
tf.reset_default_graph()# 定义送入CNN数据的接口
X = tf.placeholder(tf.float32, shape=X_shape)# 用一个布尔值控制训练/非训练状态
in_training_mode = tf.placeholder(tf.bool)# main Q network
mainQ, mainQ_outputs = q_network(X, 'mainQ')# target Q network
targetQ, targetQ_outputs = q_network(X, 'targetQ')# X_action 长度 = batch_size(48), 每1个元素都表示当时采取的动作0-8
X_action = tf.placeholder(tf.int32, shape=(None,))
# Q_action 长度 = batch_size
# Q_action计算的是样本中(s,a)的CNN估计的Q值
# (0,0,0,1,0,0,0,0,0)        *     (1,2,3,4,5,6,7,8,9)   =   (0,0,0,4,0,0,0,0,0) ==sum==> 4
# one_hot(X_action,9)    *       targetQ_outputs    ======  tf.reduce_sum ======>Q_action
Q_action = tf.reduce_sum(targetQ_outputs * tf.one_hot(X_action, n_outputs), axis=-1, keep_dims=True)copy_op = [tf.assign(main_name, targetQ[var_name]) for var_name, main_name in mainQ.items()]
copy_target_to_main = tf.group(*copy_op)# y相当于r+γ*max(Q(s,a))
y = tf.placeholder(tf.float32, shape=(None,1))# 训练任务相当于一个回归问题,让CNN计算出来的值Q_action越来越接近r+γ*max(Q(s,a))
loss = tf.reduce_mean(tf.square(y - Q_action))# Adam算法用于优化
optimizer = tf.train.AdamOptimizer(learning_rate)
training_op = optimizer.minimize(loss)# 全局参数的初始化器
init = tf.global_variables_initializer()loss_summary = tf.summary.scalar('LOSS', loss)# summary.merge_all()可以将几乎所有数据放在tensorboard上显示
merge_summary = tf.summary.merge_all()# 写入训练记录文件
file_writer = tf.summary.FileWriter(logdir, tf.get_default_graph())with tf.Session() as sess:init.run() # 参数初始化# for循环持续num_episode盘游戏for i in range(num_episodes):done = False # 该局游戏是否结束的标志obs = env.reset() # 初始化游戏环境epoch = 0 # 在游戏中每走1步  = 一个global_step = 一个epochepisodic_reward = 0 # 每局游戏的总回报actions_counter = Counter()  # 一局游戏中0-8共9种动作分别执行的次数episodic_loss = [] # 记录一局游戏中每次训练CNN时的loss# 进入循环,直到游戏结束while not done:# 可视化游戏界面env.render()# 对游戏界面做图像预处理,obs.shape=(88,80,1)obs = preprocess_observation(obs)# 将当前obs送入CNN得到每个动作的Q值actions = mainQ_outputs.eval(feed_dict={X:[obs], in_training_mode:False})# 选Q值最大的actionaction = np.argmax(actions, axis=-1)# 记录当前选择的actionactions_counter[str(action)] += 1 # 利用epsilon-greedy策略选择动作action = epsilon_greedy(action, global_step)# 执行动作,得到下一个状态、回报、是否结束的标志next_obs, reward, done, _ = env.step(action)# 将(s,a,r,s',done)作为一条exp存入经验池exp_buffer.append([obs, action, preprocess_observation(next_obs), reward, done])# 前start_steps(2000)次迭代只搜集数据,不训练CNN# 每4次迭代训练一次CNN,steps_train=4if global_step % steps_train == 0 and global_step > start_steps:# 从经验池中采样batch_size条数据o_obs, o_act, o_next_obs, o_rew, o_done = sample_memories(batch_size)# 当前状态,shape=(batch_size, 88, 80, 1)o_obs = [x for x in o_obs]# 下一状态o_next_obs = [x for x in o_next_obs]# 由o_next_obs计算的下一状态时,9个动作的Q值,shape=(batch_size, 9)next_act = mainQ_outputs.eval(feed_dict={X:o_next_obs, in_training_mode:False})# 利用时间差分算法计算当前真实回报,当游戏结束时刻,只有第1项o_rew,而无未来收益discount_factor * np.max(next_act, axis=-1)y_batch = o_rew + discount_factor * np.max(next_act, axis=-1) * (1-o_done) # 保存所有训练过程中数据mrg_summary = merge_summary.eval(feed_dict={X:o_obs, y:np.expand_dims(y_batch, axis=-1), X_action:o_act, in_training_mode:False})file_writer.add_summary(mrg_summary, global_step)# 计算loss,训练CNNtrain_loss, _ = sess.run([loss, training_op], feed_dict={X:o_obs, y:np.expand_dims(y_batch, axis=-1), X_action:o_act, in_training_mode:True})episodic_loss.append(train_loss)# print(sess.run(X_action,feed_dict={X_action:o_act}))# print(sess.run(Q_action,feed_dict={X_action:o_act,targetQ_outputs:next_act}))# 经过100次迭代,将main Q network权重拷贝给target Q networkif (global_step+1) % copy_steps == 0 and global_step > start_steps:copy_target_to_main.run()obs = next_obsepoch += 1global_step += 1episodic_reward += rewardprint('Episode',i,'Epoch', epoch, 'Reward', episodic_reward,'Buffer len',len(exp_buffer))

  开始训练,如下图。大功告成,下一篇讲讲DQN实验的细节,如何在Tensorboard上查看训练日志,以及如何搭建更复杂的模型以提高性能。


  

  

  

强化学习经典算法笔记(六):深度Q值网络 Deep Q Network相关推荐

  1. 强化学习经典算法笔记(十四):双延迟深度确定性策略梯度算法TD3的PyTorch实现

    强化学习经典算法笔记(十四):双延迟深度确定性策略梯度算法TD3的PyTorch实现 TD3算法简介 TD3是Twin Delayed Deep Deterministic policy gradie ...

  2. 强化学习经典算法笔记(十九):无监督策略学习算法Diversity Is All You Need

    强化学习经典算法笔记19:无监督策略学习算法Diversity Is All You Need DIAYN核心要点 模型定义 目标函数的构造 DIAYN算法细节 目标函数的优化 SAC的训练 判别器的 ...

  3. 强化学习经典算法笔记(十二):近端策略优化算法(PPO)实现,基于A2C(下)

    强化学习经典算法笔记(十二):近端策略优化算法(PPO)实现,基于A2C 本篇实现一个基于A2C框架的PPO算法,应用于连续动作空间任务. import torch import torch.nn a ...

  4. 【学霸笔记】AlphaGo之父David Silver的强化学习经典课程笔记

    聚焦AI干货,关注:决策智能与机器学习 AlphaGo之父David Silver的强化学习经典课程前文已有介绍,本想自己整理一下课程的学习笔记,但发现已经有学霸整理的很完善,不做东施效颦之举,在此分 ...

  5. 强化学习经典model-free方法总结

    强化学习经典model-free方法总结 1. 基于值函数(value-based)的方法 1.1 sarsa 1.2 Q-learning 1.3 DQN 1.4 Double DQN 1.5 Du ...

  6. 深度强化学习探索算法最新综述,近200篇文献揭示挑战和未来方向

    ©作者 | 杨天培.汤宏垚等 来源 | 机器之心 强化学习是在与环境交互过程中不断学习的,⽽交互中获得的数据质量很⼤程度上决定了智能体能够学习到的策略的⽔平.因此,如何引导智能体探索成为强化学习领域研 ...

  7. 深度强化学习主流算法介绍(二):DPG系列

    之前的文章可以看这里 深度强化学习主流算法介绍(一):DQN系列 相关论文在这里 开始介绍DPG之前,先回顾下DQN系列 DQN直接训练一个Q Network 去估计每个离散动作的Q值,使用时选择Q值 ...

  8. 深度强化学习——DQN算法原理

    DQN算法原理 一.DQN算法是什么 二.DQN训练过程 三.经验回放 (Experience Replay) 四.目标网络(Target Network) 1.自举(Bootstrapping) 2 ...

  9. 深度强化学习-DDPG算法原理和实现

    全文共3077个字,8张图,预计阅读时间15分钟. 基于值的强化学习算法的基本思想是根据当前的状态,计算采取每个动作的价值,然后根据价值贪心的选择动作.如果我们省略中间的步骤,即直接根据当前的状态来选 ...

  10. Python手写强化学习Q-learning算法玩井字棋

    Q-learning 是强化学习中的一种常见的算法,近年来由于深度学习革命而取得了很大的成功.本教程不会解释什么是深度 Q-learning,但我们将通过 Q-learning 算法来使得代理学习如何 ...

最新文章

  1. python中tk窗口刷新_80 行 Python 代码写个图形计算器
  2. malloc 初始化_在C语言中,请一定记得初始化局部变量!
  3. idea 自定义工具栏
  4. 阿里巴巴如何改善开发人员在 K8s 上的体验?
  5. Oracle PL/SQL中如何使用%TYPE和%ROWTYPE
  6. 音视频技术开发周刊 76期
  7. context-param和init-param的区别
  8. C++读取一整行字符串以及其他函数
  9. Spring : Spring 深入理解lombok
  10. Linux调优/优化
  11. python 编程实例
  12. 苹果app项目退款教程
  13. 计算机网络安全存在哪些潜在威胁,【计算机安全论文】威胁计算机安全论文(共4016字)...
  14. [欧洲之行]比利时布鲁塞尔
  15. 【读书笔记】计算机是怎样跑起来的 - 读书笔记(2)
  16. css解决谷歌,360浏览器默认最小字体为12px问题
  17. torchaudio安装与实例
  18. 区块链存在哪些安全缺陷?怎么解决?
  19. 【2021-11-08 更新】【梳理】简明操作系统原理 第二十章 加密(docx)
  20. 【程序员养生】:经历以及教训及生活日历

热门文章

  1. 新手常见(五国)(-v图)错误解决(原版,破解kernel,补丁kext下载)
  2. outlook电子邮件解析_在Outlook 2007中轻松重新发送电子邮件
  3. SpringBoot整体开发的详细过程(待完结)
  4. Windows xp IIS 信息服务组件安装包
  5. python乒乓球比赛规则介绍_用英语介绍乒乓球的比赛规则
  6. 设置虚拟opc服务器,ifix建虚拟opc服务器(DCS通过opc读取ifix)
  7. Solr高级查询Facet
  8. android n自带游戏,Android N玩游戏更快了 但国产ROM要等很久
  9. 【NiosII训练】第二篇、FPGA驱动AD9854高级篇
  10. SAP-ABAP 读取billing document以及其它订单附件的实例(GOS)