Proximal Policy Optimization(近端策略优化)
近端策略优化方法,也就是我们经常说的PPO算法。PPO算法是现在强化学习领域最常用的算法之一,也是我们经常用于检测算法的baseline。PPO算法的理论是建立在TRPO的理论基础之上,所以想要深入理解PPO的同学可以先去了解我之前关于TRPO的两篇文章。
PPO算法的motivation在openai的官方文档中是这样描述的1:PPO的创造是基于和TRPO相同的问题,如何通过现有数据让策略尽可能地提升,并且控制策略的步长。TRPO的方法是使用将优化函数二阶展开的方法进行优化,而PPO则采用将泰勒一阶展开的方法并使用了一些trick来保证新旧策略之间的距离不要过大(因为在使用优势函数的时候我们用旧策略的优势函数替代了新策略的优势函数)。PPO算法能够简单快速的达到TRPO相同的效果。
PPO有两种不同的实现,一种是基于惩罚的PPO,一种是基于Clip的PPO。基于惩罚的PPO是将KL散度不是作为一个硬约束,而是作为一个惩罚函数加在优化函数上。而基于Clip的PPO则是将优化函数转化成了一个Clip函数,由于Clip的方法在PPO上面取得了很好的效果,所以我们着重来介绍基于Clip的PPO。
基于Clip的PPO
对于策略梯度这类方法中最重要的就是如何将最大化策略收益转换成一个优化策略参数的函数,所以我们首先来看PPO中的策略优化函数,可以描述为:
L(s,a,\theta_k,\theta) = \min(\frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)}A^{\pi_{\theta_k}}(s|a),clip(\frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)},1-\epsilon,1+\epsilon)A^{\pi_{\theta_k}}(s|a))
其中\epsilon是控制新旧策略距离的超参数。min函数前面一部分我们应该很熟悉了,但是后面的clip函数我们应该还比较陌生,其实也并不复杂,可以通过下面这张图来表示清楚。
Clip函数
从图中我们可以理解到clip函数的意义其实是将\frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)}限制在一个范围以内,超过这个范围我们就用一个设定好的超参数\epsilon来进行代替了。
当A^{\pi_{\theta_k}}(s|a)大于0的时候,那我们可以直接把A^{\pi_{\theta_k}}(s|a)提出来而不改变\min的符号,我们需要找的就是\min(\frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)},clip(\frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)},1-\epsilon,1+\epsilon))根据我们之前画的clip图像,我们可以知道我们的函数是这个样子。
优化函数
可以不考虑1-\epsilon部分只用考虑1+\epsilon的部分。对于A^{\pi_{\theta_k}}(s|a)小于0的情况,那我们提出A^{\pi_{\theta_k}}(s|a)的时候就需要考虑变号的问题了。我们的\min\Rightarrow\max(\frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)},f(clip))。同样如果直观不好理解我们可以通过图像来看看函数。这样设计优化函数的意义在于当A^{\pi_{\theta_k}}(s|a)大于0说明当前状态的动作由于之前的策略,我们应该增大该动作的概率,也就是使得\frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)}向右边移动,如果\frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)}原本就小于1,那么移动其实是新策略朝着旧策略方向移动,两个策略趋向一致,但如果原本就大于1,那更新就会让新策略远离旧策略了,太过远离可能会破坏我们的近似条件,这个时候就用clip来进行限制就可以了,同样小于0的情况也是基于类似的考虑。
没有了原来kl散度的约束,那么我们就可以直接用优化函数对\theta进行策略更新,如果这个时候我们直接用一阶展开其实就是利用梯度来进行更新,那么我们就可以直接用loss的方式来对策略进行更新,回归到了我们最开始的策略梯度方法。
具体PPO算法的过程可以描述成这样:
[*]初始化环境和策略参数。
[*]策略和环境采样得到回报等数据
[*]计算折扣累计回报
[*]计算通过critic模型计算状态价值并通过状态价值计算优势函数A^{\theta_k}(这样计算出来的可以减小方差)
[*]通过优势函数函数和策略的概率计算出来loss(和之前策略梯度那里很类似,不过这里有一个clip)
[*]用loss来更新策略
[*]用折扣累计汇报和critic模型计算状态价值来更新critic模型(回到第2步)
PPO的使用
PPO官方代码实现的非常棒,其实我认为PPO能够取得很好的效果与其代码的简介和高效不可分割。之后我会针对PPO官方代码进行分析,这里我们介绍一个强化学习包stable_baselines3这个包封装了强化学习中DQN PPO等流行的算法作为basline,只需要将环境按照gym封装好就能够直接调用这些算法测算baseline的效果,做算法比较的时候不用再自己复现(自己复现就怕差漏了什么地方,导致效果不好自己还不知道)也不用再去github上找源码来调环境。更重要的作用是当老板让你做项目的时候,直接调用这些官方代码来训练模型,能够为自己节省大把的研究时间了。与此同时stable_baselines3封装也做的非常好,调用起来非常简单,例如咱们可以用stable_baselines3调用PPO算法来训练一个离散倒立摆模型。
import gym
from stable_baselines3 import PPO
env = gym.make('Pendulum-v1')
model = PPO(
"MlpPolicy",
env=env,
verbose=1
)
model.learn(total_timesteps=1e6)
state = env.reset()
done = False
score = 0
while not done:
action, _ = model.predict(observation=state)
state, reward, done, info = env.step(action=action)
score += reward
env.render()
env.close()
model.save('my_model.pth')
直接调用模型,设置好关键的参数,模型直接就可以开始训练,并且terminal会实时输出当前平均的收益情况和训练的参数。在训练完毕之后会可视化显示模型的效果并将模型进行保存。
参考文献
1 openai官方文档
本文使用 Zhihu On VSCode 创作并发布
页:
[1]