使用深度学习自动识别限速标志:这里有一份Keras和TensorFlow教程

2018-01-09 11:47:04 浏览数 (1)

原文来源:Medium

作者:Imaad Mohamed Khan

「雷克世界」编译:嗯~阿童木呀、多啦A亮

在我来到德国之前,我对德国道路上没有车速限制的事感到着迷。令我失望的是,几乎所有地方都有限速。公路(高速公路)上只有一些区域被指定为无限速区域,汽车和其他车辆可以测试其引擎极限。

如果一个司机正在超速行驶,他突然进入一个必须遵循一定速度限制的区域,他将如何操作?解决这个问题的一种方式,也是最常见的方式是驾驶员手动刹车并减少加速度。但是,我们现处于2017年,电脑可以识别比猫和狗更多东西!所以让我们试着让电脑自动识别限速标志!

我基于我的实现,以Oliver Zeigermann的“使用TensorFlow和Keras的卷积神经网络介绍”(https://www.youtube.com/watch?v=WIhI1W6NoZ0)的教程为基础,这是一个非常好的教程,我喜欢他从工程师的角度而不是研究员的角度来探索实施。我一直在积极尝试两种方法,在这里我学习一些数学知识,并且学习如何使用各种库来实现它。

我在本教程中发现的关键点之一是微软Azure notebooks。在他的教程中,Zeigermann要求观众在本地或在云上运行notebooks。他说他喜欢云,因为云机功能更强大,规格也比他的机器更高。我的机器也是如此。在此之前,我一直在CPU上使用Jupyter notebooks,并且遇到了我的机器快速发热的问题,所以我决定尝试Azure notebooks,并取得了一个很好的经验。它们速度很快,可以立即设置,并且它们是免费的!对于刚开始使用Python和数据科学的人来说,Azure notebooks可以帮助他们迅速起步。

实施任何数据科学或AI项目的首要任务是找到一个合适的数据集。演示者提供了本教程的数据集。他在视频中提到,该教程是基于Waleed Abdulla的类似项目(https://medium.com/@waleedka/traffic-sign-recognition-with-tensorflow-629dffc391a6)。我假设他从另一个项目中获得了数据。在这种情况下,它基于一个名为比利时交通标志数据集(Belgian Traffic Sign Dataset)的数据集(http://btsd.ethz.ch/shareddata/)。

在获得数据之后,我们仍然需要以机器学习模型可以使用的形式准备我们的数据。数据集中的图像为.ppm格式。我们将其转换成可用于使用skimage库分析的形式。这是执行转换的函数。

import os

import skimage.data

def load_data(data_dir):

directories = [d for d in os.listdir(data_dir)

labels = []

images = []

for d in directories:

for f in os.listdir(label_dir) if f.endswith(".ppm")]

for f in file_names:

images.append(skimage.data.imread(f))

labels.append(int(d))

return images, labels

在我们使用load_data函数加载数据之后,我们试着看看图像和标签是如何组织的。我们写了一个函数用来可视化我们的数据。

import matplotlib

import matplotlib.pyplot as plt

def display_images_and_labels(images, labels):

"""Display the first image of each label."""

unique_labels = set(labels)

plt.figure(figsize=(15, 15))

i = 1

for label in unique_labels:

# Pick the first image for each label.

image = images[labels.index(label)]

plt.subplot(8, 8, i) # A grid of 8 rows x 8 columns

plt.axis('off')

plt.title("Label ()".format(label, labels.count(label)))

i = 1

_ = plt.imshow(image)

plt.show()

display_images_and_labels(images, labels)

这导致以下结果。

具有各自标签和计数的限速图像

从上图可以看到,我们的数据集中有6个不同类别的限速图像,分别显示为30、50、70、80、100和120,且每个种类中分别有 79、81、68、53、41和57个样本。这并不是一个非常大的数据集,但是对于我们的问题来说,它的运行效果已经足够好了。

既然已经观察过我们图像的组织方式后,现在来看一下每个图像的形状,以及RGB颜色的最小值和最大值。

for image in images[:5]:

print("shape: , min: , max: ".format(image.shape, image.min(), image.max()))

Output:

shape: (21, 22, 3), min: 27, max: 248

shape: (23, 23, 3), min: 10, max: 255

shape: (43, 42, 3), min: 11, max: 254

shape: (61, 58, 3), min: 3, max: 255

shape: (28, 27, 3), min: 8, max: 65

从输出中我们可以清楚地看到,每个图像的形状随着最小和最大RGB值分布的变化而变化。我们的神经网络模型期望所有的图像都具有相同的形状。在调整大小的同时,我们将最小和最大RGB值在0到1之间进行正则化处理。我们使用skimage的变换函数将图像转换为64x64像素图像,其中有3个用于RGB的信道。

import skimage.transform

最后,我们执行数据准备的最后一步,将图像和标签转换为numpy数组。我们还使用to_categorical函数将我们的标签转换为不同的分类数组,其中,如果那个特定的类别被表示为0,则其表示为1。

import numpy as np

y = np.array(labels)

X = np.array(images64)

num_categories = 6

y = to_categorical(y, num_categories)

在这个阶段之后,Zeigermann解释了他是如何通过训练一个简单的keras模型来进行实验的,其中,该模型在训练数据方面表现出色,但在测试数据方面表现不佳。他还讨论了与SGD,Adagrad等其他方法相比,RMSProp似乎是更好的优化器。

最后,随着该实验的进展,他开始涉及卷积神经网络方面的知识。卷积神经网络或循环神经网络(CNN)是一种明确假定输入是图像的神经网络。在计算机视觉方面的深度学习革命大部分是由CNN领导的。下面是其架构的一个示例:

CNN架构,来源http://cs231n.github.io/convolutional-netw

由于我们所关注的重点是CNN的应用程序方面的知识,所以我不会详细介绍每个层的细节以及我们是如何调整超参数的。我们使用Keras库运行CNN。 Keras是一个建立在Tensorflow和Theano上的高级API(Theano不再进行维护)。现在让看一看代码:

from keras.models import Model

from keras.layers import Dense, Flatten, Input, Dropout

from keras.layers import Convolution2D, MaxPooling2D

from sklearn.model_selection import train_test_split

inputs = Input(shape=(64,64,3))

x = Convolution2D(32, 4,4, border_mode='same', activation='relu')(inputs)

x = Convolution2D(32, 4,4, border_mode='same', activation='relu')(x)

x = MaxPooling2D(pool_size=(2,2))(x)

x = Dropout(0.25)(x)

# one more block

x = Convolution2D(64, 4, 4, border_mode='same', activation='relu')(x)

x = MaxPooling2D(pool_size=(2, 2))(x)

x = Dropout(0.25)(x)

x = Flatten()(x)

# fully connected, 256 nodes

x = Dense(256, activation='relu')(x)

x = Dropout(0.50)(x)

# softmax activation, 6 categories

predictions = Dense(6, activation='softmax')(x)

model = Model(input=inputs, output=predictions)

model.compile(optimizer='rmsprop',

loss='categorical_crossentropy',

metrics=['accuracy'])

model.fit(X_train, y_train, nb_epoch=50, batch_size=100)

该模型现在运行50轮,批量大小为100,它在80%的总数上进行训练,而这些数据在使用sklearn的train_test_split函数之前就已经进行分割。以下是我们运行了50轮之后得到的结果:

进行50轮数据训练之后的CNN输出

该模型的收敛性为0.2489,精确度约为92%。对于一个没有进行任何超参数调整的模型来说这是很好的性能表现,让我们看看模型在训练数据集上的精确度。

train_loss, train_accuracy = model.evaluate(X_train,y_train, batch_size=32)

train_loss, train_accuracy

训练数据的精确度为83.49%,而损失为0.41。接下来看看在测试数据集上的性能表现:

test_loss, test_accuracy = model.evaluate(X_test, y_test, batch_size=32)

test_loss, test_accuracy

我们得到约68%的精确度,损失为1.29。这个结果并不是很理想。但是这里也有一些有趣的事情发生,这也是Zeigermann所提到的。这是我第二次运行该模型,而在我之前的测试中,测试精确度达到95%左右。显然,模型的输出是不确定的。也许有办法让它变得更稳定,而关于该如何实现这一点,还需要掌握更多的知识。

最后,我们在测试数据集上对模型的一些预测进行可视化。我们从测试数据集中随机抽取10个图像,并使用matplotlib绘制预测图。我们显示预测的类以及其对照比标准。如果模型的预测结果是正确的,那么我们将将其涂成绿色,否则涂成红色。

import random

random.seed(3)

sample_indexes = random.sample(range(len(X_test)), 10)

sample_images = [X_test[i] for i in sample_indexes]

sample_labels = [y_test[i] for i in sample_indexes]

#get the indices of the array using argmax

ground_truth = np.argmax(sample_labels, axis=1)

X_sample = np.array(sample_images)

prediction = model.predict(X_sample)

predicted_categories = np.argmax(prediction, axis=1)

# Display the predictions and the ground truth visually.

def display_prediction (images, true_labels, predicted_labels):

fig = plt.figure(figsize=(10, 10))

for i in range(len(true_labels)):

truth = true_labels[i]

prediction = predicted_labels[i]

plt.subplot(5, 2,1 i)

plt.axis('off')

color='green' if truth == prediction else 'red'

plt.text(80, 10, "Truth: nPrediction: ".format(truth, prediction),

fontsize=12, color=color)

plt.imshow(images[i])

display_prediction(sample_images, ground_truth, predicted_categories)

正如你在下面看到的,我们的模型对于来自测试数据集的10个随机采样图像,正确预测出了8个图像。结果很不错,而之前当我在测试数据集上获得了95%的精确度时,它正确预测出了10/10个图像。

0 人点赞