背景故事: [我们遇到的问题][使用的方法][困难]
我们经常会遇到这样的问题,如果我们做了一个小车,希望它能够智能地沿着路走,避开行人和车辆,那么,我们就会想办法检测马路线,检测行人。传统的CV方法是输入摄像头的图像,然后使用滤波器过滤,大体流程是灰度转换+降噪+边缘检测+蒙版+霍夫线变换,最终只保留下车道线的像素,后续还需要相机参数做变换,才能得到车道线的真实长度。

图表 2—基于传统CV的车道线检测
https://blog.csdn.net/qq_45199760/article/details/121453338对于车道线检测,因为其特征比较明显,所以会有不少成功的案例,但是对于行人检测,传统的CV算法几乎是不可能的,因为行人的特征多种多样。其实推广来讲,CV的车道线检测也面临着同样的问题。受光照影响,晚上,傍晚,车道线的颜色会不一样。受地域影响,不同地区的车道线会不一样。受天气影响,下雨的时候雨水会覆盖反光。总结来说,流程都是先基于人工的总结一种特征,然后再实现一种算法来进行检测,这就是特征工程。

图表 3—不同天气和光照条件下的边缘检测
到后来,有了神经网络,我们不再需要很复杂的特征提取算法,因为神经网络会自动在训练中找到这种特征。比如Anchor3DLane,这种基于卷积神经网络的自动车道线识别,输出的还是3D的车道线,这样一来是后续的处理压力小了,也不需要我们专门地设计什么滤波器。

图表 4—Anchor3DLane网络结构图,输入2D图像+相机内参,输出3D车道线
目前,神经网络已经是自动驾驶领域中不可或缺的算法,依据车辆使用的传感器不同,又分为纯视觉/纯雷达/视觉+雷达融合等不同的方向。对于纯视觉方向,较为经典的是MonoDLE。这是一个由2D卷积网络作为骨干(特征提取)+ 多个2D卷积作为检测头(多任务)的深度神经网络。(很抱歉,并没有网络结构图,作者没画)
对于视觉+雷达融合方向,22年时流行的是BEV鸟瞰图方案。将四周的各个摄像头信息先变换到鸟瞰图空间,然后与雷达点云做融合,最后再使用检查头进行目标检测。
特斯拉给出的方案是OCC,也就是占用网络,可以形象地理解为《我的世界》中的体素化格式。

图表 5—环绕相机+雷达点云融合检测示意图(BEV)
需要注意的是,算法的发展必然受制于算力,OCC网络近年来是越来越火了,但是因其比2D多一个维度,参数量也是成倍地增长。不少企业仍然在追寻纯视觉的检测方案(如特斯拉),最简单的就是一个摄像头实现所有功能,称为单目检测,但是只使用一个摄像头有着天然的计算缺陷,如不能获取准确的深度信息。所以后续的更多方案选择了多摄像头的环绕覆盖。

图表 6—基于OCC的目标检测(纯视觉)
在我们的实践中,总是会遇到各种问题,总的来说是这样的:环境管理问题,数据格式问题,实验参数问题。
许多代码仓库在作者发表论文后就销声匿迹,不再更新维护,而作者当年使用的各种软件包很可能是未标明的,也导致我们需要经常地去“考古”,依据他发布的时间去推测当年使用的版本。其中最具有代表性的就是mmcv系列,这是一个广受欢迎的通用的神经网络框架,用于2D/3D目标检测,自动驾驶领域。而早期的mmcv系列对环境的要求比较严格。具体来说,我们在尝试复现一个代码时,他很可能是基于mmcv系列修改而来,那么我们就需要首先确定这个mmcv版本对应的pytorch版本,而pytorch版本需要先匹配一下当前的CUDA版本,而CUDA版本需要注意一下目前的GPU型号,举个例子:H800这个显卡是大陆特供版,CUDA算力是9.0,意味着CUDA至少要在11.8以上,而pytorch在2.X版本以后才提供11.8的支持,那么对应的mmcv版本就需要大于2.XX,如果这时候我们拿到一个代码,他使用的是MMCV==1.4.0这个版本,那么我们就没法在H800上跑起来。
数据格式问题其实并不是非常严重,因为我们通常使用同一个公开数据集进行测试,但是不免有一些特立独行的代码。
实验参数问题其实可以理解为可复现问题,因为神经网络训练的特点,每次更新参数时可能都会有一些随机扰动,这个随机扰动可能是出现在数据集加载器(将会在2.3节中讨论)的输入顺序,底层随机数产生器的种子,CUDNN的优化选择路径不同等等,所以很多人会将训练一个神经网络比作“炼丹”,训练的好坏有相当一部分的玄学因素。
我们花了相当多的时间在解决这些问题上,也是在这个过程中,我们逐渐对整个神经网络工程产生了一些基本认识,让我们对未来的工程项目有了一些基本设计,期望能够减少人们的痛苦,加快工作效率。所以,我们将在下节详细讲述我们的理解。