本章节详细介绍 PPO 和 SAC 这类实用算法,并介绍实用离线策略方法让他们更加高效
基于我们上一章节的优化公式
∇θJ(θ)≈t,i∑∇θlogπθ(at,i∣st,i)A^πθ(st,i,at,i)
如果使用 importance weight 来对更重要的样本进行加权,则有:
∇θ′J(θ′)≈t,i∑πθ(ai,t∣si,t)πθ′(ai,t∣si,t)∇θ′logπθ′(at,i∣st,i)A^πθ(st,i,at,i)
可以发现优势函数 A^πθ 是基于旧策略 πθ 和旧数据估计出来的,如果对同一批的数据优化很多不,新策略会逐渐偏离旧策略,此时优势函数就会偏离实际的训练目标了,会导致过拟合的问题。
对于这个问题,可以尽可能让新策略和旧策略更加接近,从而降低偏离的情况。
对同一个状态 s,旧策略和新策略的动作分别是 πθ(⋅∣s) 和 πθ′(⋅∣s) ,可以记 KL 散度为:
DKL(πθ(⋅∣s)∥πθ′(⋅∣s))=a∑πθ(a∣s)logπθ′(a∣s)πθ(a∣s)
实际表示意义为 KL 越小,新旧策略在同一个状态下给出的动作概率分布越接近。
在使用了 KL 散度后优化目标为只允许在就策略的小区域内进行更新。
在原始的 J(θ) 上减去一个 KL 散度的值就可以实现控制更新范围:
J(θ)−βDKL
这是 PPO 的一个变体
对 importance weight 进行裁剪,控制 πθ(ai,t∣si,t)πθ′(ai,t∣si,t) 数值的大小到某个固定的区间内。
这也是 PPO 中的一个核心技巧,参考下文。
PPO 的核心目标函数就是从普通的 policy gradient 中优化出来的,目的就是为了解决在策略更新太快时,性能可能突然崩掉的情况。
原始的梯度策略目标的梯度为
∇θJ(θ)=Est,at∼πθ[∇θlogπθ(at∣st)Aπθ(st,at)]
最大的问题就是 优势函数是从旧的 数据算的,所以 PPO 的核心就是为了改进这个问题
PPO 中的代替目标为
J~(θ′)≈t,i∑πθ(ai,t∣si,t)πθ′(ai,t∣si,t)A^πθ(st,i,at,i)
其中优势函数前面那个加权的因子称为 importance weight / probability ratio,用于衡量新策略对某个动作的概率改变量。
rt(θ′)=πθ(at∣st)πθ′(at∣st)
这个加权因子虽然能够对让策略更新在旧的策略附近,但是乘法会引入数值的不稳定。
对 importance weight 的值进行裁剪,用来控制训练时候的稳定性
J~(θ′)≈t,i∑clip(πθ(ai,t∣si,t)πθ′(ai,t∣si,t),1−ϵ,1+ϵ)A^πθ(st,i,at,i)
例如设置一个区间 [0.8,1.2] ,限制新策略对某个动作相对于旧策略的概率比例在区间内。
但此时 clip 有可能会让目标函数变得比原来值更大,对于优化过程其实是错误的,所以还需要额外的改进。
注意实际计算中,优势函数本身的值被当做一个常数(不参与梯度计算),所以一旦发生了裁剪则整个一项的梯度都变成了 0。
为了进一步控制梯度,PPO 算法额外再取一次 clip 后的值和原来的值之间更小的那个
J~(θ′)≈t,i∑min(rt(θ′)A^t,clip(rt(θ′),1−ϵ,1+ϵ)A^t)
- 在 A^t>0 时,为了控制优化的策略不要太激进,所以使用上界 (1+ϵ)A^t 来控制,此时最小值就是 (1+ϵ)A^t
- 在 A^t<0 时,例如 rtA^t=1.5×(−10)=−15,把 因数 clip 到 1.2 会得到 −12,反而让目标函数变大了,如果取最小值则还是那个 −15
在此情况下不再是一旦裁剪就梯度归零,而是还需要看最小值实际取的是哪个值。
GAE 是用来估计 A^t 的,是一种用多步 TD 误差加权求和来估计 Advantage 的方法,它通过参数 λ 在“低方差”和“低偏差”之间折中。
上一章中讲解的 蒙特卡洛等方法其实就是 GAE 的其中一种,另一种就是 TE Error。
定义 TD 误差为
δt=rt+γV(st+1)−V(st)
表示的是:当前这一步真实拿到的奖励 + 下一状态的估计价值,是否比当前状态的估计价值更好。
如果选择不同的步数 n ,可以得到各种估计方式
At(1)=rt+γV(st+1)−V(st)
At(2)=rt+γrt+1+γ2V(st+2)−V(st)
At(n)=l=0∑n−1γlrt+l+γnV(st+n)−V(st)
如果写成递推的格式就是(写代码用这个公式)
At=δt+γλAt+1
GAE 将不同的步数的 Advantage 结合起来:
AtGAE(γ,λ)=l=0∑∞(γλ)lδt+l
其中:
δt=rt+γV(st+1)−V(st)
展开就是:
AtGAE=δt+γλδt+1+(γλ)2δt+2+(γλ)3δt+3+⋯
当前时刻的优势,不只由当前一步 TD error 决定,还由后面很多步的 TD error 共同决定;越往后的 TD error,权重越小。其中 (γλ)l 就是那个衰减的权重(小于1,所以取次方后会越来越小)。
总结成一句话就是:GAE 是一种基于多步 TD error 加权累积来估计 Advantage At 的方法;在 PPO 中,它为 policy loss 提供更稳定的优势函数估计,从而指导策略应该提高还是降低某些动作的概率。
到此为止使用了两种 policy 方式,包括:
- on-policy: 使用当前的 batch 的数据做一次梯度的 step
- off-policy: 使用一个 batch 的数据做多个梯度 step
但是还有一些额外的方法可以进一步强化这个 off-policy,也就是从之前的多个 batch 来执行梯度更新,这样流程就会变成:
- 从策略中收集 experience 并放进 replay buffer:si,ai∼πθ(a∣s)
- 从 replay buffer 中采样一个 batch:si,ai,ri,si’∼R
- 使用 TD 目标更新价值函数:yi=ri+γV^ϕπ(si’),并用该目标更新 V^ϕπ
- 计算优势函数估计:A^π(si,ai)=r(si,ai)+γV^ϕπ(si’)−V^ϕπ(si)
- 估计策略目标函数的梯度:∇θJ(θ)≈N1∑i∇θlogπθ(ai∣si)A^π(si,ai)
- 根据梯度更新策略参数:θ←θ+α∇θJ(θ)
对第 3 步中的 yi=ri+γV^ϕπ(si’) 算法中如果使用这个作为 bootstrapping 算法来更新 V^ϕπ ,那么这个估计实际上拟合的并不是某一个策略的 value function。
因此对此可以有这几个方法:
-
加入权重,例如时间越近的数据则权重更大等
-
只允许当前的 policy 用来作为 value function 的学习标签
-
使用 Q function 而不是 value function (这是最常用的)
回顾一下 Q-function 的公式,在状态 s 下,先执行动作 a,之后再按照当前策略 πθ 行动,最终能获得多少累计回报:
Qπθ(s,a)=r(s,a)+γEs′∼p(⋅∣s,a),a′∼πθ(⋅∣s′)[Qπθ(s′,a′)]
这里第一个动作 a 是从 旧策略中采样的,而新动作是当前策略采样的。
并且这个式子中,第二项中没有使用当前的 policy 的数据以外的信息,所以可以离策训练。
也就是说用 replay buffer 里的旧经验 (s,a,r,s′) 训练当前策略 πθ 的 Q 函数时,可以把旧动作 a 当作第一步动作,然后在下一状态 s′ 处接上当前策略采样的动作 a′,用 Bellman target 构造监督信号训练 critic。