jetson-reinforcement:基于PyTorch的机器人深度强化学习实现,支持虚拟仿真到现实迁移

Deep reinforcement learning GPU libraries for NVIDIA Jetson TX1/TX2 with PyTorch, OpenAI Gym, and Gazebo robotics simulator.

分支5Tags2
文件最后提交记录最后更新时间
8 年前
8 年前
7 年前
7 年前
9 年前
8 年前
8 年前
8 年前
8 年前
8 年前
8 年前
8 年前
7 年前
8 年前
6 年前

深度强化学习在机器人领域的应用

注意:此仓库支持 PyTorch v0.3 和 JetPack 3.2。想要获取最新示例,请参考:

本教程中,我们将创建人工智能代理,它们通过与环境交互、积累经验并利用深度强化学习(深度RL)系统获得奖励来学习。使用端到端神经网络,将原始像素直接转化为行动,经过RL训练的代理能够展现出直觉性行为,并执行复杂任务。

我们的最终目标是,从3D虚拟机器人仿真中训练出强化学习代理,并将其转移到真实世界的机器人上。强化学习者基于环境状态(如摄像头输入)和提供给代理关于其性能反馈的奖励选择最佳行动。在给定策略或任务(如获取奖励)的情况下,强化学习可以学会在其环境中最优地表现。

在许多情况下,状态空间极其复杂和多维,以至于越来越多地使用神经网络预测最佳行动,这就是深度强化学习和GPU加速发挥作用之处。通过深度强化学习,代理通常使用卷积神经网络(CNNs)处理2D图像,处理比低维度RL复杂的输入数量级,并具备“从视觉学习”的能力,即实现“像素到行动”。

深度强化学习架构图

此存储库包括PyTorch中的离散Deep Q-Learning(DQN)和连续A3C算法,以及示例和用于集成Linux应用程序、机器人技术、仿真和现场部署的C++互操作性库API。

目录

注意:可观看我们关于此主题的**网络研讨会**,该研讨会紧随此教程之后。

从源代码构建

在终端运行以下命令以从源码编译:

$ sudo apt-get install cmake
$ git clone http://github.com/dusty-nv/jetson-reinforcement
$ cd jetson-reinforcement
$ git submodule update --init
$ mkdir build
$ cd build
$ cmake ..
$ make

cmake步骤期间,PyTorch会被编译并安装,这可能需要一段时间(Jetson上大约30分钟到1小时)。我们目前使用的稳定版PyTorch版本为0.3.0。构建脚本会下载包并在安装过程中请求您的sudo密码。

验证PyTorch

在继续之前,为了确保PyTorch正确安装并如果您还不熟悉它,我们提供了一个名为**intro-pytorch.ipynb**的Jupyter IPython笔记本,其中包含了一些简单的PyTorch示例,这些示例验证了安装,并测试了PyTorch中的CUDA/cuDNN支持。

要本地启动这个笔记本,请运行以下命令:

$ cd jetson-reinforcement/build/aarch64/bin   # 或cd x86_64/bin 在PC上
$ jupyter notebook
# 点击:  intro-pytorch.ipynb

或者,如果你想跳过笔记本,直接运行PyTorch验证命令,你可以通过启动一个交互式的Python外壳并运行下面的代码来完成:

>>> import torch
>>> print(torch.__version__)
>>> print('CUDA可用: ' + str(torch.cuda.is_available()))
>>> a = torch.cuda.FloatTensor(2).zero_()
>>> print('张量a = ' + str(a))
>>> b = torch.randn(2).cuda()
>>> print('张量b = ' + str(b))
>>> c = a + b
>>> print('张量c = ' + str(c))

如果PyTorch在你的系统上正确安装,输出应如下:

>>> import torch
>>> print(torch.__version__)
0.3.0b0+af3964a
>>> print('CUDA available: ' + str(torch.cuda.is_available()))
CUDA available: True
>>> a = torch.cuda.FloatTensor(2).zero_()
>>> print('Tensor a = ' + str(a))
Tensor a = 
 0
 0
[torch.cuda.FloatTensor of size 2 (GPU 0)]

>>> b = torch.randn(2).cuda()
>>> print('Tensor b = ' + str(b))
Tensor b = 
 0.2190
-0.3212
[torch.cuda.FloatTensor of size 2 (GPU 0)]

>>> c = a + b
>>> print('Tensor c = ' + str(c))
Tensor c = 
 0.2190
-0.3212
[torch.cuda.FloatTensor of size 2 (GPU 0)]

现在,我们已经验证PyTorch正在加载,能够检测到GPU加速,能够在GPU上分配张量,并能使用CUDA执行基本的张量运算。

DQN + OpenAI Gym

为了首先测试并确认深度强化学习算法确实在学习,我们将在OpenAI Gym环境中运行它们(以2D形式)。作为对DQN算法的介绍,仓库中还包括了一个第二个CUDA支持的IPython笔记本**intro-DQN.ipynb**。这个笔记本在从Gym的CartPole环境捕捉到的视频上应用DQN,因此它是从GPU上的“视觉”学习,而不同于来自游戏的传统RL那样低维度的参数。

虽然CartPole是一个玩具模型,但从简单的例子开始至关重要,以便及早消除问题,在过渡到更复杂的3D场景之前,因为这些问题在后续的调试中会更加困难。并且,由于DQN从raw 2D像素数组学习,所以仍然被认为是深度强化学习。建议跟随这个笔记本来熟悉DQN算法,这样当我们稍后在更复杂的环境中从C++使用它时就有准备了。

Cartpole

要从本地机器上启动这个笔记本,运行以下命令:

$ cd jetson-reinforcement/build/aarch64/bin   # 或在PC上cd x86_64/bin
$ jupyter notebook
# 点击:  intro-DQN.ipynb

在笔记本内,DQN设置为只运行50个回合。当你看到DQN开始收敛,CartPole保持竖立的时间变得更长时,退出笔记本并从终端运行独立的**gym-DQN.py**脚本以提高性能:

$ python gym-DQN.py

(假设当前终端目录仍然是上面的jetson-reinforcement/build/<arch>/bin

三个窗口应该会出现,显示Cartpole游戏、性能图表,且DQN代理应该开始学习。DQN代理让杆子在移动的小车上保持平衡的时间越长,得到的奖励越多。在Gym中,达到200分表示情景已被掌握。短暂训练后,代理应该达到这一成就,程序将会退出。

月球着陆器

使用类似的脚本,你可以通过 --env 参数在不同的 Gym 环境中进行实验:

python gym-RL.py --env=LunarLander-v2 --render

LunarLander-v2 环境非常有趣,它的任务类似于无人机自动降落,因此与机器人技术紧密相关。最初,着陆器会猛烈坠落,但大约在第50期左右,你会看到它开始尝试保持在标志之间,而在几百期后,应该能够以控制下降的方式着陆。在终端中,你应该能看到奖励逐渐变为正数,并随着时间增加,朝着200分靠近。

LunarLander 示例图

 Episode 010   奖励:-508.10   最近长度:79   平均长度:18.20
 Episode 020   奖励:-301.04   最近长度:88   平均长度:25.02
 Episode 030   奖励:-208.76   最近长度:102   平均长度:31.96
 ...
 Episode 160   奖励:+11.95   最近长度:174   平均长度:153.23
 Episode 170   奖励:+131.50   最近长度:252   平均长度:155.50
 Episode 200   奖励:+111.07   最近长度:505   平均长度:162.06

接下来,我们将探讨如何通过我们的C++包装库将这些独立的Python示例整合到机器人代码中。

深入了解C++ API

为了将这些深度强化学习者从单一的Python示例转化为可以集成到机器人和仿真器中的库形式,我们提供了一个C++包装库和API到Python代码。底层,该库利用了Python的低级CFFI(Foreign Function Interface)来在应用和PyTorch之间传递张量内存,而无需额外复制(零拷贝)。

图书馆设计成模块化的,可扩展支持新的学习算法类型。下面是【rlAgent】接口的伪代码示例,所有RL实现都继承自这个接口:

/**
 * 深度强化学习代理的基本类
 */
class rlAgent
{
public:
    /**
     * 创建一个新的训练代理实例。
     */
    static rlAgent* Create(uint32_t width, uint32_t height, 
                            uint32_t channels, uint32_t numActions);

    /**
     * 析构函数
     */
    virtual ~rlAgent();

    /**
     * 根据输入状态预测下一个动作。
     */
    virtual bool NextAction(Tensor* state, int* action) = 0;

    /**
     * 发出下一个奖励并进行训练迭代。
     */
    virtual bool NextReward(float reward, bool end_episode) = 0;
};

存储库包含了不同【agent】的实现,包括我们将用于随后模拟场景的**dqnAgent**。用户向NextAction()函数提供他们的传感器数据或环境状态,该函数调用Python脚本并返回预测的动作,然后用户将其应用于自己的机器人或仿真环境中。接下来,在NextReward()函数中发布奖励,这为学习者提供了来自环境的反馈,并启动了使代理随时间学习的下一次训练迭代。

测试C++ API

为了确保从C++出发,强化学习者仍能正常工作,提供了一些简单例子,如使用API的**catch** 和 fruit 示例。类似概念于乒乓球,【catch** 要求一个球从环境顶部落下,代理必须在球触及屏幕底部之前通过左右移动挡板接住它。

Catch 游戏

不同于以往的单体Python脚本,【catch** 示例是一个简单的C/C++程序,链接至上述概述的强化学习库。要测试文本版的【catch** 示例,从终端运行以下可执行文件。大约100期之后,代理应开始几乎每次都能赢得游戏:

./catch 
[deepRL] 输入宽度:64
[deepRL] 输入高度:64
...
[deepRL] 创建DQN模型实例
[deepRL] DQN模型实例创建完成
[deepRL] DQN脚本初始化完成
[cuda] 分配映射内存16384字节
[deepRL] 开始游戏
WON! 第1期
001胜001局 (1.0000)
WON! 第5期
004胜005局 (0.8000)
...
WON! 第112期
080胜112局 (1.0000)

在内部,【catch** 使用了我们C++库中的【dqnAgent** API来实现学习功能。对于【catch**,有几个可选命令行参数可以调整环境尺寸和像素数组输入大小,以增加复杂性并观察这对收敛速度和训练时间的影响。

水果游戏

接下来,我们提供了一个名为fruitsamples/fruit/fruit.cpp)的C++二维图形示例,其中代理人会在随机位置出现,并必须找到“水果”对象以获得奖励并在边界外或超时前赢得关卡。代理有四个可能的动作选择:上、下、左、右移动屏幕以导航到目标物体。

请注意,此C++示例主要在GPU上运行,环境的初步二维光栅化和深度Q网络(DQN)以及OpenGL显示可视化都在CUDA中实现。“从视觉学习”——利用深度强化学习将原始像素数组转换为行动。

作为一个更复杂导航和运动规划任务的类比,简单的fruitsamples/fruit/fruit.cpp)示例旨在证明dqnAgent(c/dqnAgent.h)有能力从任意起始位置视觉识别并导航到感兴趣的对象。在后续的仓库中,我们将在此基础上构建针对三维机器人模拟的路径规划能力。

运行示例

要启动fruitsamples/fruit/fruit.cpp),请在终端中执行以下可执行文件:

$ ./fruit

默认的48x48环境中,大约在100个关卡后,它应该达到约95%的准确度:

action = DOWN   reward = +0.0628     wins = 052 of 094 (0.55)   16 of last 20  (0.80)  (max=0.80)
action = LEFT   reward = +0.0453     wins = 052 of 094 (0.55)   16 of last 20  (0.80)  (max=0.80)
action = LEFT   reward = +0.0271     wins = 052 of 094 (0.55)   17 of last 20  (0.85)  (max=0.85)
action = LEFT   reward = +0.0084     wins = 052 of 094 (0.55)   17 of last 20  (0.85)  (max=0.85)
action = UP     reward = +0.1208     wins = 052 of 094 (0.55)   17 of last 20  (0.85)  (max=0.85)
action = LEFT   reward = +0.1154     wins = 052 of 094 (0.55)   17 of last 20  (0.85)  (max=0.85)
action = UP     reward = +1.0000 EOE wins = 053 of 095 (0.56)   17 of last 20  (0.85)  (max=0.85)
action = DOWN   reward = +0.1441     wins = 053 of 095 (0.56)   18 of last 20  (0.90)  (max=0.90)
action = DOWN   reward = +0.1424     wins = 053 of 095 (0.56)   18 of last 20  (0.90)  (max=0.90)
action = DOWN   reward = +0.1406     wins = 053 of 095 (0.56)   18 of last 20  (0.90)  (max=0.90)
action = DOWN   reward = +0.1386     wins = 053 of 095 (0.56)   18 of last 20  (0.90)  (max=0.90)
action = DOWN   reward = +0.1365     wins = 054 of 096 (0.57)   19 of last 20  (0.95)  (max=0.95)
action = DOWN   reward = +0.1342     wins = 054 of 096 (0.57)   19 of last 20  (0.95)  (max=0.95)
action = RIGHT  reward = +0.0134     wins = 054 of 096 (0.57)   19 of last 20  (0.95)  (max=0.95)

可选参数

catchsamples/catch/catch.cpp)示例类似,fruitsamples/fruit/fruit.cpp)有一些可选的命令行参数供您使用:

$ ./fruit --width=64 --height=64 --episode_max_frames=100

当增加环境和像素数组输入的尺寸时,应相应地增加episode_max_frames,因为代理在较大环境中穿越整个屏幕需要更多的时间,以免在关卡超时时未完成任务。

三维模拟

至此,仓库中的环境都是二维的,主要是为了确认深度强化学习算法按预期工作。为了使代理能够操作三维世界,我们将使用仿生眼机器人仿真器来模拟包括机械臂和漫游者在内的不同自主机器,然后可以转移到现实世界的机器人。

机械臂

我们的第一个仿生眼环境训练一个机械臂无需显式IK(逆动力学)就能接触物体。手臂的运动规划由网络内部学习。从终端运行以下脚本开始:

$ ./gazebo-arm.sh

连接学习到模拟的插件位于仓库的gazebo/目录中。查看**ArmPlugin.cpp**以了解将仿生眼链接到dqnAgent(c/dqnAgent.h)并与控制手臂关节的代码。

一旦注意到机械臂收敛到物体,您可以通过按下键盘上的T键启用仿生眼的“平移”模式,然后点击并拖动视口中的物体来移动物体。

请注意,您希望让物体保持在机械臂可触及的范围内,因为机械臂的旋转基座最初只限于左右各约45度的行程。

漫游者导航

我们还有一个在仿生眼中学习跟随物体并避免其环境墙壁的滑行式漫游者,类似于fruitsamples/fruit/fruit.cpp)场景。要启动漫游者仿真,请运行以下脚本:

$ ./gazebo-rover.sh

Ctrl+T订阅~/camera/link/camera/image主题以从相机视角可视化场景。

与机械臂一样,一旦发现漫游者持续找到物体(在这个例子中是绿色盒子),就可以先按下T键移动物体。注意有一个类似fruitsamples/fruit/fruit.cpp)的关卡超时,所以在不增加代码中漫游者的maxEpisodeLength(例如这里)并重新编译之前,不要将物体移动得太远。

连续控制

我们一直使用的DQN代理是离散的,意味着网络每个时间步长选择一个输出神经元,用户随后将其映射或定义为对应于一个动作(通常是以增量/减量的方式增加/减少一个位置或速度)。这意味着对于机器人的每个自由度,都需要两个输出——一个用来增加变量,另一个用来减小它。

在更复杂的现实世界情景中,同时控制所有自由度并且让网络输出这些变量的确切值通常是有利的。例如,如果你想教一个人形机器人走路(它可以有20-40个或更多的自由度),同时控制所有关节对它的稳定性至关重要。

对于连续控制,存在一类称为Actor/Critic的更高级深度强化学习者——这是近年来产生最新最先进的解决方案如DDPGACKTRA3C/A3G的活跃研究领域。

双足步行者

为了展示一个在OpenAI Gym最具挑战性和难度的环境之一——BipedalWalkerHardcore-v2中运行的连续学习者,本仓库包含了一个A3G的演示,它利用GPU并行地启动多个Gym实例以加速学习。要启动A3G求解器,从终端运行以下命令:

$ cd jetson-reinforcement/python/A3G
$ python main.py --env BipedalWalkerHardcore-v2 --workers 8 --gpu-ids 0 --amsgrad True --model CONV --stack-frames 4

gym_bipedal

根据设置和系统资源,通常A3G需要90到120分钟来掌握这个环境,即通过障碍和陷阱。如果你的PC或服务器有多块GPU,你可以禁用渲染并增加工作线程的数量,并指定额外的gpu-ids以加快训练速度。

gym_bipedal

附录:使用LUA

默认情况下,仓库会与PyTorch和Python一起构建。然而,也提供了一个编译标志来支持Torch7和LUA脚本。该过程被编写为自动安装依赖项,如Torch7,并从源代码构建项目。 在某些时候,你可能需要输入sudo密码。

1. 克隆GitHub仓库

首先,确保安装了构建工具

$ sudo apt-get install git cmake
$ git clone http://github.com/dusty-nv/jetson-reinforcement

2. 配置构建

$ cd jetson-reinforcement
$ mkdir build
$ cd build
$ cmake ../ -DUSE_LUA=yes -DUSE_PYTHON=no

这将启动构建依赖项,如Torch及其CUDA/cuDNN绑定,这可能会花费一些时间。

3. 编译

$ cd jetson-inference/build     # 如果在步骤#2的目录已经是这个,则跳过此步
$ make

根据架构,软件包将被构建为armhf或aarch64,如下所示的目录结构:

|-build
   \aarch64		 (64位)
      \bin			应用程序二进制文件所在位置
      \include		头文件所在位置
      \lib			库文件构建位置
   \armhf            (32位)
      \bin			应用程序二进制文件所在位置
      \include		头文件所在位置
      \lib			库文件构建位置

验证Lua + Torch 安装

从源代码构建或[下载软件包](#下载软件包]之后,使用以下命令验证LuaJIT-5.1/Torch7脚本环境:

$ cd aarch64/bin

$ ./deepRL-console hello.lua			# 验证Lua解释器(如果对Lua不熟悉,请参阅)

[deepRL] 创建新的lua_State
[deepRL] 打开了LUA库
[deepRL] 加载'hello.lua'

HELLO from LUA!
my variable equals 16
list  1
map.x 10
one
two
3
4
5
6
7
8
9
10
multiply = 200
goodbye!

[deepRL] 关闭lua_State

此命令将测试加载Torch7包和CUDA/cuDNN的绑定:

$ ./deepRL-console test-packages.lua    # 加载Torch包和绑定

[deepRL] 创建新的lua_State
[deepRL] 打开了LUA库
[deepRL] 加载'test-packages.lua'

[deepRL] 在Torch/Lua环境中打个招呼(时间=0.032163)
[deepRL] 加载Lua包...
[deepRL] 加载torch...
[deepRL] 加载cutorch...
cutorch.hasHalf == false
[deepRL] 加载nn...
[deepRL] 加载cudnn...
[deepRL] 加载math...
[deepRL] 加载nnx...
[deepRL] 加载optim...
[deepRL] 包加载完成。(时间=5.234669)

[deepRL] 关闭lua_State

这些脚本应正常运行并验证Lua/Torch环境是正常的。

deepRL-console程序可以从命令行(CLI)启动用户的脚本。

使用LUA Q 学习者玩接球游戏

接下来,为了验证强化Q学习者能按预期学习,让我们玩一个简单的游戏:半乒乓,或者接球。

$ ./deepRL-console catchDQN.lua

运行上述脚本应开始你的Jetson玩游戏并实时绘制学习过程:

每个周期是一局游戏,球从屏幕顶部下落到底部。 经过几百个周期后,Q学习者应该已经开始大部分时间都能接住球了。

项目介绍

Deep reinforcement learning GPU libraries for NVIDIA Jetson TX1/TX2 with PyTorch, OpenAI Gym, and Gazebo robotics simulator.

定制我的领域