行为克隆

介绍

  行为克隆就是要让无人驾驶车辆去模仿人类司机的驾驶行为,从而实现在复杂道路上的自动驾驶。之前在youtube上看到大牛用树莓派小车在真实的路面上实现了行为克隆,效果不错。不过搭建硬件比较费时费力,有一定的门槛,没有像在无人车模拟器上玩起来那么老少咸宜啦!感谢Udacity无人车驾驶团队开源的这款模拟器,可以说是很用心了。话不多说,下面开始进入正题。   

任务要求

  在无人车模拟器track1的Training Mode下手动驾驶车辆采集足够多的训练数据,搭建合适的神经网络模型并加载数据进行训练,训练完成后在Autonoumous Mode下让车辆在跑道上保持自动驾驶不少于一圈。

准备工作

  参照我的搭建Udacity无人车开发环境这篇博客搭建所需开发环境,如果之前已搭建成功可以直接跳过。
  下载无人车模拟器和工程的启动代码:

# 无人车模拟器
https://d17h27t6h515a5.cloudfront.net/topher/2017/February/58ae4419_windows-sim/windows-sim.zip
# 工程启动代码
git clone https://github.com/udacity/CarND-Behavioral-Cloning-P3.git

采集数据

  将路径选择在工程目录下,点击”记录数据”按钮并沿着跑道track1手动驾驶几圈(注意要让车辆保持在跑道中间平稳的驾驶),结束以后需要再次点击“记录数据”按钮回放录像才能成功捕获数据,切记!如果经过训练后的车辆自动驾驶偏离了跑道,还需要具体原因具体分析再补充相应数据。
  活动的数据包括车辆3个前置摄像头采集的图像数据、方向盘角度(steering angle)、油门(throttle)、刹车(brake)和行驶速度(speed),我们主要使用center摄像头采集的图像作为feature, 方向盘角度(steering angle)作为label

加载数据

  加载driving_log.csv文件,获得图片的文件名然后到IMG文件夹下读取相应的图片images,此外还要获取对应的方向盘角度measurements。
  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import csv
import cv2
import numpy as np

# 读取driving_log.csv的每一行
lines = []
with open('.\\track1_data\\driving_log.csv') as csv_file:
reader = csv.reader(csv_file)
for line in reader:
lines.append(line)

# 读取center摄像头采集的图片和方向盘角度
images = []
measurements = []
for line in lines:
path = line[0]
filename = path.split('\\')[-1]
current_path = '.\\track1_data\\IMG\\' + filename
image = cv2.imread(current_path)
images.append(image)
measurement = float(line[3])
measurements.append(measurement)

X_train = np.array(images)
y_train = np.array(measurements)

搭建模型

  我们主要采用的是端到端的无人驾驶模型,具体可以参考Nvidia的End to End Learning for Self-Driving Cars这篇论文, 论文中只要看懂下面这张图就可以了:

  核心代码是用keras实现的,一目了然,共包括5个卷积网络和4个全连接网络。为了防止过拟合,我在卷积层之间还加了Dropout层。
  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from keras.models import Sequential
from keras.layers import Flatten, Dense, Lambda, Cropping2D, Dropout
from keras.layers.convolutional import Convolution2D

model = Sequential()

# 图像预处理--归一化并对图像进行裁剪。
model.add(Lambda(lambda x: x / 255.0 - 0.5, input_shape=(160, 320, 3)))
model.add(Cropping2D(cropping=((70, 25), (0, 0))))

# End to End Learning Model for Self-Driving Cars
model.add(Convolution2D(24, 5, 5, subsample=(2, 2), activation="relu"))
model.add(Dropout(0.7))
model.add(Convolution2D(36, 5, 5, subsample=(2, 2), activation="relu"))
model.add(Convolution2D(48, 5, 5, subsample=(2, 2), activation="relu"))
model.add(Convolution2D(64, 3, 3, activation="relu"))
model.add(Convolution2D(64, 3, 3, activation="relu"))
model.add(Dropout(0.8))
model.add(Flatten())
model.add(Dense(100))
model.add(Dense(50))
model.add(Dense(10))
model.add(Dense(1))

# 模型训练及保存
model.compile(loss='mse', optimizer='adam')
model.fit(X_train, y_train, validation_split=0.2, shuffle=True, nb_epoch=10, verbose=1)
model.save('model.h5')

实现效果

python model.py  # 对模型进行训练

  通过matplotlib可视化误差可以看到,训练数据和验证数据的误差随着迭代次数不断减小。

python drive.py model.h5 run1  # 对模型进行测试

  进入无人车模拟器的Autonoumous Mode后,我们的Anaconda Prompt终端会与模拟器通过 http://0.0.0.0:4567 连接起来,之后无人车就开启自动驾驶了,效果如下:

python video.py run1  # 可以制作run1.mp4视频保存实验结果

  哈哈,这样就大功告成啦,可以看到这个project虽然难度不大,但是趣味十足,工程类的课程要都这么玩就有趣多了!当然这里只完成了track1跑道,track2跑道按理说依样画葫芦即可,但是作为教练的我都开不好,实在是有点坑无人车啊!