一、序言
DQN算法是 DeepMind 团队在2015年提出的算法,该论文发表在 Nature 上,此后的一些DQN相关算法(如Double DQN、Dueling DQN、D3QN)都是在其基础上改进的。DQN可以说使强化学习进入到了深度强化学习时代,意义非常重大。
论文地址:Mnih, V., Kavukcuoglu, K., Silver, D. et al. Human-level control through deep reinforcement learning. Nature 518, 529–533 (2015).
二、算法介绍
2.1 核心思想
DQN的核心思想就是训练一个Q网络,这个Q网络输入当前环境的状态,输出为agent所有动作的Q值,agent选择具有最大Q值的动作作为当前时刻的行动,以此循环往复直至回合结束。
上述就是DQN的整体思想。此外,为了更好地训练Q网络以及保证算法的稳定性,论文提出了经验回放缓冲池、目标网络的思想,后续会详细讲解。
2.2 Q网络意义
在强化学习场景中,我们通过选择动作从而得到下一个状态,我们期望选择这个动作后一直到回合结束所能获得的回报最大,也就是说这个状态所能得到回报的数学期望最大。所以Q网络的Q值可以简单理解为当前状态的每个动作直到回合结束所能得到累计回报的数学期望最大值。
那么接下来核心思想就是怎么训练出这样一个Q网络,用它来指导agent选择动作。
2.3 训练Q网络
agent的探索过程为:agent根据当前环境状态
s
t
s_t
st选择动作
a
t
a_t
at,环境根据
a
t
a_t
at的好坏给一个奖励
r
t
r_t
rt,最后环境会转移到下一个状态
s
t
+
1
s_{t+1}
st+1。上述就是一步agent的操作,然后将上述提到的
s
t
s_t
st、
a
t
a_t
at、
r
t
r_t
rt、
s
t
+
1
s_{t+1}
st+1作为一个元组保存到一个列表中,后续用装满(
s
t
s_t
st、
a
t
a_t
at、
r
t
r_t
rt、
s
t
+
1
s_{t+1}
st+1)的列表去更新Q网络。上述用到的思想就是经验回放,这个列表也就是经验回放缓冲池。
具体的更新用到了时序差分的思想,结合 DQN 之后简单概括如下:
s
t
s_t
st的状态价值函数
V
t
V_t
Vt我们不确定,
s
t
+
1
s_{t+1}
st+1的状态价值函数
V
t
+
1
V_{t+1}
Vt+1我们也不确定,但是由
s
t
s_t
st变到
s
t
+
1
s_{t+1}
st+1时环境给的奖励是已知的。这就利用上了经验回放缓冲池中我们事先保存的元组(
s
t
s_t
st、
a
t
a_t
at、
r
t
r_t
rt、
s
t
+
1
s_{t+1}
st+1),将
s
t
s_t
st代入 Q 网络得到估测的
V
t
V_t
Vt,将
s
t
+
1
s_{t+1}
st+1代入 Q 网络得到估测的
V
t
+
1
V_{t+1}
Vt+1,这两个值都是估测出来的,我们通过训练让它被估测的更准确一些。
在这里给出 Q-learning 的更新公式:
Q
(
s
t
,
a
t
)
←
Q
(
s
t
,
a
t
)
+
α
[
r
t
+
γ
max
a
′
Q
(
s
t
+
1
,
a
′
)
−
Q
(
s
t
,
a
t
)
]
Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ r_t + \gamma \max_{a'} Q(s_{t+1}, a') - Q(s_t, a_t) \right]
Q(st,at)←Q(st,at)+α[rt+γa′maxQ(st+1,a′)−Q(st,at)]其中:
Q
(
s
t
,
a
t
)
Q(s_t, a_t)
Q(st,at) 是在状态
s
t
s_t
st 下选择动作
a
t
a_t
at 的 Q 值。
α
\alpha
α 是学习率,控制 Q 值的更新幅度。
r
t
r_{t}
rt 是在时间步
t
t
t 时获得的奖励。
γ
\gamma
γ 是折扣因子,用于衡量未来奖励的重要性。
max
a
′
Q
(
s
t
+
1
,
a
′
)
\max_{a'} Q(s_{t+1}, a')
maxa′Q(st+1,a′) 是在新状态
s
t
+
1
s_{t+1}
st+1 下可能获得的最大 Q 值。
在DQN算法中,更新思想也同Q-learning一样:我们使用Q网络计算出等式左右两边的值,更新网络参数使得等式左边的值无限接近等式右边的值。
在这里有人可能会有疑问:等式两边的值都是估计出来的,为什么要让等式左边的值去趋紧右边的值呢?这是因为等式右边的
r
t
r_t
rt是确定的,它是环境根据我们做的
a
t
a_t
at所反馈给我们的,它是确定的,不是估计的。
通过上述更新策略就可以训练处一个Q网络完成我们的需求了,但是DQN作者发现按照上述方法更新效果并不好,因为我们让等式左边趋近于等式右边,但是等式左右两边都是一个Q网络估算出来的,换而言之,我们在让一个动态变化的Q网络趋近于一个也在动态变化的Q网络,也就是说回归问题中的目标函数一直在变,这将会导致训练不稳定。所以为了解决这个问题,DQN使用了另一个非常重要的思想——目标Q网络,目标网络就是一个和Q网络结构一样的网络,但是参数被固定住,不随着Q网络更新而实时更新,在Q网络更新几次后再将目标网络的参数更新。
添加了目标网络之后,我们使用目标网络估算等式右边
Q
(
s
t
+
1
,
a
′
)
Q(s_{t+1}, a')
Q(st+1,a′)的值,这样就完美解决了回归问题中的不稳定问题。
2.4 实现代码
上述更新过程的核心代码如下:
q = q_net(states).gather(1, actions) # 使用 Q网络估算当前状态 s_t的 Q值
max_target_q_net = target_q_net(next_states).max(1).values.unsqueeze(1) # 使用目标 Q网络估算下一时刻状态 s_{t+1}的 Q值
target_q = rewards + (1 - ends) * GAMMA * max_target_q_net # 计算目标 Q值,让 Q网络拟合这个值
# 使用 MSELoss梯度下降更新 q_net
loss = nn.MSELoss()(q, target_q)
q_net_optimizer.zero_grad()
loss.backward()
q_net_optimizer.step()
# 每更新 q_net UPDATE_TARGET次之后更新一次目标网络
if update_count % UPDATE_TARGET == 0:
target_q_net.load_state_dict(q_net.state_dict())
DQN完整可运行代码见Github仓库,仓库的DQN目录下即为DQN算法完整代码,DQN目录下有三个文件,运行main
方法即可训练,训练完成后运行test
方法即可测试。
Github仓库地址:deep-reinforcement-learning
三、参考文献
[1]. https://www.nature.com/articles/nature14236
[2]. https://hrl.boyuai.com/
[3]. https://blog.csdn.net/qq_47997583/article/details/124457346