RLHF -- From Zero to PPO 理论篇

本文最后更新于:2025年2月16日 晚上

RLHF: From Zero to PPO 理论篇

1 强化学习101

1.1 建立基本框架

假设我们有一个个体(agent),其处在某个环境中,个体在这个环境里一定会存在一个状态(state)(空间中的位置,时间中的某一刻),个体会采取某个行动(action)(例如空间中移动)导致状态更新。个体行动的方式被policy建模。

policy的作用是使用概率建模个体在某个状态下采取某个行动的概率。假设时间步表示为t,则

atπ(st)a_t \sim \pi(\cdot|s_t)

即个体在状态sts_t下采取某个行动ata_t的概率分布是π(st)\pi(\cdot|s_t)

而我们给个体采取的每个行动都给予一个打分,这个打分叫做奖励(reward),奖励规则就定义了我们想要个体采取怎样的行动。强化学习的目标就是去选择一个policy,使agent根据policy行动的时候能够获得最大的回报(return)。

1.2 与LLM的联系

如果我们把agent看作LLM,state看作prompt,action看作模型选择的下一个token,那么语言模型其实完全可以和RL对应起来。LLM对于语言建模的方式是下一个token的概率,即

P(yx)=ip(yix,y<i)P(y|x) = \prod_{i} p(y_i|x,y_{<i})

所以模型预测下一个token就是在采取action,其state就是输入的token,即context(预测第一个token前是prompt,预测输出后是prompt+已预测的token),我们的policy就是语言模型建模的下一个token的概率分布。

但给语言模型的action打分并非易事,首先,我们打分是对于一个完整的答案进行的,例如生成答案正确的给高分,生成错误的给低分。但是当给生成风格打分的时候会很困难,因为有的人可能喜欢长的答案,有的人喜欢精简的答案,所以不同人类之间给出的分数可能会有很大的方差。

我们采取比较的方式创建reward model,而不是分数。例如给出两个答案,人类选择哪个答案更喜欢。选择的答案称为(chosen/winner),抛弃的答案称为(reject/loser)。

在实际操作中,我们一般直接拿一个预训练好的LLM,将其head替换为一个 scalar head,其将hidden state投影到一个常数,这个常数就代表某个token的reward。我们一般取eos_token的reward作为整个回答的reward。

训练reward model的方式很简单,其优化目标为

arg minθlogσ(rθ(x,yw)rθ(x,yl))\argmin_{\theta} -\log \sigma(r_\theta(x,y_w)-r_\theta(x,y_l))

观察公式不难发现,优化就是提高模型对于ywy_w(winner)的输出,降低模型对于yly_l(loser)的输出。其中σ\sigma是sigmoid函数。

1.3 轨迹(trajectories)

上文中提到,RL的目标是个体根据policy行动的最大化回报,即

π=arg maxπJ(π)\pi^*=\argmax_{\pi}J(\pi)

这里J(π)J(\pi)就是个体根据policy行动的回报,其定义为

J(π)=τP(τπ)R(τ)dτ=Eτπ[R(τ)]J(\pi) = \int_{\tau} P(\tau|\pi)R(\tau)d\tau = E_{\tau\sim\pi}[R(\tau)]

其中τ\tau是trajectory,定义为

τ=(s0,a0,s1,a1,)\tau = (s_0,a_0,s_1,a_1,\dots)

即模型从初始状态s0s_0开始采取一系列行动的序列。所以,计算J(π)J(\pi)就是计算trajectory的reward的期望,因为trajectory是随机的,所以这里是求概率期望。我们把trajectory的概率分布定义为

P(τπ)=ρ0(s0)t=0T1P(st+1st,at)π(atst)P(\tau|\pi) = \rho_0(s_0)\prod_{t=0}^{T-1}P(s_{t+1}|s_t,a_t)\pi(a_t|s_t)

即,一个Markov链,从状态s0s_0的概率ρ0(s0)\rho_0(s_0)开始,状态分布st+1s_{t+1}的概率只与上一个状态sts_t和采取的行动ata_t有关,action分布由π(atst)\pi(a_t|s_t)给出。概率分布是有关状态转移的一个Markov链。

最后,我们在reward建模上有一些trick,我们建模一个有衰减的reward,而不是简单的求和

R(τ)=t=0γtrtR(\tau) = \sum_{t=0}^\infty \gamma^t r_t

其中rtr_t是某个时间步tt下对于action ata_t的打分。γ\gamma则一般是一个0到1的数字,使得未来的奖励变小。

语言建模中对于轨迹的定义稍有区别,由于自回归的特性,在这里action本身将成为state一部分,例如

prompt: Where is Shanghai?
Response: Shanghai is in China.

"where is Shanghai?"作为状态s0s_0,采取行动a0a_0输出token “Shanghai”,之后"where is Shanghai? Shanghai"将一起作为状态s1s_1,使得模型采取行动a1a_1输出token “is”,然后与之前的token拼接一起组成状态s2s_2:“where is Shanghai? Shanghai is”.

1.4 优化policy

我们已经完成了对目标函数的建模,即

J(πθ)=Eτπθ[R(τ)]J(\pi_\theta) = E_{\tau\sim \pi_\theta}[R(\tau)]

我们的目标就是去找一个πθ\pi_\theta最大化这个函数。一般来讲,我们可以使用梯度方法更新,

θk+1=θk+αθJ(πθ)θk\theta_{k+1} = \theta_k + \alpha \nabla_\theta J(\pi_\theta)|_{\theta_k}

在这里,因为我们是最大化目标函数,与loss的优化不一样,所以我们需要梯度上升,在这里是加上梯度的方向,而不是优化loss时减去梯度方向。

但紧接着会发现一个问题,我们计算期望需要采样出所有可能的τ\tau,即trajectory,当我们状态空间很大的时候(例如LLM每预测一个token都有其词表大小这么多的可能性),计算这个目标函数几乎是不可能的。

那么,能不能尝试把这个期望的梯度θEτπθ[R(τ)]\nabla_\theta E_{\tau \sim \pi_\theta}[R(\tau)]想办法变成梯度的期望呢?

我们从目标函数的梯度开始做推导

θJ(πθ)=θEτπθ[R(τ)]=θτP(τθ)R(τ)dτ=τθP(τθ)R(τ)dτ\begin{aligned} \nabla_\theta J(\pi_\theta) &= \nabla_\theta E_{\tau \sim \pi_\theta}[R(\tau)] \\ &=\nabla_\theta \int_{\tau}P(\tau|\theta)R(\tau)d\tau \\ &=\int_{\tau}\nabla_\theta P(\tau|\theta)R(\tau)d\tau \\ \end{aligned}

注意到

θlogP(τθ)=θP(τθ)P(τθ)θP(τθ)=P(τθ)θlogP(τθ)\nabla_\theta \log P(\tau|\theta) = \frac{\nabla_\theta P(\tau|\theta)}{P(\tau|\theta)} \Rightarrow \nabla_\theta P(\tau|\theta) = P(\tau|\theta)\nabla_\theta \log P(\tau|\theta)

这里因为是优化目标所以省略log\log求导出来的常数,以上变换也叫做log-derivative trick.

所以

τθP(τθ)R(τ)dτ=τP(τθ)θlogP(τθ)R(τ)dτ=Eτπθ[θlogP(τθ)R(τ)]\begin{aligned} \int_{\tau}\nabla_\theta P(\tau|\theta)R(\tau)d\tau &= \int_\tau P(\tau|\theta)\nabla_{\theta}\log P(\tau|\theta)R(\tau)d\tau \\ &=E_{\tau\sim \pi_\theta}[\nabla_\theta \log P(\tau|\theta)R(\tau)] \end{aligned}

注意到上式还可以进一步简化,之前我们定义过

P(τπ)=ρ0(s0)t=0T1P(st+1st,at)π(atst)P(\tau|\pi) = \rho_0(s_0)\prod_{t=0}^{T-1}P(s_{t+1}|s_t,a_t)\pi(a_t|s_t)

θlogP(τθ)=θρ0(s0)+t=0T1(θP(st+1st)+θlogπθ(atst))=t=0T1θlogπθ(atst)\begin{aligned} \nabla_\theta \log P(\tau|\theta) &= \nabla_\theta \rho_0(s_0) + \sum_{t=0}^{T-1}\left(\nabla_\theta P(s_{t+1}|s_t)+\nabla_\theta \log \pi_\theta (a_t|s_t)\right) \\ &=\sum_{t=0}^{T-1}\nabla_\theta\log\pi_\theta (a_t|s_t) \end{aligned}

所以我们得到

θJ(πθ)=Eτπθ[R(τ)t=0T1θlogπθ(atst)]\nabla_\theta J(\pi_\theta)=E_{\tau\sim \pi_\theta}\left[R(\tau)\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_t|s_t)\right]

对于一个纯期望的表达式,我们可以用样本期望去逼近概率期望,即采样一部分trajectory构成集合DD,然后将梯度估计为

1DτDR(τ)t=0T1θlogπθ(atst)\frac{1}{|D|}\sum_{\tau\in D}R(\tau)\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_t|s_t)

1.5 去除bias和variance

对于我们在上面找到的梯度

1DτDR(τ)t=0T1θlogπθ(atst)\frac{1}{|D|}\sum_{\tau\in D}R(\tau)\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_t|s_t)

是无偏的,即取足够多的trajectories它会收敛到真正的梯度。但当采样的trajectory不够多的时候会有很大的方差。

但注意到,我们估计的梯度实际上可以写为

1Di=1D(t=0T1r(si,t,ai,t))(t=0T1θlogπθ(ai,tsi,t))\frac{1}{|D|}\sum_{i=1}^{|D|}\left(\sum_{t=0}^{T-1}r(s_{i,t},a_{i,t})\right)\left(\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_{i,t}|s_{i,t})\right)

这里r(si,t,ai,t)r(s_{i,t},a_{i,t})代表第ii个trajectory下对于t时刻的状态采取的action ai,ta_{i,t}的reward。

即我们的R(τ)R(\tau)是一个总的R(τ)R(\tau),每一个时间步我们都乘上了总的reward。而可以通过数学证明,历史时刻的reward是在期望计算中抵消的。所以我们的梯度可以写为

1Di=1D(t=0T1θlogπθ(ai,tsi,t)(t=tT1r(si,t,ai,t))rewards to go)\frac{1}{|D|}\sum_{i=1}^{|D|}\left(\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_{i,t}|s_{i,t})\underbrace{\left(\sum_{t‘=t}^{T-1}r(s_{i,t'},a_{i,t'})\right)}_{\text{rewards to go}}\right)

即计算到时刻tt的时候,我们只乘上从tt开始到总时间步的累计reward,而不包含时刻tt之前的。减少估计的期望数量也就间接减少了variance。

但是,reward本身也是有噪且稀疏的,这也会导致估计的梯度variance很高。在信号处理中我们都知道,要降低噪声,最好的办法是使用差值。所以,我们尝试在reward中减去一个baseline

1Di=1D(t=0T1θlogπθ(ai,tsi,t)(t=tT1r(si,t,ai,t)b))\frac{1}{|D|}\sum_{i=1}^{|D|}\left(\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_{i,t}|s_{i,t})\left(\sum_{t‘=t}^{T-1}r(s_{i,t'},a_{i,t'})-b\right)\right)

可以证明减去baseline之后梯度估计仍然无偏。

在这里,我们定义baseline为某种value function,给定一个状态sts_t,value function可以估计当前状态的价值。在这里,价值指的是状态sts_t是否重要或是否有价值。例如,我们回答"where is Shanghai?“,在状态"where is Shanghai? Shanghai is in"的价值就非常高,因为我们只剩下一个token就能准确的预测答案。但如果我们处在状态"where is Shanghai? Chocolate…”,这个状态的价值就非常低,因为我们极有可能预测出一个完全无关的答案。

我们记这个value function为Vπ(s)V^\pi(s),接下来我们正式定义value function:value function是指当个体处在状态ss并根据policy行动,未来得到的总的reward是多少。即

Vπ(st)=Eat[r(st,at)+γEst+1[Vπ(st+1)]]V^\pi (s_t) = E_{a_t}[r(s_t,a_t)+\gamma E_{s_{t+1}}[V^\pi(s_{t+1})]]

我们将value function用作baseline来计算reward和其的差值。在实现上,value function也是一个LLM+scalar head的配置,其负责预测每个时间步的价值。也就是说,我们直接用模型学一个value function出来。

在这里,我们再升级之前得到的"rewards to go"为Q function。Q function告诉我们从状态sts_t开始,做出action ata_t,然后根据policy来行动,我得到的总回报(总reward)是多少。我们还可以定义一个Q function的递归形式

Qπ(st,at)=Est+1[r(st,at)+γEat+1[Qπ(st+1,at+1)]]Q^\pi(s_t,a_t) = E_{s_{t+1}}[r(s_t,a_t)+\gamma E_{a_{t+1}}[Q^\pi (s_{t+1},a_{t+1})]]

即,从状态sts_t出发,做出action ata_t的即时奖励加上discount factor γ\gamma乘以下一个状态的Q function,在这里,期望遍历了所有可能的下一个状态st+1s_{t+1}以及所有可能在下一个状态采取的行动at+1a_{t+1}

结合Q function和我们之前介绍的value function,我们的公式变为

1Di=1D(t=0T1θlogπθ(ai,tsi,t)(Qπ(si,t,ai,t)Vπ(si,t)))=1Di=1D(t=0T1θlogπθ(ai,tsi,t)Aπ(si,t,ai,t))\begin{aligned} &\frac{1}{|D|}\sum_{i=1}^{|D|}\left(\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_{i,t}|s_{i,t})\left(Q^\pi(s_{i,t},a_{i,t})-V^\pi (s_{i,t})\right)\right)\\ &=\frac{1}{|D|}\sum_{i=1}^{|D|}\left(\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_{i,t}|s_{i,t})A^\pi (s_{i,t},a_{i,t})\right) \end{aligned}

函数Aπ(si,t,ai,t)=Qπ(si,t,ai,t)Vπ(si,t)A^\pi (s_{i,t},a_{i,t})=Q^\pi(s_{i,t},a_{i,t})-V^\pi (s_{i,t})称作advantage function。观察公式,这个差值实际上是在计算状态sts_t下,采取行动ata_t,然后根据policy行动获得的总回报减去目前状态的价值,也就是在间接衡量采取行动ata_t有多好。比如,在回答问题"where is Shanghai?"的时候,第一个词选择"Shanghai"的优势会比"chocolate"高(value在这个状态下不变,所以不同action会导致不同的advantage)。

但是计算advantage function是很困难的,主要在于Q function很难去直接计算,在这里,我们使用TD(Temporal Difference) error来近似估计advantage function。

Aπ(si,t,ai,t)=Qπ(si,t,ai,t)Vπ(si,t)r(st,at)+γVπ(st+1)Vπ(st)\begin{aligned} A^\pi (s_{i,t},a_{i,t})&=Q^\pi(s_{i,t},a_{i,t})-V^\pi (s_{i,t}) \\ &\approx r(s_t,a_t) + \gamma V^\pi(s_{t+1}) - V^{\pi}(s_t) \end{aligned}

其中δt=r(st,at)+γVπ(st+1)Vπ(st)\delta_t=r(s_t,a_t) + \gamma V^\pi(s_{t+1}) - V^{\pi}(s_t)被称为TD error。

但仅仅有一个真实的rewardr(st,at)r(s_t,a_t)会导致很大的bias,考虑以下求和

A^tπ,(1)=δt=r(st,at)+γVπ(st+1)Vπ(st)A^tπ,(2)=δt+γδt+1=r(st,at)+γr(st+1,at+1)+γ2Vπ(st+2)Vπ(st)A^tπ,(3)=δt+γδt+1+γ2δt+2=r(st,at)+γr(st+1,at+1)+γ2r(st+2,at+2)+γ3Vπ(st+3)Vπ(st)\begin{aligned} &\hat A^{\pi,(1)}_t = \delta_t = r(s_t,a_t) + \gamma V^\pi(s_{t+1}) - V^{\pi}(s_t) \\ &\hat A^{\pi,(2)}_t = \delta_t + \gamma \delta_{t+1} = r(s_t,a_t)+\gamma r(s_{t+1},a_{t+1})+\gamma^2 V^\pi (s_{t+2}) - V^\pi (s_t)\\ &\hat A^{\pi,(3)}_t = \delta_t + \gamma \delta_{t+1} + \gamma^2 \delta_{t+2} = r(s_t,a_t)+\gamma r(s_{t+1},a_{t+1})+\gamma^2 r(s_{t+2},a_{t+2}) +\gamma^3 V^\pi(s_{t+3})- V^\pi (s_t)\\ &\cdots \end{aligned}

当我们求和越来越多的时候,可以证明advantage function的估计的bias会越来越小。但是更多的求和项也会带来更大的variance,所以,为了平衡bias-variance,我们直接对上述的项进行加权求和

A^tπ=(1λ)(A^tπ,(1)+λA^tπ,(2)+λ2A^tπ,(3)+)=l=0(γλ)lδt+l\begin{aligned} \hat A^{\pi}_t &= (1-\lambda)(\hat A^{\pi,(1)}_t+\lambda \hat A^{\pi,(2)}_t+\lambda^2\hat A^{\pi,(3)}_t+\cdots) \\ &=\sum_{l=0}^\infty (\gamma \lambda)^l\delta_{t+l} \end{aligned}

上式称作Generalized Advantage Estimation(GAE)

不难发现

A^tπ=l=0(γλ)lδt+l=δt+l=1(γλ)lδt+l=i=l1δt+i=0(γλ)i+1δt+i+1δt+γλA^t+1π\begin{aligned} \hat A^{\pi}_{t} &=\sum_{l=0}^\infty (\gamma \lambda)^l\delta_{t+l}\\ &=\delta_t + \sum_{l=1}^\infty (\gamma\lambda)^l \delta_{t+l}\\ &\overset{i=l-1}{=}\delta_t + \sum_{i=0}^\infty (\gamma\lambda)^{i+1}\delta_{t+i+1} \Leftrightarrow \delta_t + \gamma\lambda \hat A^{\pi}_{t+1} \end{aligned}

即GAE也存在recursive的形式。

1.6 离策略(off-policy)方法

使用上述的梯度估计方法还存在一个问题,回顾我们找到的梯度估计方法

θJ(πθ)=1Di=1D(t=0T1θlogπθ(ai,tsi,t)Aπ(si,t,ai,t))\nabla_\theta J(\pi_\theta) = \frac{1}{|D|}\sum_{i=1}^{|D|}\left(\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_{i,t}|s_{i,t})A^\pi (s_{i,t},a_{i,t})\right)

我们通过梯度上升更新参数

θk+1=θk+αθJ(πθ)θk\theta_{k+1} = \theta_k + \alpha \nabla_\theta J(\pi_\theta)|_{\theta_k}

这样一来,我们每次更新参数的时候都要去采样trajectories,模型参数一更新,就得重新采样新的trajectories,这样一来是inefficient的。

在这里,我们使用importance sampling来重新写我们的目标函数。对于某个复合函数随机变量的期望,我们可以这样计算

Exp(x)[f(x)]=p(x)f(x)dx=q(x)q(x)p(x)f(x)dx=q(x)p(x)q(x)f(x)dx=Exq(x)[p(x)q(x)f(x)]\begin{aligned} E_{x\sim p(x)}[f(x)] &= \int p(x)f(x)dx \\ &=\int \frac{q(x)}{q(x)}p(x)f(x)dx \\ &=\int q(x)\frac{p(x)}{q(x)}f(x)dx \\ &=E_{x\sim q(x)}\left[\frac{p(x)}{q(x)}f(x)\right] \end{aligned}

这样一来,我们对xx的概率分布的期望p(x)p(x)转移到了另一个概率分布q(x)q(x)

对于原始带期望的目标函数,我们可以变换为

θJ(πθ)=Eτπθ[t=0T1θlogπθ(atst)Aπ(st,at)]=Eτπoffline[t=0T1πonline(atst)πoffline(atst)(t=0T1θlogπonline(atst)Aπ(st,at))]where online=θ\begin{aligned} \nabla_\theta J(\pi_\theta)&=E_{\tau\sim \pi_\theta}\left[\sum_{t=0}^{T-1}\nabla_\theta \log \pi_\theta (a_t|s_t)A^\pi (s_{t},a_{t})\right] \\ &=E_{\tau\sim \pi_{\text{offline}}}\left[\prod_{t=0}^{T-1}\frac{\pi_{\text{online}}(a_t|s_t)}{\pi_{\text{offline}}(a_t|s_t)}\left(\sum_{t=0}^{T-1}\nabla_\theta \log \pi_{\text{online}} (a_t|s_t)A^\pi (s_{t},a_{t})\right)\right] \\ &\text{where}\ \text{online} = \theta \end{aligned}

注意到我们梯度只针对于online模型,offline是不更新的,因为这个比例类似于加权系数,对每个样本加权就类似于对每个样本赋予一个重要度,所以叫importance sampling。

但在一些文献里面,研究者们直接优化一个更简单的目标函数

θonline=1Di=1D(t=0T1θonlinelogπθonline(ai,tsi,t)logπθoffline(ai,tsi,t)Aπ(si,t,ai,t))\nabla_{\theta_{\text{online}}} = \frac{1}{|D|}\sum_{i=1}^{|D|}\left(\sum_{t=0}^{T-1}\nabla_{\theta_{\text{online}}} \frac{\log \pi_{\theta_{\text{online}}} (a_{i,t}|s_{i,t})}{\log \pi_{\theta_{\text{offline}}} (a_{i,t}|s_{i,t})}A^\pi (s_{i,t},a_{i,t})\right)

笔者注: 可在TRPO中找到相关做法,但似乎并没有解释为什么这么做,也没有解释数学上和优化目标上的区别等等。

Schulman, John. “Trust Region Policy Optimization.” arXiv preprint arXiv:1502.05477 (2015). https://arxiv.org/abs/1502.05477

注意到上式中我们采样的DD来自于offline policy。而我们参数更新只在online上做。因为trajectory来自于另一个分布,所以我们完全可以事先采样大量的trajectories,然后取一个minibatch去更新online policy,因为我们用的另一个分布的trajectory,所以即使在参数更新的一个step中我们的online policy变了,我们仍然可以使用来自offline policy的trajectories继续进行下一个step的参数更新,甚至训练几个epoch。

从数学角度讲,原来的期望在θ\theta或者online中sample的trajectories上做,所以每当进行新的梯度估计的时候(即一个step结束计算下一个step的梯度),我们都需要在现在的θ\theta上采样trajectories。当期望换为在另一个不随时更新的 policy offline上做之后,我们采样的trajectories都来自于这个恒定的policy,所以可以直接做下一个step的梯度估计,我们只需要提前采样大量的trajectories。

在实际操作过程中,我们的θoffline\theta_{\text{offline}}θonline\theta_{\text{online}}在一开始都是同一个LLM,我们在其中采样大量的trajectories,然后使用mini-batch更新方法更新θonline\theta_{\text{online}},在采样的所有trajectories用完之后,我们另θoffline=θonline\theta_{\text{offline}}=\theta_{\text{online}},然后重复这个过程。

2 PPO算法

2.1 TRPO

PPO算法从TRPO开始改进,TRPO优化一个更为简单的目标

maxθE^t[πθ(atst)πold(atst)A^tβKL[πold(st)πθ(st)]]\max_{\theta} \mathbb{\hat E}_t\left[\frac{\pi_{\theta}(a_t|s_t)}{\pi_{\text{old}}(a_t|s_t)}\hat A_t-\beta \text{KL}[\pi_{\text{old}}(\cdot|s_t)||\pi_\theta(\cdot|s_t)]\right]

注意到这里加了一个KL散度,保证训练过的模型的分布与之前模型的分布的差距不会偏移太多,这在做RLHF时是很有用的,模型可能因为RLHF的偏好对齐忘记世界知识,或者发生reward hacking,例如我们的reward model教模型输出礼貌的回答,但模型完全只输出"Thank you",虽然能满足reward model的要求,但是其功能已经丧失。

但是,作者claim仅仅使用一个固定的β\beta来做KL散度的限制是不够的,所以他们提出对函数进行裁剪。

2.2 Clipped surrogate

rt(θ)=πθ(atst)πθold(atst)r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{\text{old}}}(a_t|s_t)},这个概率比例就反应了我们目前更新的policy与其之前分布的不同。作者认为,直接优化这个目标可能导致特别大的policy更新,所以他们直接通过裁切防止rt(θ)r_t(\theta)偏离1太远。

LCLIP(θ)=E^t[min(rt(θ)A^t,clip(rt(θ),1ϵ,1+ϵ)A^t)]L^{\text{CLIP}}(\theta) = \mathbb{\hat E}_t[\min(r_t(\theta)\hat A_t,\text{clip}(r_t(\theta),1-\epsilon, 1+\epsilon)\hat A_t)]

A^t>0\hat A_t>0, rt(θ)>1+ϵr_t(\theta) > 1+\epsilon,我们得到

min(rt(θ)A^t,clip(rt(θ),1ϵ,1+ϵ)A^t)=min(rt(θ)A^t,(1+ϵ)A^t)=(1+ϵ)A^t\begin{aligned} \min(r_t(\theta)\hat A_t,\text{clip}(r_t(\theta),1-\epsilon, 1+\epsilon)\hat A_t) &= \min(r_t(\theta)\hat A_t, (1+\epsilon)\hat A_t) \\ &=(1+\epsilon)\hat A_t \end{aligned}

A^t>0\hat A_t>0, rt(θ)<1ϵr_t(\theta) < 1-\epsilon,我们得到

min(rt(θ)A^t,clip(rt(θ),1ϵ,1+ϵ)A^t)=min(rt(θ)A^t,(1ϵ)A^t)=rt(θ)A^t\begin{aligned} \min(r_t(\theta)\hat A_t,\text{clip}(r_t(\theta),1-\epsilon, 1+\epsilon)\hat A_t) &= \min(r_t(\theta)\hat A_t, (1-\epsilon)\hat A_t) \\ &=r_t(\theta)\hat A_t \end{aligned}

A^t>0\hat A_t>0的时候,如果policy关于action过于自信,那么概率比就被截断。但不如原来的 policy自信的时候我们仍然按照之前的方法自然更新。

A^t<0\hat A_t <0, rt(θ)>1+ϵr_t(\theta) > 1+\epsilon,我们得到

min(rt(θ)A^t,clip(rt(θ),1ϵ,1+ϵ)A^t)=min(rt(θ)A^t,(1+ϵ)A^t)=rt(θ)A^t\begin{aligned} \min(r_t(\theta)\hat A_t,\text{clip}(r_t(\theta),1-\epsilon, 1+\epsilon)\hat A_t) &= \min(r_t(\theta)\hat A_t, (1+\epsilon)\hat A_t) \\ &=r_t(\theta)\hat A_t \end{aligned}

A^t<0\hat A_t<0, rt(θ)<1ϵr_t(\theta) < 1-\epsilon,我们得到

min(rt(θ)A^t,clip(rt(θ),1ϵ,1+ϵ)A^t)=min(rt(θ)A^t,(1ϵ)A^t)=(1ϵ)A^t\begin{aligned} \min(r_t(\theta)\hat A_t,\text{clip}(r_t(\theta),1-\epsilon, 1+\epsilon)\hat A_t) &= \min(r_t(\theta)\hat A_t, (1-\epsilon)\hat A_t) \\ &=(1-\epsilon)\hat A_t \end{aligned}

即当A^t<0\hat A_t<0的时候,如果policy关于这个action不如原policy自信,则截断。如果比原policy自信,则自然更新。

rt(θ)r_t(\theta)处在[1ϵ,1+ϵ][1-\epsilon,1+\epsilon]的时候我们得到的就是原来的目标函数。

2.3 PPO objective

PPO 的完整目标函数如下

LtCLIP+VF+S(θ)=E^t[LtCLIP(θ)c1LtVF(θ)+c2S[πθ](st)]L_t^{\text{CLIP}+\text{VF}+\text{S}}(\theta)=\mathbb{\hat E}_t [L_t^{\text{CLIP}}(\theta)-c_1L_t^{\text{VF}}(\theta)+c_2 S[\pi_\theta](s_t)]

我们首先在最大化第一项,即LtCLIP(θ)L_t^{\text{CLIP}}(\theta),即最大化我们的advantage,是传统的RL目标。第二项是

LtVF(θ)=Vθ(s)t=0T1(γtrts0=s)22L_t^{\text{VF}}(\theta)=\left\|V_\theta(s)-\sum_{t=0}^{T-1}(\gamma^t r_t|s_0=s) \right\|_2^2

即使用回归目标让value模型学习我们估计出来的value。系数c1c_1一般是1/21/2。这一项在目标中是被最小化的,即value模型估计出来的value应该和我们用reward估计出来的value接近。

第三项是Entropy loss,即直接计算概率分布的entropy。

S[πθ](st)=xπθ(xst)logπθ(xst)S[\pi_\theta](s_t) = -\sum_x \pi_\theta(x|s_t)\log \pi_\theta (x|s_t)

Entropy的最大值在概率分布等概的时候取到,而这一项在优化过程中是被放大的,所以我们是在约束policy对于所有选择也尽可能的均匀。这虽然违背我们学习的目标----学到一个能根据state做出有效判断的policy,但增大entropy也可以鼓励policy去探索不同的可能性,在学习目标的同时保证一定的多样性。


RLHF -- From Zero to PPO 理论篇
https://jesseprince.github.io/2025/02/13/aigcs/rlhf/ppo_from_start/
作者
林正
发布于
2025年2月13日
许可协议