深度强化学习经验回放(Experience Replay Buffer)的三点高性能修改建议:随机采样、减少保存的数据量、简化计算等

这篇具有很好参考价值的文章主要介绍了深度强化学习经验回放(Experience Replay Buffer)的三点高性能修改建议:随机采样、减少保存的数据量、简化计算等。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

高性能的 ReplayBuffer 应该满足以下三点:

  1. 随机采样 random sample 的速度要快,尽可能加快读取速度(最为重要)
  2. 减少保存的数据量,增加吞吐效率(对分布式而言重要)
  3. 保存能简化计算的变量(对特定算法而言重要)

为了达成以上要求,我建议做出以下修改:

  1. Replay Buffer 的数据都放在连续的内存里,加快读取速度
  2. 按 trajectory 的顺序保存 env transition,避免重复保存 next state,减少数据量
  3. 分开保存 state 与其他数据,减少数据量
  4. 将 off-policy 的数据一直保存在显存内
  5. 保存 mask = gamma if done else 0 用于计算 Q 值,而不是保存 done
  6. 为 on-policy 的 PPO 算法保存 noise 用于计算新旧策略的熵

本文的重点:ReplayBuffer 的数据要放在连续内存里,实验结果如下:

深度强化学习经验回放(Experience Replay Buffer)的三点高性能修改建议:随机采样、减少保存的数据量、简化计算等,强化学习(原理+项目实战)大合集,# 强化学习单智能体算法原理+项目实战,# 强化学习相关技巧(调参、画图等),人工智能,深度学习,强化学习,深度强化学习,经验回放,pytorch

我们使用 Numpy 库在内存里、使用 PyTorch 库在显存里 创建了一整块连续的空间,对比了 List 和 Tuple 的方案。结果:连续存储空间的明显更节省时间。因此,DRL 库的 ReplayBuffer 有必要围绕着 连续内存空间 来设计

代码见 github Yonv1943 ReplayBufferComparison.py ,是一份基于 Python Numpy 的实现,代码在保证高性能的同时做到了优雅。我根据这一页的结论还写出来一个 DRL 库「小雅:ElegantRL」

AI4Finance-LLC/ElegantRL

更新日志
2020-06-17 初版 匹配了文字与图片,修改语法错误
2020-12-10 第二版 在@UncleDrew 的提醒下修复了失效链接
    原标题 DRL的经验回放(Experiment Replay Buffer ) 用Numpy实现让它更快一点,改正为Experience Replay
2021-03-24 修改标题 DRL的经验回放(Experience Replay Buffer)的三点高性能修改建议
    新增 3. 将state 与其他数据分开保存

0. 简单介绍「经验回放」

简单介绍「经验回放」(Experimen Replay):当 DQN(Deep Q Network)[1] 使用一个神经网络用于拟合一个值函数时,Q-learning 完成了从离散状态空间到连续状态空间的跨越。为了更好地使用这个叫 Q Network 的神经网络,我们需要用符合独立同分布(independent and identically distributed,i.i.d.)的数据分批次地训练它。

深度强化学习经验回放(Experience Replay Buffer)的三点高性能修改建议:随机采样、减少保存的数据量、简化计算等,强化学习(原理+项目实战)大合集,# 强化学习单智能体算法原理+项目实战,# 强化学习相关技巧(调参、画图等),人工智能,深度学习,强化学习,深度强化学习,经验回放,pytorch

而 DQN 使用了 1997 年就存在的 Experience Replay [2] 技术:梯度下降要求用于批次训练的数据符合 i.i.d.,然而与环境交互后产生的数据不能直接用于训练 。因此,我们先把贝尔曼公式(Bellman Equation)需要的数据保存起来,当缓存中的数据足够多时,随机抽样得到的数据就能接近 i.i.d.。

2.而高性能的 ReplayBuffer 应该满足以下三点:

2.1. 随机采样 random sample 的速度要快,尽可能加快读取速度(重要)

需要 ReplayBuffer 完成的任务有两个,会降低读写速度的方案不应该采用:

  • 写入:actor 与环境交互,得到 environment transition 元组 (state, action, reward, done, next state),或者得到一整条 trajectory 写入其中
  • 读取:使用 ReplayBuffer 内部的数据训练网络的时候,需要从中 random sample 出许多批次的数据用于随机梯度下降(Stochastic Gradient Descent)

2.2. 减少保存的数据量,增加吞吐效率(对分布式而言重要)

深度学习(Deep Learning)中的有监督训练,训练数据一开始就存放在数据集中,因此可以进行数据预处理,预加载等操作。除去 offline RL,大部分强化学习任务做不到:数据需要智能体在环境中探索,一点点存入 ReplayBuffer 中。如果是 同策略(on-policy),那么在探索前还需要清空数据,再重新收集。

深度强化学习经验回放(Experience Replay Buffer)的三点高性能修改建议:随机采样、减少保存的数据量、简化计算等,强化学习(原理+项目实战)大合集,# 强化学习单智能体算法原理+项目实战,# 强化学习相关技巧(调参、画图等),人工智能,深度学习,强化学习,深度强化学习,经验回放,pytorch

因此,ReplayBuffer 需要减少需要保存的数据量,增加吞吐效率。

  • 这对多进程、分布式的通信很重要,直接影响通信效率。
  • 网络训练时,数据一定会从产生地(在内存中的 env)传输到使用地(在显存中的优化器 optimizer),数据量越小,吞吐效率越高。

2.3. 保存能简化计算的变量(对特定算法而言重要)

这是编程常用技巧,有一点动态规划 Dynamic Programming 的思想:已经算好的中间变量如果以后有用,就试着保存下来,简化后面的计算。例如:不要保存一个 done 这个 bool,而是保存为一个 mask float,简化 TD-errors 的计算:

state, action, reward, done, next_state, gamma
mask = 0.0 if done else gamma

bellman equation
原本的: y = r + (1-done) * gamma * next_q_value
改变为: y = r + mask * next_q_value

有一些代码保存了 undone,明显就是有 “简化计算” 的意识,却没有贯彻到底

3.优化方案

3.1. 把 Replay Buffer 的数据都放在连续的内存里

从对比实验得出:把数据都放在连续的内存 / 显存里是最快的。

实验结果如下,可以看到使用了 Numpy 将数据放在连续内存中的方法最快,用了 13 秒(比其他方法快了 50%),而不管在何时传入 GPU,对总用时的影响都很小:实验结果如下,可以看到使用了 Numpy 将数据放在连续内存中的方法最快,用了 13 秒(比其他方法快了 50%),而不管在何时传入 GPU,对总用时的影响都很小:

深度强化学习经验回放(Experience Replay Buffer)的三点高性能修改建议:随机采样、减少保存的数据量、简化计算等,强化学习(原理+项目实战)大合集,# 强化学习单智能体算法原理+项目实战,# 强化学习相关技巧(调参、画图等),人工智能,深度学习,强化学习,深度强化学习,经验回放,pytorch

Method       Used Times (second)   Detail
List         24                    list()
NamedTuple   20                    collections.namedtuple
Array(CPU)   13                    numpy.array/torch.tensor(CPU)
Array(GPU)   13                    torch.tensor (GPU)

3.22. 按 trajectory 的顺序保存 env transition,避免重复保存 next state

一般我们会说 env transition 是一个元组 (state, action, reward, next_state) ,我们保存了这些状态转移元组,来描述环境与策略。如果我们按 trajectory 的顺序保存 trainsition,那么不必重复保存 next_state。因为它可以在下一行找到。

  • 优点:如果 state 的数据量是 action 的 2 倍以上,那么数据量将降低至 60% ~ 50%。
  • 缺点:random sample 的时候,需要使用 random id 寻址两次而不是一次
ReplayBuffer (in order)

state1, reward1, mask1, action1, state2, ...
state2, reward2, mask2, action2, state3, ...
...

数据量降低带来的提升非常明显,还收顺便节省显存、内存。而寻址两次并不慢,可以承受。值得一提的是,按顺序保存,给分布式下的 ReplayBuffer 提出了更高的要求,不同 workers 收集到的 env transition 在汇集的时候,一定要以 trajectory 为单位。对于无终止状态的环境,无法以 trajectory 为单位。此时我们需要给每一个 workers 对应配置一个 ReplayBuffer,而不是直接把它们都存到同一个内

class ReplayBuffer:

class ReplayBufferMP:
    def __init__(...):
        ...
        self.buffers = [ReplayBuffer(...) for _ in range(rollout_num)]
        ...

3.3. 分开保存 state 与其他数据,减少数据量

在以图像作为 state 的任务中(Atari Game),很有必要分开保存 state 与其他数据。图片的格式是 uint8 (0~255),而其他数据是 float32。结合上面第二点:“不重复保存 next state”,ReplayBuffer 的数据量将降低至 30% ~12.5% 。分开保存之后,如果 state 是图片,它也可以直接保存成 (n, height, width, channel) 的格式,减少 flatten 的麻烦。

byte:    =      # 一个字节
uint8:   =
float16: ==
float32: ====

此外,结合上面第二点 “不重复保存 next state”,我们可以直接在 state 上寻址两次。来获取 state 以及 next state。

buf_state.shape == (sum_of_trajectory_len, state_dim) 是按trajectory顺序保存的 state

self.buf_state[indices],
self.buf_state[indices + 1]

此外,随机抽样时需要产生 indices。如果允许在同一批次中产生重复的抽样,那么算法速度更快。很意外的是:重复抽样竟然效果更好。(我猜测这是因为:这种方式丰富了 batch 数据的多样性,因此更不容易过拟合)

# indices = rd.choice(self.memo_len, batch_size, replace=False) # why perform worse?
# indices = rd.choice(self.memo_len, batch_size, replace=True) # why perform better?
# same as:
indices = rd.randint(self.now_len, size=batch_size)

buffer[indices]

3.4. 将 off-policy 的数据一直保存在显存内

异策略 off-policy:可以使用与 “被更新的策略” 相异的策略收集到的 ReplayBuffer 数据用于更新的算法。同策略 on-policy 则不能。因此异策略 的 ReplayBuffer 中,有很多数据在达到最大容量前能被保留。因此有必要将 off-policy 的数据一直保存在显存内,减少数据吞吐量。

3.5. 保存 mask = gamma if done else 0 用于计算 Q 值,而不是保存 done

不要保存一个 done 这个 bool,而是保存为一个 mask float,简化 TD-errors 的计算:

state, action, reward, done, next_state, gamma
mask = 0.0 if done else gamma

bellman equation
原本的: y = r + (1-done) * gamma * next_q_value
改变为: y = r + mask             * next_q_value

有一些代码保存了 undone,明显就是有 “简化计算” 的意识,却没有贯彻到底

3.6. 为 on-policy 的 PPO 算法保存 noise 用于计算新旧策略的熵

在随机策略中,动作由高斯噪声产生。PPO 为了计算旧策略的熵需要知道 noise 的值,PPO 算法计算新旧策略的熵 logprob 的代码如下:文章来源地址https://www.toymoban.com/news/detail-563537.html

# in AgentZoo.py AgentPPO.update_net()

action = action_avg + action_std * noise
noise = (action_avg - action)/(action_std)
a_std_log = np.log(action_std)
sqrt_2pi_log = np.log(np.sqrt(2*pi))

logprob = -(noise.pow(2).__mul__(0.5) + a_std_log + sqrt_2pi_log).sum(1)
# same as below
logprob = -((action_avg - action) ** 2 /(2 * (action_std ** 2)) + a_std_log + sqrt_2pi_log).sum(1)

4.其他:用于对比的其他 ReplayBuffer 方案

  • 使用 List:维护一个长度可变的 List,到达最大容量时,删除最早加入的记忆,这个方案最简单。此列表的每个元素为这样的一个元组(state, action, reward, mask, next_state)。但是随机抽样的速度较慢,将位于不同内存空间的元素组成批次数据时较慢。
self.buffer.append(memory_tuple)
del self.buffer[:del_len]

  • 使用 NamedTuple:具体实现与 List 相同。维护一个长度可变的 NamedTuple。(其实这也是一个 List,只是使用了 Python 内建的 NamedTuple 为 state, action, reward, mask, next_state 命名)。代码十分简洁优雅。但是随机抽样的速度较慢。PyTorch 官网上的 RL 入门教程就使用了这种方法。
from collections import namedtuple
self.transition = namedtuple(
    'Transition', ('reward', 'mask', 'state', 'action', 'next_state',)
)

self.buffer.append(self.transition(*args))

'''convert tuple into array'''
arrays = self.transition(*zip(*[self.buffer[i] for i in indices]))

  • 使用 Numpy.ndarray:直接划出一整块连续的内存空间。设置更新的指针。到达最大容量时,依照指针让新的记忆覆盖旧的记忆。抽样时使用 Numpy 自带的方法。速度较快,且代码优雅。
self.buffer = np.empty((memo_max_len, memo_dim), dtype=np.float32)

self.buffer[self.next_idx] = np.hstack(memo_tuple)

tensor = torch.tensor(buffer, device=device)

'''convert array into torch.tensor'''
tensors = (
    tensor[:, 0:1],  # rewards
    tensor[:, 1:2],  # masks, mark == (1-float(done)) * gamma
    tensor[:, 2: ],  # states
    tensor[:,  : ],  # actions
    tensor[:,  : ],  # next_states
)

参考

  1. ^DQN - Playing Atari with Deep Reinforcement Learning. 2013. https://arxiv.org/abs/1312.5602
  2. ^Experience Replay - Reinforcement Learning for Robots Using Neural Networks. 1997. http://isl.anthropomatik.kit.edu/pdf/Lin1993.pdf

到了这里,关于深度强化学习经验回放(Experience Replay Buffer)的三点高性能修改建议:随机采样、减少保存的数据量、简化计算等的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity学习】完全基于Ultimate Replay 2.0的UI回放系统

    前面两节已经介绍了本人在项目中使用的结合JSON和Ultimate Replay 2.0的UI回放系统,那是在项目结构特殊,代码不好更改的情况下,本人所做的些许调整。但在这几天的开发过程中,我发现通常情况下只使用Ultimate Replay 2.0即可实现大部分情况下的UI回放。 这在基于JSON的UI回放系

    2024年02月12日
    浏览(41)
  • FPGA学习经验分享——入门篇

    FPGA是一个高度集成化的芯片,其学习过程既需要编程,又需要弄懂硬件电路和计算机架构。涉及到的知识和基础非常多,如果不合理地安排学习内容,学习过程会非常漫长和枯燥。这篇文章主要阐述了对于入门FPGA的一些经验分享,希望能够给想学FPGA的人一些引导,少走一些

    2024年02月03日
    浏览(31)
  • 前端学习路线图和一些经验

    关于前端目前个人建议的一个路线,也是自己之前前端学习时候的一个大致路线,给想要学习前端的小白一个参考, 以前自己刚开始接触前端的时候就是不知道该按照什么路线学习 eg-前端是做什么的? 就是开发网站,移动端,小程序之类的页面  调调接口完成页面的渲染 个人比

    2024年01月19日
    浏览(35)
  • 【飞控制作】从飞控制作学习项目经验

    通过4个电机的转速,来控制飞行器X、Y、Z轴的加速度和角速度,实现悬停、垂直升降、俯仰、偏航、滚转(这里只对比较陌生的俯仰、偏偏行、滚转做示意图说明)。 运动控制主要参考:四旋翼无人机飞行原理及控制方法,你了解多少? 注意,电路图为上图,而实际设计电

    2024年04月08日
    浏览(30)
  • 北大硕士7年嵌入式学习经验分享

    大一到大三这个阶段我与大多数学生相同: 学习本专业知识(EE专业),学习嵌入式软件开发需要的计算机课程(汇编原理,计算机组成原理,操作系统,C语言等),学习嵌入式项目(来源于实验室项目,自己想到的项目以及各种比赛)。 关于如何学习嵌入式软件开发: ①

    2024年02月07日
    浏览(40)
  • 单片机学习资料和经验分享

            分享一些在学习51单片机的资料。都是自己在网上各种搜啊。学校交的51单片机课程和stm32课程太一言难尽,只能自己买书和网上刷B站看课和各种搜,自己的知识网络根本无从掌握。所以最近一直在各种搜索,整理自己的一个学习的路线之类的。         最重要的一

    2024年02月22日
    浏览(51)
  • 机器学习知识经验分享之六:决策树

         python语言用于深度学习较为广泛,R语言用于机器学习领域中的数据预测和数据处理算法较多,后续将更多分享机器学习数据预测相关知识的分享,有需要的朋友可持续关注,有疑问可以关注后私信留言。 目录 一、R语言介绍 二、R语言安装(Windows为例)         R语言

    2024年02月14日
    浏览(33)
  • Redis发布订阅机制学习|kafka相关经验

    Redis 键值数据库 key value NoSql 第一章: 差异 #1 structured 结构化 约束 primary unique unsigned #2 relational 关联的 #3 SQL查询 例 select id, name, age from tb_user where id=1 redis get user:1 mongoDB db.users.find({_id: 1}) elasticsearch GET http://localhost:9200/users/1 #4 事务 ACID 基本一致 无事务 键值类型 Redis 文档类

    2024年02月15日
    浏览(27)
  • 机器学习:经验误差与过拟合(Python)

    以目标函数 为例,采样数据并添加噪声,进行不同阶次的多项式曲线拟合,分析欠拟合和过拟合。 polynomial_feature.py polynomial_regression_curve.py test_poly_regression.py

    2024年01月23日
    浏览(35)
  • 猿创征文|【云原生】学习云原生经验分享

    博主昵称:跳楼梯企鹅 博主主页面链接: 博主主页传送门 博主专栏页面连接: 专栏传送门--网路安全技术 创作初心:本博客的初心为与技术朋友们相互交流,每个人的技术都存在短板,博主也是一样,虚心求教,希望各位技术友给予指导。 博主座右铭:发现光,追随光,

    2024年02月02日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包