从离散空间到连续空间

在之前提到的强化学习任务中,都是有限的MDP框架,即动作空间及状态空间的个数都是有限个。然而,现实生活中的很多问题动作空间与状态空间并非离散的,而是连续的。那么如何用强化学习的理论基础去解决问题呢?主要有两种思路:离散化处理、函数逼近。

离散化处理:

指的是把连续空间用区域o化的方式划分成有限的个数。具体的处理手法有Tile coding及Coarse coding。

函数逼近:

指的是把输入与输出看作是经过某个函数的映射,然后用梯度更新的方法找到这个函数。具体的处理手法有线性函数逼近、核函数逼近、以及非线性函数逼近。

深度强化学习常用的算法思路有以下三种:深度Q学习、策略梯度、行动者与评论者方法。以下逐一总结这三种思路的特点。

深度Q学习

对于传统的强化学习,我们的解题思路是通过计算最优值函数(包括状态值函数 v* 以及动作值函数 q ),从而求得最优策略 \pi_ 。而状态值函数可以看作是状态 s 到某实数的映射:s\rightarrow v{\pi}\rightarrow v{\pi}(s) \in \mathbb{R} 。而在连续空间的问题时,状态 s 一般以向量 \mathbb{x}(s) 表示,因此可以看作是状态向量 \mathbb{x}(s) 到某实数的映射: \mathbb{x}(s)\rightarrow v{\pi}\rightarrow v{\pi}(s, w) \in \mathbb{R} 。

于是我们就有了目标函数 [v{\pi}(s,w) - \hat v{\pi}(s,w)]^2 ,然后就可以通过梯度下降算法做函数逼近, \Delta w = \alpha(v_{\pi}(s) - \hat v(s,w))\triangledown _w \hat v(s,w) 。

同时,对于动作值函数,也有 \Delta w = \alpha (q_{\pi}(s, a) - \hat q(s,a,w)) \bigtriangledown _w \hat q(s,a,w) 。

然而,问题是此时我们并不知道 v{\pi} 与 q{\pi} 的函数真值是多少。于是,需要用两种方法去估算函数真值:蒙特卡罗方法与时间差分方法。

蒙特卡罗方法:

我们从前面的经验可知,基于值函数(v{\pi} 或 q{\pi})的方法,解题的思路都是 ( v{\pi} \rightarrow ) \ q{\pi} \rightarrow \pi' ,而 v{\pi} 或 q{\pi} 的更新公式为:

V(S_t) \leftarrow V(S_t) + \alpha (G_t - V(S_t)))
Q(S_t, A_t) \leftarrow Q(S_t, A_t) + \alpha (G_t - Q(S_t, A_t)))
在更新公式中可以看到每次的更新的效果为:

\Delta V = \alpha(G_t - V(S_t))
\Delta Q = \alpha(G_t - Q(S_t, A_t))
值函数的迭代过程,本质上就是一个不精确的(误差很大)的值函数,逐渐更新收敛形成精确的值函数的过程。假如把这过程理解为梯度下降,我们便可以把 Gt 看作是值函数 v{\pi}(St) 与 q{\pi}(S_t) 的真值,于是有:

\Delta w = \alpha (G_t - \hat v(S_t, w))\bigtriangledown _w \hat v(S_t, w)
\Delta w = \alpha (G_t - \hat q(S_t,A_t, w))\bigtriangledown _w \hat q(S_t, A_t, w)
有了以上转换,便可以通过Tensorflow等运算框架去计算梯度,从而求得值函数的真值。写成伪代码如下图:

从强化学习到深度强化学习(下)
资料来源:Udacity深度学习课程
代码说明:

以上伪代码使用的背景是针对阶段性任务,并且使用的 G_t 是全访问(every visit,MC算法专用定义)

时间差分方法:

对于时间差分方法,我们有值函数:

V(S_t) \leftarrow V(St) + \alpha(R{t+1} + \gamma V(S_{t+1}) - V(S_t))
Q(S_t, A_t) \leftarrow Q(S_t, At) + \alpha (R{t+1} + \gamma Q(S{t+1},A{t+1}) - Q(S_t, A_t))
与MC方法同理,TD方法的梯度更新公式可以写成:

\Delta w = \alpha (R{t+1} + \gamma \hat v(S{t+1},w) - \hat v(S_t,w))\bigtriangledown _w \hat v(St,w)
\Delta w = \alpha (R
{t+1} + \gamma \hat q(S{t+1},A{t+1}, w) - \hat q(S_t,A_t, w))\bigtriangledown _w \hat q(S_t, A_t, w)
于是,写成伪代码如下图:
从强化学习到深度强化学习(下)

资料来源:Udacity深度学习课程
代码说明:

该代码是针对阶段性任务。若要针对连续任务,只需修改循环条件;
Sarsa算法属于同步策略(on-policy),即更新值函数与行动用的是同一套策略;
该算法适合在线学习,能够快速收敛;
但该算法的更新值函数与行动之间的关联过于紧密,导致可能无法得到更优的策略
针对Sarsa的不足,Q-learning是另一种选择,伪代码如下图:
从强化学习到深度强化学习(下)

资料来源:Udacity深度学习课程
代码说明:

Q-learning与Sarsa算法最大的不同,在于更新值函数时的策略与行动策略可能不同;
Q-learning属于异步策略(off-policy),即更新值函数的策略与行动策略不同;
该算法适合离线学习,因为值函数的更新会延迟反应在行动策略的改变上;
该算法不单能学习环境反馈,还能学习人为经验;
更适合批量学习(batch learning)

以上提到的算法,仅仅解决了深度学习中梯度更新的问题。除了梯度更新,如何让智能体实现通用学习?Deep Q Network, 又称DQN。

DQN指的是模型结构是DNN,CNN,RNN等常见的神经网络模型,而梯度更新则是上述提及深度Q-learning的 \Delta w = \alpha (R_{t+1} + \gamma maxa \hat q(S{t+1},a, w) - \hat q(S_t,A_t, w))\bigtriangledown _w \hat q(S_t, A_t, w) ,并以此进行函数逼近。

DQN的训练过程需要大量的训练数据,即便这样,由于状态输入向量与动作输出向量之间的紧密联系,导致无法保证函数能够收敛成为最优值函数,从而也导致策略不稳定或者效果不佳。为了解决这个问题,需要用到以下两种处理手法来优化训练过程。

经验回放

以动作值函数为例,我们知道梯度更新公式为 \Delta w = \alpha (R_{t+1} + \gamma maxa \hat q(S{t+1},a, w) - \hat q(S_t,A_t, w))\bigtriangledown _w \hat q(S_t, A_t, w) ,因此对于每次更新计算,都需要用到一组经验元组 <S_t, At, R{t+1}, S{t+1}, A{t+1}> 。在有限MDP问题中,我们更新值函数时,每组经验元组会且只会使用一次;而(在无限MDP)我们使用DQN时,我们可以使用一个暂存区,把一定数量的经验元组暂存起来,然后能暂存区积累一定数量的经验元组时,再从暂存区随机抽取经验元组进行训练。这样做有两个好处:一是通过随机抽取经验元组,人为地切断了元组之间的前后关联关系,这样可以使函数避免落入局部最优;二是使一组经验元组可能会被使用多次,使得函数能更好地收敛。

通过经验回放处理,相当于把一个强化学习问题转化成一个监督学习问题。

固定Q目标

在梯度更新公式\Delta w = \alpha (R_{t+1} + \gamma maxa \hat q(S{t+1},a, w) - \hat q(S_t,A_t, w))\bigtriangledown _w \hat q(S_t, At, w) 中, R{t+1} + \gamma maxa \hat q(S{t+1},a, w) 实际上是梯度更新的目标值(TD target)。然而,权值 w 是一个变化量,从而导致目标值随之改变。这就好比坐在驴背手持萝卜来教驴直线走路,如下图:
从强化学习到深度强化学习(下)

资料来源:Udacity深度学习课程
由于驴在移动的过程中会同时移动萝卜的位置,因此这样是无法教会驴走直线的。正确的做法是,人站在地上固定不动,让驴靠近时,人再往后退使驴可以继续走,如下图:
从强化学习到深度强化学习(下)

资料来源:Udacity深度学习课程
同理,梯度更新时,目标值的权值应该用一个固定权值代替,使权值更新若干次后,再用最新的权值替换一次固定权值,如此类推。

深度Q学习的具体算法

以上关于深度Q学习已经作了足够的铺垫,以下来看看伪代码:
从强化学习到深度强化学习(下)

资料来源:Udacity深度学习课程
代码说明:

数组D用于暂存经验元组,容量为N个;
以随机数初始化动作值函数的权值 w ;
并以 w 初始化固定权值 w^- ;
设置M代训练循环;
对于每一代都要重新初始化起始状态向量;
对于每一代的每个时间步,主要做两件事:生成经验元组与训练;
生成的经验元组存于数组D;
从数组D获取随机批量的经验,先计算TD目标值,再进行梯度更新计算;
每隔C步就更新一次固定权值 w^- 。

深度Q学习的优化思路

\diamond 双DQN(Double DQN)

从DQN的梯度更新公式 \Delta w = \alpha (R_{t+1} + \gamma maxa \hat q(S{t+1},a, w) - \hat q(S_t,A_t, w))\bigtriangledown _w \hat q(S_t, A_t, w) 可知,其中的 maxa \hat q(S{t+1},a, w) = \hat q(S_{t+1}, argmaxa \hat q(S{t+1},a,w), w) 。由于在训练的初始阶段, \hat q 函数的值并不准确,我们并不应该太过盲目地信任这些值,并以此作为行动依据。那么怎么才能使策略更可靠呢?

其中一个被验证的方法是双DQN(论文《Deep Reinforcement Learning with Double Q-learning》)。大概的思路如下图:
从强化学习到深度强化学习(下)

资料来源:Udacity深度学习课程
对于公式中的两个权值 w ,使用不同的权值。这样就相当于使用了两个DQN,一个用于生成策略,另一个用于评估策略。如果使用之前提到的固定Q目标的方法与双DQN方法结合的话,固定权值 w^- 就可以作为评估器使用。

\diamond 优先经验回放

前面提到经验回放,我们会在经验暂存区随机取样进行批量训练。然而,有些经验比较“宝贵”出现的概率不高,但“信息量”很大,如果能进行多次训练,能有效提升DQN的性能。那么如何定义哪些经验元组更“宝贵”呢?

答案是TD error,如下图:
从强化学习到深度强化学习(下)

资料来源:Udacity深度学习课程
TD误差越大,代表实际与预测的差距越大,因此“信息量”越大,模型能从中学到的规律就越多。因此,在保存经验元组时,可以用优先队列进行保存,以TD误差的绝对值作为优先级。在经验抽样时,不再以均匀分布来抽取,而按照优先级的分值分配概率。

以上的处理经过证明,能减少值函数所需的批次更新数量(论文《Prioritized Experience Replay》)。

在上述处理的基础上,还能进行几处优化:

从强化学习到深度强化学习(下)
资料来源:Udacity深度学习课程
如果一个经验元组的TD误差很小甚至为零,那么它在抽样时被抽中的概率就几乎为零,但这并不代表这个经验就不值得学习,也许只是因为模型在之前所经历的经验样本有限,使估值比较接近真实值而已;因此在原来TD误差的基础上加上一个常量e作为优先级得分,从而让这些经验元组也有可能被选中。
另一个问题是,如果优先级得分较高的经验总是会大概率地被不断回放,这可能会导致模型过拟合于这部分经验子集;为了避免这个问题,对经验的优先级得分加上一个指数 a ,这就相当于降低了 p_i 的概率,因为当 a=0 时,相当于以均匀的概率选择经验元组,而当 a = 1 时就以优先级得分作为概率计算。
当我们使用优先级得分抽样时,我们需要微调更新规则,加上权重系数。具体原因可参考论文。

\diamond 对抗网络架构(Dueling Networks)
从强化学习到深度强化学习(下)

资料来源:Udacity深度学习课程
对抗网络与原始DQN的主要区别在于全连接层从一个变为两个,具体参考论文《Dueling Network Architectures for Deep Reinforcement Learning》。

深度Q学习是一种基于值函数的方法(value-based method),即根据状态值或动作值函数来获得最优策略。而有另一种方法,直接求最优策略而无需基于值函数(policy-based method),这就是策略梯度。

策略梯度(policy gradient)

既然已经有了基于值函数的方法,为何还需要有直接求最优策略的方法呢?

\diamond 因为更简单:
最优策略 \pi_* 本质上是一个策略函数。

对于确定性策略而言,策略函数实际上是 s\rightarrow a 的映射;
对于随机性策略而言,策略函数实际上是 s\rightarrow \mathbb P[a|s] 概率分布的映射;
直接求策略函数的好处是可以减少对大量无关数据的储存。

\diamond 因为能生成最优的随机策略:

基于值函数的方法,无法生成真正的随机策略,如下图:

从强化学习到深度强化学习(下)
资料来源:Udacity深度学习课程
智能体的目标是要拿到香蕉。辣椒代表惩罚。智能体能感知当前状态下周围的环境,当智能体位于中间时,由于三边无墙,向下移动是最优策略;当智能体位于两边时,当左边有墙则向右移动为最优,而当右边有墙则向左移动为最优。但当智能体位于阴影区域时,两块阴影区域的状态完全一样,如下图:
从强化学习到深度强化学习(下)

资料来源:Udacity深度学习课程
如果根据值函数求最优策略,会形成要么全部向左,要么全部向右的策略,这样会导致智能体陷入死循环。即便使用 \epsilon 系数来增加策略的随机性,也需要很长的时间才能让智能体“摸索”到出路,这样的模型效率相当低;如果增大 \epsilon 系数,则会严重影响模型性能。因此,最优的策略是在阴影区域使用随机策略,如下图:

从强化学习到深度强化学习(下)
资料来源:Udacity深度学习课程
基于值函数的方法倾向于学习确定性策略或者近似确定性策略,而基于策略的方法能学习期望的随机性策略。

\diamond 因为对于连续的动作空间,基于值函数的方法并不适用:

我们知道在基于值函数的方法中,最优策略是用 argmax 函数求出,这仅仅适用于离散的动作空间;要在连续的动作空间中找最大值并不容易,尤其是当动作空间不是一维而是多维。因此,需要使用策略梯度方法。

那么究竟如何求得策略函数呢?

策略函数逼近法:

(未完待续)

行动者与评论者方法