• Home
  • About
    • Dr.Zee Blog photo

      Dr.Zee Blog

      Xiangyu Zhang;PHD student;Reinforcement learning, intelligent wireless communication

    • Learn More
    • Email
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

Openai Baeslines 详解(四) Ppo中文

20 Aug 2019

Reading time ~3 minutes

2017年 OpenAI 和 Deep Mind先后推出了TRPO和PPO算法,该算法通过限制了new policy和 Old policy之间的KL散度大小(Kullback-Leibler Divergence,KLD),从而解决学习率过大引起不收敛的问题。

OPENAI-Baeslines-PPO


目录

[TOC]


基本原理

TRPO

基于策略的强化学习的主要目标是找到一个“ 可以让带有折扣的未来期望的收益达到最大 ” 的策略。带有折扣的未来期望的收益可以表示为: TRPO的主要想法就是在每一步更新的策略的时候,新的策略都要比老的策略好。那么新旧策略之间的期望收益差可以表示为: Policy gap 是老策略的优势函数(advantage function)在新策略采样轨迹下的期望值。(2)式可以进一步表示为: 在上面的等式中, $\rho_{\tilde{\pi}}(s) =\sum_{t=0}^{\infty} \gamma^{t} P\left(s_{t}=s | \tilde{\pi}\right)$ 表示在新策略 $\tilde{\pi}$ 下状态$s_t$的带有折扣因子的概率。当没有得到新策略的时候,该式是非常难以求得的。 如果采用老策略的$\rho_{\pi}(s) $ 来近似,则可以得到下式: 但是这里必须考虑到的是,新策略与老策略的差距非常小的时候,才有$L_{\pi}(\tilde{\pi})\approx \eta(\tilde{\pi})$。

如果,采用如下的方式来跟新策略: 那么$L_{\pi}(\tilde{\pi})$ 和$\eta(\tilde{\pi})$ 之间的关系可以表示为: 其中,$ \epsilon=\max {s}\left|\mathbb{E}{a \sim \pi^{\prime}(a | s)}\left[A_{\pi}(s, a)\right]\right| $,需要被注意的是,这里 $\alpha$代表了步进的大小。如果采用从方差散度(total variation divergence, $D_{T V}(p | q)=\frac{1}{2} \sum_{i}\left|p_{i}-q_{i}\right|$)的方式来衡量新旧策略的不同时, $\alpha$可以表示为 公式(5)就可以表示为: 其中,$\epsilon=\max {s, a}\left|A{\pi}(s, a)\right|$。根据 $D_{T V}(p | q)^{2} \leq D_{K L}(p | q)$,将TV散度更换成KL散度的关系,这是由于将KL散度将更利于求解高斯分布等模型。 这样式(7)可以写成: 在上式中,如果新策略等于旧策略,那么不等式变为等式,所以如果我们在每一次更新迭代的时候,都使得下届最大化而求得的新策略$\tilde{\pi}$,就一定是一个比旧策略更好的策略。这样,策略寻找问题变化成一个最优化问题,即: 有5个方法化简该问题:

  • 从公式3中可以看出$L_{\theta_{\text { old }}}(\theta)$,中包含较多常数项$\eta(\pi)$。 同时,化简后面的advantage function可以得到:
​ 上式中的$V_{old}$ 也是常数,所以直接最小化$\sum_{a}\tilde{\pi}_{\theta}(a s) Q_{\theta_{o l d}}(s, a)$即可。
  • 对目标函数中的状态概率求和项 ,用期望来表示,即$\sum_{s} \rho_{\pi}(s)$ 代替为 $\mathbb{E}_{s \sim \rho}$.

  • 对目标函数中的状态概率求和项 ,用期望来表示,即$\sum_{a} \tilde{\pi}_{\theta}(a s) Q_{\theta_{o l d}}(s, a)$ 代替为 $\mathbb{E}{a \sim \tilde{\pi}{\theta}}$.
  • 现实中无法得到根据新的策略采样得到$\sum_{a} \tilde{\pi}{\theta}(a | s) A{\theta_{o l d}}$,所以利用 the importance sampling ,可以表示为: 利用旧策略的采样 来完成新策略的估计。

  • 约束条件中,KL散度约束在每一个状态s上,所以很难求得,所以最好的方法是利用平均,即:

最后最优问题化简为: 为了求解上面的最优化问题,我们必须知道 $Q_{\theta_{\text { old }}}(s, a)$ and ${\pi}(\theta_{\text { old }})$。文中给出了2中方法来估计$Q$

第一种方法single path就是,在${\pi}(\theta_{\text { old }})$下直接找出许多条轨迹 然后求解,直接平均估计每一个状态的 $Q_{\theta_{\text { old }}}(s, a)$求解。第二种办法vine是,找一个状态,在该状态下求n次 找到估计 $Q_{\theta_{\text { old }}}(s, a)$。

解式(11)的最优化问题, 可以分为两步

1、 更新方向的选择,利用一阶模型近似约束条件和目标方程:

  • 目标方程部分: 让目标方程转化为一阶近似,令

那么 $\overline{A}(\theta’)$一阶线性近似是 $ \nabla_{\theta} \overline{A}(\theta)^{T}\left(\theta^{\prime}-\theta\right)$, 其中$\theta’$ 是下一步的策略参数,$\theta$ 是现在的策略参数。

  • 约束条件部分:

KL散度的二阶近似为: 其中A代表了Fisher information matrix: 2、 更新策略参数在该方向上执行线性搜索,确保我们在满足非线性约束的同时改善非线性目标

PPO

PPO 是一种基于TRPO的算法,在求解上面一些方法,但是本质上还是TRPO

PPO提出了两种算法:

第一种是约束限制转移概率$r_{t}(\theta)=\frac{\pi_{\theta}\left(a_{t} | s_{t}\right)}{\pi_{\theta} \operatorname{old}\left(a_{t} | s_{t}\right)}$: 是吧变化量限制在某一个范围之内。这种方式是最直接的形式,因为直接把变化量限定在一个范围之内,但是其中的参数 $\epsilon$ 还是没有给出一个固定的指标。

另一种约束是KL散度上的约束 Let $ d=\hat{\mathbb{E}}{t}\left[\mathrm{KL}\left[\pi{\theta_{\mathrm{old}}}\left(\cdot | s_{t}\right), \pi_{\theta}\left(\cdot | s_{t}\right)\right]\right] $

If $d<d_{\operatorname{targ}} / 1.5, \beta \leftarrow \beta / 2$

if $d>d_{\operatorname{targ}}\times 1.5, \beta \leftarrow \beta \times 2$

实际上, 当利用(16)作为loss function 的时候,神经网络的loss function 必须还增加策略的熵升 和 值函数误差项 其中 $S$ 代表了在该策略下的熵的奖励, 这是为了确保充分的探索。 $L_{t}^{V F}(\theta)=\left(V_{\theta}\left(s_{t}\right)-V_{t}^{\operatorname{targ}}\right)^{2}$

所以整个算法流程是 : 利用老策略 采样 计算 优势函数 更新策略 再循环

1566278934110

Baseline中的PPO

baseline的PPO有两个版本一个版本为PPO1 一个版本为PPO2, 目前看PPO1 已经被抛弃了 ,但是也是可以用的。

PPO2 是多环境并行版本。4

PPO的实际实现

从上面的伪算法可以看出,PPO还是基于actor、critic的架构。

PPO1 版本

Baseline的PPO 主要分为以下3个部分:

  • 主程序部分: pposgd_simple
    根据 env 和 提供的神经网络 创建好整个强化学习算法架构,并输出策略pi。

  • 神经网络部分: cnn_policy和mlp_policy 创建神经网络模型

  • 概率分布部分: common.distributions 根据当前所输出的动作和状态,建立对应

概率分布部分

由于采用的是随机策略PPO输出的结果都是概率分布的参数,然后再从中采样。所以在每个action输出的时候都是输出对应的概率分布的参数。这个部分主要的功能:

  • 将对应动作参数类型转化为概率分布
  • 为对应概率分布的参数生成必要的action 的placeholder
  • 求交叉熵以及散度。
  • 对概率分布采样得到动作。

神经网络部分

动作节点的创建

神经网络首先调用概率分布函数,将动作建立为对应概率分布,并在调用的时候已经建立好对应的节点。

网络中节点初始化

状态的创建:状态建立的时候 为了避免重复创建同名称的状态, 利用了 get_placeholder 这个函数创建。创建的时候 将所有的placeholder 都放入了一个字典里 类型为{“名称”:placeholder,数据类型,数据维度}。 创建好的状态都可以直接用 函数get_placeholder_cached 来进行调用。

然后对ob进行归一化,所有都归一到-5 到 5 之间。用RunningMeanStd 函数。

网络创建

vf 网络: 输入为状态 输出为vpred

pol网络: 输入为状态 输出为动作

如果是高斯变量 那么网络输出的是均值

如果不是高斯变量 那么网络输出的是概率参数

为了多次调用不同,在每次调用该类的过程中都需要先输入独特的名称 使得不同网络便于区分。 将网络利用with tf.variable_scope(name):命名。

  • Vf网络:critic网络

    每层都相等、输入为归一化之后的状态、输出为单个元素,均采用tanh。 需要参数num_hid_layers(网络层数)、hid_size(隐藏层节点个数)。

    利用for循环 循环生成。

with tf.variable_scope('vf'):
     obz = tf.clip_by_value((ob - self.ob_rms.mean) / self.ob_rms.std, -5.0, 5.0)
     last_out = obz
     for i in range(num_hid_layers):
         last_out = tf.nn.tanh(tf.layers.dense(last_out, hid_size, name="fc%i"%(i+1), kernel_initializer=U.normc_initializer(1.0)))
     
     self.vpred = tf.layers.dense(last_out, 1, name='final', kernel_initializer=U.normc_initializer(1.0))[:,0]
  • pol网络 :actor网络

    每层都相等、输入为归一化之后的状态、输出为动作,均采用tanh

主程序部分

PPO中主程序主要部分在learning中,重要参数有

  • env : 环境
  • policy_fn: 网络
  • clip_param:
准备工作

###### 网络输出输入

首先用所提供的 网络创建新旧policy

pi = policy_fn("pi", ob_space, ac_space) # Construct network for new policy
oldpi = policy_fn("oldpi", ob_space, ac_space) # Network for old policy

其中 policy_fn 是一个class(类) 具体看神经网络部分。

接着提取之前所创建的 参数 状态ob 和 动作ac

输入口:

atarg = tf.placeholder(dtype=tf.float32, shape=[None]) # 优势方程 (17式中的A)
ret = tf.placeholder(dtype=tf.float32, shape=[None]) # Empirical return
lrmult = tf.placeholder(name='lrmult', dtype=tf.float32, shape=[])
定义图中的loss

计算loss所需的值:(107-111)

kloldnew = oldpi.pd.kl(pi.pd) # 计算新老策略的KL散度 
ent = pi.pd.entropy()         # 计算新策略的熵值
meankl = tf.reduce_mean(kloldnew) # 平均KL散度
meanent = tf.reduce_mean(ent)     # 平均熵

计算(18)式的误差 包含 三项 $L^{C L I P}(\theta)$、$L_{t}^{V F}(\theta)$、$S$

  • 16式的$L^{C L I P}(\theta)$

    然后计算公式 (16)式所需要的值

    113 - 新老策略的概率π相除 然后得到 比率 114 - 比率乘以优势函数 优势函数 也是一个 placeholder 115 - 经过剪裁的比率 乘以优势函数 116 对应(16)式惩罚项 $L^{C L I P}(\theta)$

ratio = tf.exp(pi.pd.logp(ac) - oldpi.pd.logp(ac))
surr1 = ratio * atarg 
surr2 = tf.clip_by_value(ratio, 1.0 - clip_param, 1.0 + clip_param) * atarg  
pol_surr = - tf.reduce_mean(tf.minimum(surr1, surr2)) 
  • $L_{t}^{V F}(\theta)=\left(V_{\theta}\left(s_{t}\right)-V_{t}^{\operatorname{targ}}\right)^{2}$ 这个地方$V_{t}^{\operatorname{targ}}$ 是直接给出的 因为在前面定义了 一个placeholder
vf_loss = tf.reduce_mean(tf.square(pi.vpred - ret))
  • $S$ c1 是 -entcoeff 是输入参数

    pol_entpen = (-entcoeff) * meanent
    
生成梯度、优化器所需要的函数
lossandgrad = U.function([ob, ac, atarg, ret, lrmult], losses + [U.flatgrad(total_loss, var_list)])
adam = MpiAdam(var_list, epsilon=adam_epsilon)
assign_old_eq_new = U.function([],[], updates=[tf.assign(oldv, newv)    for (oldv, newv) in zipsame(oldpi.get_variables(), pi.get_variables())])
compute_losses = U.function([ob, ac, atarg, ret, lrmult], losses)

1 、 计算梯度

输入ob 状态, ac 动作 , atarg 优势函数, ret , lrmult]

计算得到pol_surr $L^{C L I P}(\theta)$ , pol_entpen $S$ , vf_loss $L_{t}^{V F}(\theta)$ , meankl 新老策略KL散度均值 , meanent 新策略熵值 以及对应的神经网络梯度

2、 生成优化器

3、 新旧策略的迭代

4、 计算loss :计算优化之后的LOSS 与1 的区别在于 不计算梯度

更新迭代过程
前期策略采样 和 优势函数估计
traj_segment_generator(pi, env, horizon, stochastic):

horizon 是采样的多少步

stochastic 标识 利用随机采样 即 pd.sample 或者 pd.mode

前向采样
seg = seg_gen.__next__()
add_vtarg_and_adv(seg, gamma, lam)
后向更新
for _ in range(optim_epochs):
    losses = [] 
    for batch in d.iterate_once(optim_batchsize):
        *newlosses, g = lossandgrad(batch["ob"], batch["ac"], batch["atarg"], batch["vtarg"], cur_lrmult)
        adam.update(g, optim_stepsize * cur_lrmult)
        losses.append(newlosses)


Share Tweet +1