过去几个月,我对自动驾驶汽车技术非常感兴趣。你可以将机器学习知识应用于开发自动驾驶汽车堆栈的各个部分,这有无数种可能性。
在这篇文章中,我将带您了解为自主机器人开发端到端运动规划器的过程。这个项目深受 comma.ai在 open pilot 中使用的方法的启发。
自动驾驶的不同方法 开发自动驾驶汽车软件的方法有很多种。模型可以采用端到端训练,也可以采用中间到中间方法训练。以下是一些示例:
图像输入,控制输出
来自 Lyft 的 2020 年运动预测挑战赛
这种方法的缺点是,错误会通过多个步骤不断累积,将所有部分组合在一起会变得困难得多。但另一方面,优点是,这个过程完全可以被人类解释,并且可以轻松推理自动驾驶汽车的决策。除此之外,现在还可以结合先验知识。
理解超级组合模型
超级组 合模型制作精良,但重量轻,其输入如下:
2 个 连续的 YUV 格式图像帧
循环 细胞
的状态(循 环神经网络)
欲 望(稍后讨论)
并预测以下输出:
路径(要遵循的轨迹输出)
左车道
右侧车道
路径和车道的标准偏差(如下所述)
领先车辆信息
未来 n 步的纵向加速度、速度和位移
姿势(如下所述)
还有一些我不太确定的东西
路径、左车道和右车道是相对于本车辆的“预测轨迹 ”和自上而下/鸟瞰坐标系中的车道线 。
超级组合的路径和车道输出 看看模型如何预测右侧道路的曲线。
这里要注意的另一件事是,当看不到车道线时,或者当模型对其预测不太有信心时,车道线也会消失。这个“信心”分数基本上也是由模型预测的,只是“标准偏差”。这些标准偏差是针对每条路径、左车道和右车道以及许多其他输出(包括姿势、领先输出等)预测的。
可以使用贝叶斯神经网络来预测标准差,该网络在计算预测时将不确定性传递到整个网络。
姿态输出是两个输入图像之间预测的平移和旋转。这可能用于执行视觉里程计并根据输出轨迹定位汽车。
数据创建
在考虑训练神经网络之前,我们需要收集数据并将其处理成适合训练的格式。Comma.ai 发布了开源数据集,其中包含大量此类信息,如车道、路径和其他内容。但我想要更多的挑战,所以决定使用 Udacity 的数据集,它只包含:
转向角
速度
陀螺仪读数
GPS 读数
来自中心、左侧和右侧安装的摄像机的图像框架。
为了训练自定义模型,我决定只预测未来的路径和速度。
欲望
希望基本上对高级动作进行独热编码,例如“左变道”、“右变道”、“保持在车道内”、“右转”、“左转”等。
Udacity 数据集不包含任何“愿望”。因此需要手动标记 10,000 帧 :(
手动标记 10,000 个帧并不容易。因此,我没有单独标记每个帧,而是为此创建了一个小工具 Autolabler
。
使用这个,我的朋友 Raghav 在 30 分钟内标记了整个数据集。它更像是一个小型视频播放器,您可以根据需要暂停、搜索、快进、减慢输入帧流。它会在播放流时不断动态标记所选标签。有关使用它的完整说明可以在我的 repo 中找到。
小路 对于轨迹地面实况,我只能使用 udacity 数据集中存在的信息。
首先,我使用了一个简单的自行车模型,通过速度和转向角输入到车辆模型中,随着时间的推移,该模型逐渐变化。
在低速时,使用以质心为参考系的简单自行车模型。
以汽车重心为参考的自行车模型
模型参数
我本可以使用动态模型进行横向控制,但我实际上没有用于收集数据集的车辆参数数据。
现在,可以肯定的是,上述模型非常简单,无法很好地模拟车辆的实际物理特性,因此使用来自陀螺仪和 GPS 的额外数据并将其与卡尔曼滤波器融合在一起绝对有意义。此外,开发算法的另一条规则是,永远不要丢弃任何数据,即使它非常嘈杂。找到整合来自其他数据源的任何信息的方法。这只会改进算法。
幸运的是,GPS 模型是已知的,所以我能够构建卡尔曼滤波器。
不同的跟踪方法的实际应用
观察一段时间后过程模型(红色)如何开始偏离原始轨迹。
我使用了 3 种跟踪方法,并使用卡尔曼滤波器将它们结合在一起。
自行 车模 型作为流 程模式
G PS 读数
基 于 IMU 的里程计
视 觉里程计
我发现的一个困难是确保所有读数都转换为具有相同参考(汽车)的同一坐标系。例如,对于 GPS 读数,必须将纬度和经度转换为以米为单位的 XY 网格系统。
对于较小的距离,我使用以下公式作为近似值来找到两个纬度经度对之间的距离(以米为单位)。纬度和经度基本上是地球仪上(角度)相对于赤道和本初子午线的测量值。
def latlon_to_xy_grid(lat1, lon1, lat2, lon2):
dx = (lon1-lon2)*40075*math.cos((lat1+lat2)*math.pi/360)/360
dy = (lat1-lat2)*40075/360
return dx, dy
现在,为了收集额外的数据,包括避开障碍物、急转弯和“汽车偏离车道”问题等情况,我使用了 CARLA 模拟器。
紧密的曲线
由于我掌握了用于收集 udacity 数据集的相机的参数,因此我能够在 CARLA 中设计类似的相机模型。从 CARLA 获取真实数据相对容易。
此外,为了避开障碍物,我编写了一个脚本,该脚本可以创建一个场景,将车辆放置在车道边缘,并使用 CARLA 自动驾驶仪生成轨迹以避开障碍物。编写脚本几分钟后,我就有了数千个此类场景。这实际上可能会使模型在现实生活中变得更糟,因为这可能与人类在现实生活中实际做的事情并不接近。
呃,看上去不错?
CARLA 将数据直接保存到磁盘的方式存在一些问题。这导致模拟器速度大幅下降,无法手动控制汽车,也导致数据收集过程变慢。
因此,我必须编写手动缓冲区,以便不断积累数据,直到达到一定大小,然后立即将其转储到磁盘。这极大地提高了数据收集过程的效率。
从数据集中采样的一组轨迹
现在数据收集过程终于完成了。让我们开始模型训练吧!
分析超级组合模型
特征提取器的一部分
对于从帧中提取特征,超级组合使用了大量跳过连接并转换 256 x 128 x 12(两个 YUV 格式的连续帧,带有 3 个额外的 alpha 通道。 参见此处 )并将它们归结为 1024 维编码。
一旦训练路径规划器,这种编码就会从图像中学习所有信息。
博客文章
“通过在图像上运行视觉模型并尝试使用 GAN 从中重建图像,我们可以深入了解视觉模型的 1024 个输出向量中编码的内容。上图是道路的原始图像,下图是通过几百万张图像和特征向量训练的 GAN 进行的重建。请注意,与规划相关的细节(例如车道和领头车的位置)是如何保留的,而无关的细节(例如汽车的颜色和背景风景)则丢失了。”—— Harald Schäfer
该模型学习将规划所需的所有相关信息编码为压缩形式。此视觉编码随后被分成几个分支,这些分支被独立处理以输出车道、路径等。
分叉成分支
Super Combo 还使用类似 GRU 的层来编码时间信息。网络是有状态的,循环层的状态输出在下一次推理期间被重新输入。
训练模型
为了训练模型,我将以愿望和帧作为输入(RNN 状态仅在推理时间内提供),输出仅仅是未来 50 米/步的路径和速度以及标准差。
贝叶斯神经网络
标准差让我们了解模型对其预测的信心程度。这可以使用一种称为贝叶斯神经网络的特殊网络来实现。
我们不会直接回归车道、路径和速度,而是预测分布。
来源 — https://www.youtube.com/watch?v=z7xV-HYVAZ8
请观看 AI 学生的这段 视频 ,了解对此的精彩解释。
我们可以使用混合密度网络来输出多条路径及其置信度分数,将其转换为混合密度网络。
输出多个高斯分布及其分数、alpha。
我使用批量大小为 16 且包含过去的 16 个时间步骤以及 2 个高斯混合来训练网络。
数据增强
我使用数据增强来使模型对噪声具有鲁棒性。这些包括向图像添加泊松噪声、打乱图像的颜色通道、水平翻转图像、增加/减少图像的对比度、温度等。
数据增强
损失函数
简单点输出(无不确定性 预测):在实际应用中,我们最小化线性函数 μ 的输出的平方误差项 ( μ( x , Θ )− y )²,给定x、其参数Θ和某个数据集 𝔻 中所有 ( x , y ) 对的目标值y。学习函数本质上是在给定数据和参数的情况下“输出”高斯分布 μ( x , Θ ) 的条件均值。它会丢弃与Θ无关的标准差和归一化常数。
我尝试了多种损失函数。对于简单回归输出(如上所述)(简单神经网络,无标准偏差输出),我使用了轨迹之间的 L2 损失和轨迹梯度之间的 L1 损失的加权和。
梯度损失背后的直觉是,我们人类会根据道路上的曲线来估计转动方向盘的“强度”。因此,将其纳入损失函数是有意义的,结果发现它比“仅在轨迹之间使用简单的 L2”表现更好。
MDN 网络:在这种情况下,标准差现在取决于输入,这使我们能够考虑可变的标准差。即使我们只使用单个高斯分布,这一优势也适用。
对于 MDN(也预测标准差),损失计算如下
cat = tfd.Categorical(logits=out_pi)
component_splits = [output_dim] * num_mixes
mus = tf.split(out_mu, num_or_size_splits=component_splits, axis=1 ) sigs = tf.split(out_sigma, num_or_size_splits=component_splits, axis=1 )
coll = [tfd.MultivariateNormalDiag(loc=loc, scale_diag=scale) for loc, scale in zip(mus, sigs)]
mixture = tfd.Mixture(cat=cat, components=coll)
loss = mixture.log_prob(y_true )
loss = tf.negative(loss)
loss = tf.reduce_mean(loss)
我使用了来自这个 repo 的实现
(https://github.com/cpmpercussion/keras-mdn-layer) 。
测试 看看网络如何输出均值(实际路径)和偏差。
最初,模型对预测很有信心,偏差也很低,但随着模型预测未来的轨迹,偏差会增加,这是直观的。
甚至 openpilot 模型也表现出类似的行为。
原始 openpilot 模型中的路径和车道
看看模型 在较短距离时如何相当自信,但在较远距离时预测会变得更加嘈杂和不稳定。
我会进行更严格的测试,并很快会发布一个模型运行的视频,既适用于现实生活,也适用于合成数据。现在我们有了轨迹输出,在下一篇文章中,我们可能会讨论如何将轨迹实际转换为控制并控制模拟汽车。但这将需要做很多工作。但让我们尝试一下 吧:D
结论 恭喜你读到了最后!这是一篇很长的文章。
因此,这是我训练端到端路径规划器的旅程,这在很大程度上受到了 comma.ai 工作的启发。我想感谢 comma.ai discord 社区解答了我的许多疑问。我不保证这篇文章中的所有内容都是正确的。请随时指出您可能发现的任何错误,并通过下面的评论来帮助纠正它们。
我在这个项目中探索了很多东西。我并没有在这篇文章中深入讨论太多细节,因为我错过了写我在这个项目中遇到的很多挑战。下次,我会尝试将这篇文章并排写出来,这样我就不会忘记添加任何东西。
更多信息请参见原文地址:
https://mankaran32.medium.com/end
-to -end -motion-planning-with -deep-learning-comma-ais-approach-5886268515 d3