分享

天下苦深度强化学习久矣,这有一份训练与调参技巧手册

 520jefferson 2022-04-14

天下苦 RL 久矣,其中最苦的地方莫过于训练和调参了,人人欲“调”之而后快。

在此为 RL 社区贡献一点绵薄之力,首先摘录 Stable Baselines3 [1] 的 RL Tips and Tricks [2],其次给出个人心得,最后提供一些其他优秀的资源。

这块主要是 RL Tips and Tricks 的翻译,其中 RL 相关的专有词汇保持英文原版。

这种格式的内容为个人注解,主要是【总结】和【扩展】。

本文的目的在于帮你更好的用 RL,涵盖了关于 RL 的一般建议(从哪里开始,选择哪种算法,如何评估算法),以及在使用自定义环境或实现 RL 算法时的 Tips 和 Tricks。我们也提供了视频和 slides。

视频: 
https://www./watch?v=Ikngt0_DXJg

Slides:

https://araffin./slides/rlvs-tips-tricks/
图片

使用RL的建议

太长不看版

1. 学习 RL 和 Stable Baselines3

2. 如有必要,进行定量的实验和超参数调整

3. 使用单独的测试环境评估效果(记得要检查 wrappers!)

4. 想要更好的效果,就增加训练预算

和其他领域一样,如果你想使用 RL,首先你要学习它(推荐资源 [3]),才能理解你在用什么。也推荐看 Stable Baselines3(SB3)的文档和教程 [4],其中包括了基本使用和进阶技巧(比如 callbacks 和 wrappers)。

强化学习与其他机器学习有很大不同:相比监督学习使用固定的数据集,强化学习的数据集是 agent 与 env 交互产生的,即自己采集数据来训练自己。这种依赖可能导致恶性循环:如果 agent 收集的数据质量很差,比如获得的 reward 很少,那么 agent 将得不到改善而继续差下去。

这也解释了为什么 RL 的结果跑一次变一次,甚至只是改变了 seed。因此为了获得可靠的结果,需要多跑几次。

RL 要想有好的结果,合适的超参数至关重要。近期的算法(PPO、SAC、TD3)通常只需要很少的超参数调节,但也不要指望算法的默认参数适合每一个 env。

因此,强烈推荐看看 RL zoo [5](或原始论文)来获得好的超参数。将 RL 应用到一个新问题时,最好的实践就是超参数的自动调优,好消息是 RL zoo 也提供了这种功能。

将 RL 应用到一个自定义问题时,应该始终 normalize 给 agent 的输入(比如使用 VecNormalize for PPO/A2C),还可以看看其他环境的常用预处理(比如 Atari 游戏的 frame-stack)。有关自定义环境更具体的 Tips 和 Tricks 请看下文相关内容。

【总结】强化学习训练困难的根源即在于数据获取的不稳定性。因为数据都是 agent 自己采集的,而每次采集的结果会因 seed 和超参数的变化而变化,再加之 stochastic 策略的随机性,数据的稳定性就更差了。既然稳定性不行,为了提高学习效果,那就堆数量,即采集足够多的数据。

图片

目前RL的局限

要入 RL 的坑,你得知道 RL 现在有哪些坑 [6]

Model-free RL 算法(比如 SB3 里实现的算法)通常 sample inefficient,即需要大量的 samples(有时需要上百万次交互)才能学到点有用的。这也是为什么大多数 RL 只在游戏和仿真里取得了成功。比如 ETH Zurich 的工作 [7],ANYmal 四足机器人只在仿真中训练,然后在现实中测试。

一个通用建议,要先获得更好效果,你需要增加 agent 的预算(训练的步数)。

为了让 agent 表现出期望的行为,通常需要 expert knowledge 来设计一个良好的 reward function,这种 reward engineering 一般也需要迭代几次。举个不错的 reward shaping 例子,Deep Mimic [8] 结合了模仿学习和强化学习来做出各种特技动作。

RL 还有一个坑在于训练的不稳定,比如在训练中看到效果突然出现断崖式下跌。这种现象容易在 DDPG 中出现,为了解决这个问题出现了它的扩展版 TD3。其他的方法比如 TRPO、PPO 使用 trust region 来避免过大的 update,进而减少出现这个问题。

【总结】坑还是围绕数据的不稳性展开,主要有三点:1) sample inefficient;2) sensitivity to seed / hyperparameters;3) reward function design。基本上所有的 RL 算法,都在围绕这三点做文章。


图片

如何评估RL算法?

因为大多数算法在训练期间会使用 exploration noise,因此需要一个独立的 test env 去评估算法。建议周期性地评估 agent,比如每交互 N(如 10000)次之后测试 n(5~20)个episodes,然后取平均得到单个 episode 的 reward。

SB3 中提供了 Evaluation [9] 和 Callbacks [10] 模块来做评估。在评估 agent 以及和其他结果对比时,要注意 env wrapper,对 episode rewards 或 lengths 的修改也可能导致不好的评估结果。

由于某些算法(如 A2C、PPO)默认采取 stochastic 策略,因此在测试即调用 .predict() 时应该设置 deterministic=True,这会有更好的效果。查看 training curve 是一种不错的方式,但会低估 agent 的真实表现。

【扩展】实际上现在不少 RL 库(比如 spinningup、Stable Baselines3)的 training curve 已经是 deterministic=True 的评估了。

我们建议你阅读 Deep Reinforcement Learning that Matters [11],其中关于 RL 评估做了很好的讨论。

你也可以看看 Cédric Colas 关于这方面的 blog [12和 issue [13]


图片

我该使用哪种算法?

在 RL 中没有万金油,使用哪种算法取决于具体的需求和问题。首先要区分 action space 是 discrete(比如上下左右) 还是 continuous(比如达到某个速度)?

一些算法只能用于对应的 action space:DQN 只能用于 discrete action,SAC 只能用于 continuous action。

【扩展】实际上也有 DQN 的 continuous 版:NAF [14],SAC 的 discrete 版:SAC-Discrete [15]


接下来看你的训练是否需要并行?如果时间对你很宝贵,你应该选择 A2C 和它的变种比如 PPO。参考 Vectorized Environment [16] 来了解更多 multiple workers 训练。


【扩展】实际上也有优秀的分布式框架 Ape-X [17],可搭配各种 off-policy RL 算法如 DQN、DDPG 使用。此外要注意的是,对于 off-policy 算法而言,多进程不一定更“快”,在 wall-clock time 和 sample efficiency 之间有个折中。更多的 envs 意味着更低的 sample efficiency 和 更短的 wall-clock time,具体见 pull #439 [18]


RL 算法的选择总结如下,注意 normalization 很重要!各个算法的超参数建议参考 RL zoo。

图片

▲ RL算法选择

【扩展】Stable Baselines3 实现的 RL 算法具体的适用情况 [19]

1. 对于状态,支持 N 维向量、图片、单级 Dict。 

2. 对于动作,支持连续(Box)和离散(Discrete、MultiDiscrete、MultiBinary)。 

3. 目前除 HER 外,都支持多进程,部分算法在 SB3 Contrib 中。


图片

▲ SB3 RL算法适用范围

如果你的 env 使用 GoalEnv 接口,那么要配合后视经验 HER [20使用,注意 HER 的 batch_size 很重要!

图片

▲ GoalEnv 的 RL 算法选择

图片

创建自定义环境的Tips和Tricks

如果你想自定义环境,推荐看这里 [21],我们也提供了一个 colab notebook 例子 [22]

一些基本的建议:

  • 尽量 normalize 你的 observation space,尤其知道边界值的时候

  • normalize 你的 action space 到 [-1,1],这个 scale 很容易做到,当与 env 交互时 rescale 回去即可

  • 从 shaped reward 开始,并且简化问题

  • 用 random actions 去测试 env 是否正常,注意保持 gym 接口

我们提供了方法查看自定义环境是否正常:

from stable_baselines3.common.env_checker import check_env

env = CustomEnv(arg1, ...)
# It will check your custom environment and output additional warnings if needed
check_env(env)

如果想用 random agent 快速测试环境,很简单:

env = YourEnv()
obs = env.reset()
n_steps = 10
for _ in range(n_steps):
    # Random action
    action = env.action_space.sample()
    obs, reward, done, info = env.step(action)
    if done:
        obs = env.reset()

action space 为什么要 normalize?

大多数 RL 算法处理 continuous aciton 是基于 Gaussian 分布(最初中心在 0,方差为 1)。因此,如果你忘了 normalize 自定义环境中的 action space,会导致学习很难,调试难上加难(见 issue #473  [23])。

图片

▲ 动作 normalizaiton

使用 Gaussian 分布会带来另一个问题,即 action range 没有边界,因此经常使用 clipping 来保证一个有效区间。一种更好的方案是使用 squashing 函数(见 SAC)或者 Beta 分布(见 issue #112  [24])。

对于 DDPG 或 TD3 来说不需要,因为它们不依赖任何概率分布。

【总结】observation、action 都尽量 normalization,从 shaped reward 开始。

图片

实现RL算法的Tips和Tricks

当你想自己写 RL 算法来复现 paper 时,John Schulman 的 nuts and bolts of RL research [25] 很有用(视频 [26])。

我们建议按照以下步骤来实现一个可用的 RL 算法:

1. 多看几次原始论文

2. 看现有的实现(如果有的话)

3. 试着在简单的 toy problems 上有点作用

4. 让算法运行在越来越难的 env 上(可以和 RL zoo 上的结果对比),配合调参

【扩展】建议从 spinningup [27] 这种 single-file 的 RL 库开始改。

在编写算法时,需要特别注意不同对象的 shape(broadcast 的错误会暗藏杀机),以及什么时候停止梯度传播。

关于从易到难的 env 选择,@ariffin 推荐如下:

图片

▲ 从易到难的 Env


图片

个人心得

个人是做机械臂+强化学习的,首先推荐一个机械臂的简单环境 [28],建议先跑跑常见的 DQN、DDPG、SAC 等算法,可以配合 spinningup [29] 使用,既学了怎么自定义 env,又学了 RL 算法。在简单环境中,可以尝试各种 shaped reward,测试 normalization 的影响。

自定义环境时,一定要注意 seed 对应的 np_random,这样能保证可复现。

observation:要提供足够多的 information,从数据完备性上要能解决问题。再说说 normalization,以机械臂为例:机械臂的角度一般在 [-π, π],实测角度作为 observation 的话可以不 normalization,但末端位置作为 observation 由于与连杆长度有关建议 normalization,不一定要严格到 [-1,1],推荐末端位置使用相对工具系的,这样与机械臂本体解耦,泛化能力更好。observation 中还可借鉴 Atari 游戏的 frame-stack,即把当前位置和上一位置组合,或者加入当前速度。

action:机械臂一般是 continuous action,使用相关 RL 算法时一定要 normalize 到 [-1,1],很重要。

reward:先 reward shaping,再说 sparse reward。多个不同的子 reward 要注意各自比例,不要让次要 reward 喧宾夺主。考虑到要让 agent 尽快完成任务,一般采用负的 reward。reward engineer 要耐心,多迭代几次。推荐定义一个 base env,派生不同 reward 的 env 分别训练好横向对比。

终止条件:可以 early stopping,也可试着 max steps,对于是真 done 还是超时 done 要区分。

网络结构:如果是向量输入,一般 2~3 个隐藏层足矣,每层 128 或 256 节点,ReLU 激活函数。

replay_buffer_size:设大一点,比如 1e6,很多时候缓存被放满前训练就收敛了,并不需要删除任何记忆。

其他资源:

关于 RL 调参方面,推荐两位知友 @曾伊言、 @WYJJYN的作品。

深度强化学习调参技巧:以D3QN、TD3、PPO、SAC算法为例:

https://zhuanlan.zhihu.com/p/345353294

深度强化学习落地方法论(8)——新书推荐《深度强化学习落地指南》:

https://zhuanlan.zhihu.com/p/403191691


图片

参考文献

图片
[1] https://stable-baselines3./en/master/
[2] https://stable-baselines3./en/master/guide/rl_tips.html
[3] https://stable-baselines3./en/master/guide/rl.html
[4] https://github.com/araffin/rl-tutorial-jnrr19/tree/sb3
[5] https://github.com/DLR-RM/rl-baselines3-zoo
[6] https://www./2018/02/14/rl-hard.html
[7] https://www./watch?v=aTDkYFZFWug
[8] https://xbpeng./projects/DeepMimic/index.html
[9] https://stable-baselines3./en/master/common/evaluation.html#eval
[10] https://stable-baselines3./en/master/guide/callbacks.html#callbacks
[11] https:///abs/1709.06560
[12] https://openlab-flowers./t/how-many-random-seeds-should-i-use-statistical-power-analysis-in-deep-reinforcement-learning-experiments/457
[13] https://github.com/hill-a/stable-baselines/issues/199
[14] http://proceedings./v48/gu16.html
[15] https:///abs/1910.07207
[16] https://stable-baselines3./en/master/guide/vec_envs.html
[17] https:///abs/1803.00933
[18] https://github.com/DLR-RM/stable-baselines3/pull/439
[19] https://stable-baselines3./en/master/guide/algos.html
[20] https://stable-baselines3./en/master/modules/her.html#her
[21] https://stable-baselines3./en/master/guide/custom_env.html
[22] https://colab.research.google.com/github/araffin/rl-tutorial-jnrr19/blob/master/5_custom_gym_env.ipynb
[23] https://github.com/hill-a/stable-baselines/issues/473
[24] https://github.com/hill-a/stable-baselines/issues/112
[25] http:///docs/nuts-and-bolts.pdf
[26] https://www./watch?v=8EcdaCk9KaQ
[27] https://spinningup./en/latest/
[28] https://github.com/ekorudiawan/gym-robot-arm
[29] https://github.com/openai/spinningup

图片

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多