强化学习笔记1——ppo算法

2023-10-12 19:59
文章标签 算法 学习 笔记 强化 ppo

本文主要是介绍强化学习笔记1——ppo算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考莫烦Python的学习视频链接: 莫烦Python的学习视频.

  1. why PPO?
    根据 OpenAI 的官方博客, PPO 已经成为他们在强化学习上的默认算法. 如果一句话概括 PPO: OpenAI 提出的一种解决 Policy Gradient 不好确定 Learning rate (或者 Step size) 的问题. 因为如果 step size 过大, 学出来的 Policy 会一直乱动, 不会收敛, 但如果 Step Size 太小, 对于完成训练, 我们会等到绝望. PPO 利用 New Policy 和 Old Policy 的比例, 限制了 New Policy 的更新幅度, 让 Policy Gradient 对稍微大点的 Step size 不那么敏感.
  2. 一些讲解,来源: link.
    在这里插入图片描述on-policy和off-policy的含义
    在这里插入图片描述
  • 1可以用迁移思想来理解这个。t1为要训练的agent, t2 为fixed的agent,用于sample
  • 2在t2上反复采样,可以理解t2是个高手。t2是固定的,也不会导致(s,a)中某个a的概率发生变化
  • 3即可以理解为t2中采的样本一定都是正确的!。把t1模型,训练成t2模型的水平。
  • 4所以alpha go 的前期训练好像是借助的棋谱。棋谱相当于t2, 刚开始的go相当于t1

简单来说,因为难以在 p ( x ) p(x) p(x)中采样,所以曲线救国,从 q ( x ) q(x) q(x)采样求期望,再乘以一个weight,即 p ( x ) / q ( x ) p(x)/q(x) p(x)/q(x)
在这里插入图片描述
如果 p ( x ) p(x) p(x) q ( x ) q(x) q(x)差距很大,要多采样才行,采样数少会错误
在这里插入图片描述
替换原理
在这里插入图片描述
原问题中的替换原理。when to stop? 引入PPO解决原网络与现在网络不能差太多的问题,即两个分布不可以差太多
在这里插入图片描述
在这里插入图片描述
4. 算法伪代码
PPO-Penalty:近似地解决了TRPO之类的受KL约束的更新,但对目标函数中的KL偏离进行了惩罚而不是使其成为硬约束,并在训练过程中自动调整惩罚系数,以便对其进行适当缩放。
PPO-Clip:在目标中没有KL散度项,也完全没有约束。取而代之的是依靠对目标函数的专门裁剪来减小新老策略的差异。
在这里插入图片描述
KL散度用来限制新策略的更新幅度(重要)
在这里插入图片描述
在PPO clip中去掉了KL散度的计算,只限制了比例。效果更好。
多线程将加快学习进程。
5. 算法结构
在这里插入图片描述
在这里插入图片描述

  1. 代码

class PPO:def __init__(self):# 建 Actor Critic 网络# 搭计算图纸 graphself.sess = tf.Session()self.tfs = tf.placeholder(tf.float32, [None, S_DIM], 'state')  # 状态空间[None, S_DIM]self._build_anet('Critic')  # 建立critic网络,更新self.v# 得到self.v之后计算损失函数with tf.variable_scope('closs'):self.tfdc_r = tf.placeholder(tf.float32, [None, 1], name='discounted_r')  # 折扣奖励self.adv = self.tfdc_r - self.v  # ?这个可以理解TD error吗?closs = tf.reduce_mean(tf.square(self.adv))  # critic的损失函数self.ctrain = tf.train.AdamOptimizer(C_LR).minimize(closs)  # 接着训练critic# 建立pi网络和old_pi网络,获得相应参数pi, pi_params = self._build_anet('pi', trainable=True)oldpi, oldpi_params = self._build_anet('oldpi', trainable=False)# ??这是什么with tf.variable_scope('sample_action'):self.sample_op = tf.squeeze(pi.sample(1), axis=0)# 将新pi参数赋给old_piwith tf.variable_scope('update_oldpi'):# 此时还没有赋值,要sess.run才行self.update_oldpi_op = [oldp.assign(p) for p, oldp in zip(pi_params, oldpi_params)]with tf.variable_scope('aloss'):self.tfa = tf.placeholder(dtype=tf.float32, shape=[None, A_DIM], name='action')  # 动作空间self.tfadv = tf.placeholder(tf.float32, [None, 1], 'advantage')  # 优势函数with tf.variable_scope('surrogate'):ratio = pi.prob(self.tfa) / oldpi.prob(self.tfa)  # 概率密度surr = ratio * self.tfadv  # 差异大,奖励大惊讶度高if METHOD['name'] == 'kl_pen':self.tflam = tf.placeholder(tf.float32, None, 'lambda')kl = tf.distributions.kl_divergence(oldpi, pi)self.kl_mean = tf.reduce_mean(kl)self.aloss = -(tf.reduce_mean(surr - self.tflam * kl))else:  # clipping method, find this is better  限制了surrogate的变化幅度self.aloss = -tf.reduce_mean(tf.minimum(surr,tf.clip_by_value(ratio, 1. - METHOD['epsilon'], 1. + METHOD['epsilon']) * self.tfadv))  # 限定ratio的范围,我也不懂这个参数是怎么调的self.atrain = tf.train.AdamOptimizer(A_LR).minimize(self.aloss) # A_LR学习率,损失函数aloss# 写日志文件tf.summary.FileWriter('log/', self.sess.graph)self.sess.run(tf.global_variables_initializer())# 搭建网络函数def _build_anet(self, name, trainable=True):# Critic网络部分if name == 'Critic':with tf.variable_scope(name):# self.s_Critic = tf.placeholder(tf.float32, [None, S_DIM], 'state')# 两层神经网络,输出是self.v,即估计state valuel1_Critic = tf.layers.dense(self.tfs, 100, tf.nn.relu, trainable=trainable, name='l1')self.v = tf.layers.dense(l1_Critic, 1, trainable=trainable, name='value_predict')# Actor部分,分为‘pi’和‘oldpi’两个神经网络# 返回动作分布以及网络参数列表else:with tf.variable_scope(name):# self.s_Actor = tf.placeholder(tf.float32, [None, S_DIM], 'state')# ??这部分l1_Actor = tf.layers.dense(self.tfs, 100, tf.nn.relu, trainable=trainable, name='l1')mu = 2 * tf.layers.dense(l1_Actor, A_DIM, tf.nn.tanh, trainable=trainable, name='mu')sigma = tf.layers.dense(l1_Actor, A_DIM, tf.nn.softplus, trainable=trainable, name='sigma')norm_list = tf.distributions.Normal(loc=mu, scale=sigma)    # 正态分布params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=name)   #提取网络参数列表return norm_list, paramsdef update(self, s, a, r):# 将值赋给old_pi网络self.sess.run(self.update_oldpi_op)#为了取回self.adv,adv = self.sess.run(self.adv, {self.tfdc_r: r, self.tfs: s})    # 后面那个字典是什么意思?if METHOD['name'] == 'kl_pen':  # 选择kl-penalty方式for _ in range(A_UPDATE_STEPS):_, kl = self.sess.run([self.atrain, self.kl_mean],{self.tfa: a, self.tfadv: adv, self.tfs: s, self.tflam: METHOD['lam']})if kl > 4 * METHOD['kl_target']:  # this in in google's paperbreakif kl < METHOD['kl_target'] / 1.5:  # adaptive lambda, this is in OpenAI's paperMETHOD['lam'] /= 2elif kl > METHOD['kl_target'] * 1.5:METHOD['lam'] *= 2METHOD['lam'] = np.clip(METHOD['lam'], 1e-4, 10)  # sometimes explode, this clipping is my solutionelse:# 训练actor网络[self.sess.run(self.atrain, {self.tfs: s, self.tfa: a, self.tfadv: adv}) for _ in range(A_UPDATE_STEPS)]# 训练critic网络[self.sess.run(self.ctrain, {self.tfs: s, self.tfdc_r: r}) for _ in range(C_UPDATE_STEPS)]def choose_action(self, s):# 选动作s = s[np.newaxis, :]a = self.sess.run(self.sample_op, {self.tfs: s})[0]return np.clip(a, -2, 2)def get_v(self, s):# 算 state valueif s.ndim < 2:s = s[np.newaxis, :]return self.sess.run(self.v, {self.tfs: s})env = gym.make('Pendulum-v0').unwrapped
S_DIM = env.observation_space.shape[0]
A_DIM = env.action_space.shape[0]
ppo = PPO()
all_ep_r = []# ppo和环境的互动
# 达到最大回合数退出
for ep in range(EP_MAX):s = env.reset()buffer_s, buffer_a, buffer_r = [], [], []ep_r = 0for t in range(EP_LEN):env.render()a = ppo.choose_action(s)s_, r, done, _ = env.step(a)# 存储在buffer当中buffer_s.append(s)buffer_a.append(a)buffer_r.append((r + 8) / 8)s = s_ep_r += r# 如果buffer收集一个batch了或者episode结束了if (t + 1) % BATCH == 0 or t == EP_LEN - 1:# 计算discounted rewardv_s_ = ppo.get_v(s_)discounted_r = []for r in buffer_r[::-1]:v_s_ = r + GAMMA * v_s_discounted_r.append(v_s_)discounted_r.reverse()bs, ba, br = np.vstack(buffer_s), np.vstack(buffer_a), np.vstack(discounted_r)# 清空bufferbuffer_s, buffer_a, buffer_r = [], [], []ppo.update(bs, ba, br)  # 更新PPOif ep == 0:all_ep_r.append(ep_r)else:all_ep_r.append(all_ep_r[-1] * 0.9 + ep_r * 0.1)print('Ep:%d | Ep_r:%f' % (ep, ep_r))plt.plot(np.arange(len(all_ep_r)), all_ep_r)
plt.xlabel('Episode')
plt.ylabel('Moving averaged episode reward')
plt.show()
  1. 多线程DPPO

这篇关于强化学习笔记1——ppo算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/198101

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]