AirSim自动驾驶教程–数据探索与准备

原文地址
https://github.com/Microsoft/AutonomousDrivingCookbook/blob/master/AirSimE2EDeepLearning/DataExplorationAndPreparation.ipynb


概述

  我们的目标是训练一个深度学习模型,能够让车辆根据拍摄照片和车辆的最后状态预测车辆行进角度。在这片文章中,我将准备端到端深度学习模型的数据。在此过程中,我们将对数据集做一些有用的监察,这将在训练模型的时候对我们有所帮助。

端到端深度学习

  端到端深度学习是一种响应深度神经网络成功的建模策略。不同于传统的方法,这种策略没有建立在特征工程上。相反的,它利用深度神经网络的强大,和近来硬件(GPU,FPGA等)的优势去利用大数据的惊人潜力。它比传统的深度学习跟接近于人类的学习方法,因为它让输入直接映射到输出端。这个方法的最大缺点是它需要大量的训练数据,使得他不适用于许多一般的应用程序。由于仿真软件能够(潜在地)生成无限大的数据,所以它们是端到端深度学习算法的完美数据源。如果你希望了解更多,这个Andrew Ng的这个视频提供了一个很好的主题概述。
  自主驾驶是一个可以从端到端的深度学习中获益良多的领域。为了实现SAE标准中4级或5级自主性,汽车需要接受大量数据的训练(汽车制造商每周收集数百pb的数据并不罕见),如果没有模拟器,这几乎是不可能的。
  有了像AirSim这样逼真的仿真器,现在可以收集大量数据来训练你的自动驾驶模型,而不必使用实际的汽车。然而,这些模型可以使用较少的真是数据进行微调,并用于实际的汽车。这种技术被称作行为克隆。这份文档中,将训练一个模型,以学习只使用汽车上的一个前置摄像头作为视觉输入如何驾驶汽车通过AirSim的一部分景观地图。我们的策略是执行一些基本的数据分析来获得数据集的感觉,然后训练一个模型,通过摄像头获取到的帧和车的当前状态参数(速度、转向角、油门等)预测正确的驾驶控制信号(在本例中是转向角)。
  在开始之前,确保已经下载了文档中的数据集。如果您错过了readme文件中的说明,可以在这儿下载。
  让我们先从导入一些标准库开始。
  注意:如果在这些notebook(原文是以notebook形式表达,CSDN中以MarkDown写成,在浏览器中以网页表示)中的注释中看到 <<…>> 的文本,这意味着你需要对附带的代码进行更改。

%matplotlib inline
import numpy as np
import pandas as pd
import h5py
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import os
import Cooking
import random

# << Point this to the directory containing the raw data >>
RAW_DATA_DIR = 'data_raw/'

# << Point this to the desired output directory for the cooked (.h5) data >>
COOKED_DATA_DIR = 'data_cooked/'

# The folders to search for data under RAW_DATA_DIR
# For example, the first folder searched will be RAW_DATA_DIR/normal_1
DATA_FOLDERS = ['normal_1', 'normal_2', 'normal_3', 'normal_4', 'normal_5', 'normal_6', 'swerve_1', 'swerve_2', 'swerve_3']

# The size of the figures in this notebook
FIGURE_SIZE = (10,10)

  让我们看一些原始数据。数据集包括两部分 - 图像和 .tsv 文件。首先让我们读一个 .tsv 文件。

sample_tsv_path = os.path.join(RAW_DATA_DIR, 'normal_1/airsim_rec.txt')
sample_tsv = pd.read_csv(sample_tsv_path, sep='\t')
sample_tsv.head()
Timestamp Speed (kmph) Throttle Steering Brake Gear ImageName
0 93683464 0 0.0 0.000000 0.0 N img_0.png
1 93689595 0 0.0 0.000000 0.0 N img_1.png
2 93689624 0 0.0 -0.035522 0.0 N img_2.png
3 93689624 0 0.0 -0.035522 0.0 N img_3.png
4 93689624 0 0.0 -0.035522 0.0 N img_4.png

  这个数据集包含我们的标签,转向角。它还具有在记录转向角时拍摄的图像的名称。让我们来看一个示例图像 - 'img_0.png’在’normal_1’文件夹内(更多关于我们的文件夹命名风格稍后介绍)。
AirSim自动驾驶教程–数据探索与准备_第1张图片
  我们可以直接观察到这幅图像只有一小部分是有趣的。例如,我们只需要关注车在下图红色的ROI(region of interest)如何驾驶。

sample_image_roi = sample_image.copy()

fillcolor=(255,0,0)
draw = ImageDraw.Draw(sample_image_roi)
points = [(1,76), (1,135), (255,135), (255,76)]
for i in range(0, len(points), 1):
    draw.line([points[i], points[(i+1)%len(points)]], fill=fillcolor, width=3)
del draw

plt.title('Image with sample ROI')
plt.imshow(sample_image_roi)
plt.show()

AirSim自动驾驶教程–数据探索与准备_第2张图片
  提取ROI能减少训练时间和训练模型的数据量。这也阻止了模型获取不相干环境特征(例如山,树等)而导致的混乱。
  我们可以做的另一个观察是数据集显示了垂直翻转公差。换言之,我们得到一个有效的数据点,如果我们把图像绕Y轴翻转如果也翻转方向盘角度的符号。这很重要,因为它有效地将我们可用的数据点数量翻了一番。
  此外,训练后的模型应该对光照条件的变化保持不变,因此我们就可以通过全局缩放图像的亮度来生成额外的数据点。

思考练习0.1:完成这份教程后,作为一个练习,您应该尝试使用提供的数据集,而不使用上面描述的三个更改中的一个或多个来修改它,保持其他所有内容不变。你是否经历过截然不同的结果?
思考练习0.2:我们在Readme 文档中指出,端对端深度学习消除了在输入数据给学习算法之前的手动特征工程。你有考虑过主动给原始数据做一些预处理当作特征处理呢?为什么或为什么不?

  现在,让我们将所有非图像数据聚合到一个数据帧中,以获得更多的信息。

full_path_raw_folders = [os.path.join(RAW_DATA_DIR, f) for f in DATA_FOLDERS]

dataframes = []
for folder in full_path_raw_folders:
    current_dataframe = pd.read_csv(os.path.join(folder, 'airsim_rec.txt'), sep='\t')
    current_dataframe['Folder'] = folder
    dataframes.append(current_dataframe)
    
dataset = pd.concat(dataframes, axis=0)

print('Number of data points: {0}'.format(dataset.shape[0]))

dataset.head()

  数据点个数:46738

Timestamp Speed (kmph) Throttle Steering Brake Gear ImageName Folder
0 93683464 0 0.0 0.000000 0.0 N img_0.png data_raw/normal_1
1 93689595 0 0.0 0.000000 0.0 N img_1.png data_raw/normal_1
2 93689624 0 0.0 -0.035522 0.0 N img_2.png data_raw/normal_1
3 93689624 0 0.0 -0.035522 0.0 N img_3.png data_raw/normal_1
4 93689624 0 0.0 -0.035522 0.0 N img_4.png data_raw/normal_1

  现在让我们处理数据集文件夹的命名。你将注意到在数据集有两种类型命名的文件夹-‘normal’,和 ‘swerve’。它们的名字指的是两种不同的驾驶策略。让我们从了解这两种驾驶方式的不同开始。首先,我们将绘制来自每种驾驶风格的数据点的一部分。

min_index = 100
max_index = 1100
steering_angles_normal_1 = dataset[dataset['Folder'].apply(lambda v: 'normal_1' in v)]['Steering'][min_index:max_index]
steering_angles_swerve_1 = dataset[dataset['Folder'].apply(lambda v: 'swerve_1' in v)]['Steering'][min_index:max_index]

plot_index = [i for i in range(min_index, max_index, 1)]

fig = plt.figure(figsize=FIGURE_SIZE)
ax1 = fig.add_subplot(111)

ax1.scatter(plot_index, steering_angles_normal_1, c='b', marker='o', label='normal_1')
ax1.scatter(plot_index, steering_angles_swerve_1, c='r', marker='o', label='swerve_1')
plt.legend(loc='upper left');
plt.title('Steering Angles for normal_1 and swerve_1 runs')
plt.xlabel('Time')
plt.ylabel('Steering Angle')
plt.show()

AirSim自动驾驶教程–数据探索与准备_第3张图片
  在这儿我们能够清晰的观察到两种驾驶策略之间的不同。蓝点显示的是正常的驾驶策略,正如你所预料的那样,它会使你的方向盘角度或多或少接近于零,这使得你的车在路上基本上是直行的。
  转向驾驶策略总是让车经过马路的时候从一边到另一边来回摆动。在训练端到端深度学习模型的时候需要记住这是一个很重要的阐述。由于我们没有进行任何功能工程,所以我们的模型几乎完全依赖于数据集来为它提供在收回期间所需的所有必要信息。因此,要考虑到模型可能遇到的任何急转弯,并让它在开始偏离道路时能够自我纠正,我们需要在训练时为它提供足够的此类例子。因此,我们创建了这些额外的数据集来关注这些场景。完成本教程后,您可以尝试仅使用 ‘normal’ 数据集重新运行所有内容,并观察汽车在路上行驶很长一段时间后失败。

思考练习0.3:您认为在这个转向角预测场景中,还需要哪些其他类似的数据收集技术?自动驾驶呢?

  现在,让我们看看每个类别中的数据点数量。

dataset['Is Swerve'] = dataset.apply(lambda r: 'swerve' in r['Folder'], axis=1)
grouped = dataset.groupby(by=['Is Swerve']).size().reset_index()
grouped.columns = ['Is Swerve', 'Count']

def make_autopct(values):
    def my_autopct(percent):
        total = sum(values)
        val = int(round(percent*total/100.0))
        return '{0:.2f}%  ({1:d})'.format(percent,val)
    return my_autopct

pie_labels = ['Normal', 'Swerve']
fig, ax = plt.subplots(figsize=FIGURE_SIZE)
ax.pie(grouped['Count'], labels=pie_labels, autopct = make_autopct(grouped['Count']))
plt.title('Number of data points per driving strategy')
plt.show()

AirSim自动驾驶教程–数据探索与准备_第4张图片
  因此,大约四分之一的数据点是用转向驾驶策略收集的,其余的数据点是用正常策略收集的。我们也看到我们总共有47000个数据点可用。这些数据几乎是不够的,因此我们的网络不能太深。

思考练习0.4:像机器学习领域的许多事情一样,这里每个类别中数据点的理想比例是特定于问题的,只能通过反复试验来优化。你能找到一个比我们的更好的吗?

  让我们看看这两种策略的标签分布情况。

bins = np.arange(-1, 1.05, 0.05)
normal_labels = dataset[dataset['Is Swerve'] == False]['Steering']
swerve_labels = dataset[dataset['Is Swerve'] == True]['Steering']

def steering_histogram(hist_labels, title, color):
    plt.figure(figsize=FIGURE_SIZE)
    n, b, p = plt.hist(hist_labels.as_matrix(), bins, normed=1, facecolor=color)
    plt.xlabel('Steering Angle')
    plt.ylabel('Normalized Frequency')
    plt.title(title)
    plt.show()

steering_histogram(normal_labels, 'Normal label distribution', 'g')
steering_histogram(swerve_labels, 'Swerve label distribution', 'r')

AirSim自动驾驶教程–数据探索与准备_第5张图片
AirSim自动驾驶教程–数据探索与准备_第6张图片
  我们可以从这些图中观察到一些数据:

  • 正常驾驶汽车时,转向角几乎总是零。有一个严重的不平衡,如果这部分数据没有向下采样,模型总是预测为零,汽车将无法转弯。
  • 当使用转向策略驾驶汽车时,我们得到了在常规策略数据集中没有出现的急转弯的例子。这验证了我们为什么要像前面解释的那样收集数据

  此时,我们需要将原始数据合并到适合培训的压缩数据文件中。在这里,我们将使用h5文件,因为这种格式完美支持大型数据集,而不需要一次性将所有内容读入内存。它还与Keras无缝合作。
  处理数据集的代码很简单,但是很长。完成后,最终的数据集将有4个部分:

  • 图像:包含图像数据的numpy数组
  • 状态:包含汽车的最后已知状态的numpy数组。这是一个(转向,油门,刹车,速度)元组
  • label:包含我们希望预测的转向角的numpy数组(在-1…1范围内归一化)
  • 元数据:包含文件元数据的numpy数组(它们来自哪个文件夹,等等)

  处理过程将花费一些时间。我们将把所有数据集合并到一起,然后将其拆分为训练/测试/验证数据集。

train_eval_test_split = [0.7, 0.2, 0.1]
full_path_raw_folders = [os.path.join(RAW_DATA_DIR, f) for f in DATA_FOLDERS]
Cooking.cook(full_path_raw_folders, COOKED_DATA_DIR, train_eval_test_split)
Reading data from data_raw/normal_1...
Reading data from data_raw/normal_2...
Reading data from data_raw/normal_3...
Reading data from data_raw/normal_4...
Reading data from data_raw/normal_5...
Reading data from data_raw/normal_6...
Reading data from data_raw/swerve_1...
Reading data from data_raw/swerve_2...
Reading data from data_raw/swerve_3...
Processing data_cooked/train.h5...
Finished saving data_cooked/train.h5.
Processing data_cooked/eval.h5...
Finished saving data_cooked/eval.h5.
Processing data_cooked/test.h5...
Finished saving data_cooked/test.h5.

  现在我们准备建立模型。预知后事如何,请听下回分解。

github项目地址
https://github.com/Microsoft/AutonomousDrivingCookbook

你可能感兴趣的:(Artificial,Intelligence)