深度 Q 网络(Deep - Q - Network) 介绍
在 Q-learning 算法中,当状态和动作空间是离散且维数不高时,可使用 Q-table 储存每个状态动作对的 Q 值,然后通过贝尔曼方差迭代求得每个状态动作对收敛的 Q 值,然后选择最优的动作当做策略。但是而当状态和动作空间是高维连续时,比如(游戏的状态动作对数目就很大)使用 Q-table 存储每个状态动作对就显得很不现实。
所以可以将 Q-Table 的更新问题变成一个函数拟合问题,相近的状态得到相近的输出动作。DQN 就是要设计一个神经网络结构,通过函数来拟合 Q 值。
下面引用一下自己写的一篇综述里面的 DQN 训练流程图,贴自己的图,不算侵犯版权吧,哈哈。知网上可以下载到这篇文章:http://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CJFD&&filename=JSJX201801001。当时3个月大概看了百余篇DRL方向的论文,才写出来的,哈哈。
DQN 的亮点:
通过 experience replay(经验池)的方法来解决相关性及非静态分布问题,在训练深度网络时,通常要求样本之间是相互独立的,所以通过这种随机采样的方式,大大降低了样本之间的关联性,从而提升了算法的稳定性。
使用一个神经网络产生当前 Q 值,使用另外一个神经网络产生 Target Q 值。
DQN 损失函数和参数更新:
损失函数:
其中 yi 表示值函数的优化目标即目标网络的 Q 值:
参数更新的梯度为:
Tensorflow 2.0 实现 DQN
整体的代码是借鉴的莫烦大神,只不过现在用的接口都是 Tensorflow 2.0,所以代码显得很简单,风格很像 keras。
# -*- coding:utf-8 -*-
# Author : zhaijianwei
# Date : 2019/6/19 19:48
import tensorflow as tf
import numpy as np
from tensorflow.python.keras import layers
from tensorflow.python.keras.optimizers import RMSprop
from DQN.maze_env import Maze
class Eval_Model(tf.keras.Model):
def __init__(self, num_actions):
super().__init__('mlp_q_network')
self.layer1 = layers.Dense(10, activation='relu')
self.logits = layers.Dense(num_actions, activation=None)
def call(self, inputs):
x = tf.convert_to_tensor(inputs)
layer1 = self.layer1(x)
logits = self.logits(layer1)
return logits
class Target_Model(tf.keras.Model):
def __init__(self, num_actions):
super().__init__('mlp_q_network_1')
self.layer1 = layers.Dense(10, trainable=False, activation='relu')
self.logits = layers.Dense(num_actions, trainable=False, activation=None)
def call(self, inputs):
x = tf.convert_to_tensor(inputs)
layer1 = self.layer1(x)
logits = self.logits(layer1)
return logits
class DeepQNetwork:
def __init__(self, n_actions, n_features, eval_model, target_model):
self.params = {
'n_actions': n_actions,
'n_features': n_features,
'learning_rate': 0.01,
'reward_decay': 0.9,
'e_greedy': 0.9,
'replace_target_iter': 300,
'memory_size': 500,
'batch_size': 32,
'e_greedy_increment': None
}
# total learning step
self.learn_step_counter = 0
# initialize zero memory [s, a, r, s_]
self.epsilon = 0 if self.params['e_greedy_increment'] is not None else self.params['e_greedy']
self.memory = np.zeros((self.params['memory_size'], self.params['n_features'] * 2 + 2))
self.eval_model = eval_model
self.target_model = target_model
self.eval_model.compile(
optimizer=RMSprop(lr=self.params['learning_rate']),
loss='mse'
)
self.cost_his = []
def store_transition(self, s, a, r, s_):
if not hasattr(self, 'memory_counter'):
self.memory_counter = 0
transition = np.hstack((s, [a, r], s_))
# replace the old memory with new memory
index = self.memory_counter % self.params['memory_size']
self.memory[index, :] = transition
self.memory_counter += 1
def choose_action(self, observation):
# to have batch dimension when feed into tf placeholder
observation = observation[np.newaxis, :]
if np.random.uniform() < self.epsilon:
# forward feed the observation and get q value for every actions
actions_value = self.eval_model.predict(observation)
print(actions_value)
action = np.argmax(actions_value)
else:
action = np.random.randint(0, self.params['n_actions'])
return action
def learn(self):
# sample batch memory from all memory
if self.memory_counter > self.params['memory_size']:
sample_index = np.random.choice(self.params['memory_size'], size=self.params['batch_size'])
else:
sample_index = np.random.choice(self.memory_counter, size=self.params['batch_size'])
batch_memory = self.memory[sample_index, :]
q_next = self.target_model.predict(batch_memory[:, -self.params['n_features']:])
q_eval = self.eval_model.predict(batch_memory[:, :self.params['n_features']])
# change q_target w.r.t q_eval's action
q_target = q_eval.copy()
batch_index = np.arange(self.params['batch_size'], dtype=np.int32)
eval_act_index = batch_memory[:, self.params['n_features']].astype(int)
reward = batch_memory[:, self.params['n_features'] + 1]
q_target[batch_index, eval_act_index] = reward + self.params['reward_decay'] * np.max(q_next, axis=1)
# check to replace target parameters
if self.learn_step_counter % self.params['replace_target_iter'] == 0:
for eval_layer, target_layer in zip(self.eval_model.layers, self.target_model.layers):
target_layer.set_weights(eval_layer.get_weights())
print('\ntarget_params_replaced\n')
"""
For example in this batch I have 2 samples and 3 actions:
q_eval =
[[1, 2, 3],
[4, 5, 6]]
q_target = q_eval =
[[1, 2, 3],
[4, 5, 6]]
Then change q_target with the real q_target value w.r.t the q_eval's action.
For example in:
sample 0, I took action 0, and the max q_target value is -1;
sample 1, I took action 2, and the max q_target value is -2:
q_target =
[[-1, 2, 3],
[4, 5, -2]]
So the (q_target - q_eval) becomes:
[[(-1)-(1), 0, 0],
[0, 0, (-2)-(6)]]
We then backpropagate this error w.r.t the corresponding action to network,
leave other action as error=0 cause we didn't choose it.
"""
# train eval network
self.cost = self.eval_model.train_on_batch(batch_memory[:, :self.params['n_features']], q_target)
self.cost_his.append(self.cost)
# increasing epsilon
self.epsilon = self.epsilon + self.params['e_greedy_increment'] if self.epsilon < self.params['e_greedy'] \
else self.params['e_greedy']
self.learn_step_counter += 1
def plot_cost(self):
import matplotlib.pyplot as plt
plt.plot(np.arange(len(self.cost_his)), self.cost_his)
plt.ylabel('Cost')
plt.xlabel('training steps')
plt.show()
def run_maze():
step = 0
for episode in range(300):
# initial observation
observation = env.reset()
while True:
# fresh env
env.render()
# RL choose action based on observation
action = RL.choose_action(observation)
# RL take action and get next observation and reward
observation_, reward, done = env.step(action)
RL.store_transition(observation, action, reward, observation_)
if (step > 200) and (step % 5 == 0):
RL.learn()
# swap observation
observation = observation_
# break while loop when end of this episode
if done:
break
step += 1
# end of game
print('game over')
env.destroy()
if __name__ == "__main__":
# maze game
env = Maze()
eval_model = Eval_Model(num_actions=env.n_actions)
target_model = Target_Model(num_actions=env.n_actions)
RL = DeepQNetwork(env.n_actions, env.n_features, eval_model, target_model)
env.after(100, run_maze)
env.mainloop()
RL.plot_cost()
参考文献:
https://www.jianshu.com/p/10930c371cac
https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow
http://inoryy.com/post/tensorf
本文转载自 Alex-zhai 知乎账号。
原文链接:https://zhuanlan.zhihu.com/p/70009692
更多内容推荐
深度学习基础入门篇 [一]:神经元简介、单层多层感知机、距离计算方法式、相似度函数
在生物学中,神经元细胞有兴奋与抑制两种状态。大多数神经元细胞在正常情况下处于抑制状态,一旦某个神经元受到刺激并且电位超过一定的阈值后,这个神经元细胞就被激活,处于兴奋状态,并向其他神经元传递信息。基于神经元细胞的结构特性与传递信息方式,神经
2023-04-05
07|模型工程:算法三大门派,取众家之长为我所用
目前,以深度学习模型为代表的连接主义派表现出色。然而,在许多情况下,AI系统仍然需要结合其他两个派别的算法,才能发挥最大的功效。
2023-08-25
Matlab 实现 Non-Local Means 算法
Non-Local Means算法是一种经典的图像降噪算法,它的基本思想是通过比较图像中不同位置的像素之间的相似性来进行降噪。Matlab是一种功能强大的数值计算软件,提供了多种用于图像处理的工具和函数,可以方便地实现Non-Local Means算法。
2023-05-02
[Python 公开课] 零基础玩转 Python 基础篇 ---- 第六节:Python 中的函数
[Python公开课]零基础玩转Python基础篇----第六节:Python中的函数
2022-02-15
强化学习入门——说到底研究的是如何学习
自机器学习重新火起来,深度强化学习就一直是科研的一大热点,也是最有可能实现通用人工智能的一个分支。
每个 Java 程序员都必须知道的四种负载均衡算法
一般来说,我们在设计系统的时候,为了系统的高扩展性,会尽可能的创建无状态的系统,这样我们就可以采用集群的方式部署,最终很方便的根据需要动态增减服务器数量。但是,要使系统具有更好的可扩展性,除了无状态设计之外,还要考虑采用什么负载均衡算法,本
2023-01-10
11|VAE 系列:如何压缩图像给 GPU 腾腾地方
这一讲,我们将一起了解VAE的基本原理,之后我们训练自己的Stable Diffusion模型时,也会用上VAE这个模块。
2023-08-09
算法题每日一练 --- 第 6 天:李白打酒
话说大诗人李白,一生好饮。幸好他从不开车。
2022-07-23
初探语音识别 ASR 算法
摘要:语音转写文字ASR技术的基本概念与数学原理简介。
2021-12-28
08|巧用神经网络:如何用 UNet 预测噪声
今天我就来为你解读UNet的核心知识。搞懂了这些,在你的日常工作中,便可以根据实际需求对预测噪声的模型做各种魔改了,也会为我们之后训练扩散模型的实战课打好基础。
2023-08-02
10|CLIP:让 AI 绘画模型乖乖听你的话
只有真正理解了CLIP,你才能知道为什么prompt可以控制AI绘画生成的内容。
2023-08-07
PyTorch 中 nn.Conv2d 与 nn.ConvTranspose2d 函数的用法
原文链接
2023-01-11
我的算法学习之路
一点儿经验,希望对想学算法的你有帮助
2021-01-29
颠覆者扩散模型:直观去理解加噪与去噪
扩散模型的工作原理是怎样的呢?算法优化目标是什么?与GAN相比有哪些异同?这一讲我们便从这些基础问题出发,开始我们的扩散模型学习之旅。
2023-07-28
强化学习基础篇 [3]:DQN、Actor-Critic 详细讲解
在之前的内容中,我们讲解了Q-learning和Sarsa算法。在这两个算法中,需要用一个Q表格来记录不同状态动作对应的价值,即一个大小为 的二维数组。在一些简单的强化学习环境中,比如迷宫游戏中(图1a),迷宫大小为4*4,因此该游戏存在16个state;而悬崖问题(
2023-06-03
强化学习从基础到进阶 - 案例与实践 [6]:演员 - 评论员算法(advantage actor-critic,A2C),异步 A2C、与生成对抗网络的联系等详解
在REINFORCE算法中,每次需要根据一个策略采集一条完整的轨迹,并计算这条轨迹上的回报。这种采样方式的方差比较大,学习效率也比较低。我们可以借鉴时序差分学习的思想,使用动态规划方法来提高采样效率,即从状态 开始的总回报可以通过当前动作的即时奖励
强化学习从基础到进阶 - 常见问题和面试必知必答 [8]:近端策略优化(proximal policy optimization,PPO)算法
强化学习从基础到进阶-常见问题和面试必知必答[8]:近端策略优化(proximal policy optimization,PPO)算法
2023-06-28
状态机的概念与设计
一般情况下,状态触发器的数量是有限的,其状态数也是有限的,故称为有限状态机(Finite State Machine,简称为FSM)。状态机中所有触发器的时钟输入端被连接到一个公共时钟脉冲源上,其状态的转换是在同一时钟源的同一脉冲边沿同步进行的,所以它也被称作时
2023-02-09
24|GBDT+LR:排序算法经典中的经典
在前面的课程中,我们讲了推荐系统中的数据处理、接口实现和一些召回算法和模型,从本章开始,我们就会进入一个新的篇章:推荐系统中的排序算法。
2023-06-09
Vue 深入学习 2—虚拟 DOM 和 Diff 算法
snabbdom 是什么?snabbdom 的 h 函数如何工作?什么是虚拟DOM?
2021-08-05
推荐阅读
5 分钟搞懂 ECN
2023-08-20
大语言模型的预训练 [1]: 基本概念原理、神经网络的语言模型、Transformer 模型原理详解、Bert 模型原理介绍| 社区征文
2023-07-17
DPO 直接偏好优化:跳过复杂的对抗学习,语言模型本来就会奖励算法
2023-07-13
26|模型工程(二):算力受限,如何为“无米之炊”?
2023-10-18
深度学习算法:从模仿到创造
2023-10-09
4. 可用性:故障检测之滑动窗口算法
2023-09-27
27|DALL-E 3 技术探秘(二):从 unCLIP 到缝合怪方案
2023-11-09
电子书
大厂实战PPT下载
换一换 张深深 | 任意门科技(Soul) 效率产品负责人
陈朝钢(摩净) | 蚂蚁集团 高级数据技术专家
吴凯凯 | 字节跳动 技术专家
评论