殊途同归的策略梯度与零阶优化
By 苏剑林 | 2020-09-15 | 63653位读者 |深度学习如此成功的一个巨大原因就是基于梯度的优化算法(SGD、Adam等)能有效地求解大多数神经网络模型。然而,既然是基于梯度,那么就要求模型是可导的,但随着研究的深入,我们时常会有求解不可导模型的需求,典型的例子就是直接优化准确率、F1、BLEU等评测指标,或者在神经网络里边加入了不可导模块(比如“跳读”操作)。
本文将简单介绍两种求解不可导的模型的有效方法:强化学习的重要方法之一策略梯度(Policy Gradient),以及干脆不需要梯度的零阶优化(Zeroth Order Optimization)。表面上来看,这是两种思路完全不一样的优化方法,但本文将进一步证明,在一大类优化问题中,其实两者基本上是等价的。
形式描述 #
首先,我们来形式地定义我们需要解决的问题。以监督学习为例,训练数据(xt,yt)∼D,模型为pθ(y|x),θ是待优化参数,其维度为d,假设模型本身是可导的,其的一般形式为softmax(fθ(y|x)/τ),其中τ称为温度参数,没有特别注明的情况下默认τ=1。假如真实标签是yt,预测标签是yp,那么单个样本的得分记为r(yt,yp),训练目标希望总得分越大越好,即
θ=argmaxθE(xt,yt)∼D[r(yt,argmaxypθ(y|xt))]
看上去挺复杂的,但事实上它的含义很直观清晰:我们想求出参数θ,使得整个数据集的得分r(yt,yp)尽可能大,而yp=argmaxypθ(y|xt),说明模型预测时输出的是概率最大的那一个。说白了,我们希望“预测概率最大的那一个y就是评测得分最高的那一个y”。
这个形式对应着相当多的机器学习任务,在NLP中包括文本分类、序列标注、文本生成等,甚至回归问题也可以对应上去,可以说是很有代表性了。其困难之处就是argmaxy这一步无法提供有效的梯度,因此不好直接用基于梯度的优化算法优化。
策略梯度 #
策略梯度的想法很直接,既然原始的目标(1)没法求梯度,那换个跟它强相关的、可求梯度的目标就行了,比如
θ=argmaxθE(xt,yt)∼D[∑ypθ(y|xt)r(yt,y)]
排序不等式 #
很明显,上述定义的目标并没有包含argmaxy之类的算子,因此它是可导的。那么我们首先想要知道的是上式跟原始目标(1)有什么关系呢?差异又在哪呢?这需要用数学中的“排序不等式”来回答:
排序不等式 对于a1≥a2≥⋯≥an以及b1≥b2≥⋯≥bn,并假设(c1,c2,…,cn)是(b1,b2,…,bn)的任一排列,那么 n∑i=1aibi≥n∑i=1aici≥n∑i=1aibn+1−i 也就是说“同序积和 ≥ 乱序积和 ≥ 倒序积和”。
排序不等式是很经典的不等式,网上很容易找到它的证明(一般用数学归纳法),这里就不证了。根据排序不等式我们可以知道,如果目标(2)达到最大值,那么pθ(y|xt)与r(yt,y)是同序的,也就是说确实可以实现“预测概率最大的那一个y就是评测得分最高的那一个y”这个目标,但是同时还实现了“预测概率第二大的那一个y就是评测得分第二高的那一个y”、“预测概率第三大的那一个y就是评测得分第三高的那一个y”等目标,而这些并不是原始目标所必须的。所以,目标(2)跟原始目标是强相关的,但是要求更多一些。
注意到,排序不等式没有要求ai,bi都是非负数,所以实际的打分函数r(yt,y)有可能是负数的。
采样估计梯度 #
确定目标(2)是可行的之后,我们可以求它的梯度:
E(xt,yt)∼D[∑y∇θpθ(y|xt)r(yt,y)]
一般来说,求梯度∇θpθ(y|xt)并不困难,而∑y才是主要的困难,因为它要对所有候选类别求和,而实际上的候选类别数目可能大到难以承受,相关讨论在之前的《漫谈重参数:从正态分布到Gumbel Softmax》也出现过。因此,比较好的办法是转化为采样估计的形式,即
E(xt,yt)∼D[∑ypθ(y|xt)∇θpθ(y|xt)pθ(y|xt)r(yt,y)]=E(xt,yt)∼D[∑ypθ(y|xt)r(yt,y)∇θlogpθ(y|xt)]=E(xt,yt)∼D,y∼pθ(y|xt)[r(yt,y)∇θlogpθ(y|xt)]
这样原则上我们就只需要采样适当数目的y估计上式了,最后的结果便称为“策略梯度”。有了梯度,就可以套用现成的优化器来完成优化了。
降低方差 #
刚才我们说,往r(yt,y)里加上一个常数,并不会改变最终的结果。但是,它有可能改变采样估算的效率,用统计的语言来说,就是它能改变采样的方差。举个简单的例子,[4,5,6]和[−10,10,15],它们的均值都是5(代表我们要估算的目标),但是它们的方差分别为0.67和116.67,也就是后者方差远大于前者。如果我们只从中采样一个样本,那么前者与目标的最大误差也不过是1,后者最大误差能达到15,最小误差都有5,所以虽然理论上最终的均值都是一样的,但是前者的估算效率要远远高于后者(采样更少的样本,得到更高的估算精度)。
这个简单的例子告诉我们要提高估算效率,就要想办法得到方差更小的估计量。这时候我们往r(yt,y)里边减去一个常数b(称为baseline,“常数”是指不依赖于y,但可以依赖于x):
Ey∼pθ(y|xt)[(r(yt,y)−b)∇θlogpθ(y|xt)]
最终的结果(均值)不会产生变化:
Ey∼pθ(y|xt)[(r(yt,y)−b)∇θlogpθ(y|xt)]=Ey∼pθ(y|xt)[r(yt,y)∇θlogpθ(y|xt)]−bEy∼pθ(y|xt)[∇θlogpθ(y|xt)]=Ey∼pθ(y|xt)[r(yt,y)∇θlogpθ(y|xt)]−b∑y∇θpθ(y|xt)=Ey∼pθ(y|xt)[r(yt,y)∇θlogpθ(y|xt)]−b∇θ∑ypθ(y|xt)=Ey∼pθ(y|xt)[r(yt,y)∇θlogpθ(y|xt)]−b∇θ1=Ey∼pθ(y|xt)[r(yt,y)∇θlogpθ(y|xt)]
但是它方差有可能变,我们希望最小化方差,根据Var[x]=E[x2]−E[x]2知最小化方差等价于最小化二阶矩
Ey∼pθ(y|xt)[(r(yt,y)−b)2‖∇θlogpθ(y|xt)‖2]
这只不过是一个二次函数最小值问题,解得最优的b是:
b=Ey∼pθ(y|xt)[r(yt,y)‖∇θlogpθ(y|xt)‖2]Ey∼pθ(y|xt)[‖∇θlogpθ(y|xt)‖2]
即以‖∇θlogpθ(y|xt)‖2为权重对r(yt,y)求加权期望。但是要获取每个候选类别的梯度成本会比较大,我们通常不考虑这个权重,而使用一个简化的版本:
b=Ey∼pθ(y|xt)[r(yt,y)]
结合式(6),我们可以发现思想其实很直观:就是要从pθ(y|xt)里边采样若干个y,然后算出r(yt,y)的均值b,大于这个均值的执行梯度上升(强化效果),小于这个均值的执行梯度下降(削弱效果)。
一言以蔽之 #
简单来说,策略梯度就是在遇到有argmax操作等不可导目标函数时,换一个可导的目标(2),这时候用强化的语言来说,y称为“策略”,pθ(y|xt)称为“决策模型”,r(yt,yp)就是“奖励”,然后配合采样估计和降低方差技巧,得到原模型的一个有效的梯度估计,从而完成模型的优化。
零阶优化 #
零阶优化泛指所有不需要梯度信息的优化方法,而一般情况下它指的是基于参数采样和差分思想来估计参数更新方向的优化算法。从形式上来看,它是直接在参数空间中进行随机采样,不依赖于任何形式的梯度,因此理论上能求解的目标是相当广泛的;不过也正因为它直接在参数空间中进行采样,只是相当于一种更加智能的网格搜索,因此面对高维参数空间时(比如深度学习场景),它的优化效率会相当低,因此使用场景会很受限。
不过就算这样,也不妨碍我们学习零阶优化的思想,毕竟技多不压身。此外,深度学习虽然往往参数量很大,但是通常来说我们设计的模型大部分模块都是可导的,不可导的可能只有一小部分,因此也许有可能让可导部分直接用梯度优化器来优化,不可导的部分才用零阶优化,这便是它的应用场景之一了,这样的思想在很多NAS的论文中都出现过。
零阶梯度 #
零阶优化不需要我们通常意义下所求的梯度,但是它定义了一个基于采样和差分的“替代品”,我们暂且称为“零阶梯度”:
对于标量函数f(x),定义它在x处的零阶梯度为 ˜∇xf(x)=Eu∼p(u)[f(x+εu)−f(x)εu] 其中ε是事先给定的小正数,p(u)则是事先指定的均值为0、协方差矩阵为单位矩阵的分布,通常我们会使用标准正态分布。
可以看到,只需要从p(u)中采样若干个点,就可以对零阶梯度进行估算,而有了零阶梯度之后,我们就可以把它当作普通的梯度来套用基于梯度的优化器,这便是零阶优化的基本思想。特别地,如果f(x)本身是可导的,那么f(x+εu)=f(x)+εu⊤∇xf(x)+O(ε2),所以当ε→0时:
˜∇xf(x)=∫p(u)u(u⊤∇xf(x))du=∫p(u)(uu⊤)∇xf(x)du=∇xf(x)
也就是说˜∇xf(x)等于普通的梯度,所以˜∇xf(x)确实是普通梯度的合理推广之一。
也有basline #
善于推导的读者可能会发现,在定义(11)中,由于p(u)的均值为0,所以−f(x)其实不影响最终结果,即
˜∇xf(x)=Eu∼p(u)[f(x+εu)εu]−Eu∼p(u)[f(x)εu]=Eu∼p(u)[f(x+εu)εu]
那么−f(x)的作用是什么呢?其实跟前面策略梯度一样,都是为了降低方差,我们同样可以引入b,然后最小化二阶矩(等价于最小化方差)
Eu∼p(u)[(f(x+εu)−bε)2‖u‖2]
解得最优的b为
b=Eu∼p(u)[f(x+εu)‖u‖2]Eu∼p(u)[‖u‖2]
实验的时候,可以直接用有限个样本估计上式。事实上,如果f(x)是可导的话,可以用泰勒展开近似完成积分,结果是f(x)+O(ε2),从这个角度看直接取b=f(x)也是一个合理的选择,这就说明了引入−f(x)项的必要性与合理性。
一言以蔽之 #
零阶优化方法主要是基于差分来定义了一个梯度的合理推广,由于算差分不需要函数的可导性,因此自然能适用于可导/不可导目标的优化。当然,由于u的维度就是全体参数θ的维度,对于深度学习这样的参数量巨大的模型,其实更新过程中的方差会很大,不好收敛,所以通常来说零阶优化只用来优化模型的一小部分参数,或者作为辅助优化手段(比如“可导目标+普通梯度+大学习率”与“不可导目标+零阶梯度+小学习率”交替更新)。对于直接在高维空间中应用零阶优化方法,也有一定的研究工作(比如《Gradientless Descent: High-Dimensional Zeroth-Order Optimization》),但还不算很成功。
此外,之前在《从采样看优化:可导优化与不可导优化的统一视角》介绍的统一视角,也可以看作是一种零阶优化方法,它是对常见优化思路的更统一的推广(通过它可以导出梯度下降、牛顿法、零阶梯度等),但原则上来说,它也存在跟零阶梯度一样的方差大等“通病”,这是零阶优化方法很难避免的。
貌离神合 #
看上去,策略梯度和零阶优化确实有很多相似之处,比如大家都是需要随机采样来估计梯度,大家都需要想办法降低方差,等等。当然,不相似之处也能列举出不少,比如策略梯度是要对策略空间采样,而零阶优化则是对参数空间采样;又比如策略梯度本质上还是基于梯度的,而零阶优化理论上完全不需要梯度。
那么,两者之间的关系究竟是怎样呢?接下来我们将会证明,对于本文开头提出来的优化问题(1)来说,两者基本上是等价的。证明的思路是求目标(1)的零阶梯度,经过一系列简化后发现它基本上就是策略梯度。
划分全空间 #
我们记
Rθ=E(xt,yt)∼D[r(yt,argmaxypθ(y|xt))]
那么根据式(13),它的零阶梯度是
˜∇θRθ=1ε∫E(xt,yt)∼D[r(yt,argmaxypθ+εu(y|xt))]p(u)udu=E(xt,yt)∼D[1ε∫r(yt,argmaxypθ+εu(y|xt))p(u)udu]
它可以转化为
˜∇θRθ=E(xt,yt)∼D[1ε∑y∫Ωy|xtr(yt,y)p(u)udu]Ωy|xt={u|u∈Rd,y=argmaxˆypθ+εu(ˆy|xt)}
看起来很复杂,其实思想很简单,就是不同的u的预测结果argmaxypθ+εu(y|xt)也不同,我们将预测结果同为y的所有u放在一起,记为Ωy|xt,这时候全空间Rd就被划分为互不相交的子集Ωy|xt了。前面没有特别注明积分区域的积分默认是在全空间Rd进行的,划分空间后,它就等于在各个划分的子集Ωy|xt上的积分之和了。
示性函数 #
然后,我们用一个“示性函数”技巧,定义
χ(y|xt,u)={1,u∈Ωy|xt0,u∉Ωy|xt
那么
1ε∑y∫Ωy|xtr(yt,y)p(u)udu=1ε∑y∫χ(y|xt,u)r(yt,y)p(u)udu
回顾Ωy|xt的含义,对于任意u∈Ωy|xt,模型pθ+εu(⋅|xt)的预测结果就是y,在示性函数里边则输出1,那么我们可以发现实际上就有
χ(y|xt,u)=lim
其中\tau是softmax里边的温度参数(文章开头已经说明)。根据这个结论,我们可以近似地用p_{\theta + \varepsilon u}(y|x_t)代替\chi(y|x_t, u),然后代入上述各个式子,得到
\begin{equation}
\tilde{\nabla}_{\theta}\mathcal{R}_{\theta} \approx \mathbb{E}_{(x_t,y_t)\sim\mathcal{D}}\left[\frac{1}{\varepsilon}\sum_y\int p_{\theta + \varepsilon u}(y|x_t) r\left(y_t, y\right)p(u) u du\right]
\end{equation}
近似求积分 #
最后,由于p_{\theta + \varepsilon u}(y|x_t)是可导的,因此利用展开p_{\theta + \varepsilon u}(y|x_t)\approx p_{\theta}(y|x_t) + \varepsilon u^{\top}\nabla_{\theta}p_{\theta}(y|x_t)代入上式完成对u的积分得
\begin{equation}
\tilde{\nabla}_{\theta}\mathcal{R}_{\theta} \approx \mathbb{E}_{(x_t,y_t)\sim\mathcal{D}}\left[\sum_y r\left(y_t, y\right)\nabla_{\theta}p_{\theta}(y|x_t)\right]
\end{equation}
对比式\eqref{eq:policy-grad-base}可以发现,上式右端正是策略梯度。
所以,看起来差异蛮大的零阶梯度,最终指向的方向实际上跟策略梯度是相近的,真可谓貌离神合、殊途同归了,有种“正确的答案只有一个”的感觉。这不禁让笔者想起了列夫·托尔斯泰的名言:
幸福的家庭都是相似的,不幸的家庭各有各的不幸。
参数的更新方向也是如此呀(正确的更新方向都是相似的)~
文末小结 #
本文主要介绍了处理不可导的优化目标的两种方案:策略梯度和零阶优化,它们分别是从两个不同的角度来定义新的“梯度”来作为参数的更新方向。表面上来看两者走了不同的路径,但笔者的探讨表明,在处理跟策略梯度一样的优化问题时,零阶优化所给出的更新方向跟策略梯度基本上是等价的,两者殊途同归。此外,本文也可以作为强化学习的入门资料供初学者参考。
转载到请包括本文地址:https://spaces.ac.cn/archives/7737
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (Sep. 15, 2020). 《殊途同归的策略梯度与零阶优化 》[Blog post]. Retrieved from https://spaces.ac.cn/archives/7737
@online{kexuefm-7737,
title={殊途同归的策略梯度与零阶优化},
author={苏剑林},
year={2020},
month={Sep},
url={\url{https://spaces.ac.cn/archives/7737}},
}
September 21st, 2020
文末的推导让我眼前一亮!不过有个点没看懂:式子(22)到(23)那个算积分,p_{\theta}(y\vert x_t)那一部分哪儿去了呢?我算的(23)期望里面那一部分只是\epsilon u^T\nabla_\theta p_{\theta}(y\vert x_t)积出来的(用了之前E_{p(u)}[u^Tu]=I的假设算出来的那部分)...
p(u)是均值为0,协方差矩阵为单位矩阵的分布,所以
\int p_{\theta}(y|x_t) r\left(y_t, y\right)p(u) u du= p_{\theta}(y|x_t) r\left(y_t, y\right)\int p(u) u du=0
噢对噢!我忘记了均值为0...
September 21st, 2020
关于policy gradient,我一直还有一个疑问:如果用统计平均去近似reward期望的梯度,即\nabla_\theta J(\theta)=\frac{1}{N}\sum_{k=1}^{N}\sum_t r(y_t^{(k)},y^{(k)})\nabla_\theta {\rm log} p_\theta(y^{(k)}\vert x_t^{(k)}), 那么,reward的期望就可以近似为J(\theta)=\frac{1}{N}\sum_{k=1}^{N}\sum_t r(y_t^{(k)},y^{(k)}){\rm log} p_\theta(y^{(k)}\vert x_t^{(k)}). 可是这样的话,我们知道{\rm log} p_\theta(y^{(k)}\vert x_t^{(k)})是负的,那么如果r(y_t^{(k)},y^{(k)})是正的(正奖励),那么r越大意味着J越小,这很反直觉(正奖励情况下,如果每一步的奖励越大,最终的期望回报J应该越大才对呀).求苏神解释!或许也可能是我哪里搞错了...
你这里给出的J(\theta),只是有相同梯度的一个函数,而不是真正的reward,真正的reward是本文的公式(2)。
如果两个函数梯度相同,那它们是不是该相差一个常数呢?我没理解这个关系额。。。
然后。。对于上面提到的J(\theta),我发现这个文章里面(https://medium.com/@ts1829/policy-gradient-reinforcement-learning-in-pytorch-df1383ea0baf)PG的实现是通过拿-J(\theta)作为Loss,然后直接做backward,这样做能train出来吗?
“如果两个函数梯度相同,那它们是不是该相差一个常数呢?”,在数学上这个并没有错,但是你定义的J(\theta)的实际梯度并不是策略梯度。
你的记号有点凌乱,我重新表述一下:你定义的J(\theta)是
J(\theta)=\frac{1}{NK}\sum_{n=1}^{N}\sum_{k=1}^{K} r(y_t^{(n)},y^{(k|n)}) \log p_\theta(y^{(k|n)}|x_t^{(n)})
其中(x_t^{(n)}, y_t^{(n)})是训练样本,y^{(k|n)}则是从p_\theta(y|x_t^{(n)})中采样出来的样本。注意到采样分布也是含有参数\theta的,这意味着y^{(k|n)}也是依赖于参数\theta的,所以要求\nabla_\theta J(\theta)的话,你还需要想办法求\nabla_{\theta}y^{(k|n)},只不过我们默认忽略了这部分梯度(没显式表达出它对\theta的依赖),只保留了\nabla_{\theta}\log p_\theta(y^{(k|n)}|x_t^{(n)})这部分,才得到它的梯度是策略梯度的“假象”。
所以,是我们人为地忽略了J(\theta)的一部分梯度,所以它的梯度才等于策略梯度,这是策略梯度的一个简单实现方法,但是对应的J(\theta)并不就是策略梯度的原函数。说白了,只是在代码实现上它的梯度是策略梯度,并不意味着在数学上成立。
此外,DL框架基本上都带有stop_gradient算子,我们很容易利用它来定义梯度相同,但是结果不止差一个常数的函数,比如\text{stop_gradient}(\text{relu}(x)-x)+x,这个函数在计算数值时不受任何影响,它等价于\text{relu}(x)-x+x=\text{relu}(x),但是求梯度,由于\text{relu}(x)-x的梯度被停止了,因此等价于求x的梯度,也就是1。这样我们就定义了一个梯度为1的\text{relu}(x)。
感谢苏神的详细解答!采样那个地方我之前确实没想明白,原来采样的过程中受参数影响这件事儿还得认真考虑。不过这么想以后,我忽然觉得直接拿J(\theta)做梯度上升感觉有点草率...
p.s. \rm sg[·]这个操作好bug啊,有点颠覆我微积分知识的意味。不知道在分析的时候能否找到合适的数学模型来做推导,还是完全没必要以分析的工具研究它,而只是把它视为一种工程上的trick...
按照常规的实现方式,J(\theta)的梯度确实等于策略梯度,所以实现上没毛病。
logpθ(y(k)|x(k)t) 为什么知道是负的啊?
因为概率小于1
October 31st, 2020
公式(14)是否应该写为\mathbb{E}_{u\sim p(u)}\left[\left(\frac{f(x+\varepsilon u)-b}{\varepsilon}\right)^2||u||^2 \right]
对的对的,已经修正,谢谢。
April 16th, 2022
苏神你好!能详细解释一下零阶梯度的定义那里吗,为什么后面要乘个u,而分母那里没有u呢
因为梯度要是一个向量,\frac{f(x + \varepsilon u) - f(x)}{\varepsilon}只是一个标量。零阶梯度其实就是想得到一个随机向量作为梯度的近似,并且在平均意义下等于精确的梯度(即(12)式)