动手学无人驾驶(1):交通标志识别
今天主要介紹無人駕駛當(dāng)中深度學(xué)習(xí)技術(shù)的應(yīng)用。
本文是根據(jù)博客專家AdamShan的文章整理而來,在此表示感謝。
關(guān)于深度學(xué)習(xí)的圖像分類技術(shù),網(wǎng)上已有很多關(guān)于深度學(xué)習(xí)的課程(如吳恩達(dá)老師的深度學(xué)習(xí)專項(xiàng)課程),故本文不對(duì)理論部分進(jìn)行闡述,只關(guān)注實(shí)踐部分,用到的深度學(xué)習(xí)框架是keras。關(guān)于keras框架的學(xué)習(xí),之前轉(zhuǎn)載了一篇黃海廣博士的文章,是很不錯(cuò)的學(xué)習(xí)書籍。
首發(fā):深度學(xué)習(xí)入門寶典-《python深度學(xué)習(xí)》原文代碼中文注釋版及電子書
(2021-03-03補(bǔ)充) 本文中使用數(shù)據(jù)集下載地址:動(dòng)手學(xué)無人駕駛(1):交通標(biāo)志識(shí)別》訓(xùn)練集和測(cè)試集
目錄
1.導(dǎo)入庫
2. 數(shù)據(jù)處理(重點(diǎn))
2.1 讀取數(shù)據(jù)集
2.2 顯示圖片
2.3 圖片尺寸處理
2.4 將圖片轉(zhuǎn)換為numpy 數(shù)組
2.5 將圖像轉(zhuǎn)為灰度圖
2.6 數(shù)據(jù)集增強(qiáng)
3. 訓(xùn)練神經(jīng)網(wǎng)絡(luò)
4. 測(cè)試驗(yàn)證
5. 使用模型
6. 總結(jié)
關(guān)于圖像分類的介紹,可以參考以下視頻(CS231n:用于視覺識(shí)別的卷積神經(jīng)網(wǎng)絡(luò)(2017年秋季)1080p_嗶哩嗶哩_bilibili)。
CS231n:用于視覺識(shí)別的卷積神經(jīng)網(wǎng)絡(luò)(2017年秋季)1080p
1.導(dǎo)入庫
在編寫代碼時(shí),首先是加載本文中所需要的庫,如下:
import os import random import scipy import skimage import matplotlib import matplotlib.pyplot as plt import numpy as np from scipy import ndimage from skimage import colorimport keras from keras.models import Sequential from keras.layers import Dense, Flatten from keras.optimizers import SGD from keras.layers import Dropout from keras.optimizers import RMSprop# Allow image embeding in notebook %matplotlib inline注意:在Jupyter Notebook運(yùn)行上述代碼時(shí)scipy庫和skimage庫會(huì)沖突,解決辦法是通過pip包安裝scipy,如下:
sudo pip3 install scipy2. 數(shù)據(jù)處理(重點(diǎn))
本文中用到的交通標(biāo)志數(shù)據(jù)集是BelgiumTS數(shù)據(jù)集,將數(shù)據(jù)集解壓位于notebook同一目錄下,
- data/Training/
- data/Testing/
每個(gè)文件夾包含了62個(gè)類,編號(hào)從 00000 到 00061.
2.1 讀取數(shù)據(jù)集
def load_data(data_dir):"""Loads a data set and returns two lists:(加載數(shù)據(jù),返回圖像列表和標(biāo)簽列表)images: a list of Numpy arrays, each representing an image.labels: a list of numbers that represent the images labels."""# Get all subdirectories of data_dir. Each represents a label.#獲取data_dir所有子文件夾,每一個(gè)包含一種標(biāo)簽#os.listdir(絕對(duì)路徑),返回文件名和目錄名組成的列表#os.path.isdir(),發(fā)【判斷是否為目錄#os.path.join(),將多個(gè)路徑組合為一個(gè)路徑directories = [d for d in os.listdir(data_dir) if os.path.isdir(os.path.join(data_dir, d))]#print(directories)# Loop through the label directories and collect the data in(循環(huán)遍歷每一個(gè)子目錄,收集數(shù)據(jù))# two lists, labels and images.labels = []images = []for d in directories:label_dir = os.path.join(data_dir, d)file_names = [os.path.join(label_dir, f) for f in os.listdir(label_dir) if f.endswith(".ppm")]#print(file_names)# For each label, load it's images and add them to the images list.# And add the label number (i.e. directory name) to the labels list.for f in file_names:images.append(skimage.data.imread(f))labels.append(int(d))return images, labels# Load training and testing datasets. ROOT_PATH = "data" train_data_dir = os.path.join(ROOT_PATH, "Training") test_data_dir = os.path.join(ROOT_PATH, "Testing")images, labels = load_data(train_data_dir)2.2 顯示圖片
加載完數(shù)據(jù)集后,顯示每個(gè)交通標(biāo)識(shí)類別的第一張圖片。
def display_images_and_labels(images, labels):"""Display the first image of each label."""unique_labels = set(labels)plt.figure(figsize=(15, 15))i = 1for 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 columnsplt.axis('off')plt.title("Label {0} ({1})".format(label, labels.count(label)))i += 1_ = plt.imshow(image)plt.show()display_images_and_labels(images, labels)效果如下,共有62類交通標(biāo)志。
2.3 圖片尺寸處理
數(shù)據(jù)集圖片大小尺寸并不統(tǒng)一,為了更好的訓(xùn)練神經(jīng)網(wǎng)絡(luò),需要將所有圖片調(diào)整到一個(gè)相同的尺寸,這里將圖片尺寸調(diào)整到(32,32)。
# Resize images(調(diào)整到(32,32)) images32 = [skimage.transform.resize(image, (32, 32))for image in images] display_images_and_labels(images32, labels)調(diào)整后的圖片如下圖所示,此時(shí)圖片大小尺寸已經(jīng)統(tǒng)一。
顯示調(diào)整后的圖片尺寸信息:
for image in images32[:5]:print("shape: {0}, min: {1}, max: {2}".format(image.shape, image.min(), image.max())) shape: (32, 32, 3), min: 0.03529411764705882, max: 0.996078431372549 shape: (32, 32, 3), min: 0.03395373774509821, max: 0.996078431372549 shape: (32, 32, 3), min: 0.03694182751225482, max: 0.996078431372549 shape: (32, 32, 3), min: 0.06460056678921586, max: 0.9191425398284314 shape: (32, 32, 3), min: 0.060355392156862725, max: 0.90284926470588232.4 將圖片轉(zhuǎn)換為numpy 數(shù)組
labels_a = np.array(labels) images_a = np.array(images32) print("labels: ", labels_a.shape, "\nimages: ", images_a.shape)2.5 將圖像轉(zhuǎn)為灰度圖
對(duì)圖像進(jìn)行一定的預(yù)處理,在這里將原來的RGB三通道的圖像轉(zhuǎn)換為灰度圖。
images_a = color.rgb2gray(images_a) display_images_and_labels(images_a, labels)2.6 數(shù)據(jù)集增強(qiáng)
這里將數(shù)據(jù)集擴(kuò)充為5倍,并顯示其中的幾類。
def expend_training_data(train_x, train_y):"""Augment training data擴(kuò)充5被"""expanded_images = np.zeros([train_x.shape[0] * 5, train_x.shape[1], train_x.shape[2]])expanded_labels = np.zeros([train_x.shape[0] * 5])counter = 0for x, y in zip(train_x, train_y):# register original data(加載原始數(shù)據(jù))expanded_images[counter, :, :] = xexpanded_labels[counter] = ycounter = counter + 1# get a value for the background# zero is the expected value, but median() is used to estimate background's valuebg_value = np.median(x) # this is regarded as background's valuefor i in range(4):# rotate the image with random degreeangle = np.random.randint(-15, 15, 1)#new_img = ndimage.rotate(x, angle, reshape=False, cval=bg_value)# shift the image with random distanceshift = np.random.randint(-2, 2, 2)new_img_ = ndimage.shift(x, shift, cval=bg_value)# register new training dataexpanded_images[counter, :, :] = new_img_expanded_labels[counter] = ycounter = counter + 1return expanded_images, expanded_labelsimages_a, labels_a = expend_training_data(images_a, labels_a) print(images_a.shape, labels_a.shape) labels = labels_a.tolist() print(len(labels)) def plot_agument(images, labels):plt.figure(figsize=(16, 9))unique_labels = set(labels)i = 1for label in unique_labels:# Pick the first image for each label.if i > 3:breakimg_index = labels.index(label)for j in range(5):image = images_a[img_index+j]plt.subplot(3, 5, (i-1)*5 + j+1) # A grid of 8 rows x 8 columnsplt.axis('off')plt.title("Label {0} ({1})".format(label, labels.count(label)))_ = plt.imshow(image, cmap='gray')i += 1plot_agument(images_a, labels)3. 訓(xùn)練神經(jīng)網(wǎng)絡(luò)
這里用到keras搭建神經(jīng)網(wǎng)絡(luò),模式為Sequential模式。
from sklearn.utils import shuffleindx = np.arange(0, len(labels_a)) indx = shuffle(indx) images_a = images_a[indx] labels_a = labels_a[indx]#總樣本數(shù)為22875 train_x, val_x = images_a[:20000], images_a[20000:] train_y, val_y = labels_a[:20000], labels_a[20000:]train_y = keras.utils.to_categorical(train_y, 62) val_y = keras.utils.to_categorical(val_y, 62)#構(gòu)建神經(jīng)網(wǎng)絡(luò) model = Sequential() model.add(Flatten(input_shape=(32, 32))) model.add(Dense(512, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(512, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(62, activation='softmax'))model.summary()model.compile(loss='categorical_crossentropy',optimizer=RMSprop(),metrics=['accuracy'])history = model.fit(train_x, train_y,batch_size=128,epochs=20,verbose=1,validation_data=(val_x, val_y))### print the keys contained in the history object #print(history.history.keys()) model.save('model.json')網(wǎng)絡(luò)的訓(xùn)練誤差和驗(yàn)證誤差如圖所示:
def plot_training(history):### plot the training and validation loss for each epochplt.plot(history.history['loss'])plt.plot(history.history['val_loss'])plt.title('model mean squared error loss')plt.ylabel('mean squared error loss')plt.xlabel('epoch')plt.legend(['training set', 'validation set'], loc='upper right')plt.show()plot_training(history=history)4. 測(cè)試驗(yàn)證
加載測(cè)試集:
# Load the test dataset. test_images, test_labels = load_data(test_data_dir) # Transform the images, just like we did with the training set. test_images32 = [skimage.transform.resize(image, (32, 32))for image in test_images]test_images_a = np.array(test_images32) test_labels_a = np.array(test_labels)test_images_a = color.rgb2gray(test_images_a)display_images_and_labels(test_images_a, test_labels) test_x = test_images_a test_y = keras.utils.to_categorical(test_labels_a, 62) score = model.evaluate(test_x, test_y, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1])測(cè)試精度為:88%。
Test loss: 0.49647544848156117 Test accuracy: 0.87896823883056645. 使用模型測(cè)試
這里選取幾張圖片樣本,進(jìn)行測(cè)試,測(cè)試結(jié)果如圖所示,其中有2張圖片測(cè)試結(jié)構(gòu)與標(biāo)簽不一致。
# Display the predictions and the ground truth visually. fig = plt.figure(figsize=(10, 10)) j = 1 for i in range(0, 1000, 100):truth = test_labels_a[i]prediction = predicted[i]plt.subplot(5, 2, j)j = j+1 plt.axis('off')color='green' if truth == prediction else 'red'plt.text(40, 10, "Truth: {0}\nPrediction: {1}".format(truth, prediction), fontsize=12, color=color)plt.imshow(test_x[i], cmap='gray')6. 總結(jié)
本文利用深度學(xué)習(xí)進(jìn)行了交通標(biāo)志識(shí)別,首先進(jìn)行了數(shù)據(jù)的處理,然后訓(xùn)練了神經(jīng)網(wǎng)絡(luò),最后進(jìn)行了測(cè)試,測(cè)試精度達(dá)到88%。主要的工作是圖像數(shù)據(jù)處理。為進(jìn)一步提高精度,可考慮使用卷積神經(jīng)網(wǎng)絡(luò)。
總結(jié)
以上是生活随笔為你收集整理的动手学无人驾驶(1):交通标志识别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度顶会论文复现(4):飞桨API详解
- 下一篇: qqlogin.exe是什么进程 qql