- 莫烦机器学习教程
- 有趣的机器学习
- 机器学习 (Machine Learning)
- 神经网络 (Neural Network)
- 卷积神经网络 CNN (Convolutional Neural Network)
- 循环神经网络 RNN (Recurrent Neural Network)
- LSTM RNN 循环神经网络 (LSTM)
- 自编码 (Autoencoder)
- 检验神经网络 (Evaluation)
- 特征标准化 (Feature Normalization)
- 选择好特征 (Good Features)
- 激励函数 (Activation Function)
- 过拟合 (Overfitting)
- 加速神经网络训练 (Speed Up Training)
- 处理不均衡数据 (Imbalanced data)
- 批标准化 (Batch Normalization)
- L1 / L2 正规化 (Regularization)
- 强化学习 (Reinforcement Learning)
- 强化学习方法汇总 (Reinforcement Learning)
- Q Leaning
- Sarsa
- Sarsa(lambda)
- DQN
- Policy Gradients
- Actor Critic
- Deep Deterministic Policy Gradient (DDPG)
- Asynchronous Advantage Actor-Critic (A3C)
- 强化学习教程
- Why?
- 课程要求
- 小例子
- Q-learning 算法更新
- Q-learning 思维决策
- Sarsa 算法更新
- Sarsa 思维决策
- Sarsa-lambda
- DQN 算法更新 (Tensorflow)
- DQN 神经网络 (Tensorflow)
- DQN 思维决策 (Tensorflow)
- OpenAI gym 环境库 (Tensorflow)
- Double DQN (Tensorflow)
- Prioritized Experience Replay (DQN) (Tensorflow)
- Dueling DQN (Tensorflow)
- Policy Gradients 算法更新 (Tensorflow)
- Policy Gradients 思维决策 (Tensorflow)
- Actor Critic (Tensorflow)
- Deep Deterministic Policy Gradient (DDPG) (Tensorflow)
- Asynchronous Advantage Actor-Critic (A3C) (Tensorflow)
- TensorFlow 教程
- 为什么选 Tensorflow
- 安装
- 神经网络在干嘛
- 处理结构
- 例子 2
- Session 会话控制
- Variable 变量
- Placeholder 传入值
- 激励函数 Activation Function
- 例子 3 添加层 def add_layer()
- 例子 3 建造神经网络
- 例子 3 结果可视化
- 优化器 optimizer
- Tensorboard 可视化好帮手 1
- Tensorboard 可视化好帮手 2
- Classification 分类学习
- Dropout 解决 overfitting
- CNN 卷积神经网络 1
- CNN 卷积神经网络 2
- CNN 卷积神经网络 3
- Saver 保存读取
- RNN 循环神经网络
- RNN LSTM 循环神经网络 (分类例子)
- RNN LSTM (回归例子)
- RNN LSTM (回归例子可视化)
- 自编码 Autoencoder (非监督学习)
- scope 命名方法
- Batch Normalization 批标准化
- PyTorch 教程
- Why?
- 安装
- Torch 或 Numpy
- 变量 (Variable)
- 激励函数 (Activation)
- 关系拟合 (回归)
- 区分类型 (分类)
- 快速搭建法
- 保存提取
- 批训练
- Optimizer 优化器
- CNN 卷积神经网络
- RNN 循环神经网络 (分类)
- RNN 循环神经网络 (回归)
- AutoEncoder (自编码/非监督学习)
- DQN 强化学习
- GAN (Generative Adversarial Nets 生成对抗网络)
- 为什么 Torch 是动态的
- GPU 加速运算
- Dropout 缓解过拟合
- Batch Normalization 批标准化
- Theano 教程
- Why?
- 安装
- 神经网络在做什么
- 基本用法
- Function 用法
- Shared 变量
- Activation function 激励函数
- 定义 Layer 类
- Regression 回归例子
- 可视化结果 回归例子
- Classification 分类学习
- Regularization 正规化
- Save 保存 提取
- 总结和更多
- Keras 教程
- Why?
- 安装
- 兼容 backend
- Regressor 回归
- Classifier 分类
- CNN 卷积神经网络
- RNN Classifier 循环神经网络
- RNN Regressor 循环神经网络
- Autoencoder 自编码
- Save & reload 保存提取
- Scikit learn 教程
- Why?
- 安装
- 选择学习方法
- 通用学习模式
- sklearn 强大数据库
- sklearn 常用属性与功能
- 正规化 Normalization
- 交叉验证 1 Cross-validation
- 交叉验证 2 Cross-validation
- 交叉验证 3 Cross-validation
- 保存模型
Double DQN (Tensorflow)
作者: Morvan 编辑: Morvan
本篇教程是基于 Deep Q network (DQN) 的选学教程. 以下教程缩减了在 DQN 方面的介绍,着重强调 Double DQN 和 DQN 在代码上不同的地方. 所以还没了解 DQN 的同学们,有关于 DQN 的知识,请从 这个视频 和 这个 Python 教程 开始学习。
接下来我们说说为什么会有 Double DQN 这种算法. 所以我们从 Double DQN 相对于 Natural DQN (传统 DQN) 的优势说起。
一句话概括, DQN 基于 Q-learning, Q-Learning 中有 Qmax
, Qmax
会导致 Q 现实
当中的过估计 (overestimate). 而 Double DQN 就是用来解决过估计的. 在实际问题中,如果你输出你的 DQN 的 Q 值,可能就会发现, Q 值都超级大. 这就是出现了 overestimate.
这次的 Double DQN 的算法基于的是 OpenAI Gym 中的 Pendulum
环境. 如果还不了解如何使用 OpenAI 的话,这里有 我的一个教程 . 以下就是这次的结果,先睹为快。
本节内容包括:
Double DQN 算法
我们知道 DQN 的神经网络部分可以看成一个 最新的神经网络
+ 老神经网络
, 他们有相同的结构,但内部的参数更新却有时差. 而它的 Q 现实
部分是这样的:
因为我们的神经网络预测 Qmax
本来就有误差,每次也向着最大误差的 Q 现实
改进神经网络,就是因为这个 Qmax
导致了 overestimate. 所以 Double DQN 的想法就是引入另一个神经网络来打消一些最大误差的影响. 而 DQN 中本来就有两个神经网络,我们何不利用一下这个地理优势呢. 所以,我们用 Q 估计
的神经网络估计 Q 现实
中 Qmax(s', a')
的最大动作值. 然后用这个被 Q 估计
估计出来的动作来选择 Q 现实
中的 Q(s')
. 总结一下:
有两个神经网络: Q_eval
(Q 估计中的), Q_next
(Q 现实中的).
原本的 Q_next = max(Q_next(s', a_all))
.
Double DQN 中的 Q_next = Q_next(s', argmax(Q_eval(s', a_all)))
. 也可以表达成下面那样。
更新方法
好了,有了理论,我们就来用 Python 实现它吧。
这里的代码都是基于之前 DQN 教程中的代码 (github) , 在 RL_brain
中,我们将 class 的名字改成 DoubleDQN
, 为了对比 Natural DQN, 我们也保留原来大部分的 DQN 的代码. 我们在 __init__
中加一个 double_q
参数来表示使用的是 Natural DQN 还是 Double DQN. 为了对比的需要,我们的 tf.Session()
也单独传入. 并移除原本在 DQN 代码中的这一句:
self.sess.run(tf.global_variables_initializer())
class DoubleDQN:
def __init__(..., double_q=True, sess=None):
...
self.double_q = double_q
if sess is None:
self.sess = tf.Session()
self.sess.run(tf.global_variables_initializer())
else:
self.sess = sess
...
接着我们来修改 learn()
中的代码. 我们对比 Double DQN 和 Natural DQN 在 tensorboard 中的图,发现他们的结构并没有不同,但是在计算 q_target
的时候,方法是不同的。
class DoubleDQN:
def learn(self):
# 这一段和 DQN 一样:
if self.learn_step_counter % self.replace_target_iter == 0:
self._replace_target_params()
print('\ntarget_params_replaced\n')
if self.memory_counter > self.memory_size:
sample_index = np.random.choice(self.memory_size, size=self.batch_size)
else:
sample_index = np.random.choice(self.memory_counter, size=self.batch_size)
batch_memory = self.memory[sample_index, :]
# 这一段和 DQN 不一样
q_next, q_eval4next = self.sess.run(
[self.q_next, self.q_eval],
feed_dict={self.s_: batch_memory[:, -self.n_features:], # next observation
self.s: batch_memory[:, -self.n_features:]}) # next observation
q_eval = self.sess.run(self.q_eval, {self.s: batch_memory[:, :self.n_features]})
q_target = q_eval.copy()
batch_index = np.arange(self.batch_size, dtype=np.int32)
eval_act_index = batch_memory[:, self.n_features].astype(int)
reward = batch_memory[:, self.n_features + 1]
if self.double_q: # 如果是 Double DQN
max_act4next = np.argmax(q_eval4next, axis=1) # q_eval 得出的最高奖励动作
selected_q_next = q_next[batch_index, max_act4next] # Double DQN 选择 q_next 依据 q_eval 选出的动作
else: # 如果是 Natural DQN
selected_q_next = np.max(q_next, axis=1) # natural DQN
q_target[batch_index, eval_act_index] = reward + self.gamma * selected_q_next
# 这下面和 DQN 一样:
_, self.cost = self.sess.run([self._train_op, self.loss],
feed_dict={self.s: batch_memory[:, :self.n_features],
self.q_target: q_target})
self.cost_his.append(self.cost)
self.epsilon = self.epsilon + self.epsilon_increment if self.epsilon < self.epsilon_max else self.epsilon_max
self.learn_step_counter += 1
记录 Q 值
为了记录下我们选择动作时的 Q 值,接下来我们就修改 choose_action()
功能,让它记录下每次选择的 Q 值。
class DoubleDQN:
def choose_action(self, observation):
observation = observation[np.newaxis, :]
actions_value = self.sess.run(self.q_eval, feed_dict={self.s: observation})
action = np.argmax(actions_value)
if not hasattr(self, 'q'): # 记录选的 Qmax 值
self.q = []
self.running_q = 0
self.running_q = self.running_q*0.99 + 0.01 * np.max(actions_value)
self.q.append(self.running_q)
if np.random.uniform() > self.epsilon: # 随机选动作
action = np.random.randint(0, self.n_actions)
return action
对比结果
接着我们就来对比 Natural DQN 和 Double DQN 带来的不同结果啦。 代码在这
import gym
from RL_brain import DoubleDQN
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
env = gym.make('Pendulum-v0')
env.seed(1) # 可重复实验
MEMORY_SIZE = 3000
ACTION_SPACE = 11 # 将原本的连续动作分离成 11 个动作
sess = tf.Session()
with tf.variable_scope('Natural_DQN'):
natural_DQN = DoubleDQN(
n_actions=ACTION_SPACE, n_features=3, memory_size=MEMORY_SIZE,
e_greedy_increment=0.001, double_q=False, sess=sess
)
with tf.variable_scope('Double_DQN'):
double_DQN = DoubleDQN(
n_actions=ACTION_SPACE, n_features=3, memory_size=MEMORY_SIZE,
e_greedy_increment=0.001, double_q=True, sess=sess, output_graph=True)
sess.run(tf.global_variables_initializer())
def train(RL):
total_steps = 0
observation = env.reset()
while True:
# if total_steps - MEMORY_SIZE > 8000: env.render()
action = RL.choose_action(observation)
f_action = (action-(ACTION_SPACE-1)/2)/((ACTION_SPACE-1)/4) # 在 [-2 ~ 2] 内离散化动作
observation_, reward, done, info = env.step(np.array([f_action]))
reward /= 10 # normalize 到这个区间 (-1, 0). 立起来的时候 reward = 0.
# 立起来以后的 Q target 会变成 0, 因为 Q_target = r + gamma * Qmax(s', a') = 0 + gamma * 0
# 所以这个状态时的 Q 值大于 0 时,就出现了 overestimate.
RL.store_transition(observation, action, reward, observation_)
if total_steps > MEMORY_SIZE: # learning
RL.learn()
if total_steps - MEMORY_SIZE > 20000: # stop game
break
observation = observation_
total_steps += 1
return RL.q # 返回所有动作 Q 值
# train 两个不同的 DQN
q_natural = train(natural_DQN)
q_double = train(double_DQN)
# 出对比图
plt.plot(np.array(q_natural), c='r', label='natural')
plt.plot(np.array(q_double), c='b', label='double')
plt.legend(loc='best')
plt.ylabel('Q eval')
plt.xlabel('training steps')
plt.grid()
plt.show()
所以这个出来的图是这样:
可以看出, Natural DQN 学得差不多后,在立起来时,大部分时间都是 估计的 Q 值 要大于 0, 这时就出现了 overestimate, 而 Double DQN 的 Q 值 就消除了一些 overestimate, 将估计值保持在 0 左右。
如果你觉得这篇文章或视频对你的学习很有帮助,请你也分享它,让它能再次帮助到更多的需要学习的人。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论