深度學(xué)習(xí)——卷積神經(jīng)網(wǎng)絡(luò)來(lái)龍去脈和MINST圖像識(shí)別應(yīng)用
點(diǎn)擊下方卡片,關(guān)注“新機(jī)器視覺(jué)”公眾號(hào)
視覺(jué)/圖像重磅干貨,第一時(shí)間送達(dá)
寫(xiě)在前面

在此之前,我總結(jié)記錄了一些機(jī)器學(xué)習(xí)的實(shí)戰(zhàn),包括《機(jī)器學(xué)習(xí)應(yīng)用——電影評(píng)論情感分析模型構(gòu)建》《多分類(lèi)器集成學(xué)習(xí):多數(shù)票機(jī)制、Bagging、Adaboost實(shí)例分析》《基于sklearn庫(kù)的機(jī)器學(xué)習(xí)模型與調(diào)優(yōu)實(shí)踐詳細(xì)步驟》等,感興趣的伙伴可以查看,偏向?qū)嵺`更加有趣!
這次準(zhǔn)備總結(jié)之前學(xué)習(xí)到的CNN,整理了卷積神經(jīng)網(wǎng)絡(luò)的詳細(xì)內(nèi)容,了解其原理來(lái)龍去脈,掌握實(shí)戰(zhàn)深入淺出。
深度卷積神經(jīng)網(wǎng)絡(luò)(DCNN)
1、卷積神經(jīng)網(wǎng)絡(luò)
卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network,CNN,又稱為ConvNet)有著它特殊的功能,網(wǎng)絡(luò)中保留了空間信息,因此可以更好地適用于圖像分類(lèi)問(wèn)題。原理來(lái)源于人類(lèi)視覺(jué)生物學(xué)數(shù)據(jù)的啟發(fā),視覺(jué)基于多個(gè)皮質(zhì)層,每層識(shí)別越來(lái)越多的結(jié)構(gòu)性信息。我們看到的是很多單個(gè)的像素;然后從這些像素中,我們識(shí)別出幾何組成;再然后……這樣越來(lái)越多的復(fù)雜的元素,如物體、面部、人類(lèi)軀干、動(dòng)物等被識(shí)別出來(lái)。
很明顯,圖像識(shí)別分類(lèi)問(wèn)題就是CNN的用武之地。
深度卷積神經(jīng)網(wǎng)絡(luò),是由很多神經(jīng)網(wǎng)絡(luò)層組成。卷積層和池化層這兩種不同的網(wǎng)絡(luò)層,經(jīng)常交互出現(xiàn)。每個(gè)濾波器的深度在網(wǎng)絡(luò)中由左向右增加。最后一部分通常由一個(gè)或多個(gè)全連接層組成,如下圖。

CNN中最基礎(chǔ)的操作是卷積,再精確一點(diǎn),基礎(chǔ)CNN所用的卷積是一種2-D卷積。也就是說(shuō),kernel只能在x,y上滑動(dòng)位移,不能進(jìn)行深度 (跨通道) 位移。
假設(shè)輸入圖像使用tf(TensorFlow)順序,它在3個(gè)信道上的形狀為(256,256),這可以表示成(256, 256, 3)。Keras中,添加一個(gè)輸出維度為32并且每個(gè)濾波器為3×3的卷積層,可以寫(xiě)成:
model = Sequential()model.add(Conv2D(32, (3, 3), input_shape=(256, 256, 3))
這就是說(shuō),我們用3個(gè)輸入信道(或輸入濾波器)在一個(gè)256×256的圖像上進(jìn)行3×3的卷積運(yùn)算,得到了一個(gè)32個(gè)信道(輸出濾波器)的輸出,卷積結(jié)果類(lèi)似下圖。

池化,是一種降采樣操作,主要目標(biāo)是降低feature maps的特征空間,或者可以認(rèn)為是降低feature maps的分辨率。因?yàn)閒eature map參數(shù)太多,而圖像細(xì)節(jié)不利于高層特征的抽取。
常用的有最大池化和平均池化。
最大池化:簡(jiǎn)單地輸出最大激活值作為這個(gè)區(qū)域的觀測(cè)結(jié)果。在Keras中,定義一個(gè)2×2的最大池化層:
model.add(MaxPooling2D(pool_size = (2, 2)))直觀地舉例如圖:

平均池化:把這個(gè)區(qū)域觀察到的激活值取平均值。如上圖用平均池化則會(huì)得到:[[1.7,4],[3.75,2,5]]
Keras構(gòu)建LeNet——CNN族群

from keras import backend as Kfrom keras.models import Sequentialfrom keras.layers.convolutional import Conv2Dfrom keras.layers.convolutional import MaxPooling2Dfrom keras.layers.core import Activationfrom keras.layers.core import Flattenfrom keras.layers.core import Densefrom keras.datasets import mnistfrom keras.utils import np_utilsfrom keras.optimizers import SGD, RMSprop, Adamimport numpy as npimport matplotlib.pyplot as plt
定義LeNet網(wǎng)絡(luò):
# 定義ConvNetclass LeNet:@staticmethoddef build(input_shape, classes):model = Sequential()# CONV => RELU => POOLmodel.add(Conv2D(20, kernel_size=5, padding="same",input_shape=input_shape))model.add(Activation("relu"))model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))# CONV => RELU => POOLmodel.add(Conv2D(50, kernel_size=5, border_mode="same"))model.add(Activation("relu"))model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))# Flatten層到RELU層model.add(Flatten())model.add(Dense(500))model.add(Activation("relu"))model.add(Dense(classes))model.add(Activation("softmax"))return model
1、最先是卷積階段,我們使用ReLU激活函數(shù),并用最大池化方法。我們的網(wǎng)絡(luò)將學(xué)習(xí)20個(gè)卷積濾波器,其中每個(gè)濾波器的大小都是5×5。輸出維度和輸入形狀相同,因而將是28×28像素。注意,因?yàn)槎S卷積是我們管道中的第一個(gè)階段,我們必須定義它的input_shape。最大池化操作實(shí)現(xiàn)了一個(gè)滑窗,它在網(wǎng)絡(luò)層上滑動(dòng),并取水平和垂直各兩個(gè)像素區(qū)域上的最大值。
2、之后的第二個(gè)卷積階段也是用ReLU激活函數(shù),后面再次跟著最大池化方法。把學(xué)到的卷積濾波器數(shù)量從前面的20增加到50個(gè)。在更深的網(wǎng)絡(luò)層增加濾波器數(shù)目是深度學(xué)習(xí)中一個(gè)普遍采用的技術(shù)。
3、最后一個(gè)全連接網(wǎng)絡(luò),它包含500個(gè)神經(jīng)元,其后是具有10個(gè)類(lèi)別的softmax分類(lèi)器。

深度學(xué)習(xí)CNN識(shí)別MINST圖像
訓(xùn)練集和測(cè)試集劃分:
60000 train samples
10000 test samples
完整代碼和詳細(xì)注釋如下:
# 網(wǎng)絡(luò)和訓(xùn)練NB_EPOCH = 5BATCH_SIZE = 128VERBOSE = 1OPTIMIZER = Adam()VALIDATION_SPLIT = 0.2IMG_ROWS, IMG_COLS = 28, 28NB_CLASSES = 10INPUT_SHAPE = (1, IMG_ROWS, IMG_COLS)# 混合并劃分訓(xùn)練集和測(cè)試集數(shù)據(jù)(X_train, y_train), (X_test, y_test) = mnist.load_data()K.set_image_dim_ordering("th")# 把它們看成float類(lèi)型并歸一化X_train = X_train.astype('float32')X_test = X_test.astype('float32')X_train /= 255X_test /= 255# 我們需要使用形狀60K×[1×28×28]作為卷積網(wǎng)絡(luò)的輸入X_train = X_train[:, np.newaxis, :, :]X_test = X_test[:, np.newaxis, :, :]print(X_train.shape[0], 'train samples')print(X_test.shape[0], 'test samples')# 將類(lèi)向量轉(zhuǎn)換成二值類(lèi)別矩陣y_train = np_utils.to_categorical(y_train, NB_CLASSES)y_test = np_utils.to_categorical(y_test, NB_CLASSES)# 初始化優(yōu)化器和模型model = LeNet.build(input_shape=INPUT_SHAPE, classes=NB_CLASSES)model.compile(loss="categorical_crossentropy", optimizer=OPTIMIZER,metrics=["accuracy"])history = model.fit(X_train, y_train,batch_size=BATCH_SIZE, epochs=NB_EPOCH,verbose=VERBOSE, validation_split=VALIDATION_SPLIT)score = model.evaluate(X_test, y_test, verbose=VERBOSE)print("Test score:", score[0])print('Test accuracy:', score[1])# 列出全部歷史數(shù)據(jù)print(history.history.keys())# 匯總準(zhǔn)確率歷史數(shù)據(jù)plt.plot(history.history['acc'])plt.plot(history.history['val_acc'])plt.title('model accuracy')plt.ylabel('accuracy')plt.xlabel('epoch')plt.legend(['train', 'test'], loc='upper left')plt.show()# 匯總損失函數(shù)歷史數(shù)據(jù)plt.plot(history.history['loss'])plt.plot(history.history['val_loss'])plt.title('model loss')plt.ylabel('loss')plt.xlabel('epoch')plt.legend(['train', 'test'], loc='upper left')plt.show()
經(jīng)過(guò)5個(gè)epoch,就獲得一個(gè)近似99%的準(zhǔn)確率,繪制出模型準(zhǔn)確率和損失函數(shù)的變化圖如圖。
Test accuracy: 0.9899


總結(jié)
這一篇整理了卷積神經(jīng)網(wǎng)絡(luò)的詳細(xì)內(nèi)容,了解其原理來(lái)龍去脈,通過(guò)簡(jiǎn)單入門(mén)項(xiàng)目深入淺出。CNN在圖像識(shí)別分類(lèi)的應(yīng)用廣泛,在許多深度學(xué)習(xí)任務(wù)中也會(huì)用到CNN神經(jīng)網(wǎng)絡(luò)。
—版權(quán)聲明—
僅用于學(xué)術(shù)分享,版權(quán)屬于原作者。
若有侵權(quán),請(qǐng)聯(lián)系微信號(hào):yiyang-sy 刪除或修改!

