当前位置: 首页 > news >正文

网站的交互设计包括哪些/seo基本步骤

网站的交互设计包括哪些,seo基本步骤,网站内页权重查询,七星迪曼网站建设由于平台字数限制,上文:https://blog.csdn.net/ooblack/article/details/144198538 4. PPO算法 近端策略优化(proximal policy optimization,PPO)算法是OpenAI的默认强化学习算法,在RLHF中也用到了这个算…

由于平台字数限制,上文:https://blog.csdn.net/ooblack/article/details/144198538

4. PPO算法

近端策略优化(proximal policy optimization,PPO)算法是OpenAI的默认强化学习算法,在RLHF中也用到了这个算法,说明这个算法还是很强的,那它到底解决了一个什么问题呢?

先介绍两个概念,同策略学习(On-Policy Learning)和异策略学习(Off-Policy Learning),在强化学习里面,要学习的是一个智能体。如果要学习的智能体和与环境交互的智能体是相同的,我们称之为同策略。如果要学习的智能体和与环境交互的智能体不是相同的,我们称之为异策略。

PPO的主要解决的问题是什么呢?

无论是A2C算法还是REINFOCE算法,都有一个问题,数据在采样完成,更新模型一次之后就丢弃了,前文不止一次强调过,数据采样是很昂贵且费事的,只用一次就丢显然是不合理的,但是数据用一次之后模型已经更新了,旧的数据是旧的模型产生的不能用来更新新的模型,PPO就是用来解决这个问题的。

它的思路是这样的,我们用梯度下降去降低损失,由于学习率的问题,我们可能方向对了,但是步子迈小了,所以用旧数据再去更新一次,再迈一步,但是直觉告诉我们不能一直用旧数据,因为模型参数多迭代几次之后可能跟产生旧数据的旧模型完全不一样了,PPO最大的贡献就在于它告诉模型什么时候旧数据不能再用了,定量分析了新模型与旧模型的差距。

这里先介绍重要性采样的概念。

4.1 重要性采样

假设我们有一个函数 f ( x ) f(x) f(x),要计算从分布 p p p 采样 x x x,再把 x x x 代入 f f f,得到 f ( x ) f(x) f(x)。我们该怎么计算 f ( x ) f(x) f(x) 的期望值呢?假设我们不能对分布 p p p 做积分,但可以从分布 p p p 采样一些数据 x i x^i xi。把 x i x^i xi 代入 f ( x ) f(x) f(x),取它的平均值,就可以近似 f ( x ) f(x) f(x)​ 的期望值。
E x ∼ p [ f ( x ) ] ≈ 1 N ∑ i = 1 N f ( x i ) \mathbb{E}_{x \sim p}[f(x)] \approx \frac{1}{N} \sum_{i=1}^{N} f(x^i) Exp[f(x)]N1i=1Nf(xi)

现在有另外一个问题,假设我们不能从分布 p p p 采样数据,只能从另外一个分布 q q q 采样数据 x i x^i xi q q q 可以是任何分布。如果我们从 q q q 采样 x i x^i xi,就不能使用刚刚的方法。因为刚刚的方法需要从 p p p里面采样。

但是我硬要从 q q q里面采,神奇的数学会给出解决方案:
E x ∼ p [ f ( x ) ] = ∫ f ( x ) p ( x ) d x = ∫ f ( x ) p ( x ) q ( x ) q ( x ) d x = E x ∼ q [ f ( x ) p ( x ) q ( x ) ] \begin{align} \mathbb{E}_{x \sim p}[f(x)] &= \int f(x)p(x)dx \\ &= \int f(x) \frac{p(x)}{q(x)} q(x) dx \\&= \mathbb{E}_{x \sim q} \left[ f(x) \frac{p(x)}{q(x)} \right] \end{align} Exp[f(x)]=f(x)p(x)dx=f(x)q(x)p(x)q(x)dx=Exq[f(x)q(x)p(x)]
我们就可以写成对 q q q里面所采样出来的 x 取期望值。我们从 q q q里面采样 x x x,再计算 f ( x ) p ( x ) q ( x ) f(x){\frac{p(x)}{q(x)}} f(x)q(x)p(x),再取期望值。所以就算我们不能从 p p p里面采样数据,但只要能从 q q q里面采样数据,就可以计算从 p p p采样 x x x代入 f f f​以后的期望值。

其中 f ( x ) p ( x ) q ( x ) f(x){\frac{p(x)}{q(x)}} f(x)q(x)p(x)称作重要性权重。它主要用来修正两个分布之间的差异,但是它也不是万能的,通过上面的式子我们能看出它只能保证两种采样方法的期望相同,没说方差相同,如果方差巨大的话,也达不到我们想要的效果,两个分布的方差如下( Var [ X ] = E [ X 2 ] − ( E [ X ] ) 2 \text{Var}[X] = \mathbb{E}[X^2] - \left(\mathbb{E}[X]\right)^2 Var[X]=E[X2](E[X])2
Var x ∼ p [ f ( x ) ] = E x ∼ p [ f ( x ) 2 ] − ( E x ∼ p [ f ( x ) ] ) 2 Var x ∼ q [ f ( x ) p ( x ) q ( x ) ] = E x ∼ q [ ( f ( x ) p ( x ) q ( x ) ) 2 ] − ( E x ∼ q [ f ( x ) p ( x ) q ( x ) ] ) 2 = E x ∼ p [ f ( x ) 2 p ( x ) q ( x ) ] − ( E x ∼ p [ f ( x ) ] ) 2 \begin{align*} \text{Var}_{x \sim p}[f(x)] &= \mathbb{E}_{x \sim p} \left[ f(x)^2 \right] - \left(\mathbb{E}_{x \sim p}[f(x)]\right)^2 \\ \text{Var}_{x \sim q} \left[f(x) \frac{p(x)}{q(x)} \right] &= \mathbb{E}_{x \sim q} \left[ \left(f(x) \frac{p(x)}{q(x)}\right)^2 \right] - \left(\mathbb{E}_{x \sim q} \left[ f(x) \frac{p(x)}{q(x)}\right] \right)^2 \\ &= \mathbb{E}_{x \sim p} \left[ f(x)^2 \frac{p(x)}{q(x)} \right] - \left(\mathbb{E}_{x \sim p}[f(x)]\right)^2 \end{align*} Varxp[f(x)]Varxq[f(x)q(x)p(x)]=Exp[f(x)2](Exp[f(x)])2=Exq[(f(x)q(x)p(x))2](Exq[f(x)q(x)p(x)])2=Exp[f(x)2q(x)p(x)](Exp[f(x)])2
可以看到对 q q q分布采样的方差比对 p p p分布采样的方差多乘了一个 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x),所以就一件事, p p p q q q的分布要尽量相似用这个方法才能有一个很好的效果。下面举个例子来说明这一点:

例如,当 p ( x ) p(x) p(x) q ( x ) q(x) q(x) 差距很大时,就会有问题。如图所示,假设蓝线是 p ( x ) p(x) p(x) 的分布,绿线是 q ( x ) q(x) q(x) 的分布,红线是 f ( x ) f(x) f(x)。如果我们要计算 f ( x ) f(x) f(x) 的期望值,从分布 p ( x ) p(x) p(x) 做采样,显然 E x ∼ p [ f ( x ) ] \mathbb E_{x \sim p}[f(x)] Exp[f(x)] 是负的。这是因为左边区域 p ( x ) p(x) p(x) 的概率很高,所以采样会到这个区域,而 f ( x ) f(x) f(x) 在这个区域是负的,所以理论上这一项算出来会是负的。

接下来我们改成从 q ( x ) q(x) q(x) 采样,因为 q ( x ) q(x) q(x) 在右边区域的概率比较高,所以如果我们的采样点不够多,可能只会采样到右侧。如果我们只采样到右侧,可能 E x ∼ q [ f ( x ) p ( x ) q ( x ) ] \mathbb E_{x \sim q}[f(x)\frac{p(x)}{q(x)}] Exq[f(x)q(x)p(x)] 是正的。我们这边采样到这些点,去计算它们的 f ( x ) p ( x ) q ( x ) f(x)\frac{p(x)}{q(x)} f(x)q(x)p(x) 都是正的。我们采样到这些点都是正的,取期望值以后也是正的,这是因为采样的次数不够多。假设我们采样次数很少,只能采样到右边。左边虽然概率很低,但也有可能被采样到。假设我们好不容易采样到左边的点,因为左边的点的 p ( x ) p(x) p(x) q ( x ) q(x) q(x) 差是很多的,这边 p ( x ) p(x) p(x) 很大, q ( x ) q(x) q(x) 很小。 f ( x ) f(x) f(x) 好不容易终于采样到一个负的,这个负的就会被乘上一个非常大的权重,这样就可以平衡刚才那边一直采样到正的值的情况。最终我们算出这一项的期望值,终究还是负的。但前提是我们要采样足够多次,这件事情才会发生。但有可能采样次数不够多, E x ∼ p [ f ( x ) ] \mathbb E_{x \sim p}[f(x)] Exp[f(x)] E x ∼ q [ f ( x ) p ( x ) q ( x ) ] \mathbb E_{x \sim q}[f(x)\frac{p(x)}{q(x)}] Exq[f(x)q(x)p(x)]​ 可能就有很大的差距,这就是重要性采样的问题。

有了重要性采样,就可以使用旧模型参数 θ ′ {\theta'} θ采集到的数据来更新新的模型参数 θ \theta θ,旧模型记作 π θ \pi_{\theta} πθ,新模型记作 π θ ′ \pi_{\theta'} πθ

梯度公式:
∇ R ˉ θ = E τ ∼ p θ ( τ ) [ p θ ( τ ) p θ ′ ( τ ) R ( τ ) ∇ log ⁡ p θ ( τ ) ] \nabla \bar{R}_{\theta} = \mathbb{E}_{\tau \sim p^{\theta}(\tau)} \left[ \frac{p^{\theta}(\tau)}{p^{\theta'}(\tau)} R(\tau) \nabla \log p^{\theta}(\tau) \right] Rˉθ=Eτpθ(τ)[pθ(τ)pθ(τ)R(τ)logpθ(τ)]
这个公式是由REINFORCE的梯度公式加了一个重要性权重变换过来的。

状态动作对概率分开算:
E ( s t , a t ) ∼ π θ [ A θ ( s t , a t ) ∇ log ⁡ p θ ( a t ∣ s t ) n ] \mathbb{E}_{(s_t, a_t) \sim \pi_{\theta}} \left[ A^{\theta}(s_t, a_t) \nabla \log p_{\theta}(a_t|s_t)^n \right] E(st,at)πθ[Aθ(st,at)logpθ(atst)n]
这个式子表示在状态-动作对$ (s_t, a_t) $服从策略 π θ π_θ πθ 分布下的期望。其中 A θ ( s t , a t ) A^{\theta}(s_t, a_t) Aθ(st,at)表示的就是优势函数,之前在A2C算法里替换的那个,这里讨论的是重要性采样,继续使用 A θ ( s t , a t ) A^{\theta}(s_t, a_t) Aθ(st,at)来表示,最后在PPO算法里换成时序差分误差即可。

我们用状态-动作对$ (s_t, a_t) $服从策略 π θ ′ π_{\theta'} πθ 分布下的期望加上重要性权重 f ( x ) p ( x ) q ( x ) f(x){\frac{p(x)}{q(x)}} f(x)q(x)p(x)来近似$ (s_t, a_t) 在 在 π_θ$下的分布,即:
E ( s t , a t ) ∼ π θ ′ [ p θ ( s t , a t ) p θ ′ ( s t , a t ) A θ ( s t , a t ) ∇ log ⁡ p θ ( a t n ∣ s t n ) n ] \mathbb{E}_{(s_t, a_t) \sim \pi_{\theta'}} \left[ \frac{p_{\theta}(s_t, a_t)}{p_{\theta'}(s_t, a_t)} A^{\theta}(s_t, a_t) \nabla \log p_{\theta}(a_t^n|s_t^n)^n \right] E(st,at)πθ[pθ(st,at)pθ(st,at)Aθ(st,at)logpθ(atnstn)n]
由于:
p θ ( s t , a t ) = p θ ( a t ∣ s t ) p θ ( s t ) p θ ′ ( s t , a t ) = p θ ′ ( a t ∣ s t ) p θ ′ ( s t ) p_{\theta}(s_t, a_t) = p_{\theta}(a_t|s_t)p_{\theta}(s_t) \\ p_{\theta'}(s_t, a_t) = p_{\theta'}(a_t|s_t)p_{\theta'}(s_t) pθ(st,at)=pθ(atst)pθ(st)pθ(st,at)=pθ(atst)pθ(st)
因此:
E ( s t , a t ) ∼ π θ ′ [ p θ ( a t ∣ s t ) p θ ( s t ) p θ ′ ( a t ∣ s t ) p θ ′ ( s t ) A θ ′ ( s t , a t ) ∇ log ⁡ p θ ( a t n ∣ s t n ) n ] \mathbb{E}_{(s_t, a_t) \sim \pi_{\theta'}} \left[ \frac{p_{\theta}(a_t|s_t)p_{\theta}(s_t)}{p_{\theta'}(a_t|s_t)p_{\theta'}(s_t)} A^{\theta'}(s_t, a_t) \nabla \log p_{\theta}(a_t^n|s_t^n)^n \right] E(st,at)πθ[pθ(atst)pθ(st)pθ(atst)pθ(st)Aθ(st,at)logpθ(atnstn)n]
假设模型是 θ {\theta} θ的时候,我们看到 s t s_t st的概率,与模型是 θ ′ θ' θ的时候,我们看到 s t s_t st的概率是一样的,即 p θ ( s t ) = p θ ′ ( s t ) {p_{\theta}(s_t)} = {p_{\theta'}(s_t)} pθ(st)=pθ(st)。因此可得:
E ( s t , a t ) ∼ π θ ′ [ p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) A θ ′ ( s t , a t ) ∇ log ⁡ p θ ( a t n ∣ s t n ) n ] \mathbb{E}_{(s_t, a_t) \sim \pi_{\theta'}} \left[ \frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)} A^{\theta'}(s_t, a_t) \nabla \log p_{\theta}(a_t^n|s_t^n)^n \right] E(st,at)πθ[pθ(atst)pθ(atst)Aθ(st,at)logpθ(atnstn)n]
为什么可以这样假设呢?有很多种解释,有的说差的不远,有的说环境状态与动作关联性不是很强,也有的说随机系统怎么怎么滴,反正也不用纠结了,不这么干这个算法很难进行下去,这么做效果好就对了!

根据之前策略梯度算法里面的套路:
∇ J θ ′ ( θ ) = E ( s t , a t ) ∼ π θ ′ [ ∇ p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) A θ ′ ( s t , a t ) ] \nabla J^{\theta'}(\theta) = \mathbb{E}_{(s_t, a_t) \sim \pi_{\theta'}} \left[ \frac{\nabla p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)} A^{\theta'}(s_t, a_t) \right] Jθ(θ)=E(st,at)πθ[pθ(atst)pθ(atst)Aθ(st,at)]
那我们要优化的目标函数就是:
J θ ′ ( θ ) = E ( s t , a t ) ∼ π θ ′ [ p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) A θ ′ ( s t , a t ) ] J^{\theta'}(\theta) = \mathbb{E}_{(s_t, a_t) \sim \pi_{\theta'}} \left[ \frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)} A^{\theta'}(s_t, a_t) \right] Jθ(θ)=E(st,at)πθ[pθ(atst)pθ(atst)Aθ(st,at)]
我们本来是要在 θ \theta θ上进行采样来更新 θ \theta θ的,但是现在变成在 θ ′ \theta' θ上采样来更新 θ \theta θ了,那就由同策略学习变成了异策略学习。

以上就是重要性采样。它有一个显而易见的问题,就是新旧策略差距过大的话,旧策略采出来的数据意义就不是很大了,PPO算法就是为了解决这一问题。

4.2近端策略优化(PPO)

为了不使 p θ ( a t ∣ s t ) p_{\theta}(a_t|s_t) pθ(atst) p θ ′ ( a t ∣ s t ) p_{\theta'}(a_t|s_t) pθ(atst)差距过大,就是让两个概率模型差距不那么大,之前我们是用交叉熵来衡量两个概率模型的差距,在这里我们使用相对熵,也就是KL散度来衡量这种差距。

KL散度公式:
D K L ( P ∣ ∣ Q ) = ∑ x P ( x ) log ⁡ P ( x ) Q ( x ) D_{KL}(P||Q) = \sum_x P(x) \log \frac{P(x)}{Q(x)} DKL(P∣∣Q)=xP(x)logQ(x)P(x)
D K L ( P ∣ ∣ Q ) D_{KL}(P||Q) DKL(P∣∣Q)表示KL散度,KL散度量化了如果用 Q Q Q来表示 P P P​,需要付出多少额外的信息代价。

既然我们可以量化两个模型之间的差距,模型之间的差距又不能过大,就顺理成章的能想到把量化过后的模型之间的差距当成一个正则项加到目标函数里面去不就行了吗,事实上PPO算法也是这样做的。

PPO算法的优化目标(损失函数):
J P P O θ ′ ( θ ) = J θ ′ ( θ ) − β K L ( θ , θ ′ ) J^{\theta'}_{PPO}(\theta) = J^{\theta'}(\theta) - \beta KL(\theta, \theta') \\ JPPOθ(θ)=Jθ(θ)βKL(θ,θ)
J θ ′ ( θ ) = E ( s t , a t ) ∼ π θ ′ [ p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) A θ ′ ( s t , a t ) ] J^{\theta'}(\theta) = \mathbb{E}_{(s_t, a_t) \sim \pi_{\theta'}} \left[ \frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)} A^{\theta'}(s_t, a_t) \right] Jθ(θ)=E(st,at)πθ[pθ(atst)pθ(atst)Aθ(st,at)]

PPO 有一个前身:信任区域策略优化(trust region policy optimization,TRPO)。TRPO 可表示为:
J T R P O θ ′ ( θ ) = E ( s t , a t ) ∼ π θ ′ [ p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) A θ ′ ( s t , a t ) ] , s.t.  K L ( θ , θ ′ ) < δ J^{\theta'}_{TRPO}(\theta) = \mathbb{E}_{(s_t, a_t) \sim \pi_{\theta'}} \left[ \frac{p_{\theta}(a_t|s_t)}{p_{\theta'}(a_t|s_t)} A^{\theta'}(s_t, a_t) \right], \text{ s.t. } KL(\theta, \theta') < \delta JTRPOθ(θ)=E(st,at)πθ[pθ(atst)pθ(atst)Aθ(st,at)], s.t. KL(θ,θ)<δ
TRPO看起来和PPO很接近了,但是它把KL散度当成一种约束了,这种约束在基于梯度优化里面很难实现它,但是如果像PPO那样直接当成一个正则项,那么梯度优化实现它就会非常简单。

PPO算法还有两个变体。

4.2.1 近端策略优化惩罚(PPO-penalty、PPO1)

在实现PPO算法的时候一般使用前一个训练的迭代得到的演员的参数 θ k \theta^k θk与环境做大量交互,得到大量数据,来更新 θ \theta θ,就可以写成这样:
J P P O θ k ( θ ) = J θ k ( θ ) − β K L ( θ , θ k ) J^{\theta^k}_{PPO}(\theta) = J^{\theta^k}(\theta) - \beta KL(\theta, \theta^k)\\ JPPOθk(θ)=Jθk(θ)βKL(θ,θk) J θ k ( θ ) ≈ ∑ ( s t , a t ) p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) A θ k ( s t , a t ) J^{\theta^k}(\theta) \approx \sum_{(s_t, a_t)} \frac{p_{\theta}(a_t|s_t)}{p_{\theta^k}(a_t|s_t)} A^{\theta^k}(s_t, a_t) Jθk(θ)(st,at)pθk(atst)pθ(atst)Aθk(st,at)

里面有个超参数 β \beta β有点不好控制,我们可以给KL散度设置一个最大值,一个最小值,当KL散度大于最大值的时候,就说明后面的罚没有发挥作用,就是正则项作用太小了,就增大 β \beta β提升KL散度的影响,当KL散度小于最小值的时候,就说明罚的太重了,后面一项的效果太强了,就减小 β \beta β​削弱KL散度的影响。

因此我们称之为自适应KL惩罚(adaptive KL penalty)

4.2.2 近端策略优化裁剪(PPO-clip、PPO2)

如果觉得计算 KL 散度太复杂了,还有一个 PPO2算法,PPO2 即近端策略优化裁剪。近端策略优化裁剪的目标函数里面没有 KL 散度,其要最大化的目标函数为
J P P O θ k ( θ ) ≈ ∑ ( s t , a t ) min ⁡ ( p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) A θ k ( s t , a t ) , clip ( p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) , 1 − ϵ , 1 + ϵ ) A θ k ( s t , a t ) ) J^{\theta^k}_{PPO}(\theta) \approx \sum_{(s_t, a_t)} \min \left( \frac{p_{\theta}(a_t|s_t)}{p_{\theta^k}(a_t|s_t)} A^{\theta^k}(s_t, a_t), \right. \\ \left. \text{clip} \left(\frac{p_{\theta}(a_t|s_t)}{p_{\theta^k}(a_t|s_t)}, 1-\epsilon, 1+\epsilon \right) A^{\theta^k}(s_t, a_t) \right) JPPOθk(θ)(st,at)min(pθk(atst)pθ(atst)Aθk(st,at),clip(pθk(atst)pθ(atst),1ϵ,1+ϵ)Aθk(st,at))

第二项前面有一个裁剪(clip)函数,裁剪函数是指,在括号里面有3项,如果第一项小于第二项,那就输出 1 − ε 1−ε 1ε;第一项如果大于第三项,那就输出 1 + ε 1+ε 1+ε​。

ε ε ε是一个超参数,是我们要调整的,可以设置成 0.1 或 0.2 。

剪裁函数图像:

看到PPO2的目标函数就不如之前的式子好理解了,那这个到底是啥意思呢,不用KL散度怎么知道新模型和旧模型之间的差距呢?

再重新审视一下剪裁函数

观察上面两幅图,绿色的线指的是 p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) \frac{p_{\theta}(a_t|s_t)}{p_{\theta^k}(a_t|s_t)} pθk(atst)pθ(atst),蓝色的线指的是被剪裁之后的样子。

  • A θ k ( s t , a t ) > 0 A^{\theta^k}(s_t, a_t) > 0 Aθk(st,at)>0表示当前状态动作对是好的。希望它的概率,也就是 p θ ( a t ∣ s t ) p_{\theta}(a_t|s_t) pθ(atst)越大越好,但是也不能太大,它与 p θ ′ ( a t ∣ s t ) p_{\theta'}(a_t|s_t) pθ(atst)的比值不能超过 1 + ε 1+ε 1+ε,如果超过了就会遇到我们之前的方差问题,红色的线就是指的是目标函数。
  • A θ k ( s t , a t ) < 0 A^{\theta^k}(s_t, a_t) < 0 Aθk(st,at)<0表示当前状态动作对是不好的。同理,希望它的概率,也就是 p θ ( a t ∣ s t ) p_{\theta}(a_t|s_t) pθ(atst)越小越好,但是也不能太小,它与 p θ ′ ( a t ∣ s t ) p_{\theta'}(a_t|s_t) pθ(atst)的比值不能低于 1 − ε 1-ε 1ε​,如果低于了就会遇到我们之前的方差问题,红色的线就是指的是目标函数。

4.3 PPO算法的实现

这里我们选择实现的是近端策略优化裁剪,也就是PPO2,PPO算法是策略梯度算法的一种,为了将其效果最大化,可以结合A2C算法一起使用,那就是Critic网络和A2C一样,A2C算法中Actor我们用PPO的优化目标来代替A2C算法中的目标,同时我们采用时时序差分的方法来做采样,把优势函数换成时序差分误差即可,损失函数就变成了以下:
J P P O θ k ( θ ) ≈ ∑ ( s t , a t ) min ⁡ ( p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) δ t n , clip ( p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) , 1 − ϵ , 1 + ϵ ) δ t n ) J^{\theta^k}_{PPO}(\theta) \approx \sum_{(s_t, a_t)} \min \left( \frac{p_{\theta}(a_t|s_t)}{p_{\theta^k}(a_t|s_t)} \delta_t^n, \right. \\ \left. \text{clip} \left(\frac{p_{\theta}(a_t|s_t)}{p_{\theta^k}(a_t|s_t)}, 1-\epsilon, 1+\epsilon \right) \delta_t^n \right) JPPOθk(θ)(st,at)min(pθk(atst)pθ(atst)δtn,clip(pθk(atst)pθ(atst),1ϵ,1+ϵ)δtn)
其中 δ t n = r t n + V π ( s t + 1 n ) − V π ( s t n ) :TD-error。 \delta_t^n = r_t^n + V_{\pi}(s_{t+1}^n) - V_{\pi}(s_t^n) \text{:TD-error。} δtn=rtn+Vπ(st+1n)Vπ(stn)TD-error

但是在PPO的实现里面我们一般不直接这么做,而是像套娃一样用了另一种叫做GAE(Generalized Advantage Estimation)的误差来取代TD-error,就像最开始我们用回报 G t G_t Gt来取代单步奖励 r t r_t rt那样, G t G_t Gt的公式是这样的:
G t = r t + 1 + γ r t + 2 + γ 2 r t + 3 + . . . + γ T − t − 1 r T G_t = r_{t+1} + \gamma r_{t+2} + \gamma^2 r_{t+3} + ... + \gamma^{T-t-1} r_T Gt=rt+1+γrt+2+γ2rt+3+...+γTt1rT

也就是:
G t = ∑ i = t + 1 T γ i − t − 1 r i G_t = \sum_{i=t+1}^T \gamma^{i-t-1} r_i Gt=i=t+1Tγit1ri
那GAE是怎么做的呢?
A t G A E = ∑ l = 0 ∞ ( γ λ ) l δ t ( l ) A^{GAE}_t = \sum_{l=0}^{\infty} (\gamma \lambda)^l \delta^{(l)}_t AtGAE=l=0(γλ)lδt(l)
也可以写成
A t G A E = ∑ l = 0 T − t − 1 ( γ λ ) l δ t + l A^{GAE}_t = \sum_{l=0}^{T-t-1} (\gamma \lambda)^l \delta_{t+l} AtGAE=l=0Tt1(γλ)lδt+l
这样看就非常清楚了,其中 δ t = r t + V π ( s t + 1 ) − V π ( s t ) :TD-error。 \delta_t = r_t + V_{\pi}(s_{t+1}) - V_{\pi}(s_t) \text{:TD-error。} δt=rt+Vπ(st+1)Vπ(st)TD-error

  • λ = 0 λ=0 λ=0,GAE等价于单步 TD,偏差低但方差高。

  • λ = 1 λ=1 λ=1,GAE近似于蒙特卡洛回报(Monte Carlo Return),方差低但偏差高。

  • 调整 λ λ λ​参数可以在偏差和方差之间找到一个更合适的折中。

  • γ γ γ是折扣因子,控制对未来奖励的关注程度。

用GAE来替代之前的 A θ k ( s t , a t ) A^{\theta^k}(s_t, a_t) Aθk(st,at),那公式就可以写成:
J P P O θ k ( θ ) ≈ ∑ ( s t , a t ) min ⁡ ( p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) A t , n G A E , clip ( p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) , 1 − ϵ , 1 + ϵ ) A t , n G A E ) J^{\theta^k}_{PPO}(\theta) \approx \sum_{(s_t, a_t)} \min \left( \frac{p_{\theta}(a_t|s_t)}{p_{\theta^k}(a_t|s_t)} A^{GAE}_{t,n}, \right. \\ \left. \text{clip} \left(\frac{p_{\theta}(a_t|s_t)}{p_{\theta^k}(a_t|s_t)}, 1-\epsilon, 1+\epsilon \right) A^{GAE}_{t,n} \right) JPPOθk(θ)(st,at)min(pθk(atst)pθ(atst)At,nGAE,clip(pθk(atst)pθ(atst),1ϵ,1+ϵ)At,nGAE)

智能体的任务和之前的A2C算法里面的任务是一样的。

import gym
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
from torch.distributions import Categorical
import matplotlib.pyplot as pltclass Config:def __init__(self):# PPO特定参数self.clip_epsilon = 0.2        # PPO裁剪系数,用于限制策略更新的幅度self.ppo_epochs = 10           # 每次更新的PPO轮数self.batch_size = 64           # 小批量训练的大小self.gae_lambda = 0.95         # GAE参数,用于计算优势函数# 基础参数self.hidden_dim = 64           # 神经网络隐藏层维度self.lr = 0.0003               # 学习率self.gamma = 0.99              # 折扣因子self.max_episodes = 5000       # 最大训练回合数self.max_steps = 500           # 每个回合最大步数self.seed = 42                 # 随机种子self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # 设备选择(GPU/CPU)self.entropy_coef = 0.01       # 熵正则化系数,用于鼓励探索# 分离Actor和Critic网络
class Actor(nn.Module):def __init__(self, state_dim, action_dim):super(Actor, self).__init__()# 定义Actor网络结构self.network = nn.Sequential(nn.Linear(state_dim, 64),  # 输入层到隐藏层nn.Tanh(),                 # 激活函数nn.Linear(64, action_dim), # 隐藏层到输出层nn.Softmax(dim=-1)         # 输出层使用Softmax得到动作概率分布)def forward(self, state):# 前向传播,返回动作概率分布return self.network(state)class Critic(nn.Module):def __init__(self, state_dim):super(Critic, self).__init__()# 定义Critic网络结构self.network = nn.Sequential(nn.Linear(state_dim, 64),  # 输入层到隐藏层nn.Tanh(),                 # 激活函数nn.Linear(64, 1)           # 隐藏层到输出层,输出状态价值)def forward(self, state):# 前向传播,返回状态价值return self.network(state)class PPO:def __init__(self, state_dim, action_dim, config):self.config = configself.actor = Actor(state_dim, action_dim)  # 初始化Actor网络self.critic = Critic(state_dim)            # 初始化Critic网络self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=config.lr)  # Actor优化器self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=config.lr)  # Critic优化器def get_action(self, state):with torch.no_grad():state = torch.FloatTensor(state)  # 转换状态为张量action_probs = self.actor(state)  # 获取动作概率分布dist = Categorical(action_probs)  # 创建类别分布action = dist.sample()            # 采样动作action_log_prob = dist.log_prob(action)  # 获取动作的对数概率return action.item(), action_log_prob.item()  # 返回动作和对数概率def compute_gae(self, values, rewards, dones, next_value):advantages = []gae = 0for t in reversed(range(len(rewards))):if t == len(rewards) - 1:next_val = next_value  # 最后一步的下一个值else:next_val = values[t + 1]  # 其他步骤的下一个值delta = rewards[t] + self.config.gamma * next_val * (1 - dones[t]) - values[t]  # TD误差gae = delta + self.config.gamma * self.config.gae_lambda * (1 - dones[t]) * gae  # 计算GAEadvantages.insert(0, gae)  # 插入到优势列表开头advantages = torch.FloatTensor(advantages)  # 转换为张量return advantagesdef update(self, states, actions, old_log_probs, rewards, dones, next_state):states = torch.FloatTensor(np.array(states))  # 转换状态为张量actions = torch.LongTensor(actions)           # 转换动作为张量old_log_probs = torch.FloatTensor(old_log_probs)  # 转换旧的对数概率为张量# 计算GAEwith torch.no_grad():values = self.critic(states).squeeze()  # 获取当前状态的价值next_value = self.critic(torch.FloatTensor(next_state)).item()  # 获取下一个状态的价值advantages = self.compute_gae(values.tolist(), rewards, dones, next_value)  # 计算优势returns = advantages + values  # 计算回报,即优势+状态价值,因为advantages是基于TD误差的是相对值,所以需要加上状态价值得到绝对值,来稳定训练advantages = (advantages - advantages.mean()) / (advantages.std() + 1e-8)  # 标准化优势# PPO更新多轮for _ in range(self.config.ppo_epochs):for idx in range(0, len(states), self.config.batch_size):batch_states = states[idx:idx + self.config.batch_size]  # 获取小批量状态batch_actions = actions[idx:idx + self.config.batch_size]  # 获取小批量动作batch_old_log_probs = old_log_probs[idx:idx + self.config.batch_size]  # 获取小批量旧的对数概率batch_advantages = advantages[idx:idx + self.config.batch_size]  # 获取小批量优势batch_returns = returns[idx:idx + self.config.batch_size]  # 获取小批量回报# 计算新的动作概率action_probs = self.actor(batch_states)dist = Categorical(action_probs)new_log_probs = dist.log_prob(batch_actions)# 计算熵entropy = dist.entropy().mean()# 计算比率和裁剪后的目标ratio = torch.exp(new_log_probs - batch_old_log_probs)surr1 = ratio * batch_advantagessurr2 = torch.clamp(ratio, 1-self.config.clip_epsilon, 1+self.config.clip_epsilon) * batch_advantages# 计算Actor损失(加入熵正则化项)actor_loss = -torch.min(surr1, surr2).mean() - self.config.entropy_coef * entropy# 计算Critic损失critic_values = self.critic(batch_states).view(-1)  # 使用 view(-1) 替代 squeeze()critic_loss = nn.MSELoss()(critic_values, batch_returns)# 更新Actor网络self.actor_optimizer.zero_grad()actor_loss.backward()self.actor_optimizer.step()# 更新Critic网络self.critic_optimizer.zero_grad()critic_loss.backward()self.critic_optimizer.step()def train_ppo():config = Config()  # 初始化配置env = gym.make("CartPole-v1")  # 创建环境state_dim = env.observation_space.shape[0]  # 获取状态维度action_dim = env.action_space.n  # 获取动作维度agent = PPO(state_dim, action_dim, config)  # 初始化PPO智能体rewards = []  # 用于存储每个回合的奖励for episode in range(config.max_episodes):state, _ = env.reset()  # 重置环境states, actions, rewards_buffer, log_probs, dones = [], [], [], [], []  # 初始化存储变量total_reward = 0  # 初始化总奖励for step in range(config.max_steps):action, log_prob = agent.get_action(state)  # 获取动作和对数概率next_state, reward, done, _, _ = env.step(action)  # 执行动作states.append(state)  # 存储状态actions.append(action)  # 存储动作rewards_buffer.append(reward)  # 存储奖励log_probs.append(log_prob)  # 存储对数概率dones.append(done)  # 存储是否结束total_reward += reward  # 累加奖励state = next_state  # 更新状态if done:breakagent.update(states, actions, log_probs, rewards_buffer, dones, next_state)  # 更新智能体rewards.append(total_reward)  # 记录每个回合的奖励print(f"Episode {episode + 1}, Total Reward: {total_reward}")  # 打印当前回合的奖励if total_reward >= 500:print("Solved!")  # 如果总奖励达到500,表示问题解决breakenv.close()  # 关闭环境# 绘制reward曲线plt.plot(rewards)plt.title('Training Rewards')plt.xlabel('Episode')plt.ylabel('Reward')plt.show()if __name__ == "__main__":train_ppo()

结果:

可以看到,两百次采样以内就能达到目标,获得奖励(500)

相关文章:

强化学习的几个主要方法(策略梯度、PPO、REINFORCE实现等)(下)

由于平台字数限制&#xff0c;上文&#xff1a;https://blog.csdn.net/ooblack/article/details/144198538 4. PPO算法 近端策略优化&#xff08;proximal policy optimization&#xff0c;PPO&#xff09;算法是OpenAI的默认强化学习算法&#xff0c;在RLHF中也用到了这个算…...

计算机网络:IP协议详细讲解

目录 前言 一、IP网段划分 二、IP报头 三、解决IP地址不足-->NAT技术 前言 在之前&#xff0c;我们学习了传输层中的TCP和UDP&#xff0c;重点是TCP协议&#xff0c;他帮我们解决具体到主机的哪个应用&#xff08;端口&#xff09;、传输的可靠&#xff08;序列号、校验和…...

2024信创数据库TOP30之华为Gauss DB

近日&#xff0c;由DBC联合CIW/CIS共同发布的“2024信创数据库TOP30”榜单正式揭晓&#xff0c;汇聚了国内顶尖的数据库企业及其产品&#xff0c;成为展示中国信创领域技术实力与发展潜力的重要平台。在这份榜单中&#xff0c;华为的GaussDB凭借其卓越的技术实力、广泛的行业应…...

在线家具商城基于 SpringBoot:设计模式与实现方法探究

第3章 系统分析 用户的需求以及与本系统相似的在市场上存在的其它系统可以作为系统分析中参考的资料&#xff0c;分析人员可以根据这些信息确定出本系统具备的功能&#xff0c;分析出本系统具备的性能等内容。 3.1可行性分析 尽管系统是根据用户的要求进行制作&#xff0c;但是…...

九、Spring Boot集成Spring Security之授权概述

文章目录 往期回顾&#xff1a;Spring Boot集成Spring Security专栏及各章节快捷入口前言一、授权概述二、用户权限三、用户授权流程三、Spring Security授权方式1、请求级别授权2、方法级别授权 往期回顾&#xff1a;Spring Boot集成Spring Security专栏及各章节快捷入口 Spr…...

python之Flask入门—路由参数

语法&#xff1a; /routerName/<string:parameter_name> 其中&#xff1a;routerName代表路由名称<>中的string是参数类型&#xff0c;parameter_name为参数名称 参数类型&#xff1a; &#xff08;1&#xff09; string 接收任何没有斜杠&#xff08;/&#x…...

txt地图格式处理

1、txt地图格式 [属性描述] 坐标系2000国家大地坐标系 几度分带3 投影类型高斯克吕格 计量单位米 带号38 精度0.001 转换参数,,,,,, [地块坐标] 5,475.888,1,测试地块1,面,J50G077061,公路用地,地下, J1,1,113.22222222222222,23.129111721551794 J2,1,113.2722314…...

《数据挖掘:概念、模型、方法与算法(第三版)》

嘿&#xff0c;数据挖掘的小伙伴们&#xff01;今天我要给你们介绍一本超级实用的书——《数据挖掘&#xff1a;概念、模型、方法与算法》第三版。这本书是数据挖掘领域的经典之作&#xff0c;由该领域的知名专家编写&#xff0c;系统性地介绍了在高维数据空间中分析和提取大量…...

GitLab CVE-2024-8114 漏洞解决方案

漏洞 ID 标题严重等级CVE ID通过 LFS 令牌提升权限高CVE-2024-8114 GitLab 升级指南GitLab 升级路径查看版本漏洞查询 漏洞解读 此漏洞允许攻击者使用受害者的个人访问令牌&#xff08;PAT&#xff09;进行权限提升。影响从 8.12 开始到 17.4.5 之前的所有版本、从 17.5 开…...

request和websocket

当然&#xff0c;可以为你详细介绍 FastAPI 中的 Request 对象。Request 对象在 FastAPI 中扮演着重要的角色&#xff0c;负责封装来自客户端的 HTTP 请求信息。了解 Request 对象的使用方法和属性&#xff0c;有助于你更高效地处理请求数据、访问请求上下文以及进行各种操作。…...

一键生成后端服务,MemFire Cloud重新定义开发效率

作为开发者&#xff0c;特别是独立开发者和小团队成员&#xff0c;大家都知道开发的最大难题之一就是搭建后端服务。要让一个应用从零开始&#xff0c;除了前端的开发工作外&#xff0c;还需要考虑数据库、接口、认证、存储等等一系列繁琐的后台工作。而MemFire Cloud这款神器&…...

短视频矩阵的营销策略:批量混剪实现高效传播

在当今的商业环境中&#xff0c;短视频营销已成为企业获得市场份额的关键策略。随着消费者注意力的分散&#xff0c;传统营销方法的效果逐渐减弱。因此&#xff0c;短视频营销的重要性不言而喻。通过短视频&#xff0c;品牌能够以更为生动和直观的方式传递信息&#xff0c;从而…...

朗迪锋亮相2024人因工程与智能系统交互国际会议

2024年11月28日至30日&#xff0c;2024人因工程与智能系统交互国际会议在深圳隆重举办。此次大会以推动我国人因工程学科发展为目标&#xff0c;致力于加强国际学术交流&#xff0c;深入探讨人工智能时代的智能系统交互&#xff0c;旨在培育新质生产力&#xff0c;助力经济社会…...

spring boot3.3.5 logback-spring.xml 配置

新建 resources/logback-spring.xml 控制台输出颜色有点花 可以自己更改 <?xml version"1.0" encoding"UTF-8"?> <!--关闭文件扫描 scanfalse --> <configuration debug"false" scan"false"><springProperty …...

Proteus8.17下载安装教程

Proteus是一款嵌入式系统仿真开发软件&#xff0c;实现了从原理图设计、单片机编程、系统仿真到PCB设计&#xff0c;真正实现了从概念到产品的完整设计&#xff0c;其处理器模型支持8051、HC11、PIC10/12/16/18/24/30/DsPIC33、AVR、ARM、8086和MSP430等&#xff0c;能够帮助用…...

一次Kafka启动失败引出的问题

背景 Some time&#xff0c;有个现场童鞋说咱的Kafka实例有个broker一直crash&#xff0c;还截图给我看了&#xff0c;大致是Kafka启动加载topic分区日志文件的时候&#xff0c;然后就没了&#xff0c;连个WARN都没有。当然&#xff0c;光看这个截图咱啥都不知道&#xff0c;因…...

mysql 查询所有的触发器

SELECTTRIGGER_SCHEMA AS Database,TRIGGER_NAME AS Trigger,EVENT_OBJECT_TABLE AS Table,EVENT_MANIPULATION AS Event,ACTION_STATEMENT AS Statement FROMinformation_schema.TRIGGERS;创建触发器遇到报错&#xff1a; You do not have the SUPER privilege and binary lo…...

704. 二分查找 C++

文章目录 一、题目链接二、参考代码三、所思所悟 一、题目链接 链接: 704. 二分查找 二、参考代码 int search(const vector<int>& nums, int target) {int left 0; int right nums.size() - 1;//左闭右闭[]while (left < right){int mid (left right) / 2;…...

SpringCloud Seata集成分布式事务管理 事务保护 XA AT两种模式的区别

介绍 阿里巴巴的 Seata&#xff08;Service Aligned Transaction Alternative&#xff09;是一个开源的分布式事务解决方案&#xff0c;旨在解决微服务架构中跨服务、跨数据库的事务一致性问题。它可以帮助开发者管理分布式系统中的全局事务&#xff0c;确保在多个服务之间的事…...

node.js基础学习-querystring模块-查询字符串处理(三)

一、前言 querystring是 Node.js 中的一个内置模块&#xff0c;主要用于处理 URL 查询字符串。它提供了一些实用的方法来解析和格式化查询字符串&#xff0c;使得在处理 HTTP 请求中的查询参数等场景时非常方便。 还可以防止sql注入 二、解析查询字符串&#xff08;parse方法&a…...

电子电气架构 --- 车载网关GW连接外部IP Tester

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…...

鸿蒙LiteOS的核心架构

鸿蒙LiteOS是华为公司推出的一款面向物联网领域的轻量级操作系统&#xff0c;它专为资源受限设备设计&#xff0c;旨在满足智能穿戴设备、智能家居、智能出行等领域的应用需求。鸿蒙LiteOS不仅能够支持多种硬件平台&#xff0c;还具备超低功耗、快速启动、高安全性等特性&#…...

C语言——实现计算房屋总价

//功能&#xff1a;计算房屋总价 //房屋总价 房屋面积 * 单价 //契税 房屋总价 * 0.15% //印花税 房屋总价 * 0.05% //功能&#xff1a;计算房屋总价 //房屋总价 房屋面积 * 单价 //契税 房屋总价 * 0.15% //印花税 房屋总价 * 0.05%#include<stdio.h>void main()…...

【380】基于springboot的闲置图书分享

摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自古…...

element-ui的下拉框报错:Cannot read properties of null (reading ‘disabled‘)

在使用element下拉框时&#xff0c;下拉框option必须点击输入框才关闭&#xff0c;点击其他地方报错&#xff1a;Cannot read properties of null (reading disabled) 造成报错原因&#xff1a;项目中使用了el-dropdown组件&#xff0c;但是在el-dropdown里面没有定义el-dropdo…...

VMware虚拟机——安装保姆级教程(附安装包)

一、下载 1、官方正版VMware下载链接&#xff1a;https://pan.quark.cn/s/c9ff7c6e06d7 2、Linux镜像下载&#xff08;CentOS7&#xff09;链接&#xff1a;https://pan.quark.cn/s/4df5f93fb83d 二、安装VMware 1、创建VMware所需文件夹 &#xff08;1&#xff09;找一个…...

如何实现表格选中时禁用树结构的复选框功能(El-Tree 与 El-Table 联动实现)

在前端开发中&#xff0c;树形结构和表格是常用的组件组合&#xff0c;尤其是在展示和管理复杂数据时。使用 Element UI 的 el-tree 和 el-table 组件&#xff0c;我们可以实现当表格中有选中行时&#xff0c;自动禁用树结构中的复选框&#xff0c;反之亦然。这不仅提升了用户体…...

STM32CUBEIDE FreeRTOS操作教程(十):interrupt on/off中断开关

STM32CUBEIDE FreeRTOS操作教程&#xff08;十&#xff09;&#xff1a;interrupt on/off中断开关 STM32CUBE开发环境集成了STM32 HAL库进行FreeRTOS配置和开发的组件&#xff0c;不需要用户自己进行FreeRTOS的移植。这里介绍最简化的用户操作类应用教程。以STM32F401RCT6开发…...

Linux的基本操作及虚拟机设置

文章目录 Linux的目录结构Linux中的常见目录 VI和VIM编辑器什么是VI和VIM编辑器VIM的一般模式VIM的编辑模式VIM的命令模式模式间的切换 虚拟机网络配置查看网络信息修改网络配置信息查看和修改主机名服务管理类命令 虚拟机管理操作VMware为虚拟机拍摄快照VMware为虚拟机执行克隆…...

oracle 用户手册

Oracle用户手册 一、Oracle数据库概述 定义与用途 Oracle数据库是一款功能强大的关系型数据库管理系统(RDBMS)。它用于存储和管理大量的结构化数据,广泛应用于企业级应用、金融系统、电商平台等各种需要高效数据处理和存储的场景。例如,银行使用Oracle数据库来存储客户账户…...