您的位置:首页 > 理论基础 > 计算机网络

用keras框架搭建神经网络——(五)识别交通标志

2019-03-13 09:45 761 查看

从这一个阶段开始,搭建的神经网络将用于更加贴近生活的实用场景,并逐步尝试优化用户体验做成某种“产品”。

源代码下载:https://download.csdn.net/download/rance_king/11015514

  1. 导入包,下载数据集
    数据集来源:https://bitbucket.org/jadslim/german-traffic-signs ,其中包含一个csv文件和三个pickle文件,csv文件将不同的交通标志名称对应到不同的class数字标号分类中,三个csv文件分别对应着训练集,测试集合验证集。
import numpy as np
import matplotlib.pyplot as plt
import keras
from keras.models import Sequential
from keras.optimizers import Adam
from keras.layers import Dense
from keras.layers import Flatten, Dropout
from keras.utils.np_utils import to_categorical
from keras.layers.convolutional import Conv2D, MaxPooling2D
import random
import pickle
import pandas as pd
import cv2
  1. 载入数据集,查看了数据集dict的key之后发现有feature和label两个键,应该是分别作为图片和标签来使用的。
#pickle文件是一种二进制文件,这里pickle.load则将这种二进制文件反序列化变成dict,‘rb’的意思是read binary
with open('german-traffic-signs/train.p', 'rb') as f:
train_data = pickle.load(f)
with open('german-traffic-signs/valid.p', 'rb') as f:
val_data = pickle.load(f)
with open('german-traffic-signs/test.p', 'rb') as f:
test_data = pickle.load(f)
X_train, y_train = train_data['features'], train_data['labels']
X_val, y_val = val_data['features'], val_data['labels']
X_test, y_test = test_data['features'], test_data['labels']
#验证一下数据集中图片和标签的一一对应关系
assert(X_train.shape[0] == y_train.shape[0]), "the number of the dataset is not equal to the number of the labels"
#通过pandas载入data,然后马上可以发现交通信号一共有43个类别需要进行鉴别,对应编号0-42
data = pd.read_csv('german-traffic-signs/signnames.csv')
  1. 查看数据集中数据的分布情况,可以发现这个数据集中各个分类下的数据不是均匀的。
num_of_samples=[]

cols = 5
num_classes = 43

fig, axs = plt.subplots(nrows=num_classes, ncols=cols, figsize=(5,50))
fig.tight_layout()
#对这个循环意思的解读:循环每一列的i(一共有五列),并在每一列i中分别返回index=j(这个j是0-42中的一个数)#row,row是data这个dict下的以0-42标号对应的标签名称
for i in range(cols):
for j, row in data.iterrows():
x_selected = X_train[y_train == j]
axs[j][i].imshow(x_selected[random.randint(0,(len(x_selected) - 1)), :, :], cmap=plt.get_cmap('gray'))
axs[j][i].axis("off")
if i == 2:
axs[j][i].set_title(str(j) + " - " + row["SignName"])
num_of_samples.append(len(x_selected))
plt.figure(figsize=(12, 4))
plt.bar(range(0, num_classes), num_of_samples)
plt.title("Distribution of the train dataset")
plt.xlabel("Class number")
plt.ylabel("Number of images")
plt.show()

  1. 对图片进行处理,将图片转换为特征更加容易突出的图片。
#用opencv库将BGR格式的图转化为灰度图片
def grayscale(img):
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
return img
img = grayscale(X_train[1000])
plt.imshow(img)
plt.axis("off")

#直方图同等化,这个方法用于改善图片的的对比度
def equalize(img):
img = cv2.equalizeHist(img)
return img
img = equalize(img)
plt.imshow(img)
plt.axis("off")
print(img.shape)


如此,图片的边界变得清晰,因而特征更加明显。

def preprocess(img):
img = grayscale(img)
img = equalize(img)
img = img/255
return img

使用map()函数将预处理的功能映射给每一张图片

X_train = np.array(list(map(preprocess, X_train)))
X_test = np.array(list(map(preprocess, X_test)))
X_val = np.array(list(map(preprocess, X_val)))

预处理后的文件需要经过reshape增加一个维度,这样才能作为数据被CNN网络进行使用。
这里要特别注意,因为CNN网络需要一个深度来使用filter提取特征,所以,这里要reshape增加一层深度给filter使用。

X_train = X_train.reshape(X_train[0], 32, 32, 1)
X_test = X_test.reshape(X_test[0], 32, 32, 1)
X_val = X_val.reshape(X_val[0], 32, 32, 1)

y_train = to_categorical(y_train, 43)
y_test = to_categorical(y_test, 43)
y_val = to_categorical(y_val, 43)
  1. 这里加入了一个新的步骤,data augmentation数据扩大化,这个步骤的作用是将现有的数据进行处理,变成更多的数据来作为学习材料,比如说将图片翻转,旋转等等来让计算机有更多的学习输入。使用kereas框架进行数据扩大化制造的图片不会在这个步骤生成图片,而是在实际训练的时候生成。
from keras.preprocessing.image import ImageDataGenerator
#imagedatagenerater,使用这个东西来制造新的图片,制造出来的内容是一种generater,可以用next来唤出。
datagen = ImageDataGenerator(width_shift_range=0.1,
height_shift_range=0.1,
zoom_range=0.2,
shear_range=0.1,
rotation_range=10.)

datagen.fit(X_train)
  1. 定义模型,这一步有反复调试参数的过程在内,注意数据之间的关联性,参数的数量对标的是计算量的大小,我发现在某些情况下增加卷积层甚至会减少整体的参数量,因为卷积层用特征替代像素点,可以有效缩减输入。
def modified_model():
model = Sequential()
model.add(Conv2D(60, (5, 5), input_shape=(32, 32, 1), activation='relu'))
model.add(Conv2D(60, (5, 5), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(30, (3, 3), activation='relu'))
model.add(Conv2D(30, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(500, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(43, activation='softmax'))

model.compile(Adam(lr = 0.001), loss='categorical_crossentropy', metrics=['accuracy'])
return model

model = modified_model()
print(model.summary())
  1. 训练开始!这一次要用data augmentation的方法来训练出模型来。
    首先是用上fit_generator方法,实际上这一次使用的数据就是data augmentation制造出的generator,datagen.flow随着运行产生image数据,每批50个,规定每个epoch需要用2000步完成
history = model.fit_generator(datagen.flow(X_train, y_train, batch_size=50),
steps_per_epoch=2000,
epochs=10,
validation_data=(X_val, y_val), shuffle = 1)
  1. 评估模型
score = model.evaluate(X_test, y_test, verbose=0)
print('Test score:', score[0])
print('Test accuracy:', score[1])

得到的结果测试验证集这一次是百分之九十七的准确率。

9.实际输入一些图片来尝试一下能否被训练好的模型认出。

import requests
from PIL import Image
url = 'https://c8.alamy.com/comp/J2MRAJ/german-road-sign-bicycles-crossing-J2MRAJ.jpg'
r = requests.get(url, stream=True)
img = Image.open(r.raw)
plt.imshow(img, cmap=plt.get_cmap('gray'))

img = np.asarray(img)
img = cv2.resize(img, (32, 32))
img = preprocess(img)
plt.imshow(img, cmap = plt.get_cmap('gray'))
print(img.shape)
img = img.reshape(1, 32, 32, 1)

print("predicted sign: "+ str(model.predict_classes(img)))

predicted sign: [30]
30号对应的是Beware of ice/snow

成功地认出了交通标志!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: