利用OS1强度数据开发自主驾驶ML算法
来源:ouster官网,由苏州索亚机器人技术有限公司翻译
该项目的目的是开发一个机器学习模型,使用Ouster OS1激光雷达传感器作为主要传感器输入,使遥控车在赛道上能够自主导航。该模型是一个端到端的卷积神经网络(CNN),它处理来自激光雷达的强度图像数据,并输出遥控车的转向指令。
这是受Udacity自动驾驶汽车“行为克隆”模块和DIY机器人赛车的启发。这个项目建立在早期工作的基础上,开发了一个类似的模型,使用来自网络摄像头的彩色摄像机图像来自主驾驶遥控汽车。
这篇文章涵盖了收集和处理训练数据的数据管道的开发,使用谷歌Colab编译和训练ML模型,以及使用ROS在遥控车上集成和部署模型。
基于遥控车的ML模型部署
平台概述
对于这个项目,遥控车的基础平台是超火焰(Hyper Blue)车辆。为了安装硬件,平台用标准的Donkey Car套件进行了修改。完整的系统如下图所示。
遥控车平台与Ouster OS1激光雷达
对于传感器,我们将使用一个Ouster OS1-64激光雷达传感器。该系统也有一个Genius 120-degree 超广角全高清会议摄像头 ( widecam F100 )和一个OpenMV Cam M7安装,但他们没有用于这个项目。
传统的激光雷达传感器输出一个包含丰富空间信息的三维点云。但是,与ML应用程序中的摄像机图像相比,这些数据更具有挑战性。之前一篇新闻博客“激光雷达就是相机”详细介绍了OS1激光雷达如何能够实时输出固定分辨率的深度图像、信号图像和环境图像,所有这些都不需要相机。开源驱动程序将这些数据层输出为固定分辨率的360°全景帧。这就产生了类似于相机的图像,可以与使用彩色相机开发的ML模型一起使用。正如博文所说,
OS1以近红外的方式捕获信号和环境数据,因此数据与相同场景的可见光图像非常相似,这使得数据看起来很自然,并且很有可能为摄像机开发的算法很好地转换成数据。
所有的处理是在一个单板计算机fitlet2与Arduino Uno提供命令的马达转向和油门通过PCA 9685伺服驱动器。这款车可以通过Xbox控制器进行远程操作。
单板计算机fitlet2运行Ubuntu 18.04作为基本的操作系统。ROS用作中间件,提供软件组件之间的进程间通信,以及特定于机器人的库和可视化工具。在ML模型开发中,Tensorflow和Keras与谷歌Colab一起提供训练环境。
之前的工作
这项工作的主要动机之一是确定来自OS1激光雷达传感器的类似相机的图像是否可以用于最初打算用于彩色相机图像的ML模型架构。
之前,同样的硬件和软件系统被用来开发和验证一个ML模型,使用彩色摄像机图像来可靠地驾驶遥控车在一个类似的赛道上行驶。
在使用真实的硬件之前,使用一个模拟的环境来验证数据管道、模型培训和模型部署过程。模拟环境为ROS Gazebo,模拟相机输出为Rviz。
为了生成模拟图像,一个模拟的RGB彩色摄像机被安装在由MIT RACECAR项目提供的一辆模拟的遥控车上。
MIT RACECAR Gazebo模拟环境
最后,Valter Costa为他的论文“教育目的的自动驾驶模拟器”开发的Conde world文件被用作模拟环境来操作系统,并作为训练的测试轨道。
为了收集训练数据,模拟车辆在赛道上采用手动驾驶,并以ROS bag格式记录转向指令和模拟图像。
ROS Gazebo ML Model 训练数据收集
然后对数据进行处理并用于训练ML模型。在这个应用程序中,实现了Nvidia开发的模型,他们开发了一个卷积神经网络(CNN),将单个前置摄像头的原始像素直接映射到转向指令。
他们开发了一个ROS节点来使用训练好的ML模型进行推理。在仿真环境中,ML模型对仿真的彩色摄像机图像进行处理,输出转向命令,控制车辆验证数据管道、模型训练、模型部署过程。
这个过程在现实世界中重复进行,围绕一个轨迹收集训练数据,训练模型,并将模型部署到物理平台上。系统运行成功,遥控车辆在轨道上自主导航,如下图所示。
遥控小车端到端ML模型验证
现实数据收集
一旦使用彩色摄像机图像对系统进行了验证,下一步就是对系统进行调整以获取OS1数据。当遥控车工作时,使用diy_driverless_car_ROS存储库,特别是rover_ml包。
当手动操作遥控车时,rc_dbw_cam.launch文件是用来启动系统的。本项目OS1采用1024×20模式运行。更高的帧率被用来更紧密地匹配彩色相机的帧率。
$ roslaunch rover_teleop rc_dbw_cam.launch os1:=true ekf:=false
使用record_training.sh脚本记录训练数据。
$ source record_training.sh
感兴趣的主要主题是/racecar/ackermann_cmd_mux/output主题上发布的控制命令和/img_node/intensity_image主题上的激光雷达强度通道图像。
车辆被手动操纵在轨道上总共10圈,每个方向5圈。
一旦我们收集了培训数据,就需要对其进行组织和处理。这涉及到从ROS包中提取激光雷达图像数据和控制命令数据,并以一种更容易用Tensorflow和Keras操作的格式保存它。
激光雷达图像以JPG文件的形式保存,文件名根据记录的时间戳不同而不同。指导命令也被提取并存储在一个CSV文件中。CSV文件中的每一行都列出了图像文件名以及与该图像关联的转向和节流值。由于激光雷达图像和转向指令是在不同的频率发布的,一个基本的插值来估计在每个激光雷达图像被捕获时的转向指令。
要执行转换,需要使用rosbag_to_csv.py脚本。这是Ross Wightmans的bagdump.py脚本的一个稍微修改过的版本。
这个CSV文件(ed. CSV)和相关的JPG图像构成了我们培训数据集的基础。CSV输出的一个示例如下所示。
遥控车搭载Ouster激光雷达数据ML模型训练数据集
结果是一个本地目录的激光雷达图像和一个内插.csv文件相关的图像文件名与相关的方向盘命令。然后将数据归档到.tar文件中,以便与谷歌Colab一起使用。
谷歌Colab的数据处理和模型训练
本节介绍了用谷歌Colab代替遥控车上的嵌入式设备进行模型训练的过程。根据数据集的大小或模型的复杂性,很难在嵌入式设备上训练ML模型。
谷歌Colab是一个免费的机器学习教育和研究的研究工具。它是一个可以通过web浏览器访问的木星笔记本环境。代码在拥有12GB RAM和320GB磁盘空间的虚拟机中执行。谷歌Colab提供了gpu的免费使用,现在也提供了TPUs。这使它们成为训练具有大数据集的ML模型的好工具。
谷歌Colab笔记本设置
我们将使用端到端ML模型的开发来使用激光雷达笔记本导航遥控车来处理数据集,训练ML模型,并评估ML模型的性能。首先,我们要确保正确地设置了运行时环境。从“运行时”菜单中选择“更改运行时类型”选项,以进入“记事本设置”菜单。
谷歌Colab笔记本设置
笔记本与python2或python3兼容,但要确保在硬件加速器下拉菜单中选择了GPU。
一旦笔记本设置正确,我们就可以开始执行笔记本了。目前,该笔记本与TF2.0不兼容。命令%tensorflow_version 1。x确保使用TF1.0而不是TF2.0。单元格输出加载的Tensorflow和Keras版本。
Tensorflow版本:1.15.0
Tensorflow Keras版本:2.2.4-tf
最后,我们确认我们选择的GPU是可用的。如果GPU可用,名字也会被打印出来。目前Nvidia Tesla P100已经上市。
数据集处理
一旦笔记本被正确配置和环境设置,我们就可以开始加载数据集,以用于培训。
数据集以.tar文件的形式存储在AWS上。将数据集下载并提取到Colab环境中。
遥控车搭载Ouster激光雷达训练数据集的文件结构
接下来,我们解析内插的.csv文件,并将信息加载到panda dataframe中。数据aframe的摘要作为单元输出提供。
遥控车ouster激光雷达训练数据框架
这个数据集有6000多个样本。
接下来,我们要处理数据集本身。这包括删除未使用的列、任何空值和任何节流阀值为0的条目。我们只希望模型能够根据遥控车移动的数据进行训练。
我们可以使用直方图来可视化转向命令的分布。小部件允许用户选择用于直方图的箱子数量。使用默认的25个箱子产生如下的直方图。
遥控车ouster激光雷达训练数据直方图
很明显,数据集包含了不均匀分布的转向命令。
我们可以将这个分布正常化,使其具有更均匀的分布,以确保ML模型在各种输入上得到训练,并且不会过度拟合。如果选择了hist复选框,则对数据集进行修剪,使每个bin中不超过一定数量的条目。这个值是使用samples_per_bin变量设置的,默认值为150。其余条目的直方图被绘制出来,它看起来比原来的直方图更加统一。
遥控车ouster激光雷达训练数据集归一化直方图
图像处理
一旦数据集被规范化,我们就可以通过可视化来评估图像的质量。我们将采取几个步骤来处理这些图像。
首先,我们将把图片从原来的1024×64调整到320×180。虽然这确实改变了原始的长宽比,但是图像中丢失的细节对这项任务来说没有价值。图像还被裁剪以删除与训练任务无关的图像区域。这就阻止了模型学习环境特有的特性。
下面的图片显示了原始的图像,大小调整为320×180,以及裁剪后的版本。裁剪后的图像保留了地板和车道,同时去掉了办公室环境的其余部分。
Ouster激光雷达训练数据裁剪强度图像
这些图像处理功能将被合并到ML模型定义和训练过程的后续步骤中。
定义培训和验证数据集
一旦数据集被处理和审查,我们需要将数据分割成一个训练集和一个验证集。训练集是在训练期间用来调整模型权重的数据。验证集不影响模型的权重,但用于验证模型没有对训练数据进行过拟合。
在分割数据集之前,我们将研究数据扩充。由于我们的数据集相对较小,我们可以使用数据扩充技术来生成稍微修改过的数据集版本,以便进行培训,并极大地扩展数据集。这可以使最终的模型对环境中的变化更加精确和健壮。
Keras提供了ImageDataGenerator类,该类有几个用于操作图像的内置函数。这包括垂直或水平移动图像,放大图像,或调整亮度。
在处理大型数据集时,使用Keras数据生成器来处理加载数据是很有帮助的。这些在操作包含图像的数据集时特别有用。对于本例,我们将定义自己的基本数据生成器。将来,我们可以使用Keras实现,比如ImageDataGenerator类。
数据生成器将接收一个样本数据集、批大小超参数值和一个标志,以确定是否应该对数据进行扩充。
def generator(samples, batch_size=32, aug=0)
数据生成器加载图像并调整大小。然后加载与该图像相关联的转向角命令。如果启用了aug标志,它将使用增强数据生成器执行基本的图像增强。不管有没有增强,图像和角度都存储在单独的数组中。这些被打乱,然后返回。
yield sklearn.utils.shuffle(X_train, y_train)
最后,我们使用来自sklearn库的train_test_split函数将数据集分割为训练和验证示例。
train_samples, validation_samples = train_test_split(sample, test_size=0.2)
我们使用80%的数据进行培训和20%的验证。最终得到大约2900个训练样本和700个验证样本。
这些数据被输入到我们的数据集生成器函数中,生成一个训练数据生成器和一个验证数据生成器。
train_generator = generator(train_samples, batch_size=batch_size_value, aug=1)
validation_generator = generator(validation_samples, batch_size=batch_size_value, aug=0)
模型架构和培训
如前所述,Nvidia开发的一个模型用于将激光雷达图像的原始像素直接映射到控制命令。
该网络由9个层组成,包括一个归一化层、5个卷积层和3个全连通层。本文模型的可视化如下图所示:
Nvidia端到端ML模型
这个模型是使用Keras API编译的。使用前面发现的裁剪值对输入图像进行裁剪。
model.add(Cropping2D(cropping=((height_min,bottom_crop), (width_min,right_crop)), input_shape=(180,320,3)))
下一个函数对传入的数据执行一些基本的预处理。将图像归一化,使像素值以0为中心,具有较小的标准偏差。
model.add(Lambda(lambda x: (x / 255.0) - 0.5))
其余的行定义了特定的模型层。一旦定义了模型,就会编译模型。
model.compile(loss='mse', optimizer=Adam(lr=0.001), metrics=['mse','mae','mape','cosine'])
在训练过程中,指定损失函数的均方误差以使其最小化。这个度量对于回归任务很有用。Adam优化器是为优化器参数指定的。
这导致了一个有701,559个可训练参数的模型。
在训练之前,还定义了几个回调。回调是在模型训练过程中被触发和调用的实用函数。
首先,设置检查点。这将在训练过程中存储模型的权重,以便系统可以重新加载模型。这在Colab环境中非常有用,因为实例可以在某个超时时间之后断开连接。
checkpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_best_only=True, mode='auto', period=1)
如果模型性能停滞不前,则使用提早停止回调来结束训练过程。这有助于防止过度拟合。ReduceLROnPlateau函数是相似的。如果模型性能停止改进,Adam优化器的学习率将自动调整。
最后,对Tensorboard进行了配置。TensorBoard是TensorFlow提供的可视化工具。它可以跟踪实验指标,如损失和准确性,以及可视化的模型图。执行单元格时,在输出中向Tensorboard实例提供一个链接。在训练过程中的一个例子图像的Tensorboard如下所示。
使用Tensorboard进行谷歌Colab ML模型训练
一旦编译了模型并定义了一组回调,就可以开始训练模型了。在训练之前,定义几个超参数。
首先,定义训练和验证数据的步骤大小。
steps_per_epoch=(len(train_samples) / batch_size_value)
validation_steps=(len(validation_samples) / batch_size_value)
这定义了在声明一个epoch结束并开始下一个epoch之前,从数据生成器生成的总步骤数(批量样本)。
接下来,定义epoch的数量。
n_epoch = 50
最后,使用fit_generator函数启动模型训练过程。
history_object = model.fit_generator(
generator=train_generator,
steps_per_epoch=STEP_SIZE_TRAIN,
validation_data=validation_generator,
validation_steps=STEP_SIZE_VALID,
callbacks=callbacks_list,
use_multiprocessing=True,
epochs=n_epoch)
一旦训练开始,单元将输出每个epoch的度量。一旦培训完成,就可以将模型保存到Colab实例中,以便下载到本地工作站。
模型评价
模型培训过程通过输出的性能指标提供了对模型性能的一些了解。但是,为了更好地理解模型的执行情况,可以使用训练后的模型对一些样本数据进行预测并查看结果。
在训练过程中,可以通过绘制训练和验证数据集的损失函数来可视化训练性能。
Ouster 激光雷达 ML模型训练损失图
很明显,损失在开始时下降得很快,但随着训练过程的继续,改善速度会减慢。训练图和验证图是相似的,表明模型没有对数据进行过拟合。
接下来,该模型可用于预测数据子集中每个图像的转向命令值。预测值将与已知的真实值进行比较,并将误差可视化。
首先,误差可以用直方图来表示。
Ouster 激光雷达 ML模型预测误差
误差分布很均匀,大部分误差都在0附近,这很好。
同样,误差可以用散点图来表示。
Ouster 激光雷达 ML模型预测误差散点图
显然,该模型在最小和最大的转向命令角比0角命令执行得更好。
也可以通过观察个别图像来了解模型的性能。下面的图像显示了一个单一图像的精确和真实的转向角。
Ouster 激光雷达 ML模型强度图像预测
最后,visualize_saliency函数可用于生成热图,指出图像中对模型输出贡献最大的区域。
显著性映射在论文《深入卷积网络:可视化图像分类模型和显著性映射》中被引入。“它们是基于梯度的,它们计算输出相对于输入图像中每个像素的梯度。这显示了相对于输入图像像素的小变化,输出是如何变化的。
grads = visualize_saliency(model,
layer_idx,
filter_indices=None,
seed_input=sample_image_mod,
grad_modifier='absolute',
backprop_modifier='guided')
在下面的示例图中,很明显,网络对车道标记附近的像素最敏感。
ouster激光雷达ML模型的显著性图像
模型部署和验证
一旦模型被训练,它就被放置在嵌入式设备上,并集成到遥控汽车控制系统中。该模型根据网络摄像头的输入图像实时预测转向指令。
开发了一个ROS节点,该节点订阅相机发布的图像主题,并发布ML模型输出的控制命令。使用drive_model.py文件来做这件事。
model_control_node用于订阅/img_node/intensity_image主题,并在/platform_control/cmd_vel主题上发布控制命令。
对于接收到的每个图像,首先将其大小调整为180×320的图像。这是模型期望的输入图像大小。
self.resized_image = cv2.resize(self.latestImage, (320,180))
对于这个项目,只估计了转向角的命令。因此,节流阀被设置在一个恒定的值。
self.cmdvel.linear。x = 0.13
接下来,模型处理输入图像并返回一个预测的转向角。
self.angle = float(model.predict(image_array[None, :, :, :], batch_size=1))
然后,预测的输出被限制在车辆允许的最大转向输入。
self.angle = -1.57 if self.angle < -1.57 else 1.57 if self.angle > 1.57 else self.angle
最后,转向角命令和所需的油门值以geometry_msgs/Twist消息的形式发布。
self.cmdVel_publish (self.cmdvel)
系统不断地完成这个预测循环,为车辆提供更新的转向角度指令。
要启动完整的系统,可以使用rc_mlmodel_cam启动使用。这个启动文件除了加载rc_dbw_cam.launch中定义的普通遥控车辆输入和控制节点外,还加载drive_model.py ROS节点。
当系统运行时,车辆可以由两个不同的输入控制。来自Xbox控制器的控制命令仍然订阅/joy_teleop/cmd_vel主题。另外,ML模型在/platform_control/cmd_vel主题上发布控制命令。
yocs_cmd_vel_mux节点用作命令速度输入的多路复用器。它仲裁来自多个主题的传入cmd_vel消息,允许一次一个主题根据优先级来命令机器人。所有主题及其优先级和超时都是通过一个YAML文件配置的,可以在运行时重新加载该文件。这是在rover_cmd_vel_mux中定义的。yaml配置文件。
一旦系统配置正确,遥控车辆将被放置在轨道上,系统将使用rc_mlmodel_cam执行。发射启动文件。
$ roslaunch behavior_clone rc_mlmodel_cam。发射os1: = true ekf: = false
下面的视频用这个过程中定义的模型描述了一个完全自主的单圈。摄像头记录的图像可以看到,以及一个重叠的显着图像描绘的地区,在图像中最有助于转向命令输出。
基于遥控车的ML模型部署
这篇文章最初出现在Wil的博客上:
https://www.wilselby.com/2020/02/rc-car-ml-model-development-with-ouster-os1-lidar/#more-9702
苏州索亚机器人技术有限公司为ouster在中国的代理商,如需获取Ouster激光雷达更详细技术资料,请扫描下面的二维码! 欢迎预定!