参考资料
https://datawhalechina.github.io/easy-rl/#/chapter5/chapter5
PPO代码实现见于github仓库
1. From On-policy to Off-policy
1.1 on policy and off policy 回顾
在讲 PPO 之前,我们先回顾下 on-policy 和 off-policy 这两种训练方法的区别。
- 如果要学习的 agent 跟和环境互动的 agent 是同一个的话, 这个叫做on-policy(同策略)。
- 如果要学习的 agent 跟和环境互动的 agent 不是同一个的话, 那这个叫做off-policy(异策略)。
比较拟人化的讲法是如果要学习的那个 agent,一边跟环境互动,一边做学习这个叫 on-policy。 如果它在旁边看别人玩,通过看别人玩来学习的话,这个叫做 off-policy。
- Policy gradient 是 on-policy 的做法,因为在做 policy gradient 时,我们需要有一个 agent、一个 policy 和一个 actor。这个 actor 先去跟环境互动去搜集资料,搜集很多的 τ \tau τ,根据它搜集到的信息按照 policy gradient 的式子去更新 policy 的参数。所以 policy gradient 是一个 on-policy 的算法。
1.2 PPO引入
-
近端策略优化(Proximal Policy Optimization,简称 PPO) 是 policy gradient 的一个变形,它是现在 OpenAI 默认的baseline。
∇ R ˉ θ = E τ ∼ p θ ( τ ) [ R ( τ ) ∇ log p θ ( τ ) ] \nabla \bar{R}_{\theta}=E_{\tau \sim p_{\theta}(\tau)}\left[R(\tau) \nabla \log p_{\theta}(\tau)\right] ∇Rˉθ=Eτ∼pθ(τ)[R(τ)∇logpθ(τ)] -
出现的问题:上面这个更新的式子中的 E τ ∼ p θ ( τ ) E_{\tau \sim p_{\theta}(\tau)} Eτ∼pθ(τ)应该是你现在的 policy π θ \pi_{\theta} πθ 所采样出来的轨迹 τ \tau τ 做期望(expectation)。一旦更新了参数,从 θ \theta θ 变成 θ ′ \theta' θ′ , p θ ( τ ) p_\theta(\tau) pθ(τ)这个概率就不对了,之前采样出来的数据就变的不能用了。所以 policy gradient 是一个会花很多时间来采样数据的算法,大多数时间都在采样数据,agent 去跟环境做互动以后,接下来就要更新参数。你只能更新参数一次。接下来你就要重新再去收集数据, 然后才能再次更新参数。
-
这显然是非常花时间的,所以我们想要从 on-policy 变成 off-policy。 这样做就可以用另外一个 policy, 另外一个 actor θ ′ \theta' θ′去跟环境做互动( θ ′ \theta' θ′被固定了)。用 θ ′ \theta' θ′ 收集到的数据去训练 θ \theta θ。假设我们可以用 θ ′ \theta' θ′ 收集到的数据去训练 θ \theta θ,意味着说我们可以把 θ ′ \theta' θ′ 收集到的数据用非常多次,我们可以执行梯度上升(gradient ascent)好几次,我们可以更新参数好几次, 都只要用同一笔数据就好了。因为假设 θ \theta θ 有能力学习另外一个 actor θ ′ \theta' θ′ 所采样出来的数据的话, 那 θ ′ \theta' θ′就只要采样一次,也许采样多一点的数据, 让 θ \theta θ 去更新很多次,这样就会比较有效率。
1.3 Importance Sampling
对于ー个随机变量,通常用概率密度函数来刻画该变量的概率分布特性。具体来说,给定随机变量的一个取值,可以根据概率密度函数来计算该值对应的概率(密度)。反过来,也可以根据概率密度函数提供的概率分布信息来生成随机变量的一个取值,这就是采样。因此,从某种意义上来说,采样是概率密度函数的逆向应用。与根据概率密度函数计算样本点对应的概率值不同,采样过程往往没有那么直接,通常需要根据待采样分布的具体特点来选择合适的采样策略。
1.3.1 重要性采样定义
-
假设有一个函数 f ( x ) f(x) f(x),要先从 p 分布采样 x x x,再把采样到的 x x x 带到 f f f 里面,得到 f ( x ) f(x) f(x)。该怎么计算这个 f ( x ) f(x) f(x) 的期望值?假设不能对 p 这个分布做积分的话,那可以从 p 这个分布去采样一些数据 x i x^i xi。把 x i x^i xi 代到 f ( x ) f(x) f(x) 里面,然后取它的平均值,就可以近似 f ( x ) f(x) f(x) 的期望值。
-
现在有另外一个问题,假设我们不能从 p 采样数据,只能从另外一个分布 q 去采样数据,q 可以是任何分布。我们从 q 去采样 x i x^i xi 的话就不能直接套下面的式子:
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)
因为上式是假设你的 x x x 都是从 p 采样出来的。 -
所以做一个修正。期望值 E x ∼ p [ f ( x ) ] E_{x \sim p}[f(x)] Ex∼p[f(x)]其实就是 ∫ f ( x ) p ( x ) d x \int f(x) p(x) dx ∫f(x)p(x)dx,我们对其做如下的变换:
∫ 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 ) ] \int f(x) p(x) d x=\int f(x) \frac{p(x)}{q(x)} q(x) d x=E_{x \sim q}[f(x){\frac{p(x)}{q(x)}}] ∫f(x)p(x)dx=∫f(x)q(x)p(x)q(x)dx=Ex∼q[f(x)q(x)p(x)]
我们就可以写成对 q 里面所采样出来的 x x x 取期望值。我们从 q 里面采样 x x x,然后再去计算 f ( x ) p ( x ) q ( x ) f(x) \frac{p(x)}{q(x)} f(x)q(x)p(x),再去取期望值。 -
这边是从 q 做采样,所以从 q 里采样出来的每一笔数据,需要乘上一个重要性权重(importance weight) p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x) 来修正这两个分布的差异。 q ( x ) q(x) q(x)可以是任何分布,唯一的限制情况就是 q ( x ) q(x) q(x) 的概率是 0 的时候, p ( x ) p(x) p(x) 的概率不为 0,这样会没有定义。假设 q ( x ) q(x) q(x) 的概率是 0 的时候, p ( x ) p(x) p(x) 的概率也都是 0 的话,那这样 p ( x ) p(x) p(x) 除以 q ( x ) q(x) q(x)是有定义的,这种情况下就可以使用重要性采样这个技巧,可以从 p 做采样换成从 q 做采样。
1.3.2 重要性采样问题
-
虽然理论上可以把 p 换成任何的 q。但是在实现上,p 和 q 不能差异太大。
E x ∼ p [ f ( x ) ] = E x ∼ q [ f ( x ) p ( x ) q ( x ) ] E_{x \sim p}[f(x)]=E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] Ex∼p[f(x)]=Ex∼q[f(x)q(x)p(x)] -
虽然上式成立(上式左边是 f ( x ) f(x) f(x) 的期望值,它的分布是 p,上式右边是 f ( x ) p ( x ) q ( x ) f(x)\frac{p(x)}{q(x)} f(x)q(x)p(x)的期望值,它的分布是 q),但如果不是算期望值,而是算方差的话, Var x ∼ p [ f ( x ) ] \operatorname{Var}_{x \sim p}[f(x)] Varx∼p[f(x)] 和 Var x ∼ q [ f ( x ) p ( x ) q ( x ) ] \operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] Varx∼q[f(x)q(x)p(x)]是不一样的。两个随机变量的平均值一样,并不代表它的方差一样。
-
我们可以代方差的公式 Var [ X ] = E [ X 2 ] − ( E [ X ] ) 2 \operatorname{Var}[X]=E\left[X^{2}\right]-(E[X])^{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 \operatorname{Var}_{x \sim p}[f(x)]=E_{x \sim p}\left[f(x)^{2}\right]-\left(E_{x \sim p}[f(x)]\right)^{2} Varx∼p[f(x)]=Ex∼p[f(x)2]−(Ex∼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{aligned} \operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] &=E_{x \sim q}\left[\left(f(x) \frac{p(x)}{q(x)}\right)^{2}\right]-\left(E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]\right)^{2} \\ &=E_{x \sim p}\left[f(x)^{2} \frac{p(x)}{q(x)}\right]-\left(E_{x \sim p}[f(x)]\right)^{2} \end{aligned} Varx∼q[f(x)q(x)p(x)]=Ex∼q[(f(x)q(x)p(x))2]−(Ex∼q[f(x)q(x)p(x)])2=Ex∼p[f(x)2q(x)p(x)]−(Ex∼p[f(x)])2
Var x ∼ p [ f ( x ) ] \operatorname{Var}_{x \sim p}[f(x)] Varx∼p[f(x)] 和 Var x ∼ q [ f ( x ) p ( x ) q ( x ) ] \operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] Varx∼q[f(x)q(x)p(x)]的差别在第一项是不同的, Var x ∼ q [ f ( x ) p ( x ) q ( x ) ] \operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] Varx∼q[f(x)q(x)p(x)] 的第一项多乘了 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x),如果 p ( x ) q ( x ) \frac{p(x)}{q(x)} q(x)p(x)差距很大的话, f ( x ) p ( x ) q ( x ) f(x)\frac{p(x)}{q(x)} f(x)q(x)p(x) 的方差就会很大。所以如果采样的次数不够多,因为它们的方差差距是很大的,所以就有可能得到非常大的差别。
1.3.3 问题举例
- 假设蓝线是 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 ) ] E_{x \sim p}[f(x)] Ex∼p[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 ) ] E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] Ex∼q[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) 很小,这样就可以平衡掉刚才那边一直采样到正的值的情况。最终你算出这一项的期望值,终究还是负的。但前提是你要采样够多次,这件事情才会发生。但有可能采样次数不够多, E x ∼ p [ f ( x ) ] E_{x \sim p}[f(x)] Ex∼p[f(x)] 跟 E x ∼ q [ f ( x ) p ( x ) q ( x ) ] E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] Ex∼q[f(x)q(x)p(x)] 就有可能有很大的差距。这就是重要性采样的问题。
1.3.4 on policy --> off policy
如何把重要性采样用在 off-policy 的情况,把 on-policy 训练的算法改成 off-policy 训练的算法?
- 之前我们是拿 θ \theta θ 这个 policy 去跟环境做互动,采样出轨迹 τ \tau τ,然后计算 R ( τ ) ∇ log p θ ( τ ) R(\tau) \nabla \log p_{\theta}(\tau) R(τ)∇logpθ(τ)。现在我们不用 θ \theta θ 去跟环境做互动,假设有另外一个 policy θ ′ \theta' θ′,它就是另外一个 actor。它的工作是去做示范(demonstration)。 θ ′ \theta' θ′ 的工作是要去示范给 θ \theta θ 看。它去跟环境做互动,告诉 θ \theta θ 说,它跟环境做互动会发生什么事,借此来训练 θ \theta θ。我们要训练的是 θ \theta θ , θ ′ \theta' θ′ 只是负责做示范,跟环境做互动。
- 我们现在的 τ \tau τ 是从 θ ′ \theta' θ′ 采样出来的,是拿 θ ′ \theta' θ′ 去跟环境做互动。所以采样出来的 τ \tau τ 是从 θ ′ \theta' θ′ 采样出来的,这两个分布不一样。但没有关系,假设你本来是从 p 做采样,但你发现你不能从 p 做采样,所以我们不拿 θ \theta θ 去跟环境做互动。你可以把 p 换 q,然后在后面补上一个重要性权重。现在的状况就是一样,把 θ \theta θ 换成 θ ′ \theta' θ′ 后,要补上一个重要性权重 p θ ( τ ) p θ ′ ( τ ) \frac{p_{\theta}(\tau)}{p_{\theta^{\prime}}(\tau)} pθ′(τ)pθ(τ)。这个重要性权重就是某一个轨迹 τ \tau τ 用 θ \theta θ 算出来的概率除以这个轨迹 τ \tau τ 用 θ ′ \theta' θ′ 算出来的概率。这一项是很重要的,因为你要学习的是 actor θ \theta θ 和 θ ′ \theta' θ′ 是不太一样的, θ ′ \theta' θ′ 会见到的情形跟 θ \theta θ 见到的情形不见得是一样的,所以中间要做一个修正的项。
Q: 现在的数据是从 θ ′ \theta' θ′ 采样出来的,从 θ \theta θ 换成 θ ′ \theta' θ′ 有什么好处?
A: 因为现在跟环境做互动是 θ ′ \theta' θ′ 而不是 θ \theta θ。所以采样出来的东西跟 θ \theta θ 本身是没有关系的。所以你就可以让 θ ′ \theta' θ′ 做互动采样一大堆的数据, θ \theta θ 可以更新参数很多次,一直到 θ \theta θ 训练到一定的程度,更新很多次以后, θ ′ \theta' θ′ 再重新去做采样,这就是 on-policy 换成 off-policy 的妙用。
-
我们通过重要性采样把 on-policy 变成 off-policy,从 θ \theta θ 变成 θ ′ \theta' θ′。所以现在 s t s_t st、 a t a_t at 是 θ ′ \theta' θ′ 跟环境互动以后所采样到的数据。 但是拿来训练要调整参数是模型 θ \theta θ。因为 θ ′ \theta' θ′ 跟 θ \theta θ 是不同的模型,所以要做一个修正的项。这项修正的项,就是用重要性采样的技术,把 s t s_t st、 a t a_t at 用 θ \theta θ 采样出来的概率除掉 s t s_t st、 a t a_t at 用 θ ′ \theta' θ′采样出来的概率。
= 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 ) ] =E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(s_{t}, a_{t}\right)}{p_{\theta^{\prime}}\left(s_{t}, a_{t}\right)} A^{\theta}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] =E(st,at)∼πθ′[pθ′(st,at)pθ(st,at)Aθ(st,at)∇logpθ(atn∣stn)] -
A θ ( s t , a t ) A^{\theta}(s_t,a_t) Aθ(st,at)有一个上标 θ \theta θ, θ \theta θ 代表说这个是 actor θ \theta θ 跟环境互动的时候所计算出来的 A。但是实际上从 θ \theta θ 换到 θ ′ \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 这一项是想要估测说现在在某一个状态采取某一个动作,接下来会得到累积奖励的值减掉 baseline 。之前是 θ \theta θ 在跟环境做互动,所以你观察到的是 θ \theta θ 可以得到的奖励。但现在是 θ ′ \theta' θ′在跟环境做互动,所以你得到的这个 advantage, 其实是根据 θ ′ \theta' θ′ 所估计出来的 advantage。但我们现在先不要管那么多,我们就假设这两项可能是差不多的。
-
接下来,我们可以拆解 p θ ( s t , a t ) p_{\theta}\left(s_{t}, a_{t}\right) pθ(st,at)和 p θ ′ ( s t , a t ) p_{\theta'}\left(s_{t}, a_{t}\right) pθ′(st,at),即
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 ) \begin{aligned} p_{\theta}\left(s_{t}, a_{t}\right)&=p_{\theta}\left(a_{t}|s_{t}\right) p_{\theta}(s_t) \\ p_{\theta'}\left(s_{t}, a_{t}\right)&=p_{\theta'}\left(a_{t}|s_{t}\right) p_{\theta'}(s_t) \end{aligned} pθ(st,at)pθ′(st,at)=pθ(at∣st)pθ(st)=pθ′(at∣st)pθ′(st) -
于是我们得到下式:
= E ( s t , a t ) ∼ π θ ′ [ p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) p θ ( s t ) p θ ′ ( s t ) A θ ′ ( s t , a t ) ∇ log p θ ( a t n ∣ s t n ) ] =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)} \frac{p_{\theta}\left(s_{t}\right)}{p_{\theta^{\prime}}\left(s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] =E(st,at)∼πθ′[pθ′(at∣st)pθ(at∣st)pθ′(st)pθ(st)Aθ′(st,at)∇logpθ(atn∣stn)] -
假设模型是 θ \theta θ 的时候, 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 ) ] (1) =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) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] \tag{1} =E(st,at)∼πθ′[pθ′(at∣st)pθ(at∣st)Aθ′(st,at)∇logpθ(atn∣stn)](1) -
现在我们得到一个新的目标函数。
J θ ′ ( θ ) = E ( s t , a t ) ∼ π θ ′ [ p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) A θ ′ ( s t , a t ) ] J^{\theta^{\prime}}(\theta)=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] Jθ′(θ)=E(st,at)∼πθ′[pθ′(at∣st)pθ(at∣st)Aθ′(st,at)]
式(1)是梯度,其实我们可以从梯度去反推原来的目标函数,我们可以用如下的公式来反推目标函数:
f ( x ) = f ( x ) ∇ log f ( x ) f(x)=f(x) \nabla \log f(x) f(x)=f(x)∇logf(x) -
要注意一点,对 θ \theta θ 求梯度时, p θ ′ ( a t ∣ s t ) p_{\theta^{\prime}}(a_{t} | s_{t}) pθ′(at∣st)) 和 A θ ′ ( s t , a t ) A^{\theta^{\prime}}\left(s_{t}, a_{t}\right) Aθ′(st,at)都是常数。
-
用 θ ′ \theta' θ′ 去跟环境做互动,采样出 s t s_t st、 a t a_t at 以后,你要去计算 s t s_t st 跟 a t a_t at 的 advantage,然后你再去把它乘上 p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) \frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} pθ′(at∣st)pθ(at∣st)。 p θ ( a t ∣ s t ) p θ ′ ( a t ∣ s t ) \frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} pθ′(at∣st)pθ(at∣st)是好算的, A θ ′ ( s t , a t ) A^{\theta^{\prime}}\left(s_{t}, a_{t}\right) Aθ′(st,at)可以从这个采样的结果里面去估测出来的,所以 J θ ′ ( θ ) J^{\theta^{\prime}}(\theta) Jθ′(θ) 是可以算的。实际上在更新参数的时候,就是按照式(1) 来更新参数。
2. PPO详解
-
我们可以通过重要性采样把 on-policy 换成 off-policy,但重要性采样有一个问题:如果 p θ ( a t ∣ s t ) p_{\theta}\left(a_{t} | s_{t}\right) pθ(at∣st)跟 p θ ′ ( a t ∣ s t ) p_{\theta'}\left(a_{t} | s_{t}\right) pθ′(at∣st)这两个分布差太多的话,重要性采样的结果就会不好。怎么避免它差太多呢?这个就是 Proximal Policy Optimization (PPO) 在做的事情。
-
注意,由于在 PPO 中 θ ′ \theta' θ′是 θ old \theta_{\text{old}} θold,即 behavior policy 也是 θ \theta θ,所以 PPO 本质上还是 on-policy 的算法。
-
PPO 实际上做的事情就是这样,在 off-policy 的方法里要优化的是 J θ ′ ( θ ) J^{\theta^{\prime}}(\theta) Jθ′(θ))。在做重要性采样的时候, p θ ( a t ∣ s t ) p_{\theta}\left(a_{t} | s_{t}\right) pθ(at∣st) 不能跟 p θ ′ ( a t ∣ s t ) p_{\theta'}\left(a_{t} | s_{t}\right) pθ′(at∣st)差太多。我们在训练的时候,多加一个约束(constrain)。这个约束是 θ \theta θ 跟 θ ′ \theta' θ′输出的动作的 KL 散度(KL divergence)。
-
在训练的过程中,我们希望学习出来的 θ \theta θ 跟 θ ′ \theta' θ′ 越像越好。所以在 PPO 里面有两个式子,一方面是优化本来要优化的东西,但再加一个约束。这个约束就好像正则化(regularization) 的项(term) 一样。
Q: 为什么不直接算 θ \theta θ 和 θ ′ \theta' θ′ 之间的距离?算这个距离的话,甚至不要用 KL 散度算,L1 跟 L2 的范数(norm)也可以保证 θ \theta θ 跟 θ ′ \theta' θ′ 很接近。
A: 在做强化学习的时候,之所以我们考虑的不是参数上的距离,而是动作上的距离,是因为很有可能对 actor 来说,参数的变化跟动作的变化不一定是完全一致的。有时候参数小小变了一下,它可能输出的行为就差很多。或者是参数变很多,但输出的行为可能没什么改变。所以我们真正在意的是这个 actor 的行为上的差距,而不是它们参数上的差距。所以在做 PPO 的时候,所谓的 KL 散度并不是参数的距离,而是动作的距离。
2.1 TRPO
-
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 ) ] K L ( θ , θ ′ ) < δ \begin{aligned} J_{T R P O}^{\theta^{\prime}}(\theta)=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} JTRPOθ′(θ)=E(st,at)∼πθ′[pθ′(at∣st)pθ(at∣st)Aθ′(st,at)]KL(θ,θ′)<δ -
它与 PPO 不一样的地方是约束的位置不一样,PPO 是直接把约束放到要优化的那个式子里面,然后就可以用梯度上升的方法去最大化这个式子。但 TRPO 是把 KL 散度当作约束,它希望 θ \theta θ 跟 θ ′ \theta' θ′ 的 KL 散度小于一个 δ \delta δ。如果你使用的是基于梯度的优化时,有约束是很难处理的。
-
TRPO 是很难处理的,因为它把 KL 散度约束当做一个额外的约束,没有放目标(objective)里面,所以它很难算,所以一般就用 PPO 而不是 TRPO。看文献上的结果是,PPO 跟 TRPO 性能差不多,但 PPO 在实现上比 TRPO 容易的多。
2.2 PPO-Penalty(PPO1)
PPO 算法有两个主要的变种:PPO-Penalty 和 PPO-Clip。我们来看一下 PPO1 的算法,即 PPO-Penalty。
- 它先初始化一个 policy 的参数 θ 0 \theta^0 θ0。然后在每一个迭代里面,用 θ k \theta^k θk 去跟环境做互动,采样到一大堆状态-动作的对。 θ k \theta^k θk 就是在前一个训练的迭代得到的 actor 的参数。
- 根据
θ
k
\theta^k
θk 互动的结果,估测
A
θ
k
(
s
t
,
a
t
)
A^{\theta^{k}}\left(s_{t}, a_{t}\right)
Aθk(st,at),然后使用 PPO 的优化的公式。但跟原来的 policy gradient 不一样,原来的 policy gradient 只能更新一次参数,更新完以后,就要重新采样数据。但是现在不用,你拿
θ
k
\theta^k
θk 去跟环境做互动,采样到这组数据以后,可以让
θ
\theta
θ 更新很多次,想办法去最大化目标函数。这边
θ
\theta
θ 更新很多次没有关系,因为我们已经有做重要性采样,所以这些状态-动作的对是从
θ
k
\theta^k
θk 采样出来的没有关系。
θ
\theta
θ 可以更新很多次,它跟
θ
k
\theta^k
θk 变得不太一样也没有关系,你还是可以照样训练
θ
\theta
θ。
2.2.1 adaptive KL divergence
在 PPO 的论文里面还有一个 adaptive KL divergence。这边会遇到一个问题就是
β
\beta
β 要设多少,它就跟正则化一样。正则化前面也要乘一个权重,所以这个 KL 散度前面也要乘一个权重,但
β
\beta
β 要设多少呢?所以有个动态调整
β
\beta
β 的方法。
- 在这个方法里面,先设一个可以接受的 KL 散度的最大值。假设优化完这个式子以后,发现 KL 散度的项太大,那就代表后面这个惩罚的项没有发挥作用,那就把 β \beta β 调大。
- 另外,设一个 KL 散度的最小值。如果优化完上面这个式子以后,发现 KL 散度比最小值还要小,那代表后面这一项的效果太强了,那 θ \theta θ 跟 θ k \theta^k θk 都一样,这不是你要的,所以你要减少 β \beta β。
2.3 PPO-Clip(PPO2)
如果你觉得算 KL 散度很复杂,有一个PPO2,PPO2 即 PPO-Clip。PPO2 要最大化的目标函数如下式所示,它的式子里面没有 KL 散度 。
J
P
P
O
2
θ
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
)
)
\begin{aligned} J_{P P O 2}^{\theta^{k}}(\theta) \approx \sum_{\left(s_{t}, a_{t}\right)} \min &\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)} A^{\theta^{k}}\left(s_{t}, a_{t}\right),\right.\\ &\left.\operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right) A^{\theta^{k}}\left(s_{t}, a_{t}\right)\right) \end{aligned}
JPPO2θk(θ)≈(st,at)∑min(pθk(at∣st)pθ(at∣st)Aθk(st,at),clip(pθk(at∣st)pθ(at∣st),1−ε,1+ε)Aθk(st,at))
- Min 这个操作符(operator)做的事情是第一项跟第二项里面选比较小的那个。
- 第二项前面有个 clip 函数,clip 函数的意思是说,
- 在括号里面有三项,如果第一项小于第二项的话,那就输出 1 − ε 1-\varepsilon 1−ε 。
- 第一项如果大于第三项的话,那就输出 1 + ε 1+\varepsilon 1+ε。
- ε \varepsilon ε 是一个超参数,需要 tune ,可以设成 0.1 或 设 0.2 。
2.3.1 clip
上图的横轴是 p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) \frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)} pθk(at∣st)pθ(at∣st),纵轴是 clip 函数的输出。
- 如果 p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) \frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)} pθk(at∣st)pθ(at∣st) 大于 1 + ε 1+\varepsilon 1+ε,输出就是 1 + ε 1+\varepsilon 1+ε。
- 如果小于 1 − ε 1-\varepsilon 1−ε, 它输出就是 1 − ε 1-\varepsilon 1−ε。
- 如果介于 1 + ε 1+\varepsilon 1+ε 跟 1 − ε 1-\varepsilon 1−ε 之间, 就是输入等于输出。
- p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) \frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)} pθk(at∣st)pθ(at∣st) 是绿色的线;
- clip ( p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) , 1 − ε , 1 + ε ) \operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right) clip(pθk(at∣st)pθ(at∣st),1−ε,1+ε) 是蓝色的线;
- 在绿色的线跟蓝色的线中间,我们要取一个最小的。假设前面乘上的这个项 A,它是大于 0 的话,取最小的结果,就变成红色的这一条线。
- 如果 A 小于 0 的话,取最小的以后,就得到红色的这一条线。
虽然这个式子看起来有点复杂,实现起来是蛮简单的,因为这个式子想要做的事情就是希望 p θ ( a t ∣ s t ) p_{\theta}(a_{t} | s_{t}) pθ(at∣st) 跟 p θ k ( a t ∣ s t ) p_{\theta^k}(a_{t} | s_{t}) pθk(at∣st),也就是拿来做示范的模型跟你实际上学习的模型,在优化以后不要差距太大。
-
怎么让它做到不要差距太大呢?
- 如果 A > 0,也就是某一个状态-动作的对是好的,那我们希望增加这个状态-动作对的概率。也就是说,我们想要让 p θ ( a t ∣ s t ) p_{\theta}(a_{t} | s_{t}) pθ(at∣st)越大越好,但它跟 p θ k ( a t ∣ s t ) p_{\theta^k}(a_{t} | s_{t}) pθk(at∣st)的比值不可以超过 1 + ε 1+\varepsilon 1+ε。如果超过 1 + ε 1+\varepsilon 1+ε 的话,就没有 benefit 了。红色的线就是我们的目标函数,我们希望目标越大越好,我们希望 p θ ( a t ∣ s t ) p_{\theta}(a_{t} | s_{t}) pθ(at∣st) 越大越好。但是 p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) \frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)} pθk(at∣st)pθ(at∣st) 只要大过 1 + ε 1+\varepsilon 1+ε,就没有 benefit 了。所以在训练的时候,当 p θ ( a t ∣ s t ) p_{\theta}(a_{t} | s_{t}) pθ(at∣st) 被训练到 p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) > 1 + ε \frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}>1+\varepsilon pθk(at∣st)pθ(at∣st)>1+ε 时,它就会停止。假设 p θ ( a t ∣ s t ) p_{\theta}(a_{t} | s_{t}) pθ(at∣st) 比 p θ k ( a t ∣ s t ) p_{\theta^k}(a_{t} | s_{t}) pθk(at∣st) 还要小,并且这个 advantage 是正的。因为这个动作是好的,我们当然希望这个动作被采取的概率越大越好,我们希望 p θ ( a t ∣ s t ) p_{\theta}(a_{t} | s_{t}) pθ(at∣st)越大越好。所以假设 p θ ( a t ∣ s t ) p_{\theta}(a_{t} | s_{t}) pθ(at∣st)还比 p θ k ( a t ∣ s t ) p_{\theta^k}(a_{t} | s_{t}) pθk(at∣st)小,那就尽量把它挪大,但只要大到 1 + ε 1+\varepsilon 1+ε就好。
- 如果 A < 0,也就是某一个状态-动作对是不好的,我们希望把 p θ ( a t ∣ s t ) p_{\theta}(a_{t} | s_{t}) pθ(at∣st) 减小。如果 p θ ( a t ∣ s t ) p_{\theta}(a_{t} | s_{t}) pθ(at∣st) 比 p θ k ( a t ∣ s t ) p_{\theta^k}(a_{t} | s_{t}) pθk(at∣st) 还大,那你就尽量把它压小,压到 p θ ( a t ∣ s t ) p θ k ( a t ∣ s t ) \frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)} pθk(at∣st)pθ(at∣st) 是 1 − ϵ 1-\epsilon 1−ϵ 的时候就停了,就不要再压得更小。
2.4 伪代码
- PPO伪代码:
- PPO-penalty:
- PPO-Clip
3. 练习
3.1 important sampling(重要性采样)
-
important sampling(重要性采样): 使用另外一种数据分布,来逼近所求分布的一种方法,在强化学习中通常和蒙特卡罗方法结合使用,公式如下: ∫ 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 ) ] = E x ∼ p [ f ( x ) ] \int f(x) p(x) d x=\int f(x) \frac{p(x)}{q(x)} q(x) d x=E_{x \sim q}[f(x){\frac{p(x)}{q(x)}}]=E_{x \sim p}[f(x)] ∫f(x)p(x)dx=∫f(x)q(x)p(x)q(x)dx=Ex∼q[f(x)q(x)p(x)]=Ex∼p[f(x)]我们在已知 q q q 的分布后,可以使用上述公式计算出从 p p p 这个distribution sample x 代入 f f f 以后所算出来的期望值。
-
基于off-policy的importance sampling中的 data 是从 θ ′ \theta' θ′sample 出来的,从 θ \theta θ 换成 θ ′ \theta' θ′有什么优势?
答:使用off-policy的importance sampling后,我们不用 θ \theta θ 去跟环境做互动,假设有另外一个 policy θ ′ \theta' θ′,它就是另外一个actor。它的工作是他要去做demonstration, θ ′ \theta' θ′ 的工作是要去示范给 θ \theta θ 看。它去跟环境做互动,告诉 θ \theta θ 说,它跟环境做互动会发生什么事。然后,借此来训练 θ \theta θ。我们要训练的是 θ \theta θ , θ ′ \theta' θ′ 只是负责做 demo,负责跟环境做互动,所以 sample 出来的东西跟 θ \theta θ 本身是没有关系的。所以你就可以让 θ ′ \theta' θ′ 做互动 sample 一大堆的data, θ \theta θ 可以update 参数很多次。然后一直到 θ \theta θ train 到一定的程度,update 很多次以后, θ ′ \theta' θ′ 再重新去做 sample,这就是 on-policy 换成 off-policy 的妙用。
3.2 简单阐述PPO
- Proximal Policy Optimization (PPO): 避免在使用important sampling时由于在 θ \theta θ 下的 p θ ( a t ∣ s t ) p_{\theta}\left(a_{t} | s_{t}\right) pθ(at∣st) 跟 在 θ ′ \theta ' θ′ 下的 p θ ′ ( a t ∣ s t ) p_{\theta'}\left(a_{t} | s_{t}\right) pθ′(at∣st) 差太多,导致important sampling结果偏差较大而采取的算法。具体来说就是在training的过程中增加一个constrain,这个constrain对应着 θ \theta θ 跟 θ ′ \theta' θ′ output 的 action 的 KL divergence,来衡量 θ \theta θ 与 θ ′ \theta' θ′ 的相似程度。
3.3 请问on-policy跟off-policy的区别是什么?
答:用一句话概括两者的区别,生成样本的policy(value-funciton)和网络参数更新时的policy(value-funciton)是否相同。具体来说,
on-policy:生成样本的policy(value function)跟网络更新参数时使用的policy(value function)相同。SARAS算法就是on-policy的,基于当前的policy直接执行一次action,然后用这个样本更新当前的policy,因此生成样本的policy和学习时的policy相同,算法为on-policy算法。该方法会遭遇探索-利用的矛盾,仅利用目前已知的最优选择,可能学不到最优解,收敛到局部最优,而加入探索又降低了学习效率。epsilon-greedy 算法是这种矛盾下的折衷。优点是直接了当,速度快,劣势是不一定找到最优策略。
off-policy:生成样本的policy(value function)跟网络更新参数时使用的policy(value function)不同。例如,Q-learning在计算下一状态的预期收益时使用了max操作,直接选择最优动作,而当前policy并不一定能选择到最优动作,因此这里生成样本的policy和学习时的policy不同,即为off-policy算法。