《MLND Capstone Project Report》翻译
文章原文链接来自GitHub项目,MLND Capstone Project Report.pdf
深度学习车道线检测项目概述
车道保持是驾车时最常见的任务之一,尽管它在人类驾驶汽车时经常使用而被忽视。只要一个人没有分心、醉酒或者残疾,大多数人经过基本训练就能做到这一点。然而,对人们来说很简单任务,对电脑来说是一个很难解决的问题。
为什么对电脑来说这么困难?首先,计算机本身并不能理解道路上的黄色和白色条纹是什么,它们之间的像素值的变化,以及在视频提要中代表道路的像素值。可行的操作是通过计算机视觉技术,包括相机校正(消除固有的变形相机使用),颜色和梯度阈值(图像的领域特定的颜色或颜色的变化集中),视角转换(类似于获得一只鸟眼中的路),等等,帮助计算机学习的检测这些线或车道。
深度学习涉及到利用多层神经网络,利用数学特性将预测与实际情况的损失最小化,在数据上进行训练时有效地学习,以达到最终的模型。
为什么这很重要
你可能觉得全自动驾驶的汽车没有必要直接检测车道线——汽车可能会学到那里有不能越过的边界线,但不会认为这和其他的边界有什么不同。如果我们直接跳到全自动驾驶汽车,这应该是对的,但是对于大多数消费者,他们更可能看到一步一步的改边,向他们展示(可能是在车内的屏幕上),汽车总是能感应到车道,这将会让他们在为他们驾驶的电脑上感到舒适。即使是这样,增强的车道检测也能提醒粗心的司机从他们的车道上越过时。
问题陈述
人们在完全专注的时候,在大多数驾驶条件下,都能很好地识别车道上的标记。计算机天生就不擅长做同样的事情。然而,人类有一个缺点,那就是能始终保持专注(无论是因为改变收音机、与另一个乘客交谈、疲劳、受影响等等),而电脑却不受这种影响。因此,如果我们能训练一台计算机在检测线线时能像人一样好,因为它已经明显地更好地集中注意力了,计算机就可以从人类司机那里接管这项工作。通过深入学习,我将培训一个比最初的基于计算机视觉的模型更健壮、更快速的模型。这个模型将基于一个叫做卷积神经网络的神经网络架构,简称CNN,它在图像数据上表现良好。这是一个很棒的架构候选,因为我将从驱动视频中输入模型帧来训练它。CNNs可以很好地处理图像,因为它们首先寻找像素级的模式(彼此之间的像素组),在图像的更大范围内发展成更大更大的模式。
评价标准
正如将在分析部分中进一步解释的那样,我在这个项目中最初的方法是教一个CNN计算线的多项式系数,然后根据这些线画出车道区域。这种方法,类似于回归类型的问题,使用均值-平方误差来最小化损失是有意义的,这意味着实际系数和模型预测之间的差异(MSE使用所有平方差异的平均值来计算损失)。我使用的最后一种方法也使用了MSE,因为我使用了一个完全卷积神经网络(即一个没有任何完全连接层的网络)来生成绿色的通道,以便绘制到原始图像上。在这里使用MSE意味着最大程度地减少输出通道图像的预期像素值和lane图像标签之间的损失。我还将直接根据我最初的纯计算机视觉模型来评估它的准确性和速度,以及比我的基于cvi的模型能够做的更有挑战性的视频。
分析
数据集以及输入
我在这个项目中使用的数据集是我从智能手机上拍摄的视频图像帧。这些视频是在水平/横向模式下拍摄的,在y轴上有720个像素,在x轴上有1280个像素,30 fps。为了减少训练时间,训练图像被缩小到80个像素点(一个稍微不同的方面比开始,主要是因为它使得在最后的CNN架构中更深入地进行适当的计算变得更容易了)。为了计算原始标签,它们是6个系数(每条线的3个系数,作为多项式拟合的系数),我还必须先做一些基本的计算机视觉技术。我必须用OpenCV来执行图像校准,以修正我的相机固有的失真,然后使用透视变换把道路线放在平面上。
最初,我想让模型更健壮我的原始模型,通过绘制图像中的行线,它可以是模糊的,或者是淡出到图像的其他部分,在图像的后面。
我画了超过1,420个红色的透视变换图像,并为红色运行了一个二进制的颜色阈值,红色灰度值达到阈值将显示白色,红色值太低的地方,不会**,显示黑色。有了这个,我重新运行了原来的模型,修改了只输出了6个系数而不是lane的绘图,这样我就可以根据这些系数作为标签来训练网络。
然而,我很快发现,我所拥有的数据量是不够的,特别是因为大多数图像都是相当直的。所以,我重新在我所有的视频中运行了原始的CV模型,视频中有很多曲线。我还在一个有限的图像从常规项目视频(我想保存这些视频真正考验我的模型),是从我以前完成的项目Udacity’s SDC Nanodegree Advanced Lane Lines project中的视频,这样的模型可以从不同的相机学习一些失真。然而,这给我的数据集带来了一个复杂的问题——Udacity的视频需要一个不同的视角转换,这对重新绘制的车道产生了巨大的影响。稍后我将回到这个问题。
我最终得到了两条直线和各种曲线的混合,以及各种条件(黑夜与白天,阴影,雨与阳光),以帮助模型的整体概括。这些将有助于覆盖更多司机每天看到的真实情况。我将在以后讨论更多的图像统计数据,关于使用的全部训练图像,但是我提供了下面两张图表,关于从我自己的驾驶视频中获得的道路状况的百分比。
我之前提到的一个问题与原视频收集的是太多的数据来自直接道,虽然很不明显的从上面的图表曲线由43%的原始数据集,我起初认为这就足够了,我很快就找到了突破非常围绕直,可以看到在下面的图表标签的系数分布。这是一个需要解决的明确问题。
算法和技术
首先,我必须从我获得的视频中提取图像帧。接下来,我必须处理在制作标签时使用的图像,我将使用与我之前在计算机视觉模型中使用的相同的技术。接下来,我将用同样的摄像机拍下棋盘上的图像,并使用cv2对图像进行不失真的图像,来校准相机的变形使用cv2.findChessboardCorners和cv2.calibrateCamera。现在有了校正的图像,我会找到好的源点(车道线在底部的角落和地平线附近)和确定好目标点(图像转换出来的)角度变换图像(主要是通过哪种方法最好的猜测。当我有这些点时,我可以用cv2。得到一个变换矩阵和cv2。把图像转换成鸟瞰图。这段就是说从视频里截取图像帧,并通过OpenCV将透视图转换成鸟瞰图。
在此基础上,为了提高模型的鲁棒性,在不清晰的线线区域,我在每幅图像中画出了红线。在这些图像上,我将使用高红色值的图像区域的二进制阈值,这样返回的图像只具有红色线线绘制的值。然后,直方图上表现的垂直下降峰值(图像以来视角转换,直车道线会出现本质上完全垂直),分割出图像的中间,这样程序将寻找一个高点左边和右边的一个单独的高点。滑动的窗口可以搜索更多的二进制**,然后再用它来尝试跟随这条线。
滑窗检测的像素值,用numpy.polyfit进行拟合,拟合二次函数,也就是有三个系数,ax^2+bx+c,两个多项式拟合两条线,将6个系数作为模型训练的label。
在培训之前,我要检查标签是否准确。使用上面的标签,我可以通过原始的不失真和透视转换来提供图像,用numpy创建一个图像。从多项式系数中,通过计算每条直线上的完整多项式拟合方程,然后使用cv2.fillPoly,从而使lane点成为多项式系数。用这些来制作一幅画。使用cv2.warpPerspective用我的透视变换矩阵的逆矩阵来计算,我可以把这条线还原回原来图像的空间,然后使用cv2.addWeighted将图与原始图像合并。通过这种方式,我可以确保我为模型提供准确的标签。
使用Keras的TensorFlow后端,创建卷积神经网络,使用keras.models.Sequential,创建卷积层、全连接层,如下图,
评价基准
我计划比较CNN和我在SDC纳米学位项目中使用的基于计算机视觉的模型的输出结果(与上面的链接)。请注意,由于我的数据没有一个基本的事实,所以我不能直接从损失/精度的角度来比较这个模型,但是由于最终的结果是非常直观的,我将看到哪个模型产生更好的结果。部分原因归结于健壮性,我的纯CV模型在我之前的项目中,没有在前几秒的时间里生成线线。如果这个模型能够在挑战视频上取得成功(也就是说,如果没有显示出这条线的时间不超过几秒钟),如果没有对该视频的图像进行专门的训练,它将会超过这个基准。第二个基准测试的速度是模型的速度,基于cva的模型只能产生大约每秒4.5帧的速度,与30 fps的视频相比,它的速度要慢得多。如果视频的书写超过了4.5 fps,这个模型将超过这个基准。
方法实现
数据预处理
加上先前的图像数据,又采集雾天、雨天的数据和高速公路数据,检查图像质量并删掉三分之一。
30秒采集一帧图像会不会使得图像相似度太大,导致模型过拟合,所以在采集的图像中每隔10个取一幅作为训练数据。还发现滑窗代码无法检测。曲线还是少了,所以在隔5张图片取一张。
通过旋转图像等方式,增强数据,使系数更均匀。
在以前的模型找中,我才用透视变换的图像和常规道路图像,将720x1289x3的图像缩放到25x80x3,灰度化,添加第三个维度,并做归一化,使其更接近于零和标准偏差的平均值,这是机器学习的关键(算法倾向于更好地收敛)。
另一方面,当我变成一个完全卷积模型,我只是把图像缩减成80 x160x3(比原来的比例略有不同,但大致8 x缩减),没有任何进一步的灰度或归一化(我在批处理而不是标准化层在Keras帮助)。此外,由于完全的卷积模型本质上是返回另一个图像作为输出,而不是将我的lane标签保存为数字,我还在将它们与道路图像合并之前保存了生成的lane图。这些新的车道图像标签是我的数据的真实标签。我仍然使用我的图像旋转来生成额外的数据,但是也将lane图像标签和训练图像一起旋转(基于原始标签系数的分布)。我还添加了每个图像的水平翻转和相应的车道图像标签,使我的数据集增加了一倍。对于这些新的车道图像标签,我放弃了R和B的颜色通道,因为这条线是用绿色画的,希望通过较少的输出来提高训练的效率。
图片统计
- 从12段视频中取的21054张图片,包括一天中不同时段、天气、交通状况、和道路曲率
- 道路还存在困难的地方,如建筑和十字路口
- 可用的图片有14235张
- 以时间序列从这些图片中取1420张
- 227张图片还是不能用,总共1193张
- 另外568张图片(其中1636张)从更弯曲的线条中收集,以帮助获得更广泛的标签分布(每5个图片中就有1个来自更弯曲的视频;从8187帧)
- 总共有1761张原始图片
- 我从Udacity的高级巷线项目(帮助模型学习额外的相机的失真)中提取了一个更简单的项目视频——1 252帧,每5帧取一帧,总共250个,其中217个可以用于训练。
- 1978张图片用于训练
- 在图像原始分布的中心外,使用小旋转的图像,增加了4,404张图片。这是在从数据中心向外缓慢移动的三轮中完成的(因此,从分布中心向外移动的距离是多次旋转的)。在这一点上有6382张图片。
- 最后,我增加了每条道路图像及其对应标签的水平翻转,使图像总数增加了一倍。总而言之,总共有12764张图片用于训练。
实现
我的第一个CNN构建了使用的透视图,将图像转换为输入,并且可以在“perspect_NN.py”中看到。它使用了批处理标准化,四个卷积层,过滤器的数量在减少,接着是一个池化层、扁平层和四个全连接层,最后一个全连接层有6个输出,这是车道线的6个系数标签。每一层都使用了RELU**或整流线性单元,因为这个**被发现比其他**更快更有效。此外,为了防止过度拟合和增强鲁棒性,大部分连接加入了dropout正则化,并且使用Keras的ImageDataGenerator来增加图像,比如更多的旋转,垂直翻转和水平位移。我最初使用的是“均值-平方误差”计算loss,但我发现,“均值-绝对误差”实际上产生了一个可以处理更多曲线的模型。注意,在使用Keras工作之前,我还将培训数据和标签放入数组中。此外,我还对数据进行了调整,以确保不同的视频得到更好的表现,而且这个模型不会在某些视频上过拟合。最后一个是分成训练集和验证集,这样我就可以检查模型的执行情况。
在培训了第一个模型并创建一个函数来实际看到重新绘制的车道之后,我发现第一个模型是适度有效的,因为您使用的是从原始模型中进行的相同的透视图转换(请参阅这里的视频)。然而,我的最终目标是忽略了对CNN的整体形象进行透视的需要,所以在发现第一个模型在产生重新绘制的车道上是适度有效的之后,我改变了方向。在road_NN.py,这第二个模型包含在内。除了在常规的道路图像中进食,我对这个模型做出的唯一改变是添加了一个作物层,在这个层中,图像的前三分之一被移除(我用了一半或三分之一的时间没有太大的差别)。我很快发现,CNN实际上可以在没有透视转换的情况下学习lane系数,而得到的模型实际上更有效(见视频)。
如果我的模型预测的是车道标签系数,仍然有一个大问题,这意味着这些线仍然需要在一个透视转换的空间中绘制,然后回到道路空间,即使原始图像不是透视转换。这在对新数据的概括中产生了大量的问题,我需要任何新数据的转换矩阵(即使是相机安装的微小变化也会导致对新矩阵的需求)。
我的第一个想法是,我是否可以直接观察卷积层的**,看看这个层是怎么看的。我假设,如果CNN能够确定适当的线系数,它很可能是在实际的车道上**,或者至少是在图像中有一些类似的区域,它会告诉我们它的值来预测。
经过一些研究,我发现keras-vis1库对于观察每一层的**非常有用。这个库实际上可以查看类**特征图(在我的例子中,类实际上是每个系数标签,因为这不是一个分类问题)在每一层。我想我已经找到了我的解决方案,直到我看了**地图。
虽然上面几层的**地图看起来不错,但实际上我能找到的最清晰的部分。有趣的是,CNN实际上是通过只看一条线来学习的,它是根据它所观察的那个线来计算另一条线的位置。但这只是直线的曲线,它根本没有在车道上**!它实际上是直接在汽车前面的道路上**,并在车道上停止活动。因此,我意识到这个模型在不同的情况下以不同的方式**,这使得使用**地图几乎是不可能的。另外,在上面的第二张图片中注意到,由于各种旋转和翻转,天空中未被剪掉的部分也被**(暗部分),模型也在从底部开始的区域中**。其他**地图也会在图像底部的汽车上**,以达到同样的目的。
直接使用原图进行训练,不进行透视转换。
结论
最后的模型
取消最后的全连接层,采用全卷积神经网络,与正常的卷积层不同,Keras翻转卷积层翻转神经网络的反向传播,所以更应该注意输入图像的大小。输入图片没有灰度的大小为80x160x3,把标签值除以255进行归一化处理。
在每一层应用dropout将耗费大量内存,所以只在开始几层应用。应用MSE作为损失函数效果很好。图像增强并不会改善模型的鲁棒性,预测效果超过5帧。
评价检测
经过20个epochs,MSE在训练集中下降到0.0046,在测试集中为0.0048,表现良好,测试丘陵地区图像和弯曲道路,表现很好。
经过GPU加速的,检测速度达到25-29帧,CV模型仅能达到4.5-5.5帧。
反思提高:
可以使用RNN提升模型性能,RNN可以查看以前的帧,另一方面,RNN可以直接查看以前的帧,以便了解在前一帧中检测到的内容对当前帧的影响。通过这样做,它将有可能完全失去任何更不稳定的预测。