【万字专栏总结】离线强化学习(OfflineRL)总结(原理、数据集、算法、复杂性分析、超参数调优等)

2022-09-23 14:57:12 浏览数 (1)

本文来源自知乎博客,作者:旺仔搬砖记

排版:OpenDeepRL

由于内容过长,本文仅展示部分内容,完整系列博客请文末阅读原文

离线强化学习(Offline RL)作为深度强化学习的子领域,其不需要与模拟环境进行交互就可以直接从数据中学习一套策略来完成相关任务,被认为是强化学习落地的重要技术之一。本文详细的阐述了强化学习到离线强化学习的发展过程,并就一些经典的问题进行了解释和说明。

1. 深度强化学习

1.1 深度强化学习简介

强化学习发展的特别早,但一直不温不火,其中Sutton老爷子早在1998年就写了强化学习领域的圣经书籍:An Introduction : Reinforcement Learning ,但也并未开启强化学习发展的新局面。直到2012年,深度学习广泛兴起,大规模的神经网络被成功用于解决自然语言处理,计算机视觉等领域,人工智能的各个方向才开始快速发展,强化学习领域最典型的就是2013年DeepMind公司的Volodymyr Mnih发表Playing Atari with Deep Reinforcement Learning(DQN技术),可以说开启了深度强化学习技术发展的新高潮,2015年该论文的加强版Human-level control through deep reinforcement learning 登上Nature, 以及2016年Nature上的AlphaGo: Mastering the game of Go with deep neural networks and tree search 充分证明了深度强化学习技术的发展潜力。

传统的强化学习和监督学习、非监督学的区别在于,后两者是通过从已标记(Label)和无标记的数据中学习一套规律(我们可以理解为学习一个函数表达式),而前者强化学习则是通过行为交互来学习一套策略,以最大化累计期望奖励,结构如图所示:

image-20220329103307041

其学习过程可以归纳为通过agent获取环境状态, 根据自身学习到的知识做出action反馈给环境,并得到一个奖励,不断地迭代出一个可以一直玩游戏并且不会死的智能体。原理就是从一个四元组<s, a,="" r,="" s^{'}="">

1.1.1 On-Policy和off-Policy区别

On-policy和Off-policy这两个词在强化学习领域非常重要,知乎上有很多关于其讨论强化学习中on-policy 与off-policy有什么区别?,最典型的莫过于李宏毅老师下棋形象例子解释,还可以从以下方式解释:

【补充】两者在学习方式上的区别:若agent与环境互动,则为On-policy(此时因为agent亲身参与,所以互动时的policy和目标的policy一致);若agent看别的agent与环境互动,自己不参与互动,则为Off-policy(此时因为互动的和目标优化的是两个agent,所以他们的policy不一致)。两者在采样数据利用上的区别On-policy:采样所用的policy和目标policy一致,采样后进行学习,学习后目标policy更新,此时需要把采样的policy同步更新以保持和目标policy一致,这也就导致了需要重新采样。Off-policy:采样的policy和目标的policy不一样,所以你目标的policy随便更新,采样后的数据可以用很多次也可以参考。

其实最经典的莫过于Sutton老爷子Introduction中的解释:

原文:On-policy methods attempt to evaluate or improve the policy that is used to make decisions, whereas off-policy methods evaluate or improve a policy different from that used to generate the data.

此外莫过于Q-learning和sarsa算法的解释

最终总结一下两者的优缺点

on-policy优点是直接了当,速度快,劣势是不一定找到最优策略。off-policy劣势是曲折,收敛慢,但优势是更为强大和通用。

本文之所以解释On-policy或者off-policy的相关内容,目的在于后文讨论以下几个问题:

  • 如何从采样轨迹(trajectory)中高效学习
  • Off-policy采样效率高,收敛慢,仍然是最重要的解决问题方法

1.1.2 Online和Offline学习的本质

监督学习中通常利用已知(已标记)的数据进行学习,其本质是从数据中总结规律,这和人从学1 1=2基本原理一致,强化学习的过程也是如此,仍然是从数据中学习,只不过强化学习中学习的数据是一系列的轨迹

所以重点来了,这里的数据才是最关键的一部分,这也强化学习中Online和offline学习中的关键, Online一方面是与环境有交互,通过采集数据学习、然后丢弃,而offline则是不用交互,直接通过采集到的轨迹数据学习,这也是off-policy到offline转换的重要原因。

1.2 落地应用的困难?

目前atari, mujoco物理引擎等各类游戏中的模拟数据很轻松拿到,这也就是目前强化学习在游戏领域非常成功的原因之一,也是各种state of the art刷榜的体现,因为游戏数据可以很轻松就100million,总结起来就是

有模拟器,易产生数据,好用!

但强化学习在落地过程中就可能遇到很多问题,比如下图这个大家伙,

总不可能让他产生100 million数据吧(不知道他的额定寿命是多少次),因此产生如下几个问题:

  1. 由于样本收集很困难,或者很危险。所以实时的和环境进行交互是不太可能的,那么可否有一种仅利用之前收集的数据来训练的方法去学习策略呢?
  2. 不管它是on-policy还是off_policy,我只要经验回放池中的交互历史数据,往大一点就是logg数据库中的数据(此处就不能探索exploration),去拟合函数是否可行?
  3. 仅利用轨迹数据学习的策略能否和Online算法的媲美?

所以有这样的方法吗?

答案:有,OfflineRL,此处有矿,赶紧来挖!

2. 离线强化学习

离线强化学习最初英文名为:Batch Reinforcement Learning [3], 后来Sergey Levine等人在其2020年的综述中使用了Offline Reinforcement Learning(Offline RL), 现在普遍使用后者表示。下图是离线强化学习近年来论文的发表情况,间接反应发展状态

2.1 离线强化学习原理

Offline RL 可以被定义为 data-driven 形式的强化学习问题,即在智能体(policy函数?)不和环境交互的情况下,来从获取的轨迹中学习经验知识,达到使目标最大化,其和Online的区别如图所示:

图片来源自:Offline Reinforcement Learning

后来Sergey在论文中归纳如下图所示:

本质上,智能体是通过静态的数据集 <s_{t}^{i},a_{t}^{i},s_{t 1}^{i},r_{t}^{i}>去对进行充分的理解,并构造一个策略pi(a|s)在实际交互中获得最多的累计奖励本文用pi_{beta}表示数据集D中的状态和动作分布,且s,a in D,s sim d^{pi_{beta}}(s),而动作asim pi_{beta}(a|s)是根据行为策略采样而来那么最终的学习目标标成了最大化J(pi)

J(pi)=mathbb{E}_{tau sim p_{pi}(tau)}left[sum_{t=0}^{H} gamma rleft(s_{t}, a_{t}right)right]

2.2 离线强化学习分类及区别

2.2.1 如何判断 Offline RL

图中很明确的从数据可否store以及reused解释了是纯Online还是offline, 以及使用经验回放的NFQ等,其本质还是是否利用trajectory去学习优化模型。

备注:离线强化学习去学习数据可以使专家数据、预训练(Pre-Train)模型产生的数据、随机(random)数据等。

2.2.2 offline RL的分类

2.2.3 Offline RL&模仿学习的区别

模仿学习(Imitation Learning, IL) 是指通过从专家(通常指人类的决策数据 )提供的范例中学习,,每个决策包含状态和动作序列 tau_{i}=,将所有「状态动作对」抽取出来构造新的集合mathcal{D}=left{left(s_{1}, a_{1}right),left(s_{2}, a_{2}right),left(s_{3}, a_{3}right), ldotsright}。之后就可以把状态作为特征,动作作为标记进行离散动作/连续动作的学习而得到最优的策略模型,模型的训练目标是使模型生成的状态-动作轨迹分布和输入的轨迹分布相匹配,最典型的就是自动驾驶的例子(此过程中一般称为行为克隆behavior clone)。

可能有人会问,模仿学习不也是从专家数据中学习一套策略吗?它和offline RL不就是一回事了?其实它们与息息相关,但有几个关键的区别:

  • Offline RL 算法(到目前为止)建立在标准的off-policy深度强化学习算法之上,这些算法倾向于优化某种形式的贝尔曼方程或TD误差。
  • 大多数 IL 问题假设有一个最优的,或者至少是一个高性能的提供数据的演示器,而Offline RL 可能必须处理高度次优(subopt)的数据。
  • 大多数 IL 问题没有奖励函数。Offline RL 有奖励,而且可以事后处理和修改。
  • 一些 IL 问题需要将数据标记为专家与非专家。Offline RL 不做这个假设(可以是专家、已训练好的模型产生的轨迹,随机数据)。

另外一方面在数据组成方面有如下区别:

2.3 离线强化学习很难学习的原因

2.3.1 无法探索(Explore)

强化学习在与环境中交互学习的过程中,最关键的一个问题便是“Exploration vs Exploitation Dilemma”, Exploration是为了收集更多信息(尝试一些不可能等),而Exploitation则根据当前信息做出最佳决策,正如Sliver总结的:

这两者可以说对一个算法的训练精度、速度等各方面有重要影响,而Offline RL算法中需要完全的依赖于静态数据集 ,但是没有办法提高exploration,因为不和环境进行交互,就无法知道探索得到的数据是否有效,是否有高质量的奖励反馈等,所以 Offline RL不可能通过探索发现高奖励的区域。而且,并没有办法解决此问题,这就变成了2.3.2中的经验最小化的问题了

2.3.2 数据质量(拟合与过拟合)

深度学习的成功可以归结为数据集(ImageNet等)的准确强大,offline RL也不例外,思考以下问题:

  • 如果轨迹(数据)全部是专家数据,Offline RL算法会学习到好策略吗?
  • 如果轨迹全是预训练好的模型(比如训练好的PPO模型)产生的,Offline RL算法会学习到好策略吗?
  • 如果轨迹全是没有任何经验,而是随机产生的,Offline RL算法会学习到好策略吗?
  • 如果轨迹是上述三种的混合,具体的比例多少才能训练出通用、高效的offline RL算法?

这个问题其实Fujimoto在2019年的时候就提到了(如图所示),但直到现在仍然对Offline RL算法的训练非常大的影响。

备注:Final buffer: train a DDPG agent for 1 million time steps, adding N (0, 0.5) Gaussian noise to actions for high exploration, and store all experienced transitions.Concurrent:train the off-policy and behavioral DDPG agents, for 1 million time steps. To ensure sufficient exploration, a standard N (0, 0.1) Gaussian noise is added to actions taken by the behavioral policy.

2.3.3 分布偏移(Distribution shift)

2.3.3.1 关于分布偏移

分布偏移(Distribution shift) 在监督学习中一般指的是训练分布与测试分布不同,在离线强化学习中指的是训练策略与行为策略不一致。(Distribution shifts, in which the training distribution differs from the testing distribution, training policy are inconsist:ent with behavioral policy in offline reinforcement learning.),下面我们进行解释

在监督学习中,训练一个模型通常追求经验风险最小化(Empirical Risk Minimization,ERM),即:

theta leftarrow arg min _{theta} E_{mathbf{x} sim p(mathbf{x}), y sim p(y mid mathbf{x})}left[left(f_{theta}(mathbf{x})-yright)^{2}right]

也就是让图中的左子图的平均损失函数最小化,那么这里就存在一个问题,给定一个最优的 , 那么 也是最优的吗?(注意这里:)

  • 如果 , 则是最小的
  • 如果 , 则不是,因为对于普通的

那么问题就变成了:如何在不同的 下能够同样能够达到

同样的情况,在Offline RL中obejctive函数则变成了:

min _{Q} E_{(mathbf{s}, mathbf{a}) sim pi_{beta}(mathbf{s}, mathbf{a})}left[(Q(mathbf{s}, mathbf{a})- left( r(mathbf{s}, mathbf{a}) E_{mathbf{a}^{prime} sim pi_{text {new }}}left[Qleft(mathbf{s}^{prime}, mathbf{a}^{prime}right)right] right )^{2}right]

其中的 是我们从offline data中学习的策略, 而我们希望 , 这样就可以达到学习目的了。

总结起来就是:别走偏了,每一步都尽量让两个分布之间距离最小化的问题,不然累计起来不知道走哪里(有点TRPO的感觉)

2.3.3.2 分布偏移对OfflineRL算法收敛的影响

对2.3.3.1中的定义 , 我们换种表达方式为 ,考虑时间步为 的情况下,在离线强化学习中误差上界和时间步之间是平方关系,直觉上造成这样的原因是因为,学习策略 可能会进入和训练分布差距很远的状态,这将导致 和 差距非常大。那么,当策略在 时刻遇到了分布之外(数据集中没见过)的状态时,策略在之后的 个时刻就有可能不断的犯错,所以累计误差 ,而且每一个时间步,都有可能进入分布外的状态,造成整体误差为 , 这对于算法的收敛来说无异于雪上加霜,关于解决这个问题的BCQ、CQL等算法将来后续博客讲解!(by Sergey)

2.4 Offline RL 发展时间线

下面是一些2012年前的offline reinforcement learning算法,最新的算法将在后面博客中详解。

至此,关于offline RL的简介到这里,下一篇是关于offline RL 中常用(最典型)的数据集D4RL的安装过程以及其中遇到的一些坑,以及如何设计一个高效的Offline RL算法

关于D4RL Benchmarks数据集[Github], [Paper]

1.1 为什么选择 D4RL?

(1) D4RL 收集了大型数据集,包括交互式环境中智能体的记录(即自动驾驶Carla、AntMaze、Mujoco等),且有简单和复杂分类,种类非常丰富,例如:

  • 通过人工演示或硬编码控制器生成的数据。
  • 具有不同策略的异构混合的数据
  • 数据观察智能体在同一环境中完成各种目标。

Environment

(2) D4RL提供了非常简单的API接口,方便于学习者直接去获取数据集完成智能体的训练。

代码语言:javascript复制
import d4rl # Import required to register environments
env = gym.make('maze2d-umaze-v1')
dataset = env.get_dataset()

(3) D4RL定义了标准的衡量指标

normalized score =100%* frac{score- random_score}{export_score-random_score}

(4) D4RL提供了丰富的baseline基准,包括了常见的Offline算法,包括BCQ、BEAR、BRAC等等

Baseline score

1.2 D4RL数据集制作影响因素

D4RL数据集目前来说是离线强化学习涵盖数据集非常丰富的一个数据集,数据质量非常高。其中最主要的是数据的采集综合了6类因素

  • Narrow and biased data distributions
  • Undirected and multitask data
  • Sparse rewards
  • Suboptimal data.
  • Non-representable behavior policies, non-Markovian behavior policies, and partial observ- ability.
  • Realistic domains

二、D4RL安装与使用

2.1 官方安装指导(有坑)

D4RL 的安装相对来说比较容易,但其中也有很多的坑

代码语言:javascript复制
git clone https://github.com/rail-berkeley/d4rl.git
cd d4rl
pip install -e .

另外一种简单的安装方法

代码语言:javascript复制
pip install git https://github.com/rail-berkeley/d4rl@master#egg=d4rl

其中会有很多坑,导致安装失败。

下面我们根据初始化安装文件setup.py分析安装

代码语言:javascript复制
from distutils.core import setup
from platform import platform

from setuptools import find_packages

setup(
    name='d4rl',
    version='1.1',
    install_requires=['gym',
                      'numpy',
                      'mujoco_py',
                      'pybullet',
                      'h5py',
                      'termcolor',  # adept_envs dependency
                      'click',  # adept_envs dependency
                      'dm_control' if 'macOS' in platform() else
                      'dm_control @ git git://github.com/deepmind/dm_control@master#egg=dm_control',
                      'mjrl @ git git://github.com/aravindr93/mjrl@master#egg=mjrl'],
    packages=find_packages(),
    package_data={'d4rl': ['locomotion/assets/*',
                           'hand_manipulation_suite/assets/*',
                           'hand_manipulation_suite/Adroit/*',
                           'hand_manipulation_suite/Adroit/gallery/*',
                           'hand_manipulation_suite/Adroit/resources/*',
                           'hand_manipulation_suite/Adroit/resources/meshes/*',
                           'hand_manipulation_suite/Adroit/resources/textures/*',
                           ]},
    include_package_data=True,
)

2.2 有效安装过程(避坑)

上述过程安装后我们会发现遇到很多问题,下面我就自己的安装过程以及遇到的问题一一列举

安装环境:Ubuntu18.04, anaconda3

第一步:安装mujoco210(针对没有安装mujoco)

代码语言:javascript复制
# 下载地址 https://github.com/deepmind/mujoco/releases/tag/2.1.0
cd ~/Downloads/
wget https://github.com/deepmind/mujoco/releases/download/2.1.0/mujoco210-linux-x86_64.tar.gz
mv mujoco210-linux-x86_64.tar.gz mujoco210
tar -zxvf mujoco210-linux-x86_64.tar.gz
mkdir ~/mujoco
cp -r mujoco210 ~/mujoco
# 添加环境变量
sudo gedit ~/.bashrc
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/.mujoco/mujoco210/bin
export MUJOCO_KEY_PATH=~/.mujoco${MUJOCO_KEY_PATH}
source ~/.bashrc

# 测试
cd ~/.mujoco/mujoco210/bin/
./simulate ../model/humanoid.xml

image-20220317113717084

坑1:can't find /.mujoco/lib/libmujoco.so.2.1.1(可能安装mujoco200的伙伴会遇到)

解决办法:

(1)下载mujoco211安装包,解压

(2)在mujoco210/lib下找到libmujoco.so.2.1.1,并复制在~/.mujoco/bin在~/.bashrc下

(3)添加环境变量并source

代码语言:javascript复制
export MJLIB_PATH=~/.mujoco/lib/libmujoco.so.2.1.1
source ~/.bashrc

第二步:安装mujoco_py

代码语言:javascript复制
# 本步跳过conda环境创建,直接进入虚拟环境(conda create -n d4rl python=3.7)
conda create -n d4rl python=3.7
conda activate d4rl
pip install mujoco_py

python
Python 3.7.11 (default, Jul 27 2021, 14:32:16) 
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import mujoco_py
>>> 
# 备:没有报错表示安装成功

image-20220328171507687

坑2:如果是fatal error: GL/osmesa.h: No such file or directory,那就安装libosmesa6-dev

代码语言:javascript复制
Python 3.7.11 (default, Jul 27 2021, 14:32:16) 
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import mujoco_py
running build_ext
building 'mujoco_py.cymj' extension
gcc -pthread -B /home/jqw/anaconda3/envs/d4rl/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py -I/home/jqw/.mujoco/mujoco210/include -I/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/numpy/core/include -I/home/jqw/anaconda3/envs/d4rl/include/python3.7m -c /home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/cymj.c -o /home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/generated/_pyxbld_2.1.2.14_37_linuxcpuextensionbuilder/temp.linux-x86_64-3.7/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/cymj.o -fopenmp -w
gcc -pthread -B /home/jqw/anaconda3/envs/d4rl/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py -I/home/jqw/.mujoco/mujoco210/include -I/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/numpy/core/include -I/home/jqw/anaconda3/envs/d4rl/include/python3.7m -c /home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/gl/osmesashim.c -o /home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/generated/_pyxbld_2.1.2.14_37_linuxcpuextensionbuilder/temp.linux-x86_64-3.7/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/gl/osmesashim.o -fopenmp -w
/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/gl/osmesashim.c:1:10: fatal error: GL/osmesa.h: No such file or directory
    1 | #include <GL/osmesa.h>
      |          ^~~~~~~~~~~~~
compilation terminated.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/__init__.py", line 2, in <module>
    from mujoco_py.builder import cymj, ignore_mujoco_warnings, functions, MujocoException
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/builder.py", line 504, in <module>
    cymj = load_cython_ext(mujoco_path)
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/builder.py", line 110, in load_cython_ext
    cext_so_path = builder.build()
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/builder.py", line 226, in build
    built_so_file_path = self._build_impl()
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/builder.py", line 278, in _build_impl
    so_file_path = super()._build_impl()
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/builder.py", line 249, in _build_impl
    dist.run_commands()
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/distutils/dist.py", line 966, in run_commands
    self.run_command(cmd)
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/distutils/dist.py", line 985, in run_command
    cmd_obj.run()
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/Cython/Distutils/old_build_ext.py", line 186, in run
    _build_ext.build_ext.run(self)
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/distutils/command/build_ext.py", line 340, in run
    self.build_extensions()
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/mujoco_py/builder.py", line 149, in build_extensions
    build_ext.build_extensions(self)
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/site-packages/Cython/Distutils/old_build_ext.py", line 195, in build_extensions
    _build_ext.build_ext.build_extensions(self)
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/distutils/command/build_ext.py", line 449, in build_extensions
    self._build_extensions_serial()
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/distutils/command/build_ext.py", line 474, in _build_extensions_serial
    self.build_extension(ext)
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/distutils/command/build_ext.py", line 534, in build_extension
    depends=ext.depends)
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/distutils/ccompiler.py", line 574, in compile
    self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
  File "/home/jqw/anaconda3/envs/d4rl/lib/python3.7/distutils/unixccompiler.py", line 120, in _compile
    raise CompileError(msg)
distutils.errors.CompileError: command 'gcc' failed with exit status 1

解决办法:

代码语言:javascript复制
sudo apt install libosmesa6-dev
# 补充命令:sudo apt-get install libgl1-mesa-glx libosmesa6

坑3:如果是fatal error: GL/glew.h: No such file or directory,那么就安装Glew库

解决办法

代码语言:javascript复制
sudo apt-get install libglew-dev glew-utils

坑4:如果是FileNotFoundError: [Errno 2] No such file or directory: 'patchelf': 'patchelf', 那就安装patchelf

解决办法:

代码语言:javascript复制
sudo apt-get -y install patchelf

安装成功是这样的效果

image-20220328174928475

第三步:安装dm_control

代码语言:javascript复制
pip install dm_control

第四步:安装d4rl

克隆D4RL仓库

代码语言:javascript复制
git clone https://github.com/rail-berkeley/d4rl.git

找到到d4rl目录下的setup.py文件,注释mujoco_py, dm_control

代码语言:javascript复制
install_requires=['gym',
                      'numpy',
                      # 'mujoco_py',
                      'pybullet',
                      'h5py',
                      'termcolor',  # adept_envs dependency
                      'click',  # adept_envs dependency
                      # 'dm_control' if 'macOS' in platform() else
                      # 'dm_control @ git git://github.com/deepmind/dm_control@master#egg=dm_control',
                      'mjrl @ git git://github.com/aravindr93/mjrl@master#egg=mjrl'],

然后直接安装并测试

代码语言:javascript复制
# installing
pip install -e .

# 测试,创建test_d4rlpy.py并添加如下内容 vim test_d4rl.py

import gym
import d4rl # Import required to register environments

# Create the environment
env = gym.make('maze2d-umaze-v1')

# d4rl abides by the OpenAI gym interface
env.reset()
env.step(env.action_space.sample())

# Each task is associated with a dataset
# dataset contains observations, actions, rewards, terminals, and infos
dataset = env.get_dataset()
print(dataset['observations']) # An N x dim_observation Numpy array of observations

# Alternatively, use d4rl.qlearning_dataset which
# also adds next_observations.
dataset = d4rl.qlearning_dataset(env)


python test_d4rlpy.py

坑5:如果遇到:下面问题,那就单独安装mjrl

代码语言:javascript复制
ERROR: Could not find a version that satisfies the requirement mjrl (unavailable) (from d4rl) (from versions: none)
ERROR: No matching distribution found for mjrl (unavailable)

安装命令

代码语言:javascript复制
pip install git https://github.com/rail-berkeley/d4rl@master#egg=d4rl

最后的D4RL安装结果结果

image-20220317180305194

最后贴出我的~/.bashrc文件,欢迎参考

代码语言:javascript复制
# cuda、anaconda等环境变量可以设置在本部分以前
# 环境变量次序也很重要

# mujoco(这里我安装了两部分)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/.mujoco/mujoco210/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/.mujoco/mujoco211/bin

export MUJOCO_KEY_PATH=~/.mujoco${MUJOCO_KEY_PATH}
export MJLIB_PATH=~/.mujoco/lib/libmujoco.so.2.1.1

# nvidia
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/nvidia

export LD_PRELOAD=~/anaconda3/envs/d3rlpy/lib/python3.7/site-packages/d3rlpy/dataset.cpython-37m-x86_64-linux-gnu.so
# export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libGLEW.so:/usr/lib/nvidia-465/libGL.so

export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libGLEW.so

更多的坑大家可以参阅issue: https://github.com/rail-berkeley/d4rl/issues

坑6:有的伙伴可能会用pycharm去运行mujoco会出现一个问题就是:有nvidia的环境变量没有mujoco的,有mujoco的没有nvidia的

代码语言:javascript复制
Exception: 
Missing path to your environment variable. 
Current values LD_LIBRARY_PATH=
Please add following line to .bashrc:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/jqw/.mujoco/mujoco210/bin

# 或者这样的
Exception: 
Missing path to your environment variable. 
Current values LD_LIBRARY_PATH=LD_LIBRARY_PATH:/usr/lib/nvidia
Please add following line to .bashrc:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/jqw/.mujoco/mujoco210/bin

解决办法

直接在pycharm运行配置中修改环境变量:python文件上右键后进入 Modify Run Configuration

image-20220328180705232

重点就是两个变量之间用 冒号隔开":",不是分号";", 然后就ok了

代码语言:javascript复制
PYTHONUNBUFFERED=1;LD_LIBRARY_PATH=LD_LIBRARY_PATH:/usr/lib/nvidia:$LD_LIBRARY_PATH:/home/jqw/.mujoco/mujoco210/bin

TD3 BC算法详解

论文信息:Scott Fujimoto, Shixiang Shane Gu: “A Minimalist Approach to Offline Reinforcement Learning”, 2021; arXiv:2106.06860.

本文是Google Brain团队和McGill大学合作,由 TD3、BCQ的作者 Fujimoto 提出并发表在NeurIPS2020 顶会上的文章,本文方法最大的优点是:方法简单、无任何复杂数学公式、可实现性强(开源)、对比实验非常充分(满分推荐),正如标题一样(A minimalist approach)。

摘要:相比于几篇博客讲过的BCQ(通过扰动网络生成动作,不断将学习策略和行为策略拉进)、BEAR(通过支撑集匹配避免分布匹配的问题)、BRAC(通过VP和PR两个方法正则化)以及REM(通过随机集成混合方法对多个值函数求取凸优化最优的鲁棒性)方法。本文作者提出的TD3 BC方法,结构简单,仅在值函数上添加一个行为克隆(BC)的正则项,并对state进行normalizing,简单的对TD3修改了几行代码就可以与前几种方法相媲美,结果表明:TD3 BC效果好,训练时间也比其他少很多。

1. Offline RL的一些挑战。

  • 实现和Tune的复杂性(Implementation and Tuning Complexities), 在强化学习中,算法的实现、论文的复现都是一个非常难的问题,很多算法并没法去复现,即使相同的seed有时候未必也能达到效果。同样在Offline中仍然存在,此外在Offline中还要解决分布偏移、OODd等之外的一些问题。
  • **额外算力需求(Extra Computation Requirement)**,由于过于复杂的数学优化、过多的超参数等算法的执行带来了很长的训练时间,导致不得不增加计算资源来学习算法使得其收敛。
  • **训练策略的不稳定性(Instability of Trained Policies)**,强化学习领域的不稳定性众所周知,所以Offline RL如何才能与Supervised leanring一样很稳定是一个重要的研究问题。
  • **Offline RL改进问题(algorithmic/Coding/Optimization)**,包括了代码层次的优化改进和理论结构方面的改进等。

其实上述的这些问题并不是去解决offline RL中的一些诸如分布偏移、OOD、过估计以及等等这些问题,而是去解决如何简单、快速、高效的实现算法的实现与高效运行问题,因此作者面对这些问题,发出疑问并给出方法:

2. TD3 BC原理

2.1 TD3 BC相比于其他的优势

下图是TD3 BC算法相对于CQL、Fish-BRC算法的复杂性对比,从表中我们可以看到CQL和Fish-BRC在算法(algorithmic)上有了很多的变种,使用生成网络,近似 等,而TD3 BC仅仅添加了一个BC term和Normalized state,足够的简单。

2.2 理论部分

对于经典的DDPG、TD3等算法来讲, 策略梯度的计算根据David sliver提出的如下定义,即求解状态-动作值函数的期望值。

pi=operatorname{argmax} mathbb{E}_{(s, a) sim mathcal{D}}[Q(s, pi(s))]

本文中,作者为了尽可能的让两个动作接近添加了一个正则项 以及 ,

pi=underset{pi}{operatorname{argmax}} mathbb{E}_{s sim mathcal{D}}[Q(s, pi(s))] rightarrow pi=underset{pi}{operatorname{argmax}} mathbb{E}_{(s, a) sim mathcal{D}}left[lambda Q(s, pi(s))-(pi(s)-a)^{2}right]

个人看法: 有点像BCQ中的让学习策略和行为策略之间的距离减少那种意思,只不过添加到正则项里面.

omega leftarrow operatorname{argmin}_{omega} sum(a-tilde{a})^{2} D_{mathrm{KL}}(mathcal{N}(mu, sigma) | mathcal{N}(0,1)) \ phi leftarrow operatorname{argmax}_{phi} sum Q_{theta_{1}}left(s, a xi_{phi}(s, a, Phi)right), a sim G_{omega}(s)

另外一个技术点就是从代码执行层面的优化,即Normalize State,具体的Normalize过程如公式所示:

s_{i}=frac{s_{i}-mu_{i}}{sigma_{i} epsilon}

其中的 表示一个normalization常量,作者在文中使用了 , 和 表示期望和标准差(standard deviation)。

实验效果(关于纵坐标Percent difference后文有说明,本部分只看效果)

最后一个技术点就是关于 的求解,作者给出了计算公式,并在后文中说取值为 的时候效果最好, 实验部分有作者做的ablation实验证明。

lambda=frac{alpha}{frac{1}{N} sum_{left(s_{i}, a_{i}right)}left|Qleft(s_{i}, a_{i}right)right|}

最后贴出作者在TD3代码上的改动部分==》TD3 BC算法实现

2.3 经典的Rebuttal场面

此外,我们看一下作者如何rebuttle这些OpenReview提出的审稿意见[1],[2]

其实这部分蛮有意思的,我们发现大多数普通人的工作还是集中在对算法的小部分优化(数学大佬和代码大神略过),这里作者教你手把手给审稿人回复(建议收藏,热别是第2条)

审稿人:(1)首先,该方法的新颖性似乎有点有限。作者似乎直接使 RL BC 适应离线设置,只是他们添加了状态归一化,这也不是新的。作者也没有从理论上证明这种方法的合理性。例如,作者应该证明该方法可以保证安全的策略改进,并且享有可比或更好的策略改进保证 w.r.t.先前的方法。如果没有理论依据,并且考虑到该方法的当前形式,我认为该方法有点增量。(2)此外,实证评估并不彻底。作者仅在 D4RL 中的简单 mujoco 环境中评估了该方法。目前尚不清楚该方法是否可以很好地执行更多无向多任务数据集,例如蚂蚁迷宫和厨房,以及更复杂的操作任务,例如 D4RL 中的 adroit。似乎该方法在随机数据集上表现不佳。这是一个主要限制吗?我还认为作者应该将状态归一化添加到所有基线以确保公平比较,因为状态归一化不是 RL 中的新技术。(3)最后,我认为比较不完整。作者还应该将该方法与最近的无模型离线 RL 方法(如 [1])和基于模型的方法(如 [2,3])进行比较,后者在随机和中等重放数据集上获得了更好的性能。总的来说,鉴于上述评论,我会投票支持弱拒绝。

下面我们看作者的神奇巧妙回复

作者回复:(1)关于新颖性:我们完全不同意我们的算法在新颖性方面是递增的(我们在相关工作中强调了许多类似的算法)。然而,我们的主要主张/贡献与其说这是最好的离线 RL 算法,或者说它特别新颖,不如说是令人惊讶的观察,即使用非常简单的技术可以匹配/优于当前算法。希望 TD3 BC 可以用作易于实现的基线或其他添加(例如 S4RL)的起点,同时消除更复杂方法所需的许多不必要的复杂性、超参数调整或计算成本. (2)关于经验评估:据我们所知,我们最强的基线 Fisher-BRC 被认为是无模型算法的 SOTA,最近在 ICML 上发表。(3)由于 D4RL 结果的标准化,我们可以直接与建议的基线进行比较(我们会将这些结果包含在最终草案中)。我们在下面报告这些,但我们想说明两点:(4)MOReL 和 MOPO 来自不同的方法系列(基于模型),并且都使用特定于环境的超参数。S4RL 与我们的方法相切,只需将 CQL 替换为 TD3 BC,就可以很容易地将其添加到我们的方法中。我们的方法可以说更适合基础算法的这些类型的添加,因为超参数更少,这意味着我们不必担心变化之间的交互作用。最终,我们没有发现添加状态归一化可以为基线提供相同水平的好处,这可能是因为这些方法需要超参数调整来补偿额外的修改。

挺有意思的,学习收藏吧!

3. 实验及过程分析

3.1 实验超参数

这部分是作者实验的一些基础,挺良心的,具体到了每一个实验环境的版本号

这部分特意说明一下作者的良心部分:代码版本都放出来了

3.2 衡量指标:百分比差异(Percent Difference)

这部分公式是作者实验的参考基准计算方式,其中在博客也提出了关于差距百分比的疑问,特意查了了一下计算过程[3](备注,有的地方可能用了绝对值):

3.3 实验验证与结果简要分析

说明:关于D4RL数据集的组成、安装和解释请参考博文 离线强化学习(Offline RL)系列2: (环境篇)D4RL数据集简介、安装及错误解决

本实验参数 HC = HalfCheetah, Hop = Hopper, W = Walker, r = random, m = medium, mr = medium-replay, me = medium-expert, e = expert. While online algorithms (TD3) typically have small episode variances per trained policy (as they should at convergence),

3.3.1 D4RL验证讨论

3.3.2 运行训练时间讨论

可以从实验结果中很直白的看到,CQL、FishBRC与TD3 BC( )的运行时间, 其实这与算法的复杂性紧密相关,对于TD3来说只需要去根据超参数学习网络即可,但对于CQL等算法,需要学习一堆的参数。

3.3.3 消融(ablation)实验(如何确定 ?)

这部分其实对比了vanillaBC方法和区别,同时就参数 做了对比得出了最好的 。

2. Offline RL误差的来源

2.1 分布偏移(distribution shift)

分布偏移最主要的原因是learned policybehavior policy之间的偏移(从图中我们可以清晰的看到两者之间的区别),这也是offlineRL相比于Online RL在不能交互学习的情况下造成的。

2.2 OOD(out-of-distribution) action问题

OOD问题在Offline RL中非常常见,简单的可以理解为状态-动作对可能不在我们的offline Dataset中,对应的分布也一样,即学习分布远在(far outside)训练(training distribution)分布之外。

那么训练和优化过程如下:

结合上图,其实真正解决这个问题,第一直观的想法就是增大数据集的数量,让数据集尽可能包含训练分布,这样学习分布基本可能会在范围内,然而这个方法并不奏效:

作者在实验中使用了大小不一样的数量实验,结果表明即使增大train samples, 算法的性能并没有得到有效提升,同时也会引发下一个累计误差问题:

此外Q值误差居高不下,是什么原因造成的?

2.3 贝尔曼误差(Bellman error)

这就是本文的核心问题了,深度强化学习中动态规规划(MC,TD)最核心的就是Q函数,我们知道在Q-learning中学习的时候,目标函数Q的计算通常是利用自举(bootstrapping)的方式,从训练集分布中去最大化函数估计,但由于OOD之外的数据,导致这个过程的error不断累积,最终导致严重偏离学习策略。

我们在Online RL中知道,最优 函数 遵循最优贝尔曼方程,如下所示:

Q^{*}=mathcal{T}^{*} Q^{*} quad ; quadleft(mathcal{T}^{*} hat{Q}right)(s, a):=R(s, a) gamma mathbb{E}_{Tleft(s^{prime} mid s, aright)}left[max _{a^{prime}} hat{Q}left(s^{prime}, a^{prime}right)right]

然后,强化学习对应于最小化该等式左侧和右侧之间的平方差,也称为均方贝尔曼误差 (MSBE),得到:

Q:=arg min _{hat{Q}} mathbb{E}_{s sim mathcal{D}, a sim beta(a mid s)}left[left(hat{Q}(s, a)-left(mathcal{T}^{*} hat{Q}right)(s, a)right)^{2}right]

MSBE 在由行为策略 生成的数据集 中的转换样本上最小化。尽管最小化 MSBE 对应于有监督的回归问题,但该回归的目标本身是从当前 函数估计中得出的。于是对于迭代 次的Q-learning来说,总误差(error) 可以定义为:

zeta_{k}(s, a)=left|Q_{k}(s, a)-Q^{*}(s, a)right|

其中当前的贝尔曼误差(Bellman error)为:

delta_{k}(s, a)=left|Q_{k}(s, a)-mathcal{T} Q_{k-1}(s, a)right|

那么我们就可以得出以下结论:

zeta_{k}(s, a) leq delta_{k}(s, a) gamma max _{a^{prime}} mathbb{E}_{s^{prime}}left[zeta_{k-1}left(s^{prime}, a^{prime}right)right]

所以说,当一个状态-动作分布处于OOD之外时,我们其实是希望 很高,因为我们的优化目标是不断将处于分布之外的策略分布与训练分布距离最小化。为了缓解这个问题,作者提出了一个解决方法就是让学习策略输出的动作处于训练分布的支撑集(Support-set)中

所谓的Support-set, 其实就是"学习策略 只有在行为策略 的密度大于阈值 ,而不是对密度 和 的值的接近约束。" 原话:

下面我们结合例子解释一下 分布匹配(Distribution-matching支撑集匹配(Support-set matching) 的区别,以及原理。

3. 从一个例子原因分析开始

考虑一维的Lineworld Environment问题,我们从 点出发到达 点,动作集分为“向左”和“向右”两种,对应的奖励在上图中有标记。

那么,行为策略在 和 之间的状态下执行次优动作,可能性为 0.9,但是动作 和 的状态都在分布内(in-distribution)。

个人理解原因

3.1 Distribution-matching

如上图,分布匹配约束(distribution matching constraint)的学习策略可以是任意次优的,事实上,通过推出该策略达到目标 G 的概率非常小,并且随着环境的建立而趋于 0 较大。

3.2 Support-constraint

然而,在support-constraint中,作者表明支持约束可以恢复概率为 1 的最优策略(其实原因很简单,就是阈值 的原因, 只要动作在训练行为策略分布的支持集内就可以)。

那么为什么Distribution-matching在这里会失败?

  • 如果惩罚被严格执行,那么智能体将被迫在 和 之间的状态中主要执行错误的动作 ,导致次优行为。
  • 如果惩罚没有严格执行,为了实现比行为策略更好的策略,智能体将使用 OOD之外的action 在 左侧的状态执行backups,这些backups 最终会影响 状态S下的Q值。这种现象将导致不正确的 Q 函数,从而导致错误的策略——可能是从 S 开始向左移动而不是向 G 移动的策略,因为 OOD 动作backups与高估偏差相结合Q-learning 可能会使状态 S 的动作 看起来更可取。如下图所示,一些状态需要强惩罚/约束(以防止 OOD backups),而其他状态需要弱惩罚/约束(以实现最优性)才能使分布匹配起作用,但是,这无法通过传统的分布匹配来实现方法。

通过上述分析,我们得出一个结论:我们希望的不是学习策略和行为策略越像越好,而是学习策略能够在行为策略的支撑集的范围内去进行优化, 如果学习策略和行为策略无限接近那不就是Behavior clone了,但offline无法无限的去逼近online,所以问题仍然存在。

下图就是关于Distribution-matching 和support constraint选择动作的区别

从图中我们可以看到:以红色的行为策略 为基准,在distribution-matching中则仅有紫色的学习策略相符,但在support-matching中黄色的都是可以匹配的learned policy, 所以更通用。

那么support-set matching更通用,具体是怎么matching的呢?下文我们从论文的理论部分开始分析。

4. 理论设计及分析(核心:建议阅读)

4.1 Support-set Matching(支撑集匹配方法)

4.1.1 支撑集匹配原理

第一步:解决策略集定义及收敛,定义Distribution-constraint operators概念,如下所示:

这里面最关键的有以下几个地方:

  • 定义了一个策略集 ,且动作空间 ,而不是定义策略
  • 根据原始的MDP问题重新定义了一个新的MDP" 问题,原理和bellman operator一样,同样利用了不动点去证明收敛性。

为了分析在近似误差下执行backup的次优(suboptimality) 问题,作者提出两个方面:

  • 次优偏置(suboptimality bias), 也就是最优的学习策略如果在行为策略支撑集之外的话,仍然能够找到次优策略。
  • 次优常数(suboptimality constant),分布偏移、OOD之外的次优问题,次优常数相当于做了一个限定(which measures how far is from ), 【 越小,policy set 距离optimal policy 的距离越小。】

这里定义了一个Concentrability【 越小,就说明policy set 中的policy 与 behavior policy 越相似】

第二步:最后作者给出了一个边界(bound)

证明过程如下:

这里的[Error Bounds for Approximate Value Iteration] 中解释了

Pi_{epsilon}:={pi mid pi(a mid s)=0 text { whenever } beta(a mid s) leq epsilon}

We choose policies only lying in high support regions of the behaviour policy.Allows for a tradeoff between: Keeping close to the data (minimizing amount of propagated error) Having freedom to find the optimal policy

这里作者不是对所有策略执行最大化,而是对集合 Pi_eps 执行受限最大值,为了实际执行此操作,使用执行支撑匹配的约束。

其中作者原话是:

We change the policy improvement step, where instead of performing a maximization over all policies, we perform the restricted max over the set and in order to do this practically, we use a constrained formulation, where we use a constraint that performs support matching. We constrain the maximum mean discrepancy distance between the dataset and the actor to a maximal limit, using samples.

4.1.2 为什么要从 选取动作?

通过以上的方法,问题最终化解为一个求解最优问题:

4.2 Maximum Mean Discrepancy (MMD)

4.2.1 MMD原理

MMD [A Kernel Two-Sample Test] 方法是一种统计测试以确定两个样本是否来自不同的分布,检验统计量是再现 kernel Hilbertspace (RKHS) 的单位球中函数的最大期望差异。

4.2.2 MMD代码求解

代码语言:javascript复制
def gaussian_kernel(x, y, sigma=0.1):
  return exp(-(x - y).pow(2).sum() / (2 * sigma.pow(2)))

def compute_mmd(x, y):
  k_x_x = gaussian_kernel(x, x)
  k_x_y = gaussian_kernel(x, y)
  k_y_y = gaussian_kernel(y, y)
  return sqrt(k_x_x.mean()   k_y_y.mean() - 2*k_x_y.mean())

4.2.3 与KL divergence的区别

4.3 双梯度下降(Dual Gradient Descent)(可跳过)

4.3.1 DGD原理及图解[Dual Gradient Descent]

双梯度下降是一种在约束条件下优化目标的流行方法。在强化学习中,它可以帮助我们做出更好的决策。

5. BEAR算法执行过程

5.1 BEAR原版

5.2 BEAR修补版

6. 部分结果分析

7. Pytorch代码实现部分浅析

本代码由原作者开源 [Github]

7.1 Installing & running

代码语言:javascript复制
python main.py --buffer_name=buffer_walker_300_curr_action.pkl --eval_freq=1000 --algo_name=BEAR
--env_name=Walker2d-v2 --log_dir=data_walker_BEAR/ --lagrange_thresh=10.0 
--distance_type=MMD --mode=auto --num_samples_match=5 --lamda=0.0 --version=0 
--mmd_sigma=20.0 --kernel_type=gaussian --use_ensemble_variance="False"

本文来源自:

https://www.zhihu.com/column/c_1487193754071617536

0 人点赞