CS294(8) 深度增强学习中的Q学习方法(总结版)
BackgroundQ学习方法抛开了一个显式的策略,直接去学习Q函数,使我们知道在某个特定的状态下执行某一操作效果有多好。但是如果我们使用神经网络来进行拟合可能出现的不收敛现象,这一问题将在所有的使用某些结构(如神经网络)拟合值函数,然后使用拟合的值函数作为“评论家”来做自助的方法中都存在。Replay Buffer & Target Network以on-line Q迭代算法为例,...
文章目录
Background
Q学习方法抛开了一个显式的策略,直接去学习Q函数,使我们知道在某个特定的状态下执行某一操作效果有多好。但是如果我们使用神经网络来进行拟合可能出现的不收敛现象,这一问题将在所有的使用某些结构(如神经网络)拟合值函数,然后使用拟合的值函数作为“评论家”来做自助的方法中都存在。
Replay Buffer & Target Network
以on-line Q迭代算法为例,它循环执行以下步骤(此处目标值已经填入):
我们之前已经说明过,它不是一个梯度下降算法,因此,梯度法的收敛性在这里不适用。第二点很关键的问题是,在普通的SGD中,我们常常认为每一次拿到的数据之间都有一定的不相关性;而在第一步收集的数据中,数据通常都是非常相关的:下一步的观察数据可能和这一步非常相关。因此,梯度也会非常相关。因此,我们会尝试去使用一些手段来缓解这些问题。我们考虑解决的问题主要有两个:序贯状态的强相关性,以及目标值总是在变动。
序贯样本为什么会成为痛点?让我们先考虑一个简单的回归问题,这个回归问题尝试去拟合一个正弦波。一般我们希望数据是独立同分布的,而我们在序贯问题中先得到了开始的几个样本,然后逐渐得到后面几组,每得到一组我们就走一个梯度步。这样我们就很难去学习整个正弦波,而更容易在局部形成过拟合的同时,忘掉了其他样本的信息。在演员-评论家算法中,可以采用一些并行学习的方法,这里Q学习也可以:使用多个独立的智能体进行独立的数据收集,然后使用同步或者异步的方法进行梯度更新,这样可以使得样本的相关度减轻,但是这样的做法可能是相当“繁重”的。
Replay Buffer
回放缓冲池 (Replay Buffer),利用到了Q学习算法本质上是离线 (off-policy) 的这样一个性质:也就是说,Q学习算法使用到的数据不需要根据当前的策略收集得到。相对的,演员-评论家算法是一个在线 (on-policy) 算法,因此对于演员-评论家算法来说并行学习是首选之一,然而在Q学习中并非如此。
在拟合Q迭代算法收集样本的步骤中,我们可以使用任意策略(当然我们希望样本的支撑集足够大),因此我们不妨假设一个极端情形:收集样本的步骤被完全省略了,我们在很早的时候就收集了非常非常多的样本,然后全部丢在了一个数据库之中,我们在每次训练更新的时候随机从里面拉出一些来(这样做完全是可以的,因为我们事实上不根据策略和模拟器进行任何交互)。这样做的好处不仅在于这样抽出的样本不再具有很强的相关性了,同时我们每次可以用的样本量也从1个变成了很多个,可以使用多个样本来降低梯度的方差(有点类似于mini-batch SGD的做法)。
现在我们想要知道的是,高覆盖面的数据到底从哪里来。在Q学习的过程中,我们依然需要使用一些探索策略向外界环境输出一些不同的策略,然后得到新的样本放入样本池。训练过程有点像某些抽奖箱子里每次抽一张卡,抽完丢回去再抽。因为我们投入的数据会被反复使用到,有点类似于回放,因此被称为回放缓冲池 (Replay Buffer),如上图所示。
于是使用回放缓冲池的在线Q-learning算法如下所示:
在
K
K
K的选择上,通常选择1就不错,然而如果数据获取代价比较高的话(如需要与真实物理系统打交道),更大的
K
K
K有时候会产生更高的数据使用效率。由此,回放缓冲池成功解决了数据的强相关性问题,但是目标值的变动问题还是没有解决。
Target Network
我们想要使得 Q ϕ ( s i , a i ) Q_{\phi}(s_i,a_i) Qϕ(si,ai)尽量靠近目标值 r ( s i , a i ) + γ max a i ′ Q ϕ ( s i ′ , a i ′ ) r(s_i,a_i)+\gamma \max_{a_i'}Q_{\phi}(s_i',a_i') r(si,ai)+γmaxai′Qϕ(si′,ai′),但只要我们不停迭代 Q ϕ ( s i , a i ) Q_{\phi}(s_i,a_i) Qϕ(si,ai),网络不停更新,我们的目标值就会一直会动来动去。但是如果我们能够像之前一样,先把目标值算出来,然后再去做最小化最小二乘的回归,那么这样的回归就会稳定很多。
我们在执行若干步(如10000步)整个算法迭代后,就把整个网络的参数
ϕ
\phi
ϕ存下来称为目标网络
ϕ
′
\phi'
ϕ′,然后我们每次做的梯度步变成了:
目标不再是
Q
ϕ
Q_{\phi}
Qϕ而是
Q
ϕ
′
Q_{\phi'}
Qϕ′了。理论上,这样做不改变任何事情,但是实践中,这样降低靶子移动的频率,非常有助于训练的稳定性,减少训练所需要的时间。
综合这两种技巧,Mnih et al. (2013) 在NIPS提出了举世闻名的深度Q网络 (Deep Q Network, DQN) 算法,也是深度Q学习中最经典的算法。
Tips:
关于目标网络,也有另一种实现策略。看上图,我们在第一个绿色方块更新了目标网络,此后若干个步骤,我们都将以这个目标网络为基础进行迭代,然后逐渐误差越来越大,直到下一个目标网络更新点,就形成了一个断点。这样其实对于步骤和步骤之间并不公平,有些步骤访问的延迟很高,有的步骤则很低。为了使得延迟公平化,可以使用一个类似于指数平滑的方法(随机优化中的Polyak Averaging),不再是若干步执行更新而是每一步都做一个小变动:
ϕ
′
←
\phi'\leftarrow
ϕ′←
τ
ϕ
′
+
(
1
−
τ
)
ϕ
\tau\phi'+(1-\tau)\phi
τϕ′+(1−τ)ϕ,实践中
τ
=
0.999
\tau=0.999
τ=0.999效果不错。
纵观以上几种Q-learning方法,我们可以把过程的主要步骤分为三部分:
- 第一步是数据收集 (data collection):
数据收集是用于充实我们的缓冲池的。使用有一定探索性质的策略与环境交互,从而获得一些转移数据;如果缓冲区太大了,我们也需要把一些旧数据丢进垃圾桶(如把缓冲区弄成一个固定大小的循环型,老的数据自然被丢弃),这是因为旧数据可能是在很垃圾的策略下得到的,已经没什么实际价值。 - 第二步是目标更新 (target update):
以一定的频率(或者Polyak Averaging)用当前的参数去更新目标网络参数,如果我们想稳定一点的话,这一步通常频率很低。 - 第三步是Q函数回归 (Q-function regression):
从目标网络中取得参数,从缓冲池中取得数据,然后进行回归以后更新当前的参数。
广义看,不同的算法之间,只在于这几个操作的频率有所区别,取决于样本取得代价,网络更新代价和对稳定性的需求。对于在线Q学习,我们取得数据后只使用一次就丢弃了(也就是样本池里只有一个样本),三个步骤的频率是一样的。对于DQN,缓冲池比较大,第一步和第三步运行频率一致,而第二步频率很低。对于拟合Q迭代,第二步和第三步运行频率一致。
让Q学习更好的技巧
我们说了很多使用值函数评估局面、Q函数来做决策的合理性。因为我们只需要按照Q函数最大的准则来进行行动,似乎只有Q的相对数值大小才有决定性作用。那么这些绝对数值是否准确?很遗憾,van Hasselt et al. (2015) 这些数值是被高估的。我们只看上图的红色部分(DQN estimate和DQN true value)。红色的波动很厉害的那条折线代表了神经网络所估计出来的Q值,而下面那条红色直线是根据DQN的策略行动实际所能得到的期望收益:所以理想情况下,在很多步估计之后,红色折线应该和红色直线有一个相切关系。但是事实上,我们在不同的游戏中都发现估计出来的红色曲线明显比真实值红色直线要高,呈现一个系统性趋势。这说明了DQN实际上严重高估了Q值。事实上DQN的表现还是不错的,尽管这个Q值可能估计得很离谱:实际上对于两个不同的操作
a
1
a_1
a1和
a
2
a_2
a2,只要让估计的
Q
(
s
,
a
1
)
−
Q
(
s
,
a
2
)
Q(s,a_1)-Q(s,a_2)
Q(s,a1)−Q(s,a2)差和真实值差不多就能让DQN工作起来。
造成高估 (overestimate)的原因在于目标值 y j = r j + γ max a j ′ Q ϕ ′ ( s j ′ , a j ′ ) y_j=r_j+\gamma \max_{a_j'}Q_{\phi'}(s_j',a_j') yj=rj+γmaxaj′Qϕ′(sj′,aj′)中的max。考虑两个随机变量 X 1 , X 2 X_1,X_2 X1,X2,我们有 E [ max ( X 1 , X 2 ) ] ≥ E[\max(X_1,X_2)]\ge E[max(X1,X2)]≥ max ( E [ X 1 ] , E [ X 2 ] ) \max(E[X_1],E[X_2]) max(E[X1],E[X2]),此结论在多随机变量中也是适用的。当这些变量中存在噪声时,max操作扩大化了这些噪声,在这种情况下我们是关于噪音取max,可能我们找到的是若干个 Q Q Q中噪音最大的那个,而不是真正Q最大的选项。
由式 max a j ′ Q ϕ ′ ( s j ′ , a j ′ ) = Q ϕ ′ ( s j ′ , arg max a j ′ Q ϕ ′ ( s j ′ , a j ′ ) ) \max_{a_j'}Q_{\phi'}(s_j',a_j')= Q_{\phi'}(s_j', \arg\max_{a_j'}Q_{\phi'}(s_j',a_j')) maxaj′Qϕ′(sj′,aj′)=Qϕ′(sj′,argmaxaj′Qϕ′(sj′,aj′))可知,若某一行动的 Q Q Q值过大,我们做 max a j ′ Q ϕ ′ ( s j ′ , a j ′ ) \max_{a_j'}Q_{\phi'}(s_j',a_j') maxaj′Qϕ′(sj′,aj′)过高估计了接下来行为的值,然后继续传递到后续迭代中去。我们的决策选择 arg max a j ′ Q ϕ ′ ( s j ′ , a j ′ ) ) \arg\max_{a_j'}Q_{\phi'}(s_j',a_j')) argmaxaj′Qϕ′(sj′,aj′))本身就是来自于值函数 Q ϕ ′ Q_{\phi'} Qϕ′。
Double Q-learning
van Hasselt et al. (2010, 2015) 的双重Q学习 (Double Q-learning) 技术用于缓解这一问题:它本身希望切断过高估计的行动→过高估计的值的传导这样的一个链条。如果最大
Q
Q
Q决策选择和它对应的
Q
Q
Q函数的相关性被斩除,那么这就不再是一个问题了。双重Q学习的想法就是,不要使用同一个网络来确定行动和估计
Q
Q
Q函数值。它使用两个网络
ϕ
A
\phi_A
ϕA和
ϕ
B
\phi_B
ϕB,更新方式如下:
也就是说,更新一个网络的时候,使用另一个网络的值。如果两个Q网络的噪音的来源不同,那么它的噪音就不再如此容易扩大了。实际上,我们在前面已经介绍了目标网络
ϕ
′
\phi'
ϕ′了,因此我们已经有两个不同的网络
ϕ
\phi
ϕ和
ϕ
′
\phi'
ϕ′了,可以把它利用起来!标准的Q学习中,我们使用
y
=
r
+
γ
Q
ϕ
′
(
s
′
,
arg
max
Q
ϕ
′
(
s
′
,
a
′
)
)
y=r+\gamma Q_{\phi'}(s',\arg\max Q_{\phi'}(s',a'))
y=r+γQϕ′(s′,argmaxQϕ′(s′,a′)),此处做出如下修改:
y
=
r
+
γ
Q
ϕ
′
(
s
′
,
arg
max
Q
ϕ
(
s
′
,
a
′
)
)
y=r+\gamma Q_{\phi'}(s',\arg\max Q_{\phi}(s',a'))
y=r+γQϕ′(s′,argmaxQϕ(s′,a′)),即用当前网络来确定我们选择哪个行动,而用目标网络来评估Q值。在实践中,我们遇到的问题就会被很大程度上缓解。
Q-learning的一些训练经验
- 上图显示了几个问题的几种不同Q学习的效果 (Schaul et al., 2015)。发现对于不同的问题,Q学习在有些问题上很可靠,在有些问题上波动很大,需要花很多力气来让Q学习稳定下来。因此发现几个能让Q学习比较可靠的问题来试验程序,譬如Pong和Breakout。如果这些例子上表现不好,那就说明程序有问题。
- 回放缓冲池的大小越大,Q学习的稳定性越好。我们往往会用到上百万个回放样本,那么内存上怎么处理是决定性的。建议图像使用uint8 (1字节无符号整型) 存储,然后在存储 ( s , a , r , s ′ ) (s,a,r,s') (s,a,r,s′)的时候不要重复存储同样的数据。
- 训练的时候要耐心。DQN的收敛速度很慢,对于Atari游戏经常需要1000-4000万帧,训练GPU也得几个小时到一天的时间,这样才能看出能显著地比随机策略要来的好。
- 在使用 ϵ \epsilon ϵ贪心等策略的时候,一开始把探索率调高一些,然后逐渐下降。
- Bellman误差可能会非常大,因此可以对梯度进行裁剪(clipping,也就是设一个上下限),或者使用Huber损失进行平滑(如下所示)
- 在实践中,使用双重Q学习很有帮助,改程序也很简单,而且几乎没有任何坏处。
- 使用N步收益也很有帮助,但是可能会带来一些问题。(见https://zhuanlan.zhihu.com/p/32994423 “让Q学习更好的技巧”这一节的最后)
- 除了探索率外,学习率 (Learning Rate, 也就是步长) 也很重要,可以在一开始的时候把步长调大一点,然后逐渐降低,也可以使用诸如ADAM的自适应步长方案。
- 多用几个随机种子试一试,有时候表现差异会很大。
行动空间连续时的Q学习
在我们之前的问题中,通常假设策略很容易得到:
求max只需要遍历行动空间就行了,目标值的max也是这样:
但是如行动空间是连续的时候,这个max就不容易做了。这个问题在后者中尤其严重,因为它是训练过程中最内层循环要做的事情,频率比前者要高多了。那么如何做max呢?
方法一
直接做优化。在最内层循环做基于梯度的优化算法(如SGD)相对来说是比较慢的。注意到我们的行动空间通常都是比较低维的(相对整个系统而言),不使用梯度信息的随机优化也许能有用武之地。最简单的方法是使用离散随机踩点:
其中行动是从某些分布(如均匀分布)中得到的。这个方法是最简单的,而且还比较容易并行,但是这样得到的结果是不准确的,尤其是在维度增加的情况下看起来就不像是能找到一个效果很好的解。不过有些时候,我们也不真正在乎优化求解的精度。此外,还有一些更好的方法,譬如交叉熵方法 (Cross-entropy Methods) 这样的迭代随机优化算法,或者如CMA-ES (Covariance Matrix Adaptation Evolutionary Strategies) 这样的进化算法。这些通常在不超过40维的决策问题中有效。
方法二
选取一个比较容易优化的函数簇来拟合我们的Q函数。在此之前,我们使用的都是通用的神经网络来拟合Q,有些情况下我们不必要这么做。譬如在Q函数是二次函数的时候:
我们就训练一个神经网络或者其他结构,输入状态,输出
(
μ
,
P
,
V
)
(\mu,P,V)
(μ,P,V),其中
μ
\mu
μ和
V
V
V都是向量,
P
P
P是矩阵(可以用如低秩形式表示)。这样的方法称为NAF (Normalized Advantage Functions),它的天然特性就是:
这个很容易和高斯分布建立起联系;当然,这样的Q函数中行动是没有界限的。我们这么做的话,算法上不需要做任何改变,非常容易,而且和原来的Q学习一样高效。但是缺点就在于Q函数只能是固定的形式(如这里的二次函数),非常受限,Q函数的建模泛化能力将大大降低。
方法三
第三种方法比第二种方法更为广泛,是去新学习一个最大化器,在Lillicrap et al. (2016) 在ICLR上的一篇文章中被作为DDPG (Deep Deterministic Policy Gradient) 算法介绍。考虑到:
可以想到的是另外训练一个最大化器
μ
\mu
μ作为最大化算子:
训练的方法是,让:
这个可以用梯度上升法,梯度可以遵循链式法则:
从而,我们的目标值为:
整个DDPG算法迭代执行以下步骤:
相当于相对DQN,只是增加了一个最大化器,第三步使用最大化器,第五步更新最大化器,同时最大化器的更新也是用Polyak Averaging。(这其实属于AC算法的一个变种,
μ
\mu
μ相当于参数化了策略
π
\pi
π)
这里放出主流强化学习的算法分类图(转自spinningup):
更多推荐
所有评论(0)