1 项目概述
1.1项目要求
自动驾驶又称无人驾驶、轮式机器人,是一种通过电脑实现无人驾驶的技术(行为)。自动驾驶依靠人工智能、计算机视觉、雷达、监控装置和全球定位系统,不需要人类主动操作,汽车自动安全地行驶。自动驾驶是目前最热门的也是最有突破性的技术之一,其中人工智能是关键技术之一,又叫深度学习,是自动驾驶的核心。
Udacity由Google公司x实验室创始人,称作无人驾驶之父的Sebastian Thrun(塞巴斯蒂安·史朗)创立,被人们称作“云端大学”。开设诸如“无人驾驶、大数据、人工智能”等高端前沿课程,授予的学位叫“Nanodegree(纳米学位)”。
1.2项目内容及方案
本项目基于深度神经网络,构建一个Udacity无人驾驶仿真环境下的无人驾驶系统。
Udacity无人驾驶仿真环境是Udacity公司为自己的学员设计的,针对无人驾驶项目的模拟环境,验证代码的有效性。该仿真环境部分免费,本项目用的就是免费部分。项目分四步实现。
第一步,使用Udacity模拟器采集数据;
第二步,对采集到的图像数据进行预处理;
第三步,使用深度卷积神经网络设计、建立、训练自动驾驶模型;
第四步,使用Udacity模拟器自动驾驶车辆,验证模型。
项目用到的第三方库包括:opencv,pandas,pillow,keras,scikit-learn,tensorflow,Python-socketio,flask,Flask-SocketIO,Python-engineio,eventlet。
2 项目原理
2.1视频图像采集
本项目使用Udacity模拟器采集视频图像数据,这里直接使用别人采集好的原始数据。原始数据提供了由安装在车辆前方的左、中、右摄像机拍摄的图片,及车辆在这个时刻的转角(方向、油门、刹车、速度),保存在driving_log.csv文件中。本项目会利用这些数据,训练一个深度学习模型模仿车辆的驾驶行为,从而达到自动控制车辆的效果。为了简单、方便,模型只训练一个图像,即模型只输入一个图像,只会预测汽车转向角(只有一个输出),速度采用限速。
2.2图像数据预处理
首先在左、中、右三张图片中随机选择一张图片,然后使用Python Opencv库中的图像处理函数对数据集做预处理(视频图像预处理)。考虑复杂的现实环境,如天气、拍摄角度、自然光照、遮挡、摄像机自身原因造成的图像模糊、歪斜或缺损的情况。图像预处理包括选择图像、翻转、平移、阴影、亮度调节、预处理。
这些图像预处理方法都是随机执行的,确保后期训练的模型具有较强的泛化能力。其中,图像翻转使用cv2.flip函数;图片平移使用仿射变换函数cv2.warpAffine;阴影遮挡方法为先将图像转换为HLS格式,对亮度(L)进行遮挡后再转换为RGB格式;亮度调节方法为将图像转换为HSV格式,对明度(V)进行调整;然后截取图像,去掉机盖和天空,调整图像尺寸并转换为YUV格式(一种颜色编码方法,常使用在各个视频处理组件中)。
2.3设计、建立、训练深度学习模型
该阶段的主要内容如下:
(1)调用argparse模块,用于向模型传递数据。首先创建一个解析对象,然后向该对象中添加你要关注的命令行参数和选项,进而执行 parse_args() 进行解析。
(2)导入数据(清单),将存储在硬盘中的数据(清单)导入内存。首先使用pd.read_csv函数读取CSV文件,获取需要的数据,然后调用train_test_split函数划分训练集和测试集。
(3)编写数据生成器,逐批生成数据,分批次向模型送入数据。对随机抽取的图像数据,20%的情况会调用图像预处理程序对图像进行随机预处理,80%的情况会直接获取中间图像。这里使用yield而不用return,目的是使程序从上一次停止的地方继续执行,抽过的数据就不会再抽了。
(4)利用Keras搭建CNN的一个顺序模型,本项目使用一个现成的模型。模型含有5个卷积层(Conv2D),输入图像是一个3通道的彩色图像,图像像素值首先会被归一化(Lambda)为0~1之间的数值;然后通过5个卷积层(Conv2D),1个扁平层(Flatten),3个全连接层(Dense)的作用后,输出方向盘角度值,这是一个回归问题(该网络被称为nvidia net)。
(5)将数据送入模型进行训练,送入数据的方式有很多种,这里使用model.fit_generator()的方式送数据。首先使用model.compile()函数设置好模型训练策略,这里使用Adam优化算法(学习率设置为0.0001)和mse损失函数。model.fit_generator()的实现方法是利用生成器,分批次向模型送入数据,生成器与模型并行运行,可以有效节省单次内存的消耗。保存训练得到的模型参数,用于后续的模型验证。
2.4验证模型
项目使用socketio和Flask,实现web服务器和web应用程序之间的通信进而对模型进行验证。其中socketio是针对Python开发的基于socket的web服务器,其中,socket为服务器和应用程序提供了双向通信机制,意味着服务器可以推送消息给应用程序。Flask是基于python的web应用程序架构。eventlet是一个网络通信应用程序,用来处理多线程。
首先,定义(建立)socketio服务器,可看做建立了一个插座。然后,采用Flask做应用程序,相当于插头。进而,将服务器与应用程序打包成WSGI(Web Server Gateway Interface),相当于把插座与插头连接在一起。WSGI指定了web服务器和Python web应用或web框架之间的标准接口,是 python web 开发的标准,规定了各自使用的接口和功能,以便二者互相配合实现连接。
连接过程本项目用到的事件包括connect event、disconnect event和telemetry event,这三个事件的表示分别是:connect event表示服务器(Python程序)与客户端(模拟器)连接成功;disconnect event表示服务器(Python程序)与客户端(模拟器)断开连接;在小车运动过程中,会通过telemetry event模拟器发送小车当前的转向角、油门、车速,以及当前摄像机拍摄的照片,要控制仿真器中小车的运动,需要向仿真器发送如下两个参数:steering_angle:转向角,throttle:油门。
设置好连接事件及相关响应函数后,加载前面训练好的模型参数文件,使用WSGI托管运行,打开Udacity模拟器点击自动驾驶,就可以看到汽车在自动向前行驶并且可以走相当一段长的距离。