狗都能看懂的Proximal Policy Optimization(PPO)PPO算法详解

On policy 与 Off policy

在讲解PPO算法前,我们需要明白On/Off policy的概念:

  • On-policy:用当前的Agent生成经验,并且用于更新这个Agent。即Agent一边和环境互动,一边学习
  • Off-policy:用其他的Agent生成经验,用于更新当前Agent。即Agent是学习其他的Agent的互动经验

之前所学习的Policy Gradient方法就是On-policy的,它的缺点就是每次更新都需要等Agent环境做互动,更新完之后,前一次互动经验又不能用了。这导致了Policy Gradient算法训练很耗时,时间都花在收集数据上。所以我们如果能将Policy Gradient变成Off-policy的算法,那之前互动的数据可以重复使用,大大提升了训练效率。

Importance Sampling

为了解决这个问题,我们先引入重要性采样的概念(Importance Sampling)。假设现在有一个 f ( x ) f(x) f(x)函数, x x x从分布 p p p采样,代入到 f ( x ) f(x) f(x)函数里。现在我们需要求它的期望值,即 E x ∼ p [ f ( x ) ] E_{x \sim p}[f(x)] Ex∼p[f(x)]。在没有办法对分布 p p p做积分的前提下,我们可以从分布 p p p里面采样几个 x x x,然后代入到 f ( x ) f(x) f(x),求和然后取平均,这就近似这个期望值了。
E x ∼ p [ f ( x ) ] ≈ 1 N ∑ i = 1 N f ( x i ) E_{x \sim p}[f(x)] \approx \frac{1}{N}\sum_{i=1}^N f(x^i) Ex∼p[f(x)]≈N1i=1∑Nf(xi)

假设我们现在不知道分布 p p p长什么样(模拟Off-policy的情况),要怎么算期望值呢?我们引入一个分布 q q q(这个是已知的条件),它可以是任何分布,我们先不管它是怎么样的分布。

我们从分布 q q q采样出来的 x x x没办法直接丢到 p ( x ) p(x) p(x)计算,所以我们现在需要做一个修正,分布 q q q的采样可以用来计算期望值。求期望值可以用它的概率密度函数表示:
E x ∼ p [ f ( x ) ] = ∫ f ( x ) p ( x ) d x E_{x \sim p}[f(x)] = \int f(x)p(x) dx Ex∼p[f(x)]=∫f(x)p(x)dx

上下同乘 q ( x ) q(x) q(x)
E x ∼ p [ f ( x ) ] = ∫ f ( x ) p ( x ) q ( x ) q ( x ) d x E_{x \sim p}[f(x)] = \int f(x) \frac{p(x)}{q(x)} q(x) dx Ex∼p[f(x)]=∫f(x)q(x)p(x)q(x)dx

将 f ( x ) p ( x ) q ( x ) f(x) \frac{p(x)}{q(x)} f(x)q(x)p(x)看成原来的 f ( x ) f(x) f(x),这样我们就可以写成从分布 q q q中采样的期望公式了:
E x ∼ q [ f ( x ) p ( x ) q ( x ) ] = ∫ f ( x ) p ( x ) q ( x ) q ( x ) d x E_{x \sim q}[f(x) \frac{p(x)}{q(x)}] = \int f(x) \frac{p(x)}{q(x)} q(x) dx Ex∼q[f(x)q(x)p(x)]=∫f(x)q(x)p(x)q(x)dx

那么 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x)这一项就是额外乘上去的,我们将其视作是一个weight,用来修正 q ( x ) q(x) q(x)和 p ( x ) p(x) p(x)的差异。分布 q q q可以是任意的分布,但也有一个前提,不能 q ( x ) q(x) q(x)几率为0的时候, p ( x ) p(x) p(x)不为0,这样会没有定义。

Issue of Importance Sampling

虽然我们说 q ( x ) q(x) q(x)可以是任意的分布,但在实际优化的过程中,还是不能和 p ( x ) p(x) p(x)差太多。尤其是它们算方差的时候,影响会比较大。如下图所示,其方差不一样就体现在第一项中,后者比前者多了一个 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x),如果分布 p p p和 q q q差太大的话,随机变量的方差就会差很多。这时,如果采样的样本数不够多的话,那么数值上的差别就会比较大。

可以用下面这个例子简单说明一下,如果两个分布差很多的时候,会有什么情况。其中绿线是指 q ( x ) q(x) q(x),蓝线是指 p ( x ) p(x) p(x),红线是指 f ( x ) f(x) f(x)。假设纵轴代表的是概率, p ( x ) p(x) p(x)在左边被sample到的概率很高, q ( x ) q(x) q(x)在右边被sample到的概率很高。

如果sample次数比较少,都只采样到正的情况, E x ∼ p [ f ( x ) ] E_{x \sim p}[f(x)] Ex∼p[f(x)]计算出来可能是正值。

如果说sample次数比较多的情况下,有几率采样到左边的情况,即使次数很少,但它 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x)算出来的weight比较大, E x ∼ p [ f ( x ) ] E_{x \sim p}[f(x)] Ex∼p[f(x)]计算出来就可能是负值。所以足够多的采样才能保证两个期望是差不多的。但sample次数不够多的情况下,左式和右式就会差很多。那么这也是Importance Sampling的一个问题所在。

From On-policy to off-policy

将重要性采样的思想迁移到Policy Gradient中去,即我们要更新的模型是参数是 θ \theta θ,我们上一次采样的数据是用参数 θ ′ \theta' θ′采样而来的。这时候可以将 θ \theta θ视作 p ( x ) p(x) p(x), θ ′ \theta' θ′视作 q ( x ) q(x) q(x)。从而使得上一个action采样出来的数据可以重复使用。同时由于 θ \theta θ与 θ ′ \theta' θ′在优化前后(只要学习率不是很大,或者同一样本优化次数不是很多)其实是差不多的,分布上也不会差太多。

我们回到之前的update Policy Gradient的公式(用 θ \theta θ这个actor去sample出 s t , a t s_t,a_t st,at,计算Advantage这项有多好,log项为发生的概率,如果为Advantage正,log项需要增加,如果Advantage为负的,log项需要减少):
E ( s t , a t ) ∼ π θ [ A θ ( s t , a t ) ∇ l o g p θ ( a t n ∣ s t n ) ] E_{(s_t,a_t) \sim \pi_\theta}[A^\theta(s_t,a_t)\nabla logp_\theta(a_t^n|s_t^n)] E(st,at)∼πθ[Aθ(st,at)∇logpθ(atn∣stn)]

引入 θ ′ \theta' θ′,这里值得注意的是,假设 A θ ( s t , a t ) A^\theta(s_t,a_t) Aθ(st,at)和 A θ ′ ( s t , a t ) A^{\theta'}(s_t,a_t) Aθ′(st,at)是差不多的,理论上是要用 A θ ′ ( s t , a t ) A^{\theta'}(s_t,a_t) Aθ′(st,at)计算
E ( s t , a t ) ∼ π θ ′ [ P θ ( s t , a t ) P θ ′ ( s t , a t ) A θ ( s t , a t ) ∇ l o g p θ ( a t n ∣ s t n ) ] E_{(s_t,a_t) \sim \pi_{\theta'}}[\frac{P_\theta(s_t,a_t)}{P_{\theta'}(s_t,a_t)} A^\theta(s_t,a_t) \nabla logp_\theta(a_t^n|s_t^n)] E(st,at)∼πθ′[Pθ′(st,at)Pθ(st,at)Aθ(st,at)∇logpθ(atn∣stn)]

进一步分解 P θ ( s t , a t ) P_\theta(s_t,a_t) Pθ(st,at)为 p θ ( s t ∣ a t ) p_\theta(s_t|a_t) pθ(st∣at)和 p θ ( s t ) p_\theta(s_t) pθ(st),而 p θ ( s t ) p_\theta(s_t) pθ(st)和 p θ ′ ( s t ) p_{\theta'}(s_t) pθ′(st)实则是环境出现的概率(通常没法计算,而且大概率都是一样的。例如,游戏第一关打完,必定出现第二关),所以这一项可近似看成1。
E ( s t , a t ) ∼ π θ ′ [ p θ ( s t ∣ a t ) p θ ′ ( s t ∣ a t ) p θ ( s t ) p θ ′ ( s t ) A θ ( s t , a t ) ∇ l o g p θ ( a t n ∣ s t n ) ] E_{(s_t,a_t) \sim \pi_{\theta'}}[\frac{p_\theta(s_t|a_t)}{p_{\theta'}(s_t|a_t)} \frac{p_\theta(s_t)}{p_{\theta'}(s_t)} A^\theta(s_t,a_t) \nabla logp_\theta(a_t^n|s_t^n)] E(st,at)∼πθ′[pθ′(st∣at)pθ(st∣at)pθ′(st)pθ(st)Aθ(st,at)∇logpθ(atn∣stn)]

根据之前常用到的公式:
∇ f ( x ) = f ( x ) ∇ l o g f ( x ) \nabla f(x) = f(x)\nabla logf(x) ∇f(x)=f(x)∇logf(x)

我们可以反推得到优化函数:
J θ ′ ( θ ) = E ( s t , a t ) ∼ π θ ′ [ p θ ( s t ∣ a t ) p θ ′ ( s t ∣ a t ) A θ ′ ( s t , a t ) ] J^{\theta'}(\theta) = E_{(s_t,a_t) \sim \pi_{\theta'}} [\frac{p_\theta(s_t|a_t)}{p_{\theta'}(s_t|a_t)} A^{\theta'}(s_t,a_t)] Jθ′(θ)=E(st,at)∼πθ′[pθ′(st∣at)pθ(st∣at)Aθ′(st,at)]

那么 J θ ′ ( θ ) J^{\theta'}(\theta) Jθ′(θ)是优化的目标,代表 θ ′ \theta' θ′做演示, θ \theta θ是实际优化的参数。

Add Constraint

我们先前提到了分布 p p p和分布 q q q不能差太远,为了进一步解决这个问题,我们再引入一个限制,KL散度。

KL散度(Kullback-Leibler Divergence)是衡量两个概率分布之间差异的一种方法。在信息论和统计学中,它描述了一个概率分布 P P P相对于另一个概率分布 Q Q Q的信息损失。KL散度可以看作是用分布 Q Q Q来近似分布 P P P所造成的差异或误差。

对于离散概率分布 P P P和 Q Q Q,KL散度定义为:
D K L ( P ∥ Q ) = ∑ x P ( x ) l o g Q ( x ) P ( x ) D_{KL}(P∥Q)= \sum_x P(x)log \frac{Q(x)}{P(x)} DKL(P∥Q)=x∑P(x)logP(x)Q(x)

对于连续概率分布 P P P和 Q Q Q,KL散度定义为:
D K L ( P ∥ Q ) = ∫ − ∞ ∞ P ( x ) l o g Q ( x ) P ( x ) d x D_{KL}(P∥Q)= \int^{\infty}_{-\infty } P(x)log \frac{Q(x)}{P(x)} dx DKL(P∥Q)=∫−∞∞P(x)logP(x)Q(x)dx

其中 p ( x ) p(x) p(x)和 q ( x ) q(x) q(x)分别是分布 P P P和 Q Q Q的概率密度函数。

通过给优化项添加一个KL散度的限制,那么我们就获得了PPO的优化公式了。

Proximal Policy Optimization(PPO)

公式如下:
J P P O θ ′ ( θ ) = J θ ′ ( θ ) − β K L ( θ , θ ′ ) J^{\theta'}_{PPO}(\theta) = J^{\theta'}(\theta) - \beta KL(\theta, \theta') JPPOθ′(θ)=Jθ′(θ)−βKL(θ,θ′)

我们需要优化的是 J θ ′ ( θ ) J^{\theta'}(\theta) Jθ′(θ),这个值越大越好,惩罚项是 β K L ( θ , θ ′ ) \beta KL(\theta, \theta') βKL(θ,θ′),是我们希望最小化的部分。这里要注意一下,虽然公式是这么写的,但我们实际希望的不是 θ \theta θ与 θ ′ \theta' θ′的实际数值越相似越好,而是它们的behavior越接近越好。就是说输入 s t s_t st给到 θ \theta θ和 θ ′ \theta' θ′,它们得到的action越接近越好。

PPO的前身是TRPO,它更复杂一点:
J T R P O θ ′ ( θ ) = E ( s t , a t ) ∼ π θ ′ [ p θ ( s t ∣ a t ) p θ ′ ( s t ∣ a t ) A θ ′ ( s t , a t ) ] K L ( θ , θ ′ ) < δ J^{\theta'}{TRPO}(\theta) = E{(s_t,a_t) \sim \pi_{\theta'}} [\frac{p_\theta(s_t|a_t)}{p_{\theta'}(s_t|a_t)} A^{\theta'}(s_t,a_t)] \qquad KL(\theta, \theta') < \delta JTRPOθ′(θ)=E(st,at)∼πθ′[pθ′(st∣at)pθ(st∣at)Aθ′(st,at)]KL(θ,θ′)<δ

TRPO是将KL散度当成一个限制,希望它小于一个值,这个值比较难确定,而且难优化。在实际优化中,PPO和TRPO效果差不多,所以后面基本都用PPO。

PPO算法流程

PPO的整个流程其实很简单,先初始化一个参数 θ \theta θ,让它与环境做互动收集数据,计算Advantage项。由于添加了惩罚项,收集的数据可以update θ \theta θ很多次,或者可以将学习率调大,直到收敛。其中 β \beta β是一个动态的数值,我们可以设置一个能够接受的最大值和最小值,让它根据实际情况动态调整。

PPO2

PPO2是PPO的加强版,我们先来看看它的公式:
J P P O 2 θ k ( θ ) ≈ ∑ ( s t , a t ) m i n ( p θ ( s t ∣ a t ) p θ k ( s t ∣ a t ) A θ k ( s t , a t ) , c l i p ( p θ ( s t ∣ a t ) p θ k ( s t ∣ a t ) , 1 − ϵ , 1 + ϵ ) A θ k ( s t , a t ) ) \begin{align*} J^{\theta^k}{PPO2}(\theta) \approx \sum{(s_t,a_t)} min( &\frac{p_\theta(s_t|a_t)}{p_{\theta^k}(s_t|a_t)} A^{\theta^k}(s_t,a_t), \\ &clip(\frac{p_\theta(s_t|a_t)}{p_{\theta^k}(s_t|a_t)}, 1 - \epsilon,1 + \epsilon) A^{\theta^k}(s_t,a_t)) \end{align*} JPPO2θk(θ)≈(st,at)∑min(pθk(st∣at)pθ(st∣at)Aθk(st,at),clip(pθk(st∣at)pθ(st∣at),1−ϵ,1+ϵ)Aθk(st,at))

我们分开来看:
c l i p ( p θ ( s t ∣ a t ) p θ k ( s t ∣ a t ) , 1 − ϵ , 1 + ϵ ) clip(\frac{p_\theta(s_t|a_t)}{p_{\theta^k}(s_t|a_t)}, 1 - \epsilon,1 + \epsilon) clip(pθk(st∣at)pθ(st∣at),1−ϵ,1+ϵ)

这一项是指 p θ ( s t ∣ a t ) p θ k ( s t ∣ a t ) \frac{p_\theta(s_t|a_t)}{p_{\theta^k}(s_t|a_t)} pθk(st∣at)pθ(st∣at)如果小于 1 − ϵ 1 - \epsilon 1−ϵ,就截断为 1 − ϵ 1 - \epsilon 1−ϵ,如果大于 1 + ϵ 1 + \epsilon 1+ϵ,那就截断为 1 + ϵ 1 + \epsilon 1+ϵ。相当于设置了一个区间,函数曲线是这样的:

接下来,我们再加上 m i n ( p θ ( s t ∣ a t ) p θ k ( s t ∣ a t ) A θ k ( s t , a t ) min(\frac{p_\theta(s_t|a_t)}{p_{\theta^k}(s_t|a_t)} A^{\theta^k}(s_t,a_t) min(pθk(st∣at)pθ(st∣at)Aθk(st,at),会有点复杂,我们可以分情况来分析:

  • 如果 A > 0 A > 0 A>0,也就是说某个状态和动作 ( s t , a t ) (s_t,a_t) (st,at)是好的,我们需要调大这一项 p θ ( s t ∣ a t ) p θ k ( s t ∣ a t ) \frac{p_\theta(s_t|a_t)}{p_{\theta^k}(s_t|a_t)} pθk(st∣at)pθ(st∣at)出现的机率。但是不要忘了,不能让 θ \theta θ和 θ ′ \theta' θ′差距太大,所以最大不能超过 1 + ϵ 1 + \epsilon 1+ϵ
  • 如果 A < 0 A < 0 A<0,也就是说某个状态和动作 ( s t , a t ) (s_t,a_t) (st,at)是不好的,我们需要减小这一项 p θ ( s t ∣ a t ) p θ k ( s t ∣ a t ) \frac{p_\theta(s_t|a_t)}{p_{\theta^k}(s_t|a_t)} pθk(st∣at)pθ(st∣at)出现的机率。同时,不能让 θ \theta θ和 θ ′ \theta' θ′差距太大,所以最小不能小于 1 − ϵ 1 - \epsilon 1−ϵ

所以 1 + ϵ 1 + \epsilon 1+ϵ和 1 − ϵ 1 - \epsilon 1−ϵ是惩罚项的上界和下界。

以上就是PPO/PPO2的全部内容。

争议

曾经在面试的时候,被问到过一个问题:"PPO是On-policy还是Off-policy的?"。当时不假思索的就回答是Off-policy的。但后面听到面试官说是Off-policy的,我又回来查了下资料。引用一下我认为比较清晰的解释

其实可以很简单的解释这个问题,根据off-policy的定义,采样的网络和要优化的网络不是一个网络,那么对于PPO来说,使用一批数据从更新actor的第二个epoch开始,数据虽然都是旧的actor采样得到的,但是我们并没有直接使用这批数据去更新我们的新的actor,而是使用imporance sampling先将数据分布不同导致的误差进行了修正 。那么这个importance sampling的目的就是让这两者数据分布之间的差异尽可能的缩小,那么就可以近似理解成做了importance sampling之后的数据就是我们的更新(这里的更新指的是多个epoch更新的中间过程)后的actor采样得来的,这样就可以理解成我们要优化得actor和采样得actor是同一个actor,那么他就是on-policy的

相关推荐
迷迭所归处2 分钟前
C++ —— 关于vector
开发语言·c++·算法
leon62532 分钟前
优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序
开发语言·算法·matlab
CV工程师小林32 分钟前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先
Navigator_Z1 小时前
数据结构C //线性表(链表)ADT结构及相关函数
c语言·数据结构·算法·链表
Aic山鱼1 小时前
【如何高效学习数据结构:构建编程的坚实基石】
数据结构·学习·算法
天玑y1 小时前
算法设计与分析(背包问题
c++·经验分享·笔记·学习·算法·leetcode·蓝桥杯
sjsjs112 小时前
【数据结构-一维差分】力扣1893. 检查是否区域内所有整数都被覆盖
数据结构·算法·leetcode
redcocal2 小时前
地平线秋招
python·嵌入式硬件·算法·fpga开发·求职招聘
码了三年又三年2 小时前
【算法】滑动窗口—找所有字母异位词
算法
山脚ice2 小时前
【Hot100】LeetCode—72. 编辑距离
算法·leetcode