RL策略梯度方法之(十一):proximalpolicyoptimization(PPO)

更新时间:2023-06-02 18:55:26 阅读: 评论:0

RL 策略梯度⽅法之(⼗⼀):proximalpolicyoptimization (PPO )
⽂章⽬录
近端策略优化算法
:[ | ]
原理解析
PPO在原⽬标函数的基础上添加了KL divergence 部分,⽤来表⽰两个分布之前的差别,差别越⼤则该值越⼤。那么施加在⽬标函数上的惩罚也就越⼤,因此要尽量使得两个分布之间的差距⼩,才能保证较⼤的⽬标函数。
TRPO 与 PPO 之间的差别在于它使⽤了 KL divergence(KL散度) 作为约束,即没有放到式⼦⾥,⽽是当做了⼀个额外的约束式⼦,这就使得TRPO的计算⾮常困难,因此较少使⽤。
理论部分推导
1. PG 算法回顾
Actor对于⼀个特定的任务,都有⾃⼰的⼀个策略 ,策略  通常⽤⼀个神经⽹络表⽰,其参数为  。从⼀个特定的状态state出发,⼀直到任务的结束,被称为⼀个完整的eposide,在每⼀步,我们都能获得⼀个奖励 ,⼀个完整的任务所获得的最终奖励被称为 。这样,⼀个有  个时刻的eposide,Actor 不断与环境交互,形成如下的序列 :
在这⾥插⼊图⽚描述
这样⼀个序列  是不确定的,因为Actor在不同state下所采取的action可能是不同的,⼀个序列  发⽣的概率为:
在这⾥插⼊图⽚描述
序列  所获得的奖励为每个阶段所得到的奖励的和,称为  。因此,在Actor的策略为  的情况下,所能获得的期望奖励为:
在这⾥插⼊图⽚描述
⽽我们的期望是调整Actor的策略 ,使得期望奖励最⼤化,于是我们有了策略梯度的⽅法,既然我们的期望函数已经有了,我们只要使⽤梯度提升的⽅法更新我们的⽹络参数 (即更新策略 )就好了,所以问题的重点变为了求参数的梯度。梯度的求解过程如下:
在这⾥插⼊图⽚描述
上⾯的过程中,我们⾸先利⽤ log 函数求导的特点进⾏转化,随后⽤  次采样的平均值来近似期望,最后,我们将  展开,将与  ⽆关的项去掉,即得到了最终的结果。所以,⼀个PG⽅法的完整过程如下:
在这⾥插⼊图⽚描述
我们⾸先采集数据,然后基于前⾯得到的梯度提升的式⼦更新参数,随后再根据更新后的策略再采集数据,再更新参数,如此循环进⾏。注意到图中的⼤红字only ud once,因为在更新参数后,我们的策略已经变了,⽽先前的数据是基于更新参数前的策略得到的。
2. PG ⽅法的⼩tip
增加⼀个基线
PPO ππθr R T ττττR (τ)ππθπN p θθ
通过上⾯的介绍你可能发现了,PG⽅法在更新策略时,基本思想就是增加reward⼤的动作出现的概率,减⼩reward⼩的策略出现的概率。假设现在有⼀种情况,我们的reward在⽆论何时都是正的,对
于没有采样到的动作,它的reward是0。因此,如果⼀个⽐较好的动作没有被采样到,⽽采样到的不好的动作得到了⼀个⽐较⼩的正reward,那么没有被采样到的好动作的出现概率会越来越⼩,这显然是不合适的,因此我们需要增加⼀个奖励的基线,让reward有正有负。⼀般增加的基线是所获得奖励的平均值:
在这⾥插⼊图⽚描述
变为reward-to-go 往往⼀个动作的reward跟之前的reward没有什么关系。所以这⾥,将这个序列的reward变为 这个动作及其之后的reward的加和:
在这⾥插⼊图⽚描述
增加折扣因⼦这个很容易理解,就像买股票⼀样,未来的1块钱的价值要⼩于当前1块钱的价值,因此未来的1块钱变成现在的价值,需要进⾏⼀定的折扣
在这⾥插⼊图⽚描述
使⽤优势函数
我们之前介绍的PG⽅法,对于同⼀个eposide中的所有数据,使⽤的奖励都是⼀样的,其实我们可以
将其变为与  和  相关的。这⾥我们使⽤的是优势函数,即  。其中  可以使⽤从当前状态开始到eposide结束的奖励折现和得到,  可以通过⼀个critic来计算得到。
在这⾥插⼊图⽚描述
3. PPO 算法原理简介
接着上⾯的讲,PG⽅法⼀个很⼤的缺点就是参数更新慢,因为我们每更新⼀次参数都需要进⾏重新的采样,这其实是中on-policy的策略,即我们想要训练的agent和与环境进⾏交互的agent是同⼀个agent;与之对应的就是off-policy的策略,即想要训练的agent和与环境进⾏交互的agent不是同⼀个agent,简单来说,就是拿别⼈的经验来训练⾃⼰。
那么为了提升我们的训练速度,让采样到的数据可以重复使⽤,我们可以将on-policy的⽅式转换为off-policy的⽅式。即我们的训练数据通过另⼀个Actor(对应的⽹络参数为  得到。这要怎么做呢?通过下⾯的思路:
重要性采样技术将其改为off-policy,重要性采样(IS)的介绍如下
通过重要性采样这种⽅式,我们的  和  的分布不能差别太⼤,否则需要进⾏⾮常多次的采样,才能得到近似的结果;下⾯通过⼀个例⼦进⾏说明。在这⾥插⼊图⽚描述
望长安如上图所⽰,很显然,在  服从  分布时,由图可见,在左半部分  的时候概率较⼤,此时  的期望为负;
荀况《劝学》原文那么此时我们从  中来采样少数的 ,那么我们采样到的  很有可能都分布在右半部分,此时  ⼤于0,我们很容易得到  的期望为正的结论,这就会出现问题,因此需要进⾏⼤量的采样。
s t a t Q (s ,a )−πt t V (s )πt Q (s ,a )πt t V (s )πt θ′E [f (x )]x ∼p (x )=p (x )f (x )dx ∫=q (x )f (x )dx ∫q (x )p (x )
=E [f (x )]x ∼q (x )q (x )p (x )
; 红⾊部分是重要性权重
p (x )q (x )x p (x )x <0f (x )q (x )x x f (x )f (x )
所以修正后的off-policy style的PG算法的⽬标函数变为
根据上个⼩节所述的tips,引⼊balines⽅法【减⼩⽅差】,同时引⼊折扣因⼦(reward-to-go考虑长期收益影响),引⼊对当前action 相对平均值有多好的评价函数,即优势函数推导可以得到新的⽬标函数如下:
在这⾥插⼊图⽚描述上式中 最后⼀项因为我们假设两个分布不能差太远,所以认为他们是相等的,为了求解⽅便,我们直接划掉。此时似然函数变为:
在这⾥插⼊图⽚描述
由梯度变为似然函数,使⽤的是下⾯式⼦:,⼤家可以⾃⼰⼿动算⼀下。
我们前⾯介绍了,我们希望  和  不能差太远,这并不是说参数的值不能差太多,⽽是说,输⼊同样的state,⽹络得到的动作的概率分布不能差太远。得到动作的概率分布的相似程度,我们可以⽤KL散度来计算,将其加⼊PPO模型的似然函数中,变为:
在这⾥插⼊图⽚描述
在实际中,我们会动态改变对  和  分布差异的惩罚,如果KL散度值太⼤,我们增加这⼀部分惩罚,如果⼩到⼀定值,我们就减⼩这⼀部分的惩罚,基于此,我们得到了PPO算法的过程:
在这⾥插⼊图⽚描述
PPO算法还有另⼀种实现⽅式,不将KL散度直接放⼊似然函数中,⽽是进⾏⼀定程度的裁剪:
在这⾥插⼊图⽚描述
上图中,绿⾊的线代表min中的第⼀项,即不做任何处理,蓝⾊的线为第⼆项,如果两个分布差距太⼤,则进⾏⼀定程度的裁剪。最后对这两项再取min,防⽌了  更新太快。
总结⼀下:
PPO算法加⼊对off-policy策略引⼊中的的约束,设定新的⽬标函数为
已可以组什么词
where ,两种⽅法的⽬的都是约束两次更新的⽹络参数分布距离较近,避免不稳定现象
通过以上介绍可以得到PPO算法的基本流程伪代码如下:
for  iteration =1,2,... do
for  actor =1,2,...N do
Run policy \theta_{old } in  env for  T timesteps
Compute advantage estimates A
end for
Optimize L for  params of actors and  critic with  batched data
\theta_{old } <-- \theta
end for
4. 特殊说明
⼏点需要特别说明的
∇=R θE [R (τ)∇logp (τ)]
τ∼p (τ)θ′p (τ)θ′p (τ)
θθA (s ,a )
πt t ∇f (x )=f (x )∇logf (x )θθ′θθ′θθ′
Clipped  V ersion J (θ)=[min(r (θ)A ,clip (r (θ,1−E t ^t t πt ϵ,1+ϵ))A )]t πKL  Penalty  V ersion J (θ)=[r (θ)A −E t ^t t πβKL [π,π]]θ′θr (θ)=t πθ′πθ
off-policy体现在只需要⽤上⼀次的actor中policy的old参数⽣成多个trajectory求得loss,再⽤梯度反向传播⽅法对新的参数进⾏更新⼀次,⽽不是需要每次都要重新⽣成数据两个分布相除是在对数域上相
减得到
算法中提到的和是两次循环更新的值,由于重要性采样得到的公式可以看到期望值是在上计算的,所以是先⽤未更新的⽹络⽣成trajectory计算loss,经过循环累加⽤来更新新的算法实现
总体流程
代码实现
风筝的起源创建环境
import  gym
env = gym .make ('Pendulum-v0').unwrapped
得到state、action、reward
表达的英语
这⾥我们⾸先得到state,action和即时奖励reward的序列,随后我们要计算折现的奖励和,get_v()是⼀个得到状态价值的函数。使⽤v(s)= r + gamma * v(s+1)不断进⾏循环。
for  t in  range (EP_LEN ):    # in one episode
env .render ()
a = ppo .choo_action (s ) # 根据⼀个正态分布,选择⼀个action
s_, r , done , _ = env .step (a )
buffer_s .append (s )
buffer_a .append (a )
buffer_r .append ((r +8)/8)    # normalize reward, find to be uful
s = s_
ep_r += r
# update ppo
if  (t +1) % BATCH == 0 or  t == EP_LEN -1:
v_s_ = ppo .get_v (s_)
discounted_r = []
for  r in  buffer_r [::-1]:
v_s_ = r + GAMMA * v_s_
discounted_r .append (v_s_) # v(s) = r + gamma * v(s+1)
discounted_r .rever ()
bs , ba , br = np .vstack (buffer_s ), np .vstack (buffer_a ), np .array (discounted_r )[:, np .newaxis ]
buffer_s , buffer_a , buffer_r = [], [], []
ppo .update (bs , ba , br )
定义critic计算优势函数
这⾥我们定义了⼀个critic来计算优势函数,状态价值定义了⼀个全联接神经⽹络来得到,⽽折扣奖励和我们之前已经计算过了:#critic
with  tf .variable_scope ('critic'):
l1 = tf .layers .den (lf .tfs ,100,tf .nn .relu )
lf .v = tf .layers .den (l1,1) # state-value
lf .tfdc_r = tf .placeholder (tf .float32,[None ,1],'discounted_r')
lf .advantage = lf .tfdc_r - lf .v
lf .closs = tf .reduce_mean (tf .square (lf .advantage ))
lf .ctrain_op = tf .train .AdamOptimizer (C_LR ).minimize (lf .closs )
θ′θθ′
θ
定义Actor
PPO⾥采⽤的是off-policy的策略,需要有⼀个单独的⽹络来收集数据,并⽤于策略的更新,同DQN的策略⼀样,我们定义了⼀个单独的⽹络,这个⽹络的参数是每隔⼀段时间由我们真正的Actor的参数复制过去的。
#actor
pi,pi_params = lf._build_anet('pi',trainable=True)
oldpi,oldpi_params = lf._build_anet('oldpi',trainable=Fal)
with tf.variable_scope('sample_action'):
lf.sample_op = tf.squeeze(pi.sample(1),axis=0)
屏幕刷新率
with tf.variable_scope('update_oldpi'):
lf.update_oldpi_op =[oldp.assign(p)for p,oldp in zip(pi_params,oldpi_params)]
lf.tfa = tf.placeholder(tf.float32,[None,A_DIM],'action')
lf.tfadv = tf.placeholder(tf.float32,[None,1],'advantage')
⽽⽹络构建的代码如下,这⾥就⽐较神奇了,我们的Actor⽹络输出⼀个均值和⽅差,并返回⼀个由该均值和⽅差得到的正态分布,动作基于此正态分布进⾏采样:
def_build_anet(lf,name,trainable):
with tf.variable_scope(name):
l1 = tf.layers.den(lf.tfs,lu,trainable=trainable)
mu =2* tf.layers.den(l1,A_anh,trainable=trainable)
sigma = tf.layers.den(l1,A_softplus,trainable=trainable)
norm_dist = tf.distributions.Normal(loc=mu,scale=sigma)# ⼀个正态分布
params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES,scope=name)
return norm_dist,params
损失计算
采⽤KL散度或者裁切的⽅式,损失计算⽅式不同:
with tf.variable_scope('loss'):
with tf.variable_scope('surrogate'):
波浪线ratio = pi.prob(lf.tfa)/oldpi.prob(lf.tfa)
思维破裂
surr = ratio * lf.tfadv
if METHOD['name']=='kl_pen':
lf.tflam = tf.placeholder(tf.float32,None,'lambda')
kl = tf.distributions.kl_divergence(oldpi,pi)
lf.kl_mean = tf.reduce_mean(kl)
lf.aloss =-tf.reduce_mean(surr-lf.tflam * kl)
el:
lf.aloss =-tf.reduce_mean(tf.minimum(surr,tf.clip_by_value(ratio,1.-METHOD['epsilon'],1.+METHOD['epsilon'])*lf.tfadv))

本文发布于:2023-06-02 18:55:26,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/836151.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:得到   函数   奖励   参数   采样
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图