本节推导的核心内容参考自Easy RL教程等资料(但修正了原教程上部分不太准确的描述,且为让初学者更好懂,补充了大量的解释说明和心得理解,倪老师则帮拆解了部分公式)。
另,都说多一个公式则少一个读者,本文要打破这点,虽然本节推导很多,但每一步推导都有介绍到,不会省略任何一步推导,故不用担心看不懂(对本文任何内容有任何问题,都欢迎随时留言评论)。
策略梯度的核心算法思想是:
- 参数为
$\theta$ 的策略$\pi_{\theta }$ 接受状态,输出动作概率分布,在动作概率分布中采样动作,执行动作(形成运动轨迹$\tau$ ),得到奖励$r$ ,跳到下一个状态 - 在这样的步骤下,可以使用策略
$\pi$ 收集一批样本,然后使用梯度下降算法学习这些样本,不过当策略$\pi$ 的参数更新后,这些样本不能继续被使用,还要重新使用策略$\pi$ 与环境互动收集数据
比如REINFORCE算法便是常见的策略梯度算法,类似下图所示(下图以及本节大部分配图/公式均来自easy RL教程)
接下来,详细阐述。首先,我们已经知道了策略函数可以如此表示:
其中,
-
当你对神经网络有所了解的话,你一定知道通过梯度下降求解损失函数的极小值(忘了的,可以复习下:首先通过正向传播产生拟合值,与标签值做“差”计算,产生误差值,然后对误差值求和产生损失函数,最后对损失函数用梯度下降法求极小值,而优化的对象就是神经网络的参数
$\theta$ -
类比到πθ这个问题上,现在是正向传播产生动作,然后动作在环境中产生奖励值,通过奖励值求和产生评价函数,此时可以针对评价函数做梯度上升(gradient ascent),毕竟能求极小值,便能求极大值,正如误差能最小化,奖励/得分就能最大化
如何评价策略的好坏呢?
假设机器人在策略
可能有读者注意到了,既然奖励是延后的,
$s_t$,$a_t$ 后的奖励怎么用$r_t$ 而非$r_{t+1}$ 呢,事实上,sutton RL书上用$S_0,A_0,R_1,S_1,A_1,R_2,S_2,A_2,R_3,\cdots,S_t,A_t,R_{t+1}$ 表示整条轨迹,其实这样更规范,但考虑到不影响大局和下文的推导,本笔记则暂且不细究了
给定智能体或演员的策略参数
其中,有的资料也会把
如何评价策略呢?这个策略评价函数为方便理解也可以称之为策略价值函数,就像上文的状态价值函数、动作价值函数,说白了,评估策略(包括状态、动作)的价值,就是看其因此得到的期望奖励
故考虑到期望的定义,由于每一个轨迹
上述整个过程如下图所示
通过上文已经知道,想让奖励越大越好,可以使用梯度上升来最大化期望奖励。而要进行梯度上升,先要计算期望奖励
考虑对
其中,只有
从而进一步转化,可得
Em,怎么来的?别急,具体推导是
$\begin{aligned} \nabla \bar{R}_{\theta}&=\sum_{\tau} R(\tau) \nabla p_{\theta}(\tau)\\&=\sum_{\tau} R(\tau) p_{\theta}(\tau) \frac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)} \\&= \sum_{\tau} R(\tau) p_{\theta}(\tau) \nabla \log p_{\theta}(\tau) \\ &=\mathbb{E}_{\tau \sim p_{\theta}(\tau)}\left[R(\tau) \nabla \log p_{\theta}(\tau)\right] \end{aligned}$ 上述推导总共4个等式3个步骤,其中,第一步 先分母分子都乘以一个
$p_{\theta}(\tau)$ ,第二步 把$\frac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)}= \nabla \log p_{\theta}(\tau)$ 代入计算,第三步 根据期望的定义$E[X] = \sum_{i}^{}p_ix_i$ 做个简单转换,此处的$X$ 就是$R(\tau )$ 此外,本文一读者在23年2.24日的留言说,还想了解
$\nabla f(x)=f(x)\nabla \log f(x)$ 是怎么推导而来的,这个式子可以通过如下推导得到首先,对函数
$f(x)$ 取对数得:
$\log f(x)$ 对上式求导数得:
$\frac{d}{dx}\log f(x) = \frac{1}{f(x)}\frac{d}{dx}$ 将等式两边同乘以
$f(x)$ ,得到:
$f(x) \frac{d}{dx} \log f(x) = \frac{d}{dx}$ 这个等式表明,我们可以用
$\nabla \log f(x)$ 来表示$\nabla f(x)$ ,即:
$\nabla f(x)=f(x)\nabla \log f(x)$
然不巧的是,期望值
任何必要的中间推导步骤咱不能省,大部分文章基本都是一笔带过,但本文为照顾初学者甚至更初级的初学者,
$\nabla \log p_{\theta}(\tau)$ 中间的推导过程还是要尽可能逐一说明下:
首先,通过上文中关于某一条轨迹
$\tau$ 发生概率的定义,可得
$p_\theta (\tau ) = p(s_{1}) \prod_{t=1}^{T_{n}}p(s_{t+1}|s_t,a_t)p_{\theta }(a_{t}|s_{t})$ 然后两边都取对数,可得
$logp_\theta (\tau ) = logp(s_1)\prod_{t=1}^{T_{n}} p(s_{t+1}|s_t,a_t)p_{\theta }(a_{t}|s_{t})$ 由于乘积的对数等于各分量的对数之和,故可得
$logp_\theta (\tau ) = logp(s_1) + \sum_{t=1}^{T_n}(logp(s_{t+1}|s_t,a_t) + logp_{\theta }(a_{t}|s_{t}))$ 接下来,取梯度可得
$\begin{aligned} \nabla \log p_{\theta}(\tau) &= \nabla \left(\log p(s_1)+ \sum_{t=1}^{T_n}\log p(s_{t+1}|s_t,a_t) + \sum_{t=1}^{T_n}\log p_{\theta}(a_t|s_t) \right) \\ &= \nabla \log p(s_1)+ \nabla \sum_{t=1}^{T_n}\log p(s_{t+1}|s_t,a_t) + \nabla \sum_{t=1}^{T_n}\log p_{\theta}(a_t|s_t) \\ &=\nabla \sum_{t=1}^{T_n}\log p_{\theta}(a_t|s_t)\\ &=\sum_{t=1}^{T_n} \nabla\log p_{\theta}(a_t|s_t) \end{aligned}$ 上述过程总共4个等式,在从第2个等式到第3个等式的过程中,之所以消掉了
$\nabla \log p(s_1)+\nabla \sum_{t=1}^{T_n}{\log}p(s_{t+1}|s_t,a_t)$ 是因为其与
$\theta$ 无关(环境状态不依赖于策略),其对$\theta$ 的梯度为0。
完美!这就是所谓的策略梯度定理,我们可以直观地理解该公式
- 即在采样到的数据里面,采样到在某一个状态
$s_t$ 要执行某一个动作$a_t$ ,$(s_t,a_t)$ 是在整个轨迹$\tau$ 的里面的某一个状态和动作的对 - 为了最大化奖励,假设在
$s_t$ 执行$a_t$ ,最后发现$\tau$ 的奖励是正的,就要增加在$s_t$ 执行$a_t$ 的概率。反之,如果在$s_t$ 执行$a_t$ 会导致$\tau$ 的奖励变成负的, 就要减少在$s_t$ 执行$a_t$ 的概率 - 最后,用梯度上升来更新参数,原来有一个参数
$\theta$ ,把$\theta$ 加上梯度$\nabla \bar{R}_{\theta}$ ,当然要有一个学习率$\eta$ (类似步长、距离的含义),学习率的调整可用 Adam、RMSProp等方法调整,即
有一点值得说明的是...,为了提高可读性,还是举个例子来说明吧。
比如到80/90后上大学时喜欢玩的另一个游戏CF(即cross fire,10多年前我在东华理工的时候也经常玩这个,另一个是DNF),虽然玩的是同一个主题比如沙漠战场,但你每场的发挥是不一样的,即便玩到同一个地方(比如A区埋雷的地方),你也可能会控制角色用不同的策略做出不同的动作,比如
- 在第一场游戏里面,我们在状态
$s_1$ 采取动作$s_1$ ,在状态$s_2$ 采取动作$a_2$ 。且你在同样的状态$s_1$ 下, 不是每次都会采取动作$a_1$ 的,所以我们要记录,在状态$s^1_1$ 采取$a^1_1$ 、在状态$s^1_2$ 采取$a^1_1$ 等,整场游戏结束以后,得到的奖励是$R(\tau^1)$ - 在第二场游戏里面,在状态
$s^2_1$ 采取$a^2_1$ ,在状态$s^2_2$ 采取$a^2_2$ ,采样到的就是$\tau^2$ ,得到的奖励是$R(\tau^2)$ 这时就可以把采样到的数据用梯度计算公式把梯度算出来
然而策略梯度有个问题,在于
换言之,策略梯度是一个会花很多时间来采样数据的算法,其大多数时间都在采样数据。智能体与环境交互以后,接下来就要更新参数,我们只能更新参数一次,然后就要重新采样数据, 才能再次更新参数。
这显然是非常花时间的,怎么解决这个问题呢?为避免采样到的数据只能使用一次的问题,还记得上文介绍过的重要性采样否,使得
- 可以用另外一个策略
$\pi_{\theta'}$ 与环境交互,用$\theta'$ 采样到的数据去训练$\theta$ - 假设我们可以用
$\theta'$ 采样到的数据去训练$\theta$ ,我们可以多次使用$\theta'$ 采样到的数据,可以多次执行梯度上升,可以多次更新参数$\theta$ , 都只需要用$\theta'$ 采样到的同一批数据
故基于重要性采样的原则,我们可以用另外一个策略
- 只需在
$R(\tau) \nabla \log p_{\theta}(\tau)$ 的基础上补上一个重要性权重:$\frac{p_{\theta}(\tau)}{p_{\theta^{\prime}}(\tau)}$ ,这个重要性权重针对某一个轨迹$\tau$ 用$\theta$ 算出来的概率除以这个轨迹$\tau$ 用$\theta^{'}$ 算出来的概率 - 注意,上面例子中的
$p$ /$q$ 与此处的$p_{\theta}(\tau)/p_{\theta^{\prime}}(\tau)$ 没有任何联系,前者只是为了说明重要性权重的两个普通的分布而已
最终加上重要性权重之后,可得
怎么来的?完整推导如下
梯度的计算好像差不多了?但实际在做策略梯度的时候,并不是给整个轨迹
- 问题1:所有动作均为正奖励
- 问题2:出现比较大的方差(另,重要性采样时,采样的分布与当前分布之间也可能会出现比较大的方差,具体下一节详述)
对于第一个问题,举个例子,比如在某一一个状态,可以执行的动作有a、b、c,但我们可能只采样到动作b或者只采样到动作c,没有采样到动作a
- 但不管采样情况如何,现在所有动作的奖励都是正的,所以采取a、b、c的概率都应该要提高
- 可实际最终b、c的概率按预期提高了,但因为a没有被采样到,所以a的概率反而下降了
- 然而问题是a不一定是一个不好的动作,它只是没有被采样到
为了解决奖励总是正的的问题,也为避免方差过大,需要在之前梯度计算的公式基础上加一个基准线
上面说
-
$b$ 有一种选择是使用轨迹上的奖励均值,即$b=\frac{1}{T}\sum_{t=1}^{T}R_t(\tau)$
从而使得$R(\tau)−b$ 有正有负
当$R(\tau)$ 大于平均值$b$ 时,则$R(\tau)−b$ 为正,则增加该动作的概率
当$R(\tau)$ 小于平均值$b$ 时,则$R(\tau)−b$ 为负,则降低该动作的概率
如此,对于每条轨迹,平均而言,较好的50%的动作将得到奖励,避免所有奖励均为正或均为负,同时,也减少估计方差 -
$b$ 还可以是状态价值函数$V_{\pi}(st)$
可曾还记得2.1节介绍过的所谓Actor-Criti算法(一般被翻译为演员-评论家算法)
Actor学习参数化的策略即策略函数,Criti学习值函数用来评估状态-动作对,然后根据评估结果改进或更新策略当然,Actor-Criti本质上是属于基于策略的算法,毕竟算法的目标是优化一个带参数的策略(实际用到PPO算法时,会计算一个策略损失),只是会额外学习价值函数(相应的,运用PPO算法时,也会计算一个价值损失),从而帮助策略函数更好的学习,而学习优势函数的演员-评论家算法被称为优势演员-评论家(Advantage Actor-Criti,简称A2C)算法
而这个
-
在考虑到评估动作的价值,就看其因此得到的期望奖励,故一般有
$A_\pi (s,a) = Q_\pi (s,a) - V_\pi (s)$ ,此举意味着在选择一个动作时,根据该动作相对于特定状态下其他可用动作的执行情况来选择,而不是根据该动作的绝对值(由$Q$ 函数估计)
且通常我们只学习$V_\pi (s)$ 「比如通过时序差分法估计」,然后通过$V_\pi (s)$ 与奖励的结合来估计$Q_\pi$ ,即$Q_{\pi}=R+\gamma V\pi (st+1)$ ,从而可得
$A\pi (s,a)=Q\pi (s,a)−V\pi (s)=R+\gamma V\pi (st+1)−V\pi (s)$ -
总之,
$A^{\theta }(s_{t},a_{t})$ 要估测的是在状态$s_{t}$ 采取动作$a_{t}$ 是好的还是不好的:即
$→$ 如果$A^{\theta }(s_{t},a_{t})$ 是正的(即大于0),意味着在状态$s_{t}$ 采取动作$a_{t} $ 获得的回报比在状态$s_{t}$ 采取任何其他可能的动作获得的回报都要好,就要增加概率;
$→$ 如果$A^{\theta }(s_{t},a_{t})$ 是负的(即小于0),意味着在状态$s_{t}$ 采取动作$a_{t}$ 得到的回报比其他动作的平均回报要差,要减少概率 -
最终在更新梯度的时候,如下式所示『我们用演员
$\theta$ 去采样出$s_{t}$ 跟$a_{t}$ ,采样出状态跟动作的对$(s_{t},a_{t})$ ,计算这个状态跟动作对的优势$A^{\theta }(s_{t},a_{t})$ 』
进一步,由于
基础上,
接下来,我们可以拆解
于是可得公式
这里需要做一件事情,假设模型是
为什么可以这样假设呢?一种直观的解释就是
$p_{\theta}(s_t)$ 很难算,这一项有一个参数$\theta$ ,需要拿$\theta$ 去跟环境做互动,算$s_{t}$ 出现的概率。 尤其是如果输入是图片的话,同样的$s_{t}$ 根本就不会出现第二次。我们根本没有办法估这一项,所以就直接无视这个问题。但是
$p_{\theta}(a_t|s_t)$ 是很好算,我们有$\theta$ 这个参数,它就是个网络。我们就把$s_{t}$ 带进去,$s_{t}$ 就是游戏画面。 我们有个策略的网络,输入状态$s_{t}$ ,它会输出每一个$a_{t}$ 的概率。所以,我们只要知道$\theta$ 和$\theta'$ 的参数就可以算$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)}$ 。
所以,实际上在更新参数的时候,我们就是按照下式来更新参数:
从而最终可以从梯度
终于大功告成!
好巧不巧,看似大功告成了,但重要性采样还是有个问题。具体什么问题呢,为更好的说明这个问题,我们回到上文的那个例子中。
还是那两个分布:
$p$ 、$q$ ,当不能从$p$ 里面很好的采样数据,而能从$q$ 里面很好的采样数据时,基于重要性采样的原则,虽然我们可以把$p$ 换成任何的$q$ ,但是在实现上,$p$ 和$q$ 的差距不能太大,差距太大,会出问题$\mathbb{E}_{x \sim p}[f(x)]=\mathbb{E}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$ 比如,虽然上述公式成立,但如果不是计算期望值,而是
- 计算方差时
$Var_{x∼p}[f(x)]$ 和$Var_{x∼q}[f(x)\frac{p(x)}{q(x)}]$ 是不一样的 因为两个随机变量的平均值相同,并不代表它们的方差相同此话怎讲?以下是推导过程: 将
$f(x)$ 、$f(x) \frac{p(x)}{q(x)}$ 分别代入方差的公式
则分别可得(且考虑到不排除会有比初级更初级的初学者学习本文,故把第二个公式拆解的相对较细)
上述两个公式前后对比,可以很明显的看出 后者的第一项多乘了
$p(x)q(x)$ ,如果$p(x)q(x)$ 差距很大,$f(x)p(x)q(x)$ 的方差就会很大
所以结论就是,如果我们只要对分布
这意味着什么呢,意味着我们目前得到的这个公式里
如果
2015年John Schulman等人提出了信任区域策略优化(Trust Region Policy Opimization,简称TRPO),表面上,TRPO的出现解决了同时解决了两个问题,一个是解决重要性采样中两个分布差距太大的问题,一个是解决策略梯度算法中步长难以确定的问题
-
关于前者,在1.2.2节得到的目标函数基础上(下图第一个公式),增加了一个KL散度约束(如下图第二个公式)
$J^{\theta^{\prime}}(\theta)=\mathbb{E}_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)\right]$ $\begin{aligned} J_{\mathrm{TRPO}}^{\theta^{\prime}}(\theta)=\mathbb{E}_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)\right],\mathrm{KL}\left(\theta, \theta^{\prime}\right)<\delta \end{aligned}$ 至此采样效率低效的问题通过重要性采样(重要性权重)、以及增加KL散度约束解决了
KL散度(KL divergence),也称相对熵,而相对熵 = 交叉熵 - shannon熵,其衡量的是两个数据分布
$p$ 和$q$ 之间的差异$D_{KL}(P||Q) = E_x log\frac{P(x)}{Q(x)}$ 下图左半边是一组原始输入的概率分布曲线
$p(x)$ ,与之并列的是重构值的概率分布曲线$q(x)$ ,下图右半边则显示了两条曲线之间的差异顺带从零推导下KL散度的公式
1 所谓概率:对于
$x$ ,可以定义概率分布为$p(x)$ 或$q(x)$ 2 所谓信息:对
$p(x)$ 取对数,加符号得正值$I(p) = -logp(x)$ ,概率越高,包含的信息越小,因为事件越来越确定;相反,概率越低,包含的信息越多,因为事件具有很大的不确定性3 所谓Shannon熵(熵是信息的平均,直观上,Shannon熵是信息在同一分布下的平均):
$p(x)$ 对$I(p)$ 平均,即$\begin{aligned} H(p) &= E_{x\sim P} [I(p)] \\&= \sum p(x)I(p) \\&= - \sum p(x)logp(x) \end{aligned}$ 4 所谓交叉熵Cross-Entropy(直观上,交叉熵是信息在不同分布下的平均),即指
$p(x)$ 对$I(q)$ 平均,即$\begin{aligned} H(p,q) &= E_{x\sim P} [I(q)] \\&= \sum p(x)I(q) \\&= - \sum p(x)logq(x) \end{aligned}$ 5 所谓相对熵或KL散度 = 交叉熵 - shannon熵,即
$\begin{aligned} D_{KL}(p||q) &= H(p,q) - H(p) \\&= -\sum p(x)logq(x) + \sum p(x)logp(x) \\&= -\sum p(x)log\frac{q(x)}{p(x)} \\&= \sum p(x)log\frac{p(x)}{q(x)} \end{aligned}$ 所以如果在KL散度表达式的最前面加个负号,再结合Jensen不等式自然有
$\begin{aligned} -D_{KL}(p||q) &= \sum p(x)log\frac{q(x)}{p(x)} \\& \leq log \sum p(x)\frac{q(x)}{p(x)} \\&= log1 \\&= 0 \end{aligned}$ -
关于后者,具体而言,当策略网络是深度模型时,沿着策略梯度更新参数,很有可能由于步长太长,策略突然显著变差,进而影响训练效果
这是1.2.1节,我们已经得到的策略梯度计算、策略梯度更新公式如下(别忘了,学习率
$\eta$ 类似步长、距离的含义)分别如下$\nabla \bar{R}_{\theta}=\frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}} R\left(\tau^{n}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)$ $\theta \leftarrow \theta+\eta \nabla \bar{R}_{\theta}$ 对这个问题,我们考虑在更新时找到一块信任区域(trust region),在这个区域上更新策略时能够得到安全性保证,这就是TRPO算法的主要思想
本质上,其实这两个问题是同一个问题(简言之,避免两个分布相差大即意味着避免步长过大)。举个例子,比如爬两面都是悬崖的山,左右脚交替往前迈步,无论哪只脚向前迈步都是一次探索
- 为尽快到达山顶且不掉下悬崖,一方面 你会选择最陡峭的方向,二方面 你会用目光选择一片信任区域,从而尽量远离悬崖边,在信任区域中,首先确定要探索的最大步长(下图的黄色圆圈),然后找到最佳点并从那里继续搜索
- 好,现在问题的关键变成了,怎么确定每一步的步长呢?如果每一步的步长太小,则需要很长时间才能到达峰值,但如果步长太大,就会掉下悬崖(像不像两个分布之间差距不能太大)
- 具体做法是,从初始猜测开始可选地,然后动态地调整区域大小。例如,如果新策略和当前策略的差异越来越大,可以缩小信赖区域。怎么实现?KL散度约束!
总之,TRPO就是考虑到连续动作空间无法每一个动作都搜索一遍,因此大部分情况下只能靠猜。如果要猜,就最好在信任域内部去猜。而TRPO将每一次对策略的更新都限制了信任域内,从而极大地增强了训练的稳定性。
至此,PG算法的采样效率低下、步长难以确定的问题都被我们通过TRPO给解决了。但TRPO的问题在哪呢?
TRPO的问题在于把 KL 散度约束当作一个额外的约束,没有放在目标里面,导致TRPO很难计算,总之因为信任域的计算量太大了,John Schulman等人于2017年又推出了TRPO的改进算法:PPO
如上所述,PPO算法是针对TRPO计算量的大的问题提出来的,正因为PPO基于TROP的基础上改进,故PPO也解决了策略梯度不好确定学习率Learningrate(或步长Stepsize)的问题。毕竟通过上文,我们已经得知
- 如果stepsize过大,学出来的Policy会一直乱动,不会收敛;但如果StepSize太小,想完成训练,我们会等到地老天荒
- 而PPO利用NewPolicy和OldPolicy的比例,限制了NewPolicy的更新幅度,让策略梯度对稍微大点的Stepsize不那么敏感
具体做法是,PPO算法有两个主要的变种:近端策略优化惩罚(PPO-penalty)和近端策略优化裁剪(PPO-clip),其中PPO-penalty和TRPO一样也用上了KL散度约束。
近端策略优化惩罚PPO-penalty的流程如下
-
首先,明确目标函数,通过上节的内容,可知咱们需要优化
$J^{\theta'}(\theta)$ ,让其最大化$J^{\theta^{\prime}}(\theta)=\mathbb{E}_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} \mid s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} \mid s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)\right]$ -
接下来,先初始化一个策略的参数
$\theta$ ,在每一个迭代里面,我们用前一个训练的迭代得到的actor的参数$\theta '$ 与环境交互,采样到大量状态-动作对,根据$\theta '$ 交互的结果,估测$A^{\theta '}(s_t,a_t)$ -
由于目标函数牵涉到重要性采样,而在做重要性采样的时候,
$p_\theta(a_t|s_t)$ 不能与$p_{\theta}'(a_t|s_t)$ 相差太多,所以需要在训练的时候加个约束,这个约束就好像正则化的项一样,是$\theta$ 与$\theta'$ 输出动作的 KL散度,用于衡量$\theta$ 与$theta'$ 的相似程度,我们希望在训练的过程中,学习出的$theta$ 与$theta'$ 越相似越好 所以需要最后使用 PPO 的优化公式:$\\J_{\mathrm{PPO}}^{\theta^{\prime}}(\theta)=J^{\theta^{\prime}}(\theta)-\beta \mathrm{KL}\left(\theta, \theta^{\prime}\right)$ 当然,也可以把上述那两个公式合二为一『如此可以更直观的看出,PPO-penalty把KL散度约束作为惩罚项放在了目标函数中(可用梯度上升的方法去最大化它),此举相对TRPO减少了计算量』
$J_{\mathrm{PPO}}^{\theta^{\prime}}(\theta)=\mathbb{E}_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} \mid s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} \mid s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)\right] \quad-\beta \mathrm{KL}\left(\theta, \theta^{\prime}\right)$
上述流程有一个细节并没有讲到,即
-
先设一个可以接受的 KL 散度的最大值
$KL_{max}$ 假设优化完$J_{\mathrm{PPO}}^{\theta^{\prime}}(\theta)=J^{\theta^{\prime}}(\theta)-\beta \mathrm{KL}\left(\theta, \theta^{\prime}\right)$ 以后,KL 散度值太大导致$KL(\theta,\theta^{\prime})> KL_{max}$ ,意味着$\theta$ 与$\theta'$ 差距过大(即学习率/步长过大),也就代表后面惩罚的项$\beta \mathrm{KL}\left(\theta, \theta^{\prime}\right)$ 惩罚效果太弱而没有发挥作用,故增大惩罚把$\beta$ 增大 -
再设一个 KL 散度的最小值
$KL_{min}$ 如果优化完$J_{\mathrm{PPO}}^{\theta^{\prime}}(\theta)=J^{\theta^{\prime}}(\theta)-\beta \mathrm{KL}\left(\theta, \theta^{\prime}\right)$ 以后, KL散度值比最小值还要小导致$KL(\theta ,\theta ^{\prime})< KL_{max}$ ,意味着$\theta$ 与$\theta'$ 差距过小,也就代表后面惩罚的项$\beta \mathrm{KL}\left(\theta, \theta^{\prime}\right)$ 惩罚效果太强了,我们担心它只优化后一项,使$\theta$ 与$\theta'$ 一样,这不是我们想要的,所以减小惩罚即减小$\beta$
关于
$\beta$ 具体怎么设置的?除了上面提到的自适应KL惩罚(adaptive KL penalty),来自2017年发表的PPO论文另外,2019年发表的论文《Fine-Tuning Language Models from Human Preferences》『也是本博客内另一篇文章“ChatGPT相关技术论文100篇”中提到的第56篇,另这是论文对应的代码:微调GPT2』,其中也提到了根据 KL_target 自适应调节
$\beta$ 的算法,这个方法已经被 TRLX/TRL实现更多训练细节可以看下instructGPT论文原文
总之,近端策略优化惩罚可表示为
如果觉得计算 KL散度很复杂,则还有一个PPO2算法,即近端策略优化裁剪PPO-clip。近端策略优化裁剪的目标函数里面没有 KL 散度,其要最大化的目标函数为(easy RL上用
整个目标函数在
换言之,这个裁剪算法和KL散度约束所要做的事情本质上是一样的,都是为了让两个分布之间的差距不致过大,但裁剪算法相对好实现,别看看起来复杂,其实代码很好写
// ratios即为重要性权重,exp代表求期望,括号里的environment_log_probs代表用于与环境交互的策略
ratios = torch.exp(log_probs - environment_log_probs)
// 分别用sur_1、sur_2来计算公式的两部分
// 第一部分是重要性权重乘以优势函数
sur_1 = ratios * advs
// 第二部分是具体的裁剪过程
sur_2 = torch.clamp(ratios, 1 - clip_eps, 1 + clip_eps) * advs
// 最终看谁更小则取谁
clip_loss = -torch.min(sur_1,sur_2).mean()
回到公式,公式的第一部分我们已经见过了,好理解,咱们来重点分析公式的第二部分
- 首先是
${clip}$ 括号里的部分,用一句话简要阐述下其核心含义就是:如果${p_{\theta}(a_{t}|s_{t})}$ 和${p_{\theta'}(a_{t}|s_{t})}$ 之间的概率比落在范围$(1- \varepsilon)$ 和$(1+\varepsilon)$ 之外,$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta'}\left(a_{t} | s_{t}\right)}$ 将被剪裁,使得其值最小不小于$(1- \varepsilon)$ ,最大不大于$(1+\varepsilon)$
- 然后是
${clip}$ 括号外乘以$A^{\theta '}(s_t,a_t)$ ,如果$A^{\theta '}(s_t,a_t)$ 大于0,则说明这是好动作,需要增大$p_{\theta }(a_{t}|s_{t})$ ,但$\frac{p_{\theta}(a_{t}|s_{t})}{p_{\theta'}(a_{t}|s_{t})}$ 最大不能超过$(1+\varepsilon)$
如果
需要减小
最后把公式的两个部分综合起来,针对整个目标函数
如果
$A^{\theta'}(s_t,a_t)$ 大于0且$\frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)}$ 大于$(1+\epsilon)$ 则相当于第二部分是$(1+\epsilon)×A^{\theta'}(s_t,a_t)$ ,和第一部分$\frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)}*A^{\theta'}(s_t,a_t)$ 对比取更小值当然是$(1+\epsilon)$ 的截断值:$(1+\epsilon )*A^{\theta \prime}(s_t,a_t)$
如果
$A^{\theta'}(s_t,a_t)'大于0且\frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)}$ 小于$(1-\epsilon)$ 则相当于第二部分是$(1-\epsilon)*A^{\theta'}(s_t,a_t)$ ,和第一部分$\frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)}*A^{\theta'}(s_t,a_t)$ 对比取更小值当然是原函数值:$\frac{p_{\theta}(a_t|s_t)}{p_{\theta \prime}(a_t|s_t)}*A^{\theta \prime}(s_t,a_t)$ 反之,如果
$A^{\theta \prime}(s_t,a_t)$ 小于0,则最终目标函数的取值为了更小则和$A^{\theta \prime}(s_t,a_t)$ 大于0时反过来,毕竟加了个负号自然一切就不同了,为方便初学者一目了然,咱们还是把计算过程列出来,即
如果
$A^{\theta'}(s_t,a_t)$ 小于0且$\frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)}$ 大于$(1+\epsilon)$ 则相当于第二部分是$(1+\epsilon)*A^{\theta'}(s_t,a_t)$ ,和第一部分$\frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)}*A^{\theta'}(s_t,a_t)$ 对比
取更小值当然是原函数值:$\frac{p_{\theta}(a_t|s_t)}{p_{\theta \prime}(a_t|s_t)}*A^{\theta \prime}(s_t,a_t)$ 如果
$A^{\theta'}(s_t,a_t)$ 小于0且$\frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)}$ 小于$(1-\epsilon)$ 则相当于第二部分是$(1-\epsilon)×A^{\theta'}(s_t,a_t)$ ,和第一部分$\frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)}*A^{\theta'}(s_t,a_t)$ 对比取更小值当然是$(1-\epsilon)$ 的截断值:$(1-\epsilon )*A^{\theta \prime}(s_t,a_t)$
综上,PPO算法是一种具体的Actor-Critic算法实现,比如在对话机器人中,输入的prompt是state,输出的response是action,想要得到的策略就是怎么从prompt生成action能够得到最大的reward,也就是拟合人类的偏好。具体实现时,可以按如下两大步骤实现
-
首先定义4个模型:Actor(action_logits)、SFT(sft_logits)、Critic(value)、RM「r(x, y)」,和kl_div、reward、优势函数adv 从prompt库中采样出来的prompt在经过SFT(微调过GPT3/GPT3.5的模型称之为SFT)做generate得到一个response,这个『prompt + response』定义为sequence(这个采样的过程是批量采样进行generate,得到一个sequence buffer),然后这个sequence buffer的内容做batched之后输入给4个模型做inference
这4个模型分别为Actor、SFT、Critic、RM,其中: Actor和SFT都是175B的模型,且Actor参数由SFT初始化(SFT是baseline),Actor输出action_logits,SFT输出sft_logits sft_logits和action_logits做kl_div,为了约束actor模型的更新step不要偏离原始模型SFT太远
Critic和RM是6B的模型,Critic参数由RM初始化 Critic输出标量value,RM输出标量r(x, y),由r(x, y)和kl_div计算得到reward,
reward和value计算得到adv
-
其次,通过pg_loss和value_loss优化迭代 Actor的流程是取出sequence,然后inference生成新的logits,再和sequence对应的之前的logits计算ratio,和adv计算出pg_loss,也就是actor的loss,然后反向传播,优化器迭代 Critic的流程是取出sequence,然后inference得到新的value,和old_value做clip_value,再和reward计算value loss,然后反向传播,优化器迭代
至于代码实现可以参阅此文:类ChatGPT逐行代码解读(2/2):从零实现ChatLLaMA、ColossalChat、DeepSpeed Chat
1.6日决定只是想写个ChatGPT通俗导论,但为了讲清楚其中的PPO算法,更考虑到之后还会再写一篇强化学习极简入门,故中途花了大半时间去从头彻底搞懂RL,最终把网上关于RL的大部分中英文资料都翻遍之外(详见参考文献与推荐阅读),还专门买了这几本书以系统学习
- 第1本,《白话强化学习与pytorch》,偏通俗,对初学者友好,缺点是部分内容混乱,且对部分前沿/细节比如PPO算法阐述不足,毕竟19年出版的了
- 第2本,《EazyRL强化学习教程》,基于台大李宏毅等人的公开课,虽有不少小问题且其对MDP和三大表格求解法的阐述比较混乱,但其对策略梯度和PPO的阐述于初学入门而言还不错的
- 第3本,《动手学强化学习》,张伟楠等人著,概念讲解、公式定义都很清晰,且配套代码实现,当然 如果概念讲解能更细致则会对初学者更友好
- 第4本,《深度强化学习》,王树森等人著,偏原理讲解(无代码),此书对于已对RL有一定了解的是不错的选择
- 第5本,《强化学习2》,权威度最高但通俗性不足,当然 也看人,没入门之前你会觉得此书晦涩,入门之后你会发现经典还是经典、不可替代,另书之外可配套七月的强化学习2带读课
- 第6本,《深度强化学习:基于Python的理论与实践》,理论讲的挺清楚,代码实践也不错
- 第7本,《强化学习(微课版)》,这本书是作为RL教材出版的,所以有教材的特征,即对一些关键定理会举例子展示实际计算过程,比如马尔可夫决策的计算过程,对初学者友好
总之,RL里面的概念和公式很多(相比ML/DL,RL想要机器/程序具备更好的自主决策能力),而
-
一方面,绝大部分的资料没有站在初学者的角度去通俗易懂化、没有把概念形象具体化、没有把公式拆解举例化(如果逐一做到了这三点,何愁文章/书籍/课程不通俗)
-
二方面,不够通俗的话,则资料一多,每个人的公式表达习惯不一样便会导致各种形态,虽说它们最终本质上都是一样的,可当初学者还没有完全入门之前,就不一定能一眼看出背后的本质了,然后就不知道该以哪个为准,从而丧失继续前进的勇气(这种情况下,要么硬着头皮继续啃 可能会走弯路,要么通过比如七月在线的课程问老师或人 提高效率少走弯路)
比如一个小小的策略梯度的计算公式会有近10来种表达,下面特意贴出其中6种,供读者辨别
第一种,本笔记和Easy RL中用的
第二种,Sutton强化学习《Reinforcement Learning: An Introduction》第一版中用的
其中
第三种,David sliver在2014年的《Deterministic Policy Gradient Algorithm》论文中用的
其中,
第四种,肖志清《强化学习:原理与Python实现》中用的
第五种,Sutton强化学习在2018年的第二版中用的
其中,
是stationary distribution (undiscounted state distribution)
第六种,Open AI spinning up教程中用的
-
关于强化学习入门的一些基本概念
-
《白话强化学习与Pytorch》,此书让我1.6日起正式开启RL之旅,没看此书之前,很多RL资料都不好看懂
-
《动手学强化学习》,张伟楠等人著
-
台大李宏毅RL公开课,这是其:视频/PPT/PDF下载地址
-
UCLA周博磊RL公开课,这是其:GitHub地址
-
关于Q-leaning的几篇文章:1如何用简单例子讲解 Q - learning 的具体过程?2莫烦:什么是 Q-Learning
-
AlphaGo作者之一David Silver主讲的增强学习笔记1、笔记2,另附其讲授的《UCL Course on RL》的课件地址
-
huggingface的两篇RL教程:An Introduction to Deep Reinforcement Learning、GitHub:The Hugging Face Deep Reinforcement Learning Course
-
TRPO原始论文:Trust Region Policy Optimization
-
PPO算法解读(英文2篇):解读1 RL — Proximal Policy Optimization (PPO) Explained、解读2Proximal Policy Optimization (PPO)
-
PPO算法解读(中文4篇):Easy RL上关于PPO的详解、详解近端策略优化、详解深度强化学习 PPO算法、ChatGPT第二弹:PPO算法
-
PPO算法实现:GitHub - lvwerra/trl: Train transformer language models with reinforcement learning.
-
《强化学习(微课版)》,清华大学出版社出版
RL里的细节、概念、公式繁多,想完全阐述清楚是不容易的,以下是自从23年1.16日以来的修改、完善、新增记录:
-
1.16日,第一轮修改/完善/新增 修正几个笔误,且考虑到不排除会有比初级更初级的初学者阅读本文,补充部分公式的拆解细节
-
1.17日,先后修正了2.2节重要性采样与重要性权重的部分不准确的描述、修正个别公式的笔误,以及补充1.4.2中关于PPO-clip的细节阐述、优化第四部分的相关描述
-
1.18日,为措辞更准确,优化1.2.5节“基于信任区域的TRPO:通过KL散度解决两个分布相差大和步长难以确定的问题”的相关描述
-
1.19日,为让读者理解起来更一目了然 优化1.3.1节中关于什么是近端策略优化PPO的描述 优化1.3.2节中关于“近端策略优化惩罚PPO-penalty关于自适应KL惩罚(adaptive KL penalty)”的描述 拆解细化关于
$\nabla \log p_{\theta}(\tau )$ 的推导过程 补充说明对优势函数$A^{\theta}(s_t,a_t)$ 的介绍 -
1.20日,第五轮修改/完善/新增 通过LaTeX重新编辑部分公式,以及补充说明1.2.1节中关于某一条轨迹
$\tau $ 发生概率的定义 -
1.21日(大年三十),新增对蒙/新增特卡洛方法的介绍,以及新增
$R(\tau )-b$ 中基线$b$ 的定义,且简化2.1.1节中关于强化学习过程的描述 -
1.22日,为严谨起见改进第二部分中对回报
$G$ 、状态价值函数、动作价值函数、马尔可夫决策、策略评价函数的描述,并纠正个别公式的笔误 -
1.23日,梳理1.1节的整体内容结构和顺序脉络,以让逻辑更清晰,补充了MDP的整个来龙去脉(包括且不限于马尔可夫过程、马尔可夫奖励、马尔可夫决策以及贝尔曼方程)
-
1.25日,为方便对高数知识有所遗忘的同学更顺畅的读懂本文,新增对导数、期望的简单介绍(后汇总至概率统计极简入门笔记里),以及补充对
$R(\tau )-b$ 中基线$b$ 的定义的介绍 -
1.26日,第十轮修改/完善/新增 优化改进2.2节关于策略梯度的梯度计算的整个推导过程,以让逻辑更清晰
-
1.27日,优化关于增加基线baseline和优势函数等内容的描述 在后记里补充策略梯度计算公式的5种其它表达 优化关于“近端策略优化惩罚PPO-penalty的流程”的描述
-
1.28日,新增对MC和TD方法各自的阐述及两者的对比,优化对KL散度定义的描述,新增近端策略优化裁剪PPO-clip的关键代码
-
1.30日,新增马尔可夫决策的贝尔曼方程以及对应的计算图解,以方便一目了然 简单阐述了下GPT2相比GPT的结构变化,以及完善丰富了下文末的参考文献与推荐阅读,比如增加图解GPT2、图解GPT3的参考文献
-
1.31日,为行文严谨,针对1.1.2节中关于马尔可夫奖 励的部分
规范统一个别公式的大小写表示
补充状态$s$ 下奖励函数的定义$R(s)=E[R_{t+1}|S_t=s]$
修正回报公式的笔误$G_t=R_{t+1}+\gamma \cdot R_{t+2}+\gamma ^2\cdot R_{t+3}+\gamma ^3\cdot R_{t+4}+\cdots $
修正状态价值函数公式的笔误
且为形象起见,新增一个“吃饭-抽烟/剔牙”的例子以展示利用贝尔曼方程计算的过程
此外,且为通俗细致,针对1.1.3节中关于马尔科夫决策的部分 拆解状态价值函数、动作价值函数的定义公式,拆解关于状态价值函数和动作价值函数之间联系的推导过程 -
2.1日,第十五轮修改/完善/新增 参考sutton RL一书,补充对奖励函数、回报公式、轨迹定义的公式表达规范的说明
-
2.12日,为更一目了然,新增对状态价值函数的贝尔曼方程的解释,与例子说明
-
2.13日,开始完善动态规划一节的内容,然后发现之前写的一篇关于DP的博客不够通俗,故本周得先修订下那篇旧文,以通俗理解DP
-
2.15日,基于已经修订好的DP旧文,完善本文对DP算法的阐述 并修正第一部分里关于“什么是强化学习”的不够准确的表述
-
2.16日,新增对蒙特卡洛方法和时序差分法的介绍,并重点对比DP、MC、TD三者的区别与联系 明确全文结构,分为四大部分,一一对应:RL基础、RL进阶、RL深入、RL高级
-
2.17日,第二十轮修改/完善/新增 新增第三部分价值学习:从n步Sarsa算法到Q-learning、DQN,并修订部分细节 润色部分细节,修订部分目录
-
2.20日,新增一节“RL的分类:基于模型(Value-base/Policy-based)与不基于模型”
-
2.21日,新增KL散度公式的从零推导过程
-
2.24日,新增关于
$E[G_{t+1}|S_t = s]$ 为何等于$E[V(S_{t+1}|S_t = s)]$ 的详细推导 -
2.26日,新增关于
$\nabla f(x)=f(x)\nabla \log f(x)$ 如何而来的推导 -
3.4日,完善对于“Q学习的两种策略:行为策略和目标策略”的描述
-
2年4月,纠正本文下面几个热心读者指出的笔误,大家有啥问题 继续随时反馈,非常感谢
-
4.27,针对一读者留言所表达的疑惑,新增1.2.2节中关于「奖励函数
$R(s,a)$ 推导」的说明解释 并新增一节“4.4.3 PPO算法的一个简单实现:对话机器人”