卷積神經網絡,在圖像識別和自然語言處理中有很大的作用,講cnn的中文博客也不少,但是個人感覺說的脈絡清晰清晰易懂的不多.
無意中看到這篇博客,寫的很好,圖文並茂.建議英文好的直接去看原文.英文不好的就直接看我這篇,算是讀后總結吧.原文里對數學原理的着墨不多,在這篇文章里我會留着相關的標題,待日后慢慢補充這篇文章.

卷積神經網絡

以上是一個cnn的典型結構.包含以下3種結構
- 卷積層
- 池化層
- 全連接層
卷積層

這是數字8的圖片,圖片其實就是一堆像素點的組合,可以理解為一個M*N的矩陣,矩陣中每一個元素的值就是像素值,取值從0-255.彩色的圖有RGB三個通道,可以理解為3個M*N矩陣.為了簡化討論,我們以灰度圖為例,灰度圖是單通道的.
卷積在做什么
假設我們有一個5*5的圖片

我們有一個3*3的矩陣,在CNN中,我們稱之為‘filter‘ or ‘kernel’ or ‘feature detector’。
,
我們用這個kenel對輸入的圖像做卷積,過程如下所示:
其中,卷積的過程,用filter與input的相應位置相乘再相加.得到新的矩陣的對應元素的值.

然后滑動這個filter矩陣,滑動x個像素,x稱之為步長stride(在這個例子中步長=1),算出下一個矩陣對應元素的值.不斷重復這個過程. 完整過程如下所示:

卷積后得到的這個3*3的矩陣稱之為‘Activation Map’ or the ‘Feature Map‘.
卷積層完成了特征提取.
卷積有什么效果


不同的filter有不同的效果.比如上圖展示了邊緣檢測,銳化,模糊等等.
下圖很好的展示了cnn卷積操作做了什么:

不同的filter提取出了圖片的不同角度的特征,得到了不同的特征圖.注意將上述的圖片都理解為一個一個的矩陣.
It is important to note that the Convolution operation captures the local dependencies in the original image.
影響我們得到的特征圖的參數有以下幾個:
Depth:
depth與filter數量是一致的.不同的獨立的filter提取出不同的特征. 比如如下,有3個filter對原始圖片進行處理,得到的特征圖可以理解為3個疊在一起的矩陣.

Stride
步長是filter矩陣在輸入矩陣上每次滑動的距離.步長越大,最終得到的特征圖越小.
Zero-padding
補零操作,在原始矩陣周圍補0. 添加補0的卷積叫wide convolution, 不添加補0的卷積叫 narrow convolution.

以原始圖像為32*32,filter為5*5為例,不做補0的話,得到的特征圖矩陣大小為28*28.在神經網絡的前幾層,我們希望保留盡可能多的信息,好提取更多的特征.即我們希望依然得到一個32*32的矩陣.
https://adeshpande3.github.io/A-Beginner%27s-Guide-To-Understanding-Convolutional-Neural-Networks-Part-2/
Now, let’s take a look at padding. Before getting into that, let’s think about a scenario. What happens when you apply three 5 x 5 x 3 filters to a 32 x 32 x 3 input volume? The output volume would be 28 x 28 x 3. Notice that the spatial dimensions decrease. As we keep applying conv layers, the size of the volume will decrease faster than we would like. In the early layers of our network, we want to preserve as much information about the original input volume so that we can extract those low level features. Let’s say we want to apply the same conv layer but we want the output volume to remain 32 x 32 x 3. To do this, we can apply a zero padding of size 2 to that layer. Zero padding pads the input volume with zeros around the border. If we think about a zero padding of two, then this would result in a 36 x 36 x 3 input volume.
卷積為什么有這種效果
卷積為什么可以提取特征,背后的數學原理,日后補充
非線性(ReLU)

ReLU作用於卷積后得到的特征圖. 將矩陣中的負數替換為0.
ReLU為卷積神經網絡引入非線性.真實世界里的數據絕大多數是非線性的(卷積是一種線性操作)
The purpose of ReLU is to introduce non-linearity in our ConvNet, since most of the real-world data we would want our ConvNet to learn would be non-linear (Convolution is a linear operation – element wise matrix multiplication and addition, so we account for non-linearity by introducing a non-linear function like ReLU)
對特征圖中的每一個像素做ReLU操作后的效果如上圖所示.
其他的非線性函數還有tanh,sigmoid。但是實際使用中,大多情況下ReLU效果更好.
池化層
上面經過多個filter卷積,以及ReLU處理之后,我們得到了多個特征圖.
此時我們想減小特征矩陣的維度,但是又保留下最重要的特征.和上面介紹的卷積過程類似,我們定義一個空間池.池化操作有Max, Average, Sum etc.
Spatial Pooling (also called subsampling or downsampling) reduces the dimensionality of each feature map but retains the most important information. Spatial Pooling can be of different types: Max, Average, Sum etc.
下圖展示了用一個2*2的filter做最大池化后的效果:

下圖展示了實際的特征圖做不同的池化操作的效果:

池化有以下4個作用
- 減少特征維度
- 減少參數及運算量,這樣模型的復雜度降低,避免過擬合
- 使得神經網絡對原始圖像的一些小改變可以無視,仍然取的相同的處理效果. 比如原始圖片的某個像素從0-->10.假設這個像素周邊的像素最大值為20.那做完max池化操作后,我們得到的仍然是20.
- 讓我們得到等變的圖像.(這句沒大理解啥意思).作用就是:無論圖片中的物體位於什么位置,我們都能識別.
- makes the input representations (feature dimension) smaller and more manageable
- reduces the number of parameters and computations in the network, therefore, controlling overfitting [4]
- makes the network invariant to small transformations, distortions and translations in the input image (a small distortion in input will not change the output of Pooling – since we take the maximum / average value in a local neighborhood).
- helps us arrive at an almost scale invariant representation of our image (the exact term is “equivariant”). This is very powerful since we can detect objects in an image no matter where they are located (read [18] and [19] for details).
全連接層
全連接層是一個在輸出層使用了softmax激活函數的多層感知機.
卷積層和池化層的輸出的特征圖矩陣,代表了輸入圖像的高層次特征(high-level features).全連接層使用這些高層次特征對輸入圖片進行分類.

除了用於分類,添加一個全連接層通常也是一種為特征組合添加非線性的方式.對分類任務來說,使用卷積和池化層輸出的特征就已經能取得不錯的結果,但是把這些特征組合到一起,效果會更好.
全連接層輸出的分類概率之和為1.這是由softmax保證的.
CNN的完整過程

以上述圖片識別為例,我們要識別出來這張圖應該被分類為dog/cat/boat/bird?
上文說過了,卷積層和池化層的作用是特征提取,全連接層的作用是分類.
整個神經網絡的訓練過程如下:
- step1:用隨機值初始化所有的filter和參數/權重
- step2:CNN接收待識別圖片作為輸入,經過卷積,ReLU,池化,全連接層的一系列操作后,可以輸出分類概率
- 比如我們得到概率為[0.2, 0.4, 0.1, 0.3]
- 由於權重值是隨機設置的,所以第一次訓練后得到的分類概率也是隨機的.
- step3:計算分類結果的錯誤.
- Total Error = ∑ ½ (target probability – output probability) ²
- step4:用反向傳播算法計算Total Error 對網絡中所有權值的梯度,利用梯度下降更新所有filter/權重值和參數值,使輸出誤差最小。
- 權重根據它們對總誤差的貢獻按比例進行調整
- 對同一圖片再進行訓練,這時候得到的概率可能是[0.1, 0.1, 0.7, 0.1],距離正確的目標[0, 0, 1, 0]又更近一步了.這說明神經網絡通過調整weights/filters的值已經更好地學到了圖片的信息.
- 在訓練過程中,filters,filter size,cnn的結構這些是在step1之前就確定的,不會在訓練過程中改變.只有filter矩陣的值和連接的權重會更新.
- step5:對訓練集中的所有圖片重復step2-step4.
這樣我們的神經網絡的filter/parameters/weights這些就確定下來了,當來了一個新的圖片,我們就可以按照前面說的卷積-池化-全連接這個過程處理圖片對其進行分類.

幾點要注意的:
- 上面的例子里我們使用了2個卷積層+池化層,實際上這個次數是沒有限制的.
- 並不是一定要一個卷積層接一個池化層,池化層前面可以有多個卷積層.
手寫數字識別示例

這是一個1024個像素點(32*32)的圖片。
卷積層1有6個filter,每個filter是5*5矩陣(stride=1)。 28*28
池化層1做2*2 max pooling(stride=2)。

可以看出來做max pooling之后,圖片留下了最亮的點.
卷積層2有6個filter,每個filter是5*5矩陣(stride=1)。
池化層2做2*2 max pooling(stride=2)。
接下來是3個全連接層
- 第一個連接層有120個神經元
- 第二個連接層有100個神經元
- 第三個連接層(也叫輸出層),有10個神經元,代表數字0-9.

cnn識別手寫數字集
model = Sequential() model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same',activation ='relu', input_shape = (28,28,1))) model.add(Conv2D(filters = 64, kernel_size = (5,5),padding = 'Same', activation ='relu')) model.add(MaxPool2D(pool_size=(2,2))) model.add(Flatten()) model.add(Dense(256, activation = "relu")) model.add(Dropout(0.2)) model.add(Dense(10, activation = "softmax")) model.compile(optimizer = "SGD" , loss = "categorical_crossentropy", metrics=["accuracy"]) model.fit(X_train, Y_train, batch_size=100, verbose=1,epochs=5,validation_data=(X_val, Y_val))
完整代碼見https://github.com/sdu2011/nlp/blob/master/keras.ipynb.

