卷積神經網絡之LeNet


開局一張圖,內容全靠編。

上圖引用自 【卷積神經網絡-進化史】從LeNet到AlexNet. 目前常用的卷積神經網絡

深度學習現在是百花齊放,各種網絡結構層出不窮,計划梳理下各個常用的卷積神經網絡結構。 目前先梳理下用於圖像分類的卷積神經網絡

  • LeNet
  • AlexNet
  • VGG
  • GoogLeNet
  • ResNet

本文是關於卷積神經網絡的開山之作LeNet的,之前想着論文較早,一直沒有細讀,仔細看了一遍收獲滿滿啊。
本文有以下內容:

  • LeNet 網絡結構
  • LeNet 論文
  • LeNet keras實現,並應用CIFAR10進行測試

LeNet的貢獻

LeNet-5可謂是第一個卷積神經網絡,並且在手寫數字識別上取得了很好的效果。
對於圖像像素作為神經網絡的輸入數據面臨的一些問題:

  1. 圖像數據量較大,單獨像素獨立輸入神經元中,需要很大的網絡結構,訓練參數過多
  2. 圖像的形變,形變引起的圖像特征位置變化的問題
  3. 圖像的局部相關性。

其提出了卷積神經網絡的概念,並應用

  • 局部感受野
  • 權值共享
  • 下采樣(池化)

來解決上述問題。

LeNet網絡結構

1998年的誕生的LeNet(LeCun et al. Gradient-Based Learning Applied to Document Recognition)可謂是現在各種卷積神經網絡的始祖了,其網絡結構雖然只有5層,卻包含了卷積神經網絡的基本組件(卷積層,池化層,全連接層)

  • 輸入層 INPUT
    輸入\(32\times32\times1\)的圖像
  • 第一個卷積層 CONV1
    使用6個尺寸為\(5 \times 5\)的濾波器,在卷積的過程中不做邊緣填充,步長為\(stride=1\)。單個核的卷積輸出大小為\((32 - 5 + 1) \times (32 - 5 + 1) = 28 \times 28\)。由於有6個卷積核,所以整個卷積層輸出得到為Feature Map為 \(28 \times 28 \times 6\)。該層的參數
  • 濾波器的核: \((5 \times 5 + 1) \times 6 = 156\),每個濾波器除了\(5 \times 5\)的核以外,還有一個偏置。
  • 神經元的個數:\(28 \times 28 \times 6\)在卷積層中,卷積核每移動一步產生一個神經元的輸出,也就相當於一個神經元。卷積的過程中,不做邊緣填充,對於\(32 \times 32\)的輸入,一個\(5\times5\)的卷積核產生\(28 \times 28\)個輸出,共有6個卷積核,有\(28 \times 28 \times 6\)個神經元。
  • 總共的連接數: \((5 \times 5 + 1) \times 28 \times 28 \times 6 = 122304\)。在卷積層,每個輸出的\(28 \times 28\)的Feature Map,都和一個\(5 \times 5\)卷積核相連。每個卷積核都有一個偏置。
  • 參數個數:按照神經網絡的全連接設計,每個像素間都有連接的話,輸入層和卷積層之間就要有122304個參數。但是在卷積神經網絡中,引入了權值共享,就大大的減少了卷積層的參數的個數。對\(32\times32\)的輸入,使用\(5\times5\)的核進行卷積,步長為1,卷積核每移動一步,就得到一個輸出,也就需要一個權值參數(有一個連接),這就需要\((5 \times 5 + 1) \times 28 \times 28\)個參數。引入權值共享,也就是一個卷積核在卷積的產生輸出的過程中,每移動一步產生輸出,都使用相同的權值參數,這時候參數的個數為\((5 \times 5 + 1) \times 1\)。共有6個卷積核,\((5 \times 5 + 1) \times 6 = 156\)個參數。

設輸入尺寸為\(W \times W\),卷積核尺寸為\(F \times F\),卷積步長為\(S\),填充寬度為\(P\),則卷積后輸出的尺寸為\((W - F + 2P) / S + 1\)

  • 池化層 POOL1
    池化層用於降采樣,其輸入是上一卷積層的輸出為\(28 \times 28 \times 6\)。在本層采用尺寸\(2 \times 2\)的池化單元,池化時的沿長和寬的步長均為2。 池化后的輸出為\((28 - 2) / 2 + 1 = 14\)。深度為6,則池化的輸出為\(14 \times 14 \times 6\)
    • 連接個數: \((2 \times 2 + 1 ) \times 14 \times14 \times 6 = 5880\)
    • 參數個數:和卷積層類似,每個池化單元進行池化的時候使用相同的權值,則訓練參數為$ (1 + 1) \times 6 = 12\(。 其中,一個是池化單元的權值\)w$,另一個是偏置參數。

池化層輸入尺寸為\(W \times W\),池化尺寸為\(F \times F\),池化步長為\(S\),則池化后的輸出尺寸為\((W - F)/S + 1\)

  • 第二個卷積層 CONV2
    該層的輸入為\(14 \times 14 \times 6\),使用16個核為\(5\times5\),步長為1。則其輸出尺寸為\(14 - 5 + 1 = 10\)。整個層的輸出為\(10 \times 10 \times 16\)。 這里要注意的本層的輸入有6個Feature Map,而輸出有16個Feature Map。 輸入的FeatureMap和輸出的FeatureMap之間並不是全連接的,而是局部連接的,具體規則如下:

上圖所示,輸出的6個FeatureMap只和輸入的3個FeatureMap相連接;輸出的9個FeatureMap和輸入的4個FeatureMap相連接;然后1個和6個連接。
- 參數個數: 由於權值共享,每個卷積核產生的輸出共享同一個權值。例如,對於和3個Feature Map相連接的輸出的FeatureMap,在卷積的時候,使用3個不同的卷積核分別對三個輸入的FeatureMap進行卷積,然后將卷積的結果進行求和,所以其權值參數的個數是\(5 \times 5 \times + 1\)。所以,總的參數個數是\(6 \times (5 \times 5 \times 3 + 1) + 9 \times ( 5 \times 5 \times 4 + 1) + 1 \times (5 \times 5 \times 6 + 1) = 1516\)
- 連接個數:輸出的Feature Map的尺寸是\(10 \times 10\),則連接個數是: \(1516 \times 10 \times = 151600\)

  • 第二個池化層 POOL2
    輸入是\(10 \times 10 \times 16\),池化參數和第一個池化層一樣采用尺寸\(2 \times 2\)的池化單元,池化時的沿長和寬的步長均為2,其輸出為\(5 \times 5 \times 16\),參數個數是\((1 + 1) \times 16 = 32\),連接數\((2 \times 2 + 1) \times 5 \times 5 \times 16 = 2000\)

  • 第三個卷積層 CONV3
    120個\(5\times5\)的卷積核,輸入的是\(5 \times 5 \times 16\),輸入的Feature Map和輸出的Feature Map是全連接,輸出的尺寸為\(1\times1 \times 120\)(卷積核和輸入尺寸相同,且沒有邊緣填充)。其卷積核的參數是\(5\times5 \times 16 + 1\)。 而輸出的120個神經元每個都和上一層的相連,則連接和參數的個數相同為\((5\times5 \times 16 + 1) \times 120 = 48120\)

  • 全連接層
    輸入是120維的向量,本層有84個神經元,參數個數是\((120 + 1) \times 84 = 10164\)

  • 輸出層
    全連接層,10個神經元,代表10個不同的數字。參數/連接個數為\(84 \times 10 = 840\)

LeNet論文

LeNet是在1998年提出的,用於手寫體數字的識別, 首次提出了卷積神經網絡的基本組成:卷積層,池化層和全連接層以及權值共享,感受野等概念。 雖然時間比較久i,但是作為卷積神經網絡的開山之作,還是值得入門者研讀一番的。

論文提出了:

  • 傳統的機器學習進行圖像分類,需要手工的設計特征提取器從圖像集中提取特征,然后輸入到機器學習算法中進行學習。
  • 使用梯度下降的方法訓練的多層神經網絡,可以直接從大量的數據集中學習到復雜的,高維度以及非線性的特征,這些特征遠比人工設計的特征要好很多。
  • 最后,可以在神經網絡的全連接層直接利用前面網絡層提取到的特征進行分類,不用像傳統的機器學習分類那樣,分成兩個步,而是進行end-to-end的學習。

但是將像素獨自的輸入到神經元中則有以下問題:

  • 訓練難。圖像的數據由一個個的像素組成,如果將每個像素都輸入到一個的單獨的神經元中,那神經網絡的尺寸,權值參數將是非常的大的。這么多的參數,需要消耗非常多的計算資源,以及需要非常大的數據集。
  • 無法應對圖像內容位置的變化。對於手寫體的數字圖像,其每個字符的大小,傾斜度,書寫的位置都會導致特征位置的變化。如果將每個像素輸入到一個單獨的神經元中,則需要大量的不同位置的訓練數據輸入到神經元中。
  • 忽略了圖像的局部相關性。 圖像的相鄰像素有很強的相關性。單獨一個像素輸入到神經元中則丟失了這種相關性。

有了以上的問題,LeCun就提出了大名鼎鼎的卷積神經網絡(CNN)

  • 利用卷積核對輸入進行卷積后輸入到神經元中,來保持圖像局部相關性
  • 使用局部感受野,權值共享,池化(下采樣)來實現圖像的平移,縮放和形變的不變性。

局部感受野
在卷積神經網絡的卷積層中,神經元的輸入是上一層中一個像素鄰域(也就是一個卷積核卷積后的結果,稱為局部感受野)。 使用局部感受野,在淺層網絡中神經元可以提取到圖像的邊緣,角點等視覺特征,這些特征在后面的網絡中進行結合,組成更高層的特征。(在人工設計的特征提取器中,則很難提取圖像的高層特征)。

感受野的定義: 感受野是卷積神經網絡(CNN)每一層輸出的特征圖(feature map)上的像素點在原始輸入圖像上映射的區域大小。
一個局部感受野可以看作是一個卷積核進行一次卷積的結果,一個\(5\times5\)的卷積核對輸入圖像的\(5\times5\)鄰域進行卷積得到一個輸出\(P\),輸入到神經元中。 在當前的卷積層中,這個\(P\)就可以代表上一層的\(5\times5\)鄰域。 個人理解。

權值共享
引入權值共享的一個原因是為了解決圖像的形變和平移導致的圖像顯著特征位置的變化。將同一個卷積核得到的結果設為相同的權值,可以有效的降低其位置不同帶來的影響。權值共享的另一個依據是,在一個位置能夠提取到有效的特征,在另外的位置也能提取到(特別是基礎的點線特征)。另外,使用權值共享也大大的降低的網絡的參數。

一個卷積核就相當於一個特征提取器,每個卷積和和輸入圖像進行卷積得到輸出稱為Feature Map,一個FeatureMap中所有的像素點和上一層的連接,使用相同的權值參數,即為權值共享。

每一層中所有的神經元形成一個平面,這個平面中所有神經元共享權值。神經元(unit)的所有輸出構成特征圖,特征圖中所有單元在圖像的不同位置執行相同的操作(同一個特征圖是使用同意給卷積核得到),這樣他們可以在輸入圖像的不同位置檢測到同樣的特征,一個完整的卷積層由多個特征圖組成(使用不同的權值向量),這樣每個位置可以提取多種特征。
一個具體的示例就是圖2 LeNet-5中的第一層,第一層隱藏層中的所有單元形成6個平面,每個是一個特征圖。一個特征圖中的一個單元對應有25個輸入,這25個輸入連接到輸入層的5x5區域,這個區域就是局部感受野。每個單元有25個輸入,因此有25個可訓練的參數加上一個偏置。由於特征圖中相鄰單元以前一層中連續的單元為中心,所以相鄰單元的局部感受野是重疊的。比如,LeNet-5中,水平方向連續的單元的感受野存在5行4列的重疊,之前提到過,一個特征圖中所有單元共享25個權值和一個偏置,所以他們在輸入圖像的不同位置檢測相同的特征,每一層的其他特征圖使用不同的一組權值和偏置,提取不同類型的局部特征。LeNet中,每個輸入位置會提取6個不同的特征。特征圖的一種實現方式就是使用一個帶有感受野的單元,掃面整個圖像,並且將每個對應的位置的狀態保持在特征圖中,這種操作等價於卷積,后面加入一個偏置和一個函數,因此,取名為卷積網絡,卷積核就是連接的權重。卷積層的核就是特征圖中所有單元使用的一組連接權重。卷積層的一個重要特性是如果輸入圖像發生了位移,特征圖會發生相應的位移,否則特征圖保持不變。這個特性是CNN對位移和形變保持魯棒的基礎。

一個卷積核提取輸入數據的某種特征輸出一個Feature Map。 既然提取的是同一種特征,那么使用同一個權值也是應該的。

下采樣,池化
在圖像分類中,起主導作用的是圖像特征的相對位置,如圖像中的數字7從左上角移到右下角,仍然是數字7,重要的是直線-點-直線之間的相對位置。因為圖像的平移,形變是很常見的,所以圖像特征的精確的位置信息,在分類識別中甚至是有害的。 通過降低圖像分辨率的方式來降低圖像特征位置的精度,使用池化函數(均值或者最大)對圖像進行下采樣,降低網絡的輸出對圖像形變和平移的敏感程度。如果對圖像做平移,那么對應於高層特征的平移(因為權值共享);如果對圖像做局部旋轉,小范圍旋轉/扭曲會被局部感受野消除,大范圍扭曲會因為降采樣而模糊掉其影響。

Keras實現

並沒有,精確的實現論文中描述的LeNet-5的網絡結構,只是照着實現了一個簡單的卷積神經網絡,網絡結構如下:

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 32, 32, 20)        1520
_________________________________________________________________
activation_1 (Activation)    (None, 32, 32, 20)        0
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 16, 16, 20)        0
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 16, 16, 50)        25050
_________________________________________________________________
activation_2 (Activation)    (None, 16, 16, 50)        0
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 8, 8, 50)          0
_________________________________________________________________
flatten_1 (Flatten)          (None, 3200)              0
_________________________________________________________________
dense_1 (Dense)              (None, 500)               1600500
_________________________________________________________________
activation_3 (Activation)    (None, 500)               0
_________________________________________________________________
dense_2 (Dense)              (None, 10)                5010
_________________________________________________________________
activation_4 (Activation)    (None, 10)                0
=================================================================
Total params: 1,632,080
Trainable params: 1,632,080
Non-trainable params: 0
_________________________________________________________________

調用Keras API可以很容易的實現上述的結構

# -*- coding:utf-8 -*-

from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Flatten
from keras.layers.core import Dense
from keras import backend as K 

class LeNet:
    @staticmethod
    def build(width,height,depth,classes):
        model = Sequential()
        inputShape = (height,width,depth)

        if K.image_data_format() == "channels_first":
            inputShape = (depth,height,width)

        # first set of CONV => RELU => POOL
        model.add(Conv2D(20,(5,5),padding="same",input_shape=inputShape))
        model.add(Activation("relu"))
        model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))

        # second set of CONV => RELU => POOL_layers
        model.add(Conv2D(50,(5,5),padding="same"))
        model.add(Activation("relu"))
        model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))

        # set of FC => RELU layers
        model.add(Flatten())
        model.add(Dense(500))
        model.add(Activation("relu"))

        # softmax classifier
        model.add(Dense(classes))
        model.add(Activation("softmax"))

        return model

將上述網絡應用於CIFAR10數據集進行分類

測試代碼,首先使用scikit-learn加載CIFAR10數據,並進行歸一化

print("[INFO] loading CIFAR-10 data...")
((trainX,trainY),(testX,testY)) = cifar10.load_data()
trainX = trainX.astype("float")  /  255.0
testX = testX.astype("float")  /  255.0

對CIFAR10的類別進行編碼

lb =  LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.fit_transform(testY)

處理完數據后,調用上面的LeNet建立LeNet網絡結構並使用trainX數據集進行訓練

print("[INFO] compiling model...")
opt =  SGD(lr=0.05)
model = lenet.LeNet.build(width=width,height=height,depth=depth,classes=classes)
model.compile(loss="categorical_crossentropy",optimizer=opt,metrics=["accuracy"])

# train
print("[INFO] training network...")
H = model.fit(trainX,trainY,validation_data=(testX,testY),batch_size=32,epochs=epochs,verbose=1)

最后使用testX數據集進行評估

# evaluate the network
print("[INFO] evaluating networking...")
predictions = model.predict(testX,batch_size=32)
print(classification_report(testY.argmax(axis=1),predictions.argmax(axis=1),
	target_names=labelNames))

很明顯的過擬合了,這里就不關注這個精度了,只是簡單的測試下。

更詳細的測試代碼,可以Start/Fork GitHub上https://github.com/brookicv/machineLearningSample 以及 https://github.com/brookicv/imageClassification


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM