OPENAI 提供了2个版本的PPO PPO1 网上标注是(obsolete version, left here temporarily) PPO2 属于 正式版本吧。 这里粗略描述一下,PPO2的整体过程 。
ppo2.ppo2
来创建learner 进行训练和更新网络,主要的流程都在这里
common.policy
建立PPO所需要的值网络和策略网络
ppo2.model
确立静态图中的loss、以及各种梯度
ppo2.runner
利用所创建的策略来进行环境交互
policy = build_policy(env, network, **network_kwargs)
# 88行 建立policy
model = model_fn()# 107行 建立model
runner = Runner(env=env, model=model, nsteps=nsteps, gamma=gamma, lam=lam) # 114行
obs, returns, masks, actions, values, neglogpacs, states, epinfos = runner.run() # 142行
第三部 循环更新noptepochs次
mblossvals.append(model.train(lrnow, cliprangenow, *slices))
# 166行
mblossvals.append(model.train(lrnow, cliprangenow, *slices))
# 180行 recurrent version
policy = build_policy(env, network, **network_kwargs)
# ppo2 第88行
1、建立actor网络(policy网络),建立输入tensor,并进行归一化,送入给定的神经网络,得到网络输出tensor。
建立critic网络,可以选择critic网络与actor 共享参数。
2、首先根据动作类型建立动作分布函数类型(是建立pdtype 还没有建立分布函数)
self.pdtype = make_pdtype(env.action_space)
# 具体的对应建立请看PPO1 policies 47行
3、利用动作network创建,根据动作分布函数类型,在神经网络的最后一层建立对应的输出层,
self.pd, self.pi = self.pdtype.pdfromlatent(latent, init_scale=0.01)
# policies 47行
其中self.pd 是一个类,该类接受 网络的输出,并计算
neglogp(求概率的对数的复数)、 kl(KL散度)、entropy(熵)、sample(根据输出的概率分布进行采样)等函数。注意 这些计算都是图上的节点 需要输入状态 用sess.run进行计算。
建立loss 之后 建立训练函数:
其中输入为
td_map = {
self.train_model.X : obs, # 观察 计算pd
self.A : actions, # 动作 计算neglogpac
self.ADV : advs, # 优势函数 计算pg—loss
self.R : returns, # 奖励
self.LR : lr, # 学习率
self.CLIPRANGE : cliprange, # 剪裁范围
self.OLDNEGLOGPAC : neglogpacs, # 负对数概率密度
self.OLDVPRED : values # 老策略值函数
}
if states is not None:
td_map[self.train_model.S] = states
td_map[self.train_model.M] = masks
在输出的过程中 进行训练 并利用Loss反向传播
self.loss_names = ['policy_loss', 'value_loss', 'policy_entropy', 'approxkl', 'clipfrac']
self.stats_list = [pg_loss, vf_loss, entropy, approxkl, clipfrac]
利用policy 动作函数网络 obs 可以得到 动作概率分布pd
actions, values, self.states, neglogpacs = self.model.step(self.obs, S=self.states, M=self.dones)# runner 29行
actions, 对pd采样得到
values, 由于是参数共享,相当于计算Q值,所以可以直接得到(程序中还给出了其他的方法,也可以使用)
self.states,
neglogpacs 负对数概率分布
利用policy 中值函数网络 可以得到 最后的值函数
last_values = self.model.value(self.obs, S=self.states, M=self.dones)# runner 50行
并开始计算优势函数:
for t in reversed(range(self.nsteps)):
# 从最后一个时间时刻开始 依次向前
if t == self.nsteps - 1:
nextnonterminal = 1.0 - self.dones
nextvalues = last_values
else:
nextnonterminal = 1.0 - mb_dones[t+1]
nextvalues = mb_values[t+1]
# 蒙特卡洛方法依次计算上一个时刻的td 误差
delta = mb_rewards[t] + self.gamma * nextvalues * nextnonterminal - mb_values[t]
# 计算优势函数
mb_advs[t] = lastgaelam = delta + self.gamma * self.lam * nextnonterminal * lastgaelam
最后runner 返回一系列轨迹 (采样并行采样的)