大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
个人主页-Sonhhxg_柒的博客_CSDN博客
欢迎各位→点赞 + 收藏⭐️ + 留言
系列专栏 - 机器学习【ML】 自然语言处理【NLP】 深度学习【DL】
foreword
✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。
如果你对这个系列感兴趣的话,可以关注订阅哟
文章目录
自动驾驶汽车简介
AV研究简史
自动化水平
视音频系统的组件
环境感知
传感
本土化
运动物体检测与跟踪
路径规划
3D数据处理简介
模仿驾驶政策
使用 PyTorch 进行行为克隆
生成训练数据集
实现代理神经网络
训练
让代理开车
把它们放在一起
使用 ChauffeurNet 的驾驶政策
输入和输出表示
模型架构
训练
概括
让我们想想自动驾驶汽车 ( AV )将如何发展 影响我们的生活。一方面,我们可以在旅途中做其他事情,而不是把注意力集中在驾驶上。满足这些旅行者的需求本身可能会催生一个完整的行业。但这只是一个额外的好处。如果我们在旅行期间可以更有效率或只是放松一下,那么我们很可能会开始更多地旅行,更不用说对自驾能力有限的人的好处了。让交通这样一种必不可少的基本商品变得更容易获得,有可能改变我们的生活。这只是对我们个人的影响——从交付服务到准时制造,自动驾驶汽车也可以对经济产生深远的影响。简而言之,让 AV 工作是一项非常高风险的游戏。那么难怪,近年来,该领域的研究已从学术界转向实体经济。从 Waymo、Uber 和 NVIDIA 到几乎所有主要汽车制造商,公司都在争相开发 AV。
但是,我们还没有到达那里。原因之一是自动驾驶是一项复杂的任务,由多个子问题组成,每个子问题本身就是一项主要任务。为了成功导航,车辆程序需要一个准确的环境 3D 模型。构建这种模型的方法是将来自多个传感器的信号组合起来。一旦我们有了模型,我们仍然需要解决实际的驾驶任务。想想驾驶员必须克服的许多意外和独特的情况而不会撞车。但即使我们创建了一个驾驶策略,它也需要几乎 100% 准确。假设我们的 AV 将成功停在 100 个红绿灯中的 99 个。99% 的准确率对于任何其他机器学习(ML ) 任务; 自动驾驶并非如此,即使是一个错误也可能导致撞车。
在本章中,我们将探讨深度学习在 AV 中的应用。我们将研究如何使用深度网络来帮助车辆了解其周围环境。我们还将了解如何在实际控制车辆时使用它们。
本章将涵盖以下主题:
我们将从 AV 研究的简史开始本节(令人惊讶的是很久以前就开始了)。我们还将尝试根据汽车工程师协会( SAE ) 定义不同级别的 AV 自动化。
实施自动驾驶汽车的第一次认真尝试 始于 1980 年代的欧洲和美国。自 2000 年代中期以来,进展迅速加快。该领域的第一个重大努力是Eureka Prometheus 项目 ( https://en.wikipedia.org/wiki/Eureka_Prometheus_Project ),该项目从 1987 年到 1995 年。它在 1995 年达到顶峰,当时一辆自动驾驶的梅赛德斯-奔驰 S-Class 使用计算机视觉从慕尼黑到哥本哈根进行了 1,600 公里的旅行,然后返回。在某些时候,这辆车在德国高速公路上的速度高达 175 公里/小时(有趣的事实:高速公路的某些路段没有速度限制)。这辆车能够自行超越其他汽车。人工干预之间的平均距离为 9 公里,在没有干预的情况下,它曾一度行驶 158 公里。
1989 年,卡内基梅隆大学的院长 Pomerleau 发表了ALVINN: An Autonomous Land Vehicle in a Neural Network ( https://papers.nips.cc/paper/95-alvinn-an-autonomous-land-vehicle-in-a-neural -network.pdf ),一篇关于在 AV 中使用神经网络的开创性论文。这项工作特别有趣,因为它应用了我们在 30 年前的 AV 中讨论过的许多主题。让我们看看 ALVINN 最重要的属性:
接下来,让我们看一下(主要是)商业 AV 进展的最新时间表:
当我们谈论 AV 时,我们通常会 想象 完全无人驾驶的车辆。但实际上,我们的汽车需要司机,但仍提供一些自动化功能。
SAE 开发了一个包含六个自动化级别的规模:
今天所有的商用车辆最多都具有 2 级的功能(甚至是特斯拉的自动驾驶仪)。唯一的例外(根据制造商的说法)是 2018 年的奥迪 A8,它具有称为 AI Traffic Jam Pilot 的 3 级功能。该系统负责在多车道道路上以高达 60 公里/小时的速度行驶,两个交通方向之间有物理障碍。 可以通过 10 秒的提前警告提示驾驶员进行控制。此功能在车辆发布期间已展示,但在撰写本章时,奥迪引用了监管限制,并未将其包含在所有市场中。我没有关于此功能在哪里(或是否)可用的信息。
在下一节中,我们将了解构成 AV 系统的组件。
在本节中,我们将从软件架构的角度概述两种类型的 AV 系统。第一种类型使用具有多个组件的顺序架构,如下图所示:
该系统类似于我们在第 10 章“元学习”中简要讨论过的强化学习框架。我们有一个反馈循环,其中环境(物理世界或模拟)为代理(车辆)提供其当前状态。反过来,代理决定它的新轨迹,环境对其做出反应,等等。让我们从环境感知子系统开始,它具有以下模块(我们将在以下部分更详细地讨论它们):
感知系统的输出结合了来自其各个模块的数据,以产生周围环境的中级虚拟表示。这种表示通常是环境的自上而下(鸟瞰)2D 视图,称为占用图。以下屏幕截图显示了 ChauffeurNet 系统的示例占用地图,我们将在本章后面讨论。它包括路面(白线和黄线)、交通信号灯(红线)和其他车辆(白色矩形)。最好以彩色方式查看图像:
占用图用作路径规划模块的输入,该模块使用它来确定车辆的未来轨迹。控制模块采用所需的轨迹并将其转换为车辆的低级控制输入。
中层表示方法有几个优点。首先,它非常适合路径规划和控制模块的功能。此外,我们可以使用模拟器生成它,而不是使用传感器数据来创建自上而下的图像。通过这种方式,收集训练数据会更容易,因为我们不必驾驶真正的汽车。更重要的是,我们将能够模拟现实世界中很少发生的情况。例如,我们的 AV 必须不惜一切代价避免崩溃,但现实世界的训练数据将很少(如果有的话)崩溃。如果我们只使用真实的传感器数据,最重要的驾驶情况之一将被严重低估。
第二种类型的 AV 系统使用单个端到端组件,它将原始传感器数据作为输入,并以转向控制的形式生成驾驶策略,如下图所示:
端到端的视音频系统
事实上,我们在讨论 ALVINN 时已经提到了端到端系统(在 AV 研究简史部分)。接下来,我们将关注顺序系统的不同模块。我们将在本章后面更详细地介绍端到端系统。
要使任何自动化功能发挥作用, 车辆需要对其周围环境有良好的感知。环境感知系统必须识别移动物体(例如行人、骑自行车者和其他车辆)的准确位置、距离和方向。此外,它必须创建路面的精确映射以及车辆在该路面和整个环境中的准确位置。让我们讨论帮助 AV 创建这个虚拟环境模型的硬件和软件组件。
建立良好环境模型的关键是车辆传感器。以下是最重要的传感器列表:
来自多个传感器的数据可以通过称为传感器融合的过程合并到一个环境模型中。传感器融合通常使用卡尔曼滤波器 ( https://en.wikipedia.org/wiki/Kalman_filter )实现。
定位是确定车辆 在 地图上的准确位置的过程。为什么这很重要?HERE ( HERE Technologies | The world's #1 location platform ) 等公司专注于创建极其精确的道路地图,其中道路表面的整个区域已知在几厘米以内。这些地图还可以包括有关静态感兴趣对象的信息,例如车道标记、交通标志、交通信号灯、限速、斑马线、减速带等。因此,如果我们 知道车辆在道路上的准确位置,就不难计算出最优轨迹。
一种明显的解决方案是使用 GPS。但是,在完美的条件下,GPS 可以精确到 1-2 米以内。在有高层建筑或山区的地区,精度可能会受到影响,因为 GPS 接收器无法从足够数量的卫星获得信号。解决此问题的一种方法是使用同步定位和映射 ( SLAM ) 算法。这些算法超出了本书的范围,但我鼓励 你 对这个主题进行自己的研究。
我们现在对车辆使用的传感器有所了解,并且我们已经简要提到了了解其在地图上的确切位置的重要性。有了这些知识,车辆理论上可以通过简单地跟踪细粒度点的面包屑路径导航到目的地。然而,自动驾驶的任务并没有那么简单,因为环境是动态的,因为它包括移动的物体,如车辆、行人、骑自行车的人等。自动驾驶汽车必须不断了解移动物体的位置,并在规划其轨迹时对其进行跟踪。这是我们可以将深度学习算法应用于原始传感器数据的一个领域。首先,我们将为相机执行此操作。第5章,目标检测和图像分割 ,我们讨论了如何 在两个高级视觉任务——对象检测和语义分割中使用卷积网络 ( CNN )。
回顾一下,对象检测会在图像中检测到的不同类别的对象周围创建一个边界框。语义分割为图像的每个像素分配一个类标签。我们可以使用分割来检测路面的确切形状和摄像头图像上的车道标记。我们可以使用物体检测对环境中感兴趣的运动物体进行分类和定位;但是,我们已经在第 5 章,目标检测和图像分割中介绍了这些主题。在本章中,我们将重点关注激光雷达传感器,并讨论如何在该传感器产生的 3D 点云上应用 CNN。
现在我们已经概述了感知子系统组件,在下一节中,我们将介绍路径规划子系统。
路径规划(或驾驶策略)是计算 车辆 轨迹和速度的过程。尽管我们可能有准确的地图和车辆的确切 位置 ,但我们仍然需要牢记环境的动态。汽车被其他移动的车辆、行人、红绿灯等包围。如果前面的车辆突然停下来怎么办?或者如果它移动得太慢?我们的 AV 必须做出超车决定,然后执行机动。这是一个机器学习和深度学习特别有用的领域,我们将在本章讨论两种实现它们的方法。更具体地说,我们将讨论在端到端学习系统中使用模仿驾驶策略,以及由 Waymo 开发的称为 ChauffeurNet 的驾驶策略算法。
AV 研究的一个障碍是构建 AV 并获得必要的许可来测试它是非常昂贵和耗时的。值得庆幸的是,我们仍然可以在 AV 模拟器的帮助下训练我们的算法。
一些最受欢迎的模拟器如下:
我们对 AV 系统组件的描述到此结束。接下来,我们将讨论如何处理 3D 空间数据。
激光雷达产生一个点云——三维空间中的一组数据点。请记住,激光雷达会发射激光束。从表面反射并返回接收器的光束会生成点云的单个数据点。如果我们假设激光雷达设备是坐标系的中心,并且每个激光束是一个矢量,那么一个点由矢量的方向和大小定义。因此,点云是一组无序的向量。或者,我们可以通过它们在空间中的笛卡尔坐标来定义点,如下图左侧所示。在这种情况下,点云是一组向量,其中每个向量包含点的三个坐标。为了清楚起见,每个点都表示为一个立方体:
接下来,让我们关注神经网络的输入数据格式,特别是 CNN。2D 彩色图像表示为具有三个切片(每个通道一个)的张量,每个切片是由像素组成的矩阵(2D 网格)。CNN 使用 2D 卷积(参见第 2 章,了解卷积网络)。直觉上,我们可能会认为我们可以为 3D 点云使用类似的 3D 体素网格(体素是 3D 像素),如上图的右图所示。假设点云点没有颜色,我们可以将网格表示为 3D 张量,并将其用作具有 3D 卷积的 CNN 的输入。
但是,如果我们仔细观察这个 3D 网格,我们会发现它是稀疏的。例如,在上图中,我们有一个包含 8 个点的点云,但网格包含 4 x 4 x 4 = 64 个单元。在这个简单的例子中,我们将数据的内存占用增加了八倍,但在现实世界中,情况可能会更糟。在本节中,我们将介绍 PointNet(参见PointNet:Deep Learning on Point Sets for 3D Classification and Segmentation,https ://arxiv.org/abs/1612.00593 ),它提供了该问题的解决方案。
PointNet 将点云向量p i集合作为输入,而不是它们的 3D 网格表示。为了理解它的架构,我们将从导致网络设计的点云向量集的属性开始(以下项目符号包含原始论文的引用):
现在我们知道了这些先决条件,让我们看看 PointNet 如何解决它们。我们将从网络架构开始,然后更详细地讨论它的组件:
PointNet 是一个多层感知器( MLP )。这是一个前馈网络,仅由完全连接的层(和最大池,但稍后会详细介绍)组成。正如我们所提到的,输入点云向量p i的集合表示为一个n × 3 张量。重要的是要注意网络(直到最大池化层)在集合的所有点之间共享。也就是说,尽管输入大小为n × 3,但我们可以将 PointNet 视为在 n 上应用相同的网络n次输入向量大小为 1 × 3。换句话说,网络权重在点云的所有点之间共享。这种顺序排列还允许任意数量的输入点。
输入通过输入变换(稍后我们将更详细地讨论),它输出另一个n × 3 张量,其中每个n个点由三个分量定义(类似于输入张量)。该张量被馈送到一个上采样全连接层,该层将每个点编码为一个 64 维向量,用于n × 64 输出。网络继续进行另一个转换,类似于输入转换。然后用 64、128、最后 1,024 个全连接层逐渐对结果进行上采样,以产生最终的n × 1024 输出。该张量用作最大池化层的输入,该层取所有n中同一位置的最大元素点并产生一个 1,024 维的输出向量。该向量是整个点集的聚合表示。
但是为什么首先使用最大池呢?请记住,最大池化是一种对称操作——也就是说,无论输入的顺序如何,它都会产生相同的输出。同时,点集也是无序的。使用最大池确保网络将产生相同的结果,而不管点的顺序如何。该论文的作者选择了最大池而不是其他对称函数,例如平均池和求和,因为最大池在基准数据集中展示了最高的准确性。
在最大池化之后,网络根据任务的类型分为两个网络(参见上图):
到目前为止,我们已经通过最大池化操作明确地解决了输入数据的无序性质,但我们仍然需要解决点之间的不变性和交互性。这就是输入和特征转换将有所帮助的地方。让我们从输入变换开始(在上图中,这是 T-net)。T-net 是一个 MLP,类似于完整的 PointNet(它被称为 mini-PointNet),如下图所示:
输入变换 T-net 将n × 3 点集(与完整网络相同的输入)作为输入。与完整的 PointNet 一样,T-net在所有点之间共享。首先,输入被上采样到n × 1024,有 64 个,然后是 128 个,最后是 1024 个单元的全连接层。上采样的输出被馈送到最大池操作,该操作输出 1 × 1024 向量。然后,使用两个 512 和 256 单元的全连接层将向量下采样到 1 × 256。1 × 256 向量乘以 256 × 9 全局(共享)可学习权重矩阵。结果被重新整形为一个 3 × 3 矩阵,在所有点上乘以原始输入点p i以产生最终的n× 3 输出张量。中间的 3 × 3 矩阵在点集上充当一种可学习的仿射变换矩阵。通过这种方式,这些点被归一化为一个熟悉的关于网络的视角——也就是说,网络在变换下变得不变。第二个 T-net(特征变换)与第一个几乎相同,不同之处在于输入张量是n × 64,这会产生一个 64 × 64 的矩阵。
尽管全局最大池化层确保网络不受数据顺序的影响,但它还有另一个缺点,因为它创建了整个输入点集的单一表示;但是,这些点可能属于不同的对象(例如,车辆和行人)。在这种情况下,全局聚合可能会出现问题。为了解决这个问题,PointNet 的作者介绍了 PointNet++(参见PointNet++:Deep Hierarchical Feature Learning on Point Sets in a Metric Space at https://arxiv.org/abs/1706.02413),它是一种分层神经网络,将 PointNet 递归应用于输入点集的嵌套分区。
在本节中,我们研究了 AV 环境感知系统背景下的 3D 数据处理。在下一节中,我们将把注意力转移到具有模仿驾驶策略的路径规划系统上。
在AV 系统的组件部分,我们概述了自动驾驶系统所需的几个模块。在本节中,我们将了解如何在 DL 的帮助下实施其中之一——驱动策略。一种方法是使用 RL,其中汽车是代理,环境就是环境。另一种流行的方法是模仿学习,其中模型(网络)学习模仿专家(人类)的行为。让我们看看模仿学习在 AV 场景中的属性:
行为克隆场景如下图所示:
正如我们已经提到的,ALVINN(来自 AV 研究简史部分)是一个行为克隆端到端系统。最近,论文End to End Learning for Self-Driving Cars ( https://arxiv.org/abs/1604.07316 ) 介绍了一个类似的系统,该系统使用具有五个卷积层的 CNN,而不是完全连接的网络。在他们的实验中,车辆上前置摄像头的图像作为输入输入到 CNN。CNN 的输出是单个标量 值,代表汽车所需的转向角。网络不控制加速和制动。为了构建训练数据集,该论文的作者收集了大约 72 小时的真实驾驶视频。在评估期间,该车能够在郊区 98% 的时间内自行驾驶(不包括变道和从一条道路转向另一条道路)。此外,它还设法在一条多车道分隔的高速公路上无干预地行驶了 16 公里。在下一节中,我们将实现一些有趣的东西——一个使用 PyTorch的行为克隆示例。
在本节中,我们将使用 PyTorch 1.3.1实现一个 行为克隆示例。 为了帮助我们完成这项任务,我们将使用 OpenAI Gym ( Gym Documentation ),这是一个用于开发和比较强化学习算法的开源工具包。它允许我们教代理承担各种任务,例如走路或玩乒乓球、弹球、其他一些 Atari 游戏甚至 Doom 等游戏。
我们可以安装它: pip
pip install gym[box2d]
在本例中,我们将使用OpenAI Gym 环境,如以下屏幕截图所示: CarRacing-v0
目标是让红色赛车(称为代理)在不滑离路面的情况下尽可能快地在赛道上行驶。我们可以使用四种动作来控制汽车:加速、刹车、左转和右转。每个动作的输入是连续的——例如,我们可以指定全油门值为 1.0,半油门值为 0.5(其他控件也是如此)。
为了简单起见,我们假设我们只能指定两个离散的动作值:0 表示无动作,1 表示完全动作。由于最初这是一个 RL 环境,因此代理将在沿轨道前进的每一步获得奖励;但是,我们不会使用它,因为代理会直接从我们的操作中学习。我们将执行以下步骤:
介绍完之后,让我们继续准备训练数据集。
在本节中,我们将了解如何生成训练数据集并将其作为 PyTorchtorch.utils.data.DataLoader类的实例加载。我们将突出显示代码中最相关的部分,但完整的源代码位于https://github.com/PacktPublishing/Advanced-Deep-Learning-with-Python/blob/master/Chapter11/imitation_learning/train。 py
我们将分几个步骤创建训练数据集:
一旦我们有了训练样本的数组,我们将使用该函数将它们转换为实例。这些类只允许我们以小批量提取数据并应用数据增强。 numpy create_datasetstorch.utils.data.DataLoader
但首先,让我们实现data_transform转换列表,在将图像输入网络 之前 对其进行修改。完整的实现可在Advanced-Deep-Learning-with-Python/util.py at master · PacktPublishing/Advanced-Deep-Learning-with-Python · GitHub获得。我们将图像转换为灰度,标准化[0, 1]范围内的颜色值,并裁剪框架的底部(黑色矩形, 显示 奖励和其他信息)。实现如下:
data_transform = torchvision.transforms.Compose([
torchvision.transforms.ToPILImage(),
torchvision.transforms.Grayscale(1),
torchvision.transforms.Pad((12, 12, 12, 0)),
torchvision.transforms.CenterCrop(84),
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0,), (1,)),
])
接下来,让我们将注意力转移到create_datasets函数上。我们将从声明开始:
def create_datasets():
然后,我们将实现帮助类,以便能够对输入图像应用转换。实现如下(请记住缩进,因为这段代码仍然是函数的一部分):TensorDatasetTransforms data_transform create_datasets
class TensorDatasetTransforms(torch.utils.data.TensorDataset):
def __init__(self, x, y):
super().__init__(x, y)
def __getitem__(self, index):
tensor = data_transform(self.tensors[0][index])
return (tensor,) + tuple(t[index] for t in self.tensors[1:])
接下来,我们将完整读取之前生成的数据集:
x, y = read_data()
x = np.moveaxis(x, 3, 1) # channel first (torch requirement)
然后,我们将创建训练和验证数据加载器(train_loader和val_loader)。最后,我们将它们作为create_datasets函数的结果返回:
# train dataset
x_train = x[:int(len(x) * TRAIN_VAL_SPLIT)]
y_train = y[:int(len(y) * TRAIN_VAL_SPLIT)]
train_set = TensorDatasetTransforms(torch.tensor(x_train), torch.tensor(y_train))
train_loader = torch.utils.data.DataLoader(train_set, batch_size=BATCH_SIZE,
shuffle=True, num_workers=2)
# test dataset
x_val, y_val = x[int(len(x_train)):], y[int(len(y_train)):]
val_set = TensorDatasetTransforms(torch.tensor(x_val), torch.tensor(y_val))
val_loader = torch.utils.data.DataLoader(val_set, batch_size=BATCH_SIZE,
shuffle=False, num_workers=2)
return train_loader, val_loader
接下来,让我们关注代理 NN 架构。
.
代理由具有以下属性的 CNN 表示:
以下代码块显示了网络 实现:
def build_network():
return torch.nn.Sequential(
torch.nn.Conv2d(1, 32, 8, 4),
torch.nn.BatchNorm2d(32),
torch.nn.ELU(),
torch.nn.Dropout2d(0.5),
torch.nn.Conv2d(32, 64, 4, 2),
torch.nn.BatchNorm2d(64),
torch.nn.ELU(),
torch.nn.Dropout2d(0.5),
torch.nn.Conv2d(64, 64, 3, 1),
torch.nn.ELU(),
torch.nn.Flatten(),
torch.nn.BatchNorm1d(64 * 7 * 7),
torch.nn.Dropout(),
torch.nn.Linear(64 * 7 * 7, 120),
torch.nn.ELU(),
torch.nn.BatchNorm1d(120),
torch.nn.Dropout(),
torch.nn.Linear(120, len(available_actions)),
)
实现了训练数据集和代理后,我们可以继续训练。
我们将在函数的帮助下实现训练本身,该train 函数将网络和设备作为参数。我们将使用交叉熵损失和 Adam 优化器(分类任务的常用组合)。该函数简单地迭代时间并为每个时期调用and函数。以下是实现: cuda EPOCHS train_epoch test
def train(model: torch.nn.Module, device: torch.device):
loss_function = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())
train_loader, val_order = create_datasets() # read datasets
# train
for epoch in range(EPOCHS):
print('Epoch {}/{}'.format(epoch + 1, EPOCHS))
train_epoch(model, device, loss_function, optimizer, train_loader)
test(model, device, loss_function, val_order)
# save model
model_path = os.path.join(DATA_DIR, MODEL_FILE)
torch.save(model.state_dict(), model_path)
然后,我们将实现train_epoch 单个 epoch 训练。此函数迭代所有小批量并为每个小批量执行前向和后向传递。以下是实现:
def train_epoch(model, device, loss_function, optimizer, data_loader):
model.train() # set model to training mode
current_loss, current_acc = 0.0, 0.0
for i, (inputs, labels) in enumerate(data_loader):
inputs, labels = inputs.to(device), labels.to(device) # send to device
optimizer.zero_grad() # zero the parameter gradients
with torch.set_grad_enabled(True):
outputs = model(inputs) # forward
_, predictions = torch.max(outputs, 1)
loss = loss_function(outputs, labels)
loss.backward() # backward
optimizer.step()
current_loss += loss.item() * inputs.size(0) # statistics
current_acc += torch.sum(predictions == labels.data)
total_loss = current_loss / len(data_loader.dataset)
total_acc = current_acc / len(data_loader.dataset)
print('Train Loss: {:.4f}; Accuracy: {:.4f}'.format(total_loss, total_acc))
我们将运行大约 100 个 epoch 的训练,但您可以将其缩短到 20 或 30 个 epoch 以进行快速实验。使用默认训练集,一个 epoch 通常需要不到一分钟的时间。现在我们已经熟悉了训练,让我们看看如何在我们的模拟环境中使用代理 NN 来驾驶赛车。
我们将从实现nn_agent_drive 允许代理玩游戏的功能开始(在https://github.com/PacktPublishing/Advanced-Deep-Learning-with-Python/blob/master/Chapter11/imitation_learning/nn_agent 中定义。 py )。该 函数 将以初始状态(游戏帧)启动环境。我们将使用它作为网络的输入。然后,我们将 softmax 网络输出从 one-hot 编码转换为基于数组的动作,并将其发送到环境以进行下一步。我们将重复这些步骤,直到剧集结束。该功能还允许用户通过按Escape 退出。请注意,我们仍然使用与训练相同的转换。 env nn_agent_drivedata_transform
首先,我们将实现初始化部分,它绑定Esc键并初始化环境:
def nn_agent_drive(model: torch.nn.Module, device: torch.device):
env = gym.make('CarRacing-v0')
global human_wants_exit # use ESC to exit
human_wants_exit = False
def key_press(key, mod):
"""Capture ESC key"""
global human_wants_exit
if key == 0xff1b: # escape
human_wants_exit = True
state = env.reset() # initialize environment
env.unwrapped.viewer.window.on_key_press = key_press
接下来,我们将实现主循环,其中代理(车辆)获取一个action,环境返回新的state,等等。这种动态反映在无限while循环中(请注意缩进,因为这段代码仍然是 的一部分nn_agent_play):
while 1:
env.render()
state = np.moveaxis(state, 2, 0) # channel first image
state = torch.from_numpy(np.flip(state, axis=0).copy()) # np to tensor
state = data_transform(state).unsqueeze(0) # apply transformations
state = state.to(device) # add additional dimension
with torch.set_grad_enabled(False): # forward
outputs = model(state)
normalized = torch.nn.functional.softmax(outputs, dim=1)
# translate from net output to env action
max_action = np.argmax(normalized.cpu().numpy()[0])
action = available_actions[max_action]
action[2] = 0.3 if action[2] != 0 else 0 # adjust brake power
state, _, terminal, _ = env.step(action) # one step
if terminal:
state = env.reset()
if human_wants_exit:
env.close()
return
我们现在拥有运行程序的所有要素,我们将在下一节中进行。
最后,我们可以运行整个事情。完整代码可在Advanced-Deep-Learning-with-Python/main.py at master · PacktPublishing/Advanced-Deep-Learning-with-Python · GitHub获得。
以下 代码 段构建和恢复(如果可用)网络、运行训练并评估网络:
# create cuda device
dev = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# create the network
model = build_network()
# if true, try to restore the network from the data file
restore = False
if restore:
model_path = os.path.join(DATA_DIR, MODEL_FILE)
model.load_state_dict(torch.load(model_path))
# set the model to evaluation (and not training) mode
model.eval()
# transfer to the gpu
model = model.to(dev)
# train
train(model, dev)
# agent play
nn_agent_drive(model, dev)
虽然我们无法在此处显示代理的运行情况,但您可以按照本节中的说明轻松查看它的运行情况。尽管如此, 我们可以说它学得很好,并且能够定期(但并非总是)在赛道上跑完整圈。有趣的是,网络的驾驶风格与生成数据集的操作员的风格非常相似。这个例子还表明我们不应该低估监督学习。我们 能够 用一个小数据集创建一个表现不错的代理,并且训练时间相对较短。
至此,我们结束了我们的模仿学习示例。接下来,我们将讨论一种更复杂的驾驶策略算法,称为 ChauffeurNet。
在本节中,我们将讨论最近发表的一篇名为ChauffeurNet:通过模仿最佳和综合最差来学习驾驶( https://arxiv.org/abs/1812.03079 ) 的论文。它由 AV 领域的领导者之一 Waymo 于 2018 年 12 月发布。让我们看一下ChaffeurNet模型的一些属性:
我们将从输入和输出数据表示开始讨论 ChauffeurNet。
端到端方法将原始传感器数据(例如,相机图像)提供给 ML 算法 (NN),进而生成驾驶策略(转向角和加速度)。相比之下,ChauffeurNet 使用我们在AV 系统的组件部分中介绍的中级输入和输出。让我们先看看 ML 算法的输入。这是一系列自上而下(鸟瞰)视图的 400 × 400 图像,类似于CarRacing-v0环境图像,但要复杂得多。 时间t的 一个时刻由多个图像表示,其中每个图像都包含环境的不同元素。
我们可以在下图中看到一个 ChauffeurNet 输入/输出组合的示例:
让我们按字母顺序查看输入元素((a)到(g)):
这里,I是所有前面的输入图像,pt 是时间t的代理位置,δt 是 0.2 s 的时间增量。δt的值是任意的,由论文作者选择。一旦我们有了t+δt,我们就可以将它添加到过去的轨迹 (g) 中,并且我们可以使用它在步骤t+2δt以循环方式生成下一个位置。新生成的轨迹被馈送到车辆的控制模块,该模块尽力通过车辆控制(转向、加速和制动)来执行它。
正如我们在AV 系统的组件部分中提到的,这种中级输入表示允许我们轻松使用不同来源的训练数据。它可以通过融合车辆传感器输入(如摄像头和激光雷达)和地图数据(如街道、交通信号灯、交通标志等)从现实世界的驾驶中生成。但我们也可以在模拟环境中生成相同格式的图像。这同样适用于中级输出,其中控制模块可以连接到各种类型的物理车辆或模拟车辆。使用模拟可以从现实世界中很少发生的情况中学习,例如紧急制动甚至碰撞。为了帮助代理了解这种情况,论文的作者使用模拟明确地合成了多个罕见的场景。
现在我们已经熟悉了数据表示,让我们将注意力转移到模型的核心组件上。
下图说明了ChauffeurNet 模型架构:
首先,我们有 FeatureNet(在上图中,这由 (a) 标记)。这是一个带有残差连接的 CNN,其输入是我们在输入和输出表示部分中看到的自上而下的图像。FeatureNet 的输出是一个特征向量F ,它代表了合成网络对当前环境的理解。该向量作为循环网络 AgentRNN 的输入之一,它迭代地预测驾驶轨迹中的连续点。假设我们想在步骤k预测智能体轨迹的下一个点。在这种情况下,AgentRNN 具有以下输出:
ChauffeurNet 还包括一个附加记忆,用M表示(在上图中,用 (b) 标记)。M是我们在输入和输出表示部分中定义的单通道输入图像 (g) 。它表示过去步骤k的航路点预测 ( p k, p k-1 , ...., p 0 ) 。当前航路点p k 在每一步都被添加到内存中,如上图所示。
输出p k 和B k作为下一步k+1的 AgentRNN 的输入递归地反馈。AgentRNN 输出的公式如下:
接下来,让我们检查一下 ChauffeurNet 如何在顺序 AV 管道中集成:
该系统类似于我们在AV 系统组件部分介绍的反馈回路。让我们看看它的组成部分:
ChauffeurNet 是一个相当复杂的系统,所以现在让我们看看如何训练它。
ChauffeurNet 使用模仿监督学习训练了 3000 万个专家驾驶示例。模型输入是我们在输入和输出表示部分中定义的自上而下的图像,如下面的扁平(聚合)输入图像所示:
最好以彩色方式查看图像。来源:https : //arxiv.org/abs/1812.03079
接下来,我们看一下ChauffeurNet训练过程的组成部分:
ChauffeurNet 训练组件:(a) 模型本身,(b) 附加网络,以及 (c) 损失。来源:https : //arxiv.org/abs/1812.03079
我们已经熟悉了ChauffeurNet 模型本身(在上图中标记为 (a))。让我们关注该过程中涉及的两个附加网络(在上图中标记为(b)):
来源:https : //arxiv.org/abs/1812.03079
这些网络不 参与 最终的车辆控制,仅在训练期间使用。使用它们的目的是,与简单地从 AgentRNN 获得反馈相比,如果 FeatureNet 网络从树任务(AgentRNN、Road Mask Net 和 PerceptionRNN)接收反馈,它将学习更好的表示。
现在,让我们关注各种损失函数(ChauffeurNet 模式的底部 (c))。我们将从模仿损失开始,它反映了未来智能体位置的模型预测与人类专家基础事实的不同之处。以下列表显示了AgentRNN输出及其相应的损失函数:
这里,W和H是输入图像的尺寸,是预测的热图,是地面实况热图。
该论文的作者还介绍了过去的运动丢失。我们可以通过引用论文来最好地解释这一点:
他们还观察到,当驾驶情况与专家驾驶训练数据没有显着差异时,模仿学习方法效果很好。但是,代理必须为许多不属于训练的驾驶情况做好准备,例如碰撞。如果代理只依赖于训练数据,它将不得不隐式学习碰撞,这并不容易。为了解决这个问题,本文针对最重要的情况提出了明确的损失函数。其中包括:
在本章中,我们探讨了深度学习在 AV 中的应用。我们从对 AV 研究的简要历史概述开始,并讨论了不同程度的自治。然后我们描述了 AV 系统的组件,并确定了何时适合使用 DL 技术。接下来,我们研究了 3D 数据处理和 PointNet。然后我们介绍了使用行为克隆实现驾驶策略的主题,并使用 PyTorch 实现了一个模仿学习示例。最后,我们查看了 Waymo 的 ChauffeurNet 系统。