基于深度学习网络在Airsim中的自动驾驶

**Airsim仿真平台介绍及模型建立**

Airsim是一款基于Unreal Engine构建的无人机、汽车等模拟器的开源平台,并且可以跨平台的通过PX4飞行控制器进行仿真控制,在物理和视觉上逼真的模拟环境使得它成为一款很好的平台。不仅模拟了汽车无人机等动力学模型,甚至对天气效果灯光控制也做出了非常好的模拟。并且官方发布了很多测试环境,诸如森林、平原、乡村等。Airsim公开了API,可以通过Python等语言与仿真程序中的车辆无人机进行交互,可以使用这些API进行图像检索,获取状态,控制车辆等。相较于现实中的自动驾驶等实际应用,Airsim提供了更好的对于数据集的收集,相较于一些汽车公司动辄几百PB的数据资源,通过模拟器显然可以更好的构建网络学习而不用受制于数据收集的问题。端到端的深度学习是一种建模策咯,是对深度神经网络的成功响应。随着近些年硬件的升级进步(如GPU、FPGA等),使我们批量处理大量数据成为可能,相较于传统的ML,端到端深入学习更接近人类的学习方式,因为它允许神经网络将原始的数据直接映射到输出。本文的目的是将Airsim作为AI研究平台,收集数据进行深度学习,运用较少的数据集完成模型的建立,进而可以在Airsim平台上模拟运行自动驾驶汽车。
#Airsim仿真软件结构
Airsim结构图Airsim结构图

Airisim中的API接口都保存在AirLib文件下,由以下几部分组成:

l 物理引擎:旨在快速,可扩展的实现不同车辆

l 传感器模型:气压计,IMU,GPS和磁力计等

l 车辆模型:用于车辆配置的模型

l 控件库:提供抽象的API接口,还具有RPC客户端和服务器的类

可见,Airsim提供了不同形式不同接口的传感器,本文将运用汽车前方的单目摄像头对前方图像进行采样训练,以得到一个简单的自动驾驶模型,设计方案如下:
在这里插入图片描述
我们通过三部分进行实验:

第一部分是在人为操作下,让车辆随机在地图内行走,通过摄像头和传感器记录图像和汽车动力学模型;

第二部分是进行模型训练,将得到的图片分为两个子集——训练集和验证集,将在训练集训练好的模型放在验证集进行测试,如果准确率高于一定阈值,则模型拟合程度较好,如果准确率较低,则重复一二部分;

第三部分是将训练好的模型连接到Airsim软件,通过学习出来的结果控制车辆前进转弯,检测和分析仿真结果。

#数据收集
在AirsimNeibourhood中运行汽车,记录汽车运行时前方‘0’号摄像头记录的图片和汽车姿态速度转角等自身信息,分别存入/images文件夹和airsim_rec.txt文件。并获得有关图像相对应的汽车各个参数标签:
在这里插入图片描述
在这里插入图片描述

通过数据收集,共得到294张图片及标签,我们随机将34张图片取出作为验证集,将其余260张图片打上标签作为数据喂入。我们将标签设定为一个三分类问题,即steering=0/0.5/-0.5,分别对应直行左转和右转。在测试的时候,我们始终控制汽车的行进速度为5m/s,因此需要控制的变量只有转角一个。下面是收集到数据的形式:
在这里插入图片描述
可见,我们收集到的图片直行和转弯的比例大概是1:1,而右转信息则稍稍高于左转信息,如果我们将所有的数据喂入神经网络中,则会出现过拟合现象——即模型对右转弯信息敏感而对左转弯信息敏感度不够,会在行驶过程中发生转弯方向随机或转弯时间不固定的现象。因此,在对训练的图片做多次观察和处理后,提出可以采用上述提到的“丢弃法”——对于转角为right的图像信息,随机丢弃20%的数据集,使具有左转信息和右转信息的数据接近相等,有效抑制过拟合现象。
#数据预处理

l 随机改变图像的亮暗程度、对比度以及颜色等

基于Airsim软件优秀的仿真能力,可以在不同天气不同光照条件进行仿真,因此对图片进行亮暗程度、对比度、以及颜色等处理显得尤为重要。通过对照片的随机处理可以提高模型的适应能力,比如不光在训练集场景上可以良好运行,也可以在其他测试集上有较好表现。

l 随机反转

可以发现在该数据集中照片具有高度对称性,具有垂直翻转容差,因此我们可以将图片按照中心Y轴翻转,同时对角度的标志取反,以生成新的数据集,以提高模型对转弯操作的识别能力。

l 在处理中选取ROI区域——即我们感兴趣的一小部分区域

我们抛去了原本照片中位于上方的像素点,由于偏上的图像的一般构成为树木房子天空,对我们需要的转向关系不大,因此合理将它们丢弃,提高模型训练速度,并且提高了模型的泛化能力和准确性。

可见我们将原图像256144的像素裁剪出ROI为25664的像素。并随机做填充、裁剪、缩放、翻转处理,可以得到:
在这里插入图片描述
#卷积模型建立

基于上述介绍的卷积网络结构,本文将采用卷积&最大池化层的标注组合来处理图像。然后将每张图像所对应的车辆模型信息喂入网络,进行参数模型的建立。

VGG是当前流行的CNN模型之一,在2014年由Simonyan和Zisserman提出。VGG模型通过一系列

的卷积核和池化层取得了较好的效果,总共由13层卷积和3层全连接层,在每层VGG中使用ReLU激活函数,在全连接层之后添加dropout来抑制过拟合现象。当采用两层

卷积核时,其等效是得到了感受野为

的特征图,而这样做比

需要更少的参数,加快了模型的计算训练速度。并且由于卷积核的尺寸比较小,可以堆叠更多的卷积层,加深网络深度,提取更多特征。VGG结构如下图所示:
在这里插入图片描述
采用3x3的卷积核和2x2的池化层,并做padding=1的填充和stride=1的步幅,每轮卷积过后经过ReLU激活函数,池化模式使用最大池化,随机dropout=0.5的数据集,在经过全连接网络。采用Adam梯度下降函数,具体结构如下:

model = Sequential()
model.add(Conv2D(64, (3, 3),activation='relu', strides=(1,1), padding = 'same', use_bias = True, data_format='channels_first', input_shape = (3, 256,64)))
model.add(Conv2D(64, (3, 3), activation='relu', strides=(1,1), padding = 'same', use_bias = True))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))

model.add(Conv2D(128, (3, 3),activation='relu', strides=(1,1), padding = 'same', use_bias = True))
model.add(Conv2D(128, (3, 3), activation='relu', strides=(1,1), padding = 'same', use_bias = True))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))

model.add(Flatten())
model.add(Dense(512, use_bias=True, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(512, use_bias=True, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(3, use_bias=True, activation='softmax'))

adam = keras.optimizers.Adam(lr=0.0000005, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)
#编译模型
model.compile(loss='categorical_crossentropy', optimizer=adam,  metrics=['accuracy'])
#creat a history
history = LossHistory()
model.summary()

Layer (type) Output Shape Param #

=================================================================

conv2d_1 (Conv2D) (None, 64, 256, 64) 1792


conv2d_2 (Conv2D) (None, 64, 256, 64) 36928


max_pooling2d_1 (MaxPooling2 (None, 64, 128,
32) 0


dropout_1 (Dropout) (None, 64, 128, 32) 0


conv2d_3 (Conv2D) (None, 128, 128, 32) 73856


conv2d_4 (Conv2D) (None, 128, 128, 32) 147584


max_pooling2d_2 (MaxPooling2 (None, 128, 64,
16) 0


dropout_2 (Dropout) (None, 128, 64, 16) 0


conv2d_5 (Conv2D) (None, 256, 64, 16) 295168


conv2d_6 (Conv2D) (None, 256, 64, 16) 590080


conv2d_7 (Conv2D) (None, 256, 64, 16) 65792


max_pooling2d_3 (MaxPooling2 (None, 256, 32,
8) 0


dropout_3 (Dropout) (None, 256, 32, 8) 0


flatten_1 (Flatten) (None, 65536) 0


dense_1 (Dense) (None, 512) 33554944


dropout_4 (Dropout) (None, 512) 0


dense_2 (Dense) (None, 512) 262656


dropout_5 (Dropout) (None, 512) 0


dense_3 (Dense) (None, 3) 1539

=================================================================

Total params: 35,030,339

Trainable params: 35,030,339

Non-trainable params: 0


最后输出的是一个三分类问题,因此采取softmax函数进行处理。可见在该卷积神经网络中有足够多的参数对图片进行处理,进而训练出有效的模型。训练过程分为10个epochs,每个epoch中batchsize=10,总共训练260个batches,训练过程中的loss和acc如图所示:
在这里插入图片描述
可见在前50batches中,模型的准确率大幅度变换但总体上升,到130batches之后能够稳定维持在接近100%的准确率,而训练的loss值逐渐下降,模型拟合程度较好。在验证集的表现如下:
在这里插入图片描述
在验证集上表现良好,34个验证样本均维持了较高的准确率,且loss值稳定下降。该模型表现良好,我们将它拿到仿真软件上进行测试。

class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.losses = {'batch':[], 'epoch':[]}
        self.accuracy = {'batch':[], 'epoch':[]}
        self.val_loss = {'batch':[], 'epoch':[]}
        self.val_acc = {'batch':[], 'epoch':[]}
    def on_batch_end(self, batch, logs={}):
        self.losses['batch'].append(logs.get('loss'))
        self.accuracy['batch'].append(logs.get('acc'))
        self.val_loss['batch'].append(logs.get('val_loss'))
        self.val_acc['batch'].append(logs.get('val_acc'))
    def on_epoch_end(self, batch, logs={}):
        self.losses['epoch'].append(logs.get('loss'))
        self.accuracy['epoch'].append(logs.get('acc'))
        self.val_loss['epoch'].append(logs.get('val_loss'))
        self.val_acc['epoch'].append(logs.get('val_acc'))
     def loss_plot(self, loss_type):
        iters = range(len(self.losses[loss_type]))
        plt.figure()
        # acc
        plt.plot(iters, self.accuracy[loss_type], 'r', label='train acc')
        # loss
        plt.plot(iters, self.losses[loss_type], 'g', label='train loss')
        if loss_type == 'epoch':
            # val_acc
            plt.plot(iters, self.val_acc[loss_type], 'b', label='val acc')
            # val_loss
            plt.plot(iters, self.val_loss[loss_type], 'k', label='val loss')
        plt.grid(True)
        plt.xlabel(loss_type)
        plt.ylabel('acc-loss')
        plt.legend(loc="upper right")
        plt.show()    

#Airsim上平台的训练和测试

将训练好的模型在Airsim仿真平台上运行,得到的结果如下:
在这里插入图片描述

如图可见,在Airsim引擎上表现达到预期,汽车可以在转弯处识别并进行转向,同时,在笔直路的行进前遇到障碍物也可以自行避开,并迅速调整运动姿态回到原来的运行状态。不过仍有一些问题出现,在笔直路面行驶过程中汽车模型的左右抖动比较大。在实际应用中,路面上不可能存在单一的汽车,如果多台汽车并行驾驶的话很有可能发生碰撞。因此要改变在平稳路线上的稳定性,也是接下来研究侧重的方向。

由此,通过深度学习平台搭建网络,在Airsim仿真软件中可以实现一种单一摄像头进行避障的模型。由于PC设备的原因,我们无法实现对几万张数据集和多分类输出方式的训练,但是本文设计出来模型验证结果可用,则提供了一种接下去深入学习的可能。

发布了1 篇原创文章 · 获赞 1 · 访问量 92

猜你喜欢

转载自blog.csdn.net/shayinzzh/article/details/104688839