在本教程中,我们将创建人工智能代理,从与环境交互中学习,收集经验,并通过深度强化学习(深度RL)获得奖励系统。使用将原始像素转换为动作的端到端神经网络,RL训练的代理能够展示直观的行为并执行复杂的任务。
最终,我们的目标是通过3D虚拟机器人仿真训练强化学习代理,并将代理转移到真实世界的机器人。强化学习者根据环境状态(如摄像机输入)和奖励向代理提供关于其性能的反馈,为代理选择最佳行为。强化学习可以学习在给定策略或任务的环境中表现最佳,例如获得奖励。
在许多情况下,状态空间非常复杂且多维度,因此越来越多地使用神经网络来预测最佳动作,这是深度强化学习和GPU加速技术发挥作用的地方。通过深入的强化学习,代理人通常使用卷积神经网络(CNN)处理2D图像,处理比低维RL更复杂一个数量级的输入,并且能够通过最终结果学习“从视觉” (被称为“像素到动作”)。
该存储库包括PyTorch中的离散Deep Q-Learning(DQN)和连续A3G算法,C ++中的示例和互操作性库API,用于将Linux应用程序集成到机器人,仿真和现场部署中。
从终端运行以下命令以从源代码构建:
$ 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将被编译和安装,因此可能需要一段时间(约30分钟到1小时在Jetson上)。我们目前使用的PyTorch的稳定版本是0.3.0
。构建脚本将下载pacekages并sudo
在安装期间询问您的密码。
在继续之前,为确保PyTorch安装正确,并且如果您不熟悉PyTorch,请提供一个名为Jupyter IPython的笔记本intro-pytorch.ipynb
,其中包含一些简单的PyTorch示例,用于验证安装并测试CUDA / cuDNN支持PyTorch。
要在系统本地启动笔记本,请运行以下命令:
$ cd jetson-reinforcement / build / aarch64 / bin #或cd在PC上的x86_64 / bin
$ jupyter notebook intro-pytorch.ipynb
或者,如果您希望跳过笔记本并直接运行PyTorch验证命令,可以通过使用python
命令启动交互式Python shell 并运行以下命令来完成此操作:
>>> import pytorch
>>> print(torch.__version__)
>>> print('CUDA available: ' + str(torch.cuda.is_available()))
>>> a = torch.cuda.FloatTensor(2).zero_()
>>> print('Tensor a = ' + str(a))
>>> b = torch.randn(2).cuda()
>>> print('Tensor b = ' + str(b))
>>> c = a + b
>>> print('Tensor c = ' + str(c))
如果PyTorch在您的系统上正确安装,则输出应如下所示:
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pytorch
>>> 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执行基本张量操作。
为了首先测试和验证深层强化学习算法的确在学习,我们将在OpenAI Gym环境(2D)中运行它们。作为DQN算法的介绍,第二个支持CUDA的IPython笔记本包含在回购中intro-DQN.ipynb
。这款笔记本将DQN应用于从Gym的CartPole
环境中捕捉的视频,因此它在GPU上从“视觉”学习,而不是像传统RL那样从游戏获取低维参数。
虽然CartPole是一个玩具的例子,但是从一个简单的例子开始,至关重要的一点是,在毕业后将更容易地调试到更复杂的3D场景,并且由于DQN从原始的2D像素数组中学习,它仍然被考虑深入强化学习。建议您按照下面的笔记本进行操作,以熟悉DQN算法,以便在后面的更复杂环境中从C ++转换到更复杂的环境时使用它。
要从您的机器本地启动笔记本,请运行以下命令:
$ cd jetson-reinforcement / build / aarch64 / bin #或者cd x86_64 / bin
$ jupyter notebook intro-DQN.ipynb
在笔记本内部,DQN设置为仅运行50集。在目睹DQN开始收敛并且CartPole开始长时间保持正常之后,退出笔记本并gym-DQN.py
从终端运行独立脚本以提高性能:
$ python gym-DQN.py
(假设你的终端的当前目录仍然
jetson-reinforcement/build/
在上面)/bin
应该出现三个窗口,显示小推车游戏,一个性能图表,DQN代理应该开始学习。DQN特工能够平衡移动手推车上的杆子的时间越长,奖励得分越多。在健身房,200分表示场景已被掌握。经过一段时间的培训后,代理人应该实现它,程序将退出。
使用类似的脚本,您可以在不同的健身房环境中使用--env
参数进行实验:
$ python gym-RL.py --env = LunarLander-v2 --render
该LunarLander-v2
环境是有趣的探索,因为它是一个类似的任务,无人机自动着陆,因此对机器人技术相关。起初,着陆器将会疯狂地坠毁,但从第50集开始,你可能会注意到它开始试图留在旗帜之间,并且在几百集之后,它应该开始以受控制的下降着陆。在终端,你应该看到奖励变得积极,随着时间的推移会增加到200:
Episode 010 Reward: -508.10 Last length: 079 Average length: 18.20
Episode 020 Reward: -301.04 Last length: 088 Average length: 25.02
Episode 030 Reward: -208.76 Last length: 102 Average length: 31.96
Episode 040 Reward: -98.75 Last length: 071 Average length: 48.18
Episode 050 Reward: -155.66 Last length: 107 Average length: 53.96
Episode 060 Reward: -103.31 Last length: 091 Average length: 58.13
Episode 070 Reward: -64.71 Last length: 095 Average length: 64.51
Episode 080 Reward: -93.23 Last length: 147 Average length: 76.15
Episode 090 Reward: -150.40 Last length: 120 Average length: 86.76
Episode 100 Reward: -218.14 Last length: 100 Average length: 98.21
Episode 110 Reward: -93.55 Last length: 101 Average length: 100.55
Episode 120 Reward: -32.54 Last length: 120 Average length: 105.52
Episode 130 Reward: -112.93 Last length: 183 Average length: 120.30
Episode 140 Reward: -188.25 Last length: 110 Average length: 149.31
Episode 150 Reward: -78.87 Last length: 176 Average length: 148.66
Episode 160 Reward: +11.95 Last length: 174 Average length: 153.23
Episode 170 Reward: +131.50 Last length: 252 Average length: 155.50
Episode 180 Reward: +110.42 Last length: 128 Average length: 154.47
Episode 190 Reward: +86.32 Last length: 161 Average length: 156.21
Episode 200 Reward: +111.07 Last length: 505 Average length: 162.06
接下来,我们将看看通过我们的C ++包装库将这些独立的Python示例集成到机器人代码中。
为了将这些深入的强化学习者从庞大的Python示例转化为可与机器人和模拟器集成的libray形式,我们为Python代码提供了一个C ++包装库和API。在下面,该库使用Python的低级别C FFI在应用程序和PyTorch之间传递张量内存,而无需额外的副本(ZeroCopy)。
该库的架构可扩展到新型学习算法。下面是伪代码,说明rlAgent
RL实现继承的接口的签名:
/**
* Base class for deep reinforcement learning agent
*/
class rlAgent
{
public:
/**
* Create a new instance of a module for training an agent.
*/
static rlAgent* Create( uint32_t width, uint32_t height,
uint32_t channels, uint32_t numActions );
/**
* Destructor
*/
virtual ~rlAgent();
/**
* From the input state, predict the next action
*/
virtual bool NextAction( Tensor* state, int* action );
/**
* Issue the next reward and training iteration
*/
virtual bool NextReward( float reward, bool end_episode );
};
回购中包含代理的不同实现,包括dqnAgent
我们将在模拟场景中使用的实现。用户将其传感器数据或环境状态提供给NextAction()
调用Python脚本并返回预测动作的函数,然后用户将其应用于其机器人或模拟。
接下来,在NextReward()
函数中发布奖励,该函数从环境中向学习者提供反馈,并开始下一次训练迭代,使代理随着时间学习。
为了确保强化学习者在C ++中仍能正常工作,使用调用catch
和调用的API的一些简单示例fruit
。在概念上与乒乓球类似,catch
球在球到达屏幕底部之前必须捕捉的环境顶部的球落下,通过向左或向右移动桨。
与以前的单片Python脚本示例不同,该catch
示例是一个简单的C / C ++程序,它链接到上述强化学习库。要测试文本catch
示例,请从终端运行以下可执行文件。在大约100集左右之后,代理人应该几乎100%的时间开始赢得剧集:
$ ./catch
[deepRL] input_width: 64
[deepRL] input_height: 64
[deepRL] input_channels: 1
[deepRL] num_actions: 3
[deepRL] optimizer: RMSprop
[deepRL] learning rate: 0.01
[deepRL] replay_memory: 10000
[deepRL] batch_size: 32
[deepRL] gamma: 0.9
[deepRL] epsilon_start: 0.9
[deepRL] epsilon_end: 0.05
[deepRL] epsilon_decay: 200.0
[deepRL] allow_random: 1
[deepRL] debug_mode: 0
[deepRL] creating DQN model instance
[deepRL] DQN model instance created
[deepRL] DQN script done init
[cuda] cudaAllocMapped 16384 bytes, CPU 0x1020a800000 GPU 0x1020a800000
[deepRL] pyTorch THCState 0x0318D490
[deepRL] nn.Conv2d() output size = 800
WON! episode 1
001 for 001 (1.0000)
WON! episode 5
004 for 005 (0.8000)
WON! episode 10
007 for 010 (0.7000)
WON! episode 15
010 for 015 (0.6667)
WON! episode 20
013 for 020 (0.6500) 13 of last 20 (0.65) (max=0.65)
WON! episode 25
015 for 025 (0.6000) 11 of last 20 (0.55) (max=0.65)
LOST episode 30
018 for 030 (0.6000) 11 of last 20 (0.55) (max=0.65)
LOST episode 35
019 for 035 (0.5429) 09 of last 20 (0.45) (max=0.65)
WON! episode 40
022 for 040 (0.5500) 09 of last 20 (0.45) (max=0.65)
LOST episode 45
024 for 045 (0.5333) 09 of last 20 (0.45) (max=0.65)
WON! episode 50
027 for 050 (0.5400) 09 of last 20 (0.45) (max=0.65)
WON! episode 55
031 for 055 (0.5636) 12 of last 20 (0.60) (max=0.65)
LOST episode 60
034 for 060 (0.5667) 12 of last 20 (0.60) (max=0.65)
WON! episode 65
038 for 065 (0.5846) 14 of last 20 (0.70) (max=0.70)
WON! episode 70
042 for 070 (0.6000) 15 of last 20 (0.75) (max=0.75)
LOST episode 75
045 for 075 (0.6000) 14 of last 20 (0.70) (max=0.75)
WON! episode 80
050 for 080 (0.6250) 16 of last 20 (0.80) (max=0.80)
WON! episode 85
055 for 085 (0.6471) 17 of last 20 (0.85) (max=0.85)
WON! episode 90
059 for 090 (0.6556) 17 of last 20 (0.85) (max=0.85)
WON! episode 95
063 for 095 (0.6632) 18 of last 20 (0.90) (max=0.90)
WON! episode 100
068 for 100 (0.6800) 18 of last 20 (0.90) (max=0.90)
WON! episode 105
073 for 105 (0.6952) 18 of last 20 (0.90) (max=0.90)
WON! episode 110
078 for 110 (0.7091) 19 of last 20 (0.95) (max=0.95)
WON! episode 111
079 for 111 (0.7117) 19 of last 20 (0.95) (max=0.95)
WON! episode 112
080 for 112 (0.7143) 20 of last 20 (1.00) (max=1.00)
在内部,我们catch
正在使用dqnAgent
C ++库中的API来实现学习。
有一些可供选择的命令行参数catch
可用于改变环境的大小和像素数组输入大小,增加复杂性以查看它如何影响收敛和训练时间:
$ ./catch --width = 96 --height = 96
$ ./catch --render #启用环境的文本输出
在96x96
环境规模的情况下,捕鱼剂在150-200集之后达到75%以上的精度。
在128x128
环境规模的情况下,大约325集之后,捕鱼剂的准确度达到75%以上。
接下来,我们提供了一个名为C ++的二维图形样本fruit
,其中代理出现在随机位置,并且必须找到“水果”对象才能获得奖励并在超出限制或超时期限到期之前赢取剧集。该fruit
代理有4个可能的动作可供选择:移动上,下,左,右屏幕上,以导航到该对象。
请注意,此C ++示例主要在GPU上运行,其中CUDA中的环境的基本2D栅格化以及DQN和OpenGL中的显示可视化。和以前一样,它正在学习“从视觉上”,利用深度强化学习将原始像素阵列转换为动作。
与更复杂的导航和运动计划任务类似,这个简单的fruit
示例旨在证明dqnAgent
能够从任何起始位置以可视方式识别和导航感兴趣的对象。稍后在回购协议中,我们将在3D机器人仿真中建立这种路径规划功能。
首先fruit
,从终端启动以下可执行文件:
$ ./fruit
在默认48x48
环境下约100集后,它应该达到85%的准确度:
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) 16 of last 20 (0.80) (max=0.80)
action = LEFT reward = +0.0084 wins = 052 of 094 (0.55) 16 of last 20 (0.80) (max=0.80)
action = UP reward = +0.1208 wins = 052 of 094 (0.55) 16 of last 20 (0.80) (max=0.80)
action = LEFT reward = +0.1154 wins = 052 of 094 (0.55) 16 of last 20 (0.80) (max=0.80)
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) 17 of last 20 (0.85) (max=0.85)
action = DOWN reward = +0.1424 wins = 053 of 095 (0.56) 17 of last 20 (0.85) (max=0.85)
action = DOWN reward = +0.1406 wins = 053 of 095 (0.56) 17 of last 20 (0.85) (max=0.85)
action = DOWN reward = +0.1386 wins = 053 of 095 (0.56) 17 of last 20 (0.85) (max=0.85)
action = DOWN reward = +0.1365 wins = 053 of 095 (0.56) 17 of last 20 (0.85) (max=0.85)
action = DOWN reward = +0.1342 wins = 053 of 095 (0.56) 17 of last 20 (0.85) (max=0.85)
action = RIGHT reward = +0.0134 wins = 053 of 095 (0.56) 17 of last 20 (0.85) (max=0.85)
与catch
样本类似fruit
,您可以使用一些可选的命令行参数:
$ ./fruit --width = 64 --height = 64 --episode_max_frames = 100
当增加环境和像素阵列输入的尺寸时,episode_max_frames
应该相应地增加,因为在情节暂停之前,代理将需要更多时间在更大的环境中穿过屏幕。
直到回购的这一点,环境都是二维的,即确认深度RL算法正在按照预期学习。为了将代理迁移到3D世界中,我们将使用Gazebo机器人模拟器来模拟不同的自动机器,包括机器人手臂和漫游器,然后可以将其转移到真实世界的机器人。
我们的第一个Gazebo环境训练机器人手臂触摸物体,而不需要明确的IK(逆运动学)。
手臂的运动计划由网络内部学习。要开始,请从终端运行以下脚本:
$ ./gazebo-arm.sh
将学习与模拟挂钩的插件位于gazebo/
回购目录中。
请参阅ArmPlugin.cpp
链接Gazebo与代码,dqnAgent
并控制手臂关节。
一旦您注意到手臂物剂会聚在物体上,您可以通过按T
键盘上的按键启动Translation
Gazebo中的模式,然后通过单击并拖动视口周围的物体,开始在场景周围移动物体。
请注意,您需要移动物体,以便手臂仍能够到达它,因为手臂的旋转底座最初被限制在任一方向的行程约45度。
我们在Gazebo还有一个滑行转向火车,学习跟踪物体,同时避开其环境的墙壁,类似于fruit
场景。要启动流动站模拟,请运行以下脚本:
$ ./gazebo-rover.sh
按下
Ctrl+T
并订阅~/camera/link/camera/image
主题以从相机中可视化场景。
与手臂类似,一旦您注意到流动站一直在寻找物体(在这种情况下为绿色框),您可以通过T
先按下,在场景周围移动物体。请注意,有一个情节超时类似于fruit
,所以如果不先maxEpisodeLength
在代码中增加流动站并重新编译,您不会希望将对象移动太远。
我们一直使用的DQN代理是离散的,这意味着网络每个时间步选择一个输出神经元,然后用户明确地映射或定义对应于一个动作(通常按增量增加/减少位置或速度) 。这意味着对于机器人中的每个自由度,需要2个输出 - 一个是通过增量增加变量,另一个是减小它。
在更复杂的现实世界中,同时控制所有自由度并使网络输出这些变量的精确值通常是有利的。例如,如果你想教一个人形行走(可以有20-40或更多的自由度),同时控制所有关节对于它的稳定性很重要。
对于连续控制,存在一类更先进的深度强化学习者,称为Actor / Critic - 这是一个活跃的研究领域,最近得到了最新的最先进的解决方案,如DDPG,ACKTR和A3C / A3G。
为了在最具挑战性和困难的OpenAI健身房环境之一中演示持续学习者BipedalWalkerHardcore-v2
,在回购中包含了一个A3G演示,它启动了许多Gym实例,以便使用GPU并行快速学习。要启动A3G解算器,请从终端运行以下命令:
$ cd jetson-reinforcement / python / A3G
$ python main.py --env BipedalWalkerHardcore-v2 --workers 8 --gpu-ids 0 --amsgrad True - moduleCONV --stack-frames 4
根据设置和系统资源的不同,通常需要90-120分钟的时间通过清除障碍和陷阱来掌握环境。如果您的PC或服务器中有多个GPU,则可以禁用渲染并增加工作线程的数量并指定其他设置gpu-ids
以加速培训。
默认情况下,回购利用PyTorch和Python构建。但是,Torch7和LUA脚本中也包含对编译标志的支持。该过程被编写为自动安装Torch7等依赖项,并从源代码构建项目。
您可能需要在某个时间输入sudo密码。
首先,确保构建工具
$ sudo apt-get install git cmake
$ git clone http://github.com/dusty-nv/jetson-reinforcement
$ cd jetson-reinforcement
$ mkdir构建
$ cd build
$ cmake ../ -DUSE_LUA = yes -DUSE_PYTHON = no
这将启动构建诸如Torch之类的依赖关系,并且这对CUDA / cuDNN是有约束力的,这可能需要一些时间。
$ cd jetson-inference / build # omit如果pwd已经是来自步骤#2
$ make
根据体系结构,该软件包将被构建为armhf或aarch64,具有以下目录结构:
|-build
\aarch64 (64-bit)
\bin where the application binaries are built to
\include where the headers reside
\lib where the libraries are build to
\armhf (32-bit)
\bin where the application binaries are built to
\include where the headers reside
\lib where the libraries are build to
在从源代码构建或[下载程序包](#downloaded-the-package)之后,使用以下命令验证LuaJIT-5.1 / Torch7脚本环境:
$ cd aarch64/bin
$ ./deepRL-console hello.lua # verify Lua interpreter (consult if unfamiliar with Lua)
[deepRL] created new lua_State
[deepRL] opened LUA libraries
[deepRL] loading '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] closing lua_State
该命令将测试加载Torch7包和CUDA / cuDNN的绑定:
$ ./deepRL-console test-packages.lua # load Torch packages and bindings
[deepRL] created new lua_State
[deepRL] opened LUA libraries
[deepRL] loading 'test-packages.lua'
[deepRL] hello from within Torch/Lua environment (time=0.032163)
[deepRL] loading Lua packages...
[deepRL] loading torch...
[deepRL] loading cutorch...
cutorch.hasHalf == false
[deepRL] loading nn...
[deepRL] loading cudnn...
[deepRL] loading math...
[deepRL] loading nnx...
[deepRL] loading optim...
[deepRL] done loading packages. (time=5.234669)
[deepRL] closing lua_State
这些脚本应该正常运行并验证Lua / Torch环境是否健全。
deepRL控制台程序可以从命令行(CLI)启动用户的脚本。
接下来,为了验证强化Q-learner学习它应该如何学习,让我们玩一个简单的游戏:半球或捕捉。
$ ./deepRL-console catchDQN.lua
启动上面的脚本应该开始你的Jetson玩捕捉游戏并实时绘制学习过程:
每个时代都是一场比赛,球从球幕的顶部落到底部。在几百个时代之后,Q-learner应该在大多数时候开始接球。