深度学习方法,在复杂的场景中具有出色的性能。深度学习中的卷积神经网络(CNN),在计算机视觉领域中尤为重要,很多最新方法都使用CNN进行特征提取。语义分割方法也经常用于车道检测,以推断车道的形状和位置。这些方法还可用于区分整张图像上像素的实例和标签。本节将以论文 [56] 中的内容为例,并结合代码来进行分析和讨论。
假设预测的车道上的准确点小于输入像素大小,并将点区分为每个实例。在论文 [57] 中,将沙漏网络(Hourglass Network)应用于关键点估计领域(例如,姿态估计和对象检测)。沙漏网络可以通过下采样和上采样的序列来提取有关各种比例的信息。如果将一些沙漏网络堆叠起来,则可将损失函数应用于每个堆叠的网络,此举有助于更稳定地训练。在计算机视觉领域中,通过实例分割方法能生成属于每个实例的像素簇。
对于训练用于车道检测的神经网络,该网络(通常称为PINet,或点实例网络)在整个通道上生成“点”,并将点区分为每个实例。该网络的损失函数的思想来自SGPN(Similarity Group Proposal Network) [58] ,后者是3D点云的实例分割框架。与计算机视觉领域中的其他实例分割方法不同,在上述所提出的方法中,仅预测点而非所有像素都需要嵌入。在这方面,3D点云实例分割方法便适合处理这里的任务。另外,简单的后处理方法适用于网络的原始输出。由此可见,后处理消除了每个预测点的异常值,并使每个车道更加平滑。
PINet生成点并将其区分为每个实例。PINet输入大小为512×256,并将其传递到调整大小层(Resizing Layer)和特征提取层。卷积层和最大池化层的序列,将512×256大小的输入数据压缩为较小的规模。在此项研究中,作者尝试了两种调整输入大小的情况:64×32和32×16。特征提取层的思路来自堆叠的沙漏网络,该网络在关键点预测方面实现了优良的性能。PINet还包括两个用于功能提取的沙漏块,其中每个块都具有3个输出分支,并且输出网格的大小与调整后的输入大小相同。
图3-2显示了沙漏块和瓶颈层(Bottleneck Layer)体系结构。图中,深灰色框表示下采样瓶颈层,浅灰色框表示相同瓶颈层,而黑色框则表示上采样瓶颈层。沙漏网络中的调整大小层和每个瓶颈层的详细信息,可以在图3-3中看到。批处理归一化和ReLU层在每个卷积层之后应用,除非它们在输出分支的末尾应用。
图3-2 沙漏块和瓶颈层体系结构 [56]
图3-3 沙漏网络的具体信息
下面结合代码看一下网络结构。首先看调整大小层,其包括卷积层、最大池化层和瓶颈层。
代码3-6 调整大小层
在网络中,采用了输入和输出同样大小的瓶颈层,每一个瓶颈层都由3个卷积层和1个残差卷积层组成。具体代码如下:
代码3-7 相同瓶颈层
一个瓶颈层主要由3个卷积层和1个残差卷积层组成。上采样瓶颈层的代码如下:
代码3-8 上采样瓶颈层
下采样瓶颈层的代码如下:
代码3-9 下采样瓶颈层
最后,沙漏网络结构的代码如下:
代码3-10 沙漏网络结构
输出分支中的滤波器数量,由输出值确定。例如,置信度分支为1,偏移分支为2,特征分支为4。下面将详细介绍每个输出分支的作用和损失函数。
置信度分支的功能在于预测每个网格的置信度值。置信度分支的输出只有一个通道,并将其传递到下一个沙漏块,有助于训练的稳定性。置信度分支的损失函数可定义如下:
式中, N e 与 N n 分别表示点存在和不存在的网格数, G 表示网格数, g c 表示网格中的置信度输出, 表示真实值, γ 为系数。
代码3-11 置信度损失函数计算
从偏移分支中可以找到每个点的确切位置。偏移分支的输出值在0和1之间,用于表示与网格相关的位置。这里根据输入大小和输出大小之间的比率,将网格匹配为8或16个像素。偏移分支具有两个通道,用于预测 x 轴偏移和 y 轴偏移。偏移分支的损失函数可定义如下:
代码3-12 偏移损失函数计算
特征分支的思路来自SGPN(一种3D点云实例分割方法)。该特征包含有关实例的信息,并且对分支进行了训练,以使同一实例中的网格特征更加接近。特征分支的损失函数可定义如下:
式中, G ij 用于表示点 i 和点 j 是否属于相同的实例, F i 表示提议网络对点 i 的预测特征; G ij =1表示点 i 和点 j 属于相同的实例; G ij =2表示点 i 和点 j 属于不同的实例。在训练网络时,如果损失函数在两个点属于同一实例,则特征更接近;反之,当两个点属于不同的实例时,两者相距较远。因此,可通过距离的远近等简单聚类技术,将点区分为每个实例。这里将特征尺寸设置为4,观察到该尺寸对性能没有重大影响。
代码3-13 特征损失函数计算
显然,总损失函数 L total 等于上述三个损失函数的总和,并且使用以下损失函数,通过端到端过程训练整个网络。
代码3-14 总损失函数计算
网络的原始输出可能存在一些错误。原则上,一个实例只应该包含一个平滑的车道。然而,对于有些离群值或其他通道,可以从视觉上进行区分。后处理方法的步骤如下:
(1)找到6个起点(将起点定义为3个最低点和3个最左的点或最右的点)。如果预测车道位于与图像中心相关的点的左侧,则选择最左的点。
(2)在高于每个起点的点中选择3个最接近起点的点。
(3)考查一条直线,将在第1步和第2步中选择的两个点连接起来。
(4)计算这条直线与其他点之间的距离。
(5)计算边界内的点数。这里将边距γ设置为12。
(6)选择最大计数和大于阈值的点作为新起点,并认为该点与起点属于同一簇。将阈值设置为剩余部分的20%。
(7)重复第2步至第6步,直到在第2步中无点可找为止。
(8)对所有起点重复第1步至第7步,并将最大长度的群集视为结果车道。
(9)对所有预测车道重复第1步至第8步。
代码3-15 直线提取的后处理
使用Adam优化器,在TuSimple数据集的训练集上训练网络,初始学习率为2e-4。在最初的1000个迭代周期内,使用初始设置来训练网络,并且在最近的200个周期内,将学习率设置为1e-4。其他超参数(例如,后处理的边距大小)由实验方法确定。对于这些超参数的优化值,需要根据训练结果稍做修改。不使用任何其他数据集和预先训练的权重,并评估两种大小不同的输出,即64×32和32×16。训练使用的硬件为NVIDIA RTX 2080Ti。
本章的参考代码是在TuSimple数据集上开发的,可从GitHub上下载数据集(地址见“链接4”。
本书提供了训练好的模型,并将其保存在savefile目录中,读者可运行test.py进行测试。注意,它具有类似于以下功能的模式。
● 模式0:可视化测试集上的结果。
● 模式1:在给定的视频上运行模型。如果使用此模式,则可在test.py中修改输入视频的路径。
● 模式2:在给定的图像上运行模型。如果使用此模式,则可在test.py中修改输入图像的路径。
● 模式3:在整个测试集上测试模型,并将结果保存为JSON文件。
读者可以在parameters.py中更改模式。
如果读者通过“模式3”运行test.py,则将生成test_result.json文件。读者可以只通过运行evaluation.py来对其进行评估。在test.py中,以下3行用于后处理。如果不进行后处理,则可注释掉这3行。
在上述研究过程中,论文作者提出了一种结合点估计和点实例分割方法的新型车道检测方法,它可以实时运行。另外,此方法还实现了最低误报率,并保证了自动驾驶汽车的安全性能,因为很少发生错误预测车道。实验结果表明,后处理方法显著提高了车道检测模块的性能。然而,当前实现的版本需要大量的计算开销,作者希望可以通过并行计算或其他优化技术来解决此问题。