Intro
2016年Schulman等人提出了Trust Region Policy Optimization算法。后来他们又发现TRPO算法在scalable(用于大模型和并行实现), data efficient(高效利用采样数据), robust(同一套超参,在大量不同的env上取得成功)上可以改进,于是作为TRPO的改进版本提出了PPO。
PPO在2017年被Schulman等人提出后就刷新了continous control领域的SOTA记录,并且成为了OPENAI的default algorithm。虽然现在它已经不是领域的SOTA算法了,但因为PPO易于部署而且迭代过程方差小,训练较稳定,关键是使用方便,所以目前(2020.11)它还是大多数场景下的default algorithm。
PPO造出来前,其他的流行RL算法缺点在哪?
DQN pooly understood,而且在很多简单任务上失败; 不支持continious control;训练过程poorly robust。
vanilla policy gradient 数据利用效率低,训练过程poorly robust。
trust region policy gradient 算法结构复杂,而且兼容性差,
PPO算法结构设计思想
为actor设计新的损失函数。clipped surrogate objective
采样得到的数据,在更新agent的时候重复使用。multiple epochs of minibatch updates
基本算法构造
神经网络架构
在PPO中critic的价值函数是Vs),而不是Qs,a)。这和DDPG就相反,DDPG中critic的价值函数是Qs,a)。
PPO的paper并未写明算法的具体实现。因此我浏览github,调查了两种实现方法。
我和作者都proposed的版本是让actor和critic参数共享。一个输入,即obs。两个输出,即actor输出和value输出。如:
class PPOnn.Module):
def __init__self, num_inputs, num_actions):
superPPO, self).__init__)
self.conv1 = nn.Conv2dnum_inputs, 32, 3, stride=2, padding=1)
self.conv2 = nn.Conv2d32, 32, 3, stride=2, padding=1)
self.conv3 = nn.Conv2d32, 32, 3, stride=2, padding=1)
self.conv4 = nn.Conv2d32, 32, 3, stride=2, padding=1)
self.linear = nn.Linear32 * 6 * 6, 512)
self.critic_linear = nn.Linear512, 1)
self.actor_linear = nn.Linear512, num_actions)
self._initialize_weights)
def _initialize_weightsself):
for module in self.modules):
if isinstancemodule, nn.Conv2d) or isinstancemodule, nn.Linear):
nn.init.orthogonal_module.weight, nn.init.calculate_gain'relu'))
# nn.init.xavier_uniform_module.weight)
# nn.init.kaiming_uniform_module.weight)
nn.init.constant_module.bias, 0)
def forwardself, x):
x = F.reluself.conv1x))
x = F.reluself.conv2x))
x = F.reluself.conv3x))
x = F.reluself.conv4x))
x = self.linearx.viewx.size0), -1))
return self.actor_linearx), self.critic_linearx)
GAEgeneralized advantage estimator)
一项在Schulman, John, et al. “High-dimensional continuous control using generalized advantage estimation.” arXiv preprint arXiv:1506.02438 2015)中提出的技术。它是针对过去policy gradient系列算法中的returns作了调整,用GAE方法获取returns。
def compute_gaenext_value, rewards, masks, values, gamma=0.99, tau=0.95):
values = values + [next_value]
gae = 0
returns = []
for step in reversedrangelenrewards))):
delta = rewards[step] + gamma * values[step + 1] * masks[step] - values[step]
gae = delta + gamma * tau * masks[step] * gae
returns.insert0, gae + values[step])
return returns
actor损失函数设计
PPO paper中对比了三个损失函数设计,CPI版本作为baseline,就是没有clipping也没有KL penalty的),Clipping版本,KL penalty版本。
根据实验结果,Clipping版本的损失函数作为proposed损失函数。
Clipping版本如下:
L^{CLIP} heta) = E_{t} min<r_t heta)A_{t}, clipr_t heta), 1-epsilon,1+epsilon)A_{t}> ))
1) A_{t})
这里的A表示advantage。advantage = returns – values)。returns是计算得到的GAE值,values是模型的一步输出。
2) r heta)_{t})
这里的r表示ratio,是新旧策略得到的logit_prob的比值。旧,指从env采样的时候用的policy。新,指在多步更新agent时的实时policy。
r heta)_{t} = frac{pia_{t}|s_{t})}{pi_{old}a_{t}|s_{t})})
PPO整体损失函数设计
PPO的actor和critic参数共享,用一个loss来同时更新actor和critic。loss设计如下:
LOSS = actor_loss + 0.5*critic_loss)
actor-loss即前面的L^{CLIP} heta))。critic_loss如下:
critic_loss = sumreturn – value))
这里return就是前面advantage用的return,value是多步更新时实时从agent输出出来的value。
采样sample from environment)与更新update our agent)
强化学习算法,无外乎两个东西的交替迭代,即“sample from environment”和“update our agent”。在PPO算法中,采用这样的时序设计。
LOOP for l rides:
LOOP for s steps:
sample from env, select action, according to current agent
compute advantages for each transition
compute GAE for each transition
compute GAE as return for each step
enough states, actions, log_probs, returns, advantages) were collected
LOOP for p minibatchs:
compute logit_probs, value, according to current agent
compute loss
update our agent
大规模、并行场景下实现PPO算法
./keep