淺談卷積神經網絡(CNN)——卷積、批標準化、池化、失活

記錄一下昨天半夜學的東西,以下代碼均通過tensorflow2自帶的keras實現。


卷積神經網絡(CNN)

  • 爲什麼要使用卷積神經網絡?
    卷積神經網絡常用於圖像處理。它可以提取關鍵信息,如圖片輪廓、主色調等信息,在減少喂入數據量的同時,又能增加模型深度,提高準確率。其具體實現筆者將在下文中介紹。

概念

卷積

卷積是通過兩個函數f 和g 生成第三個函數的一種數學算子,可以理解爲,在原函數f上,通過函數g進行處理,得到結果函數。這個處理卷積過程的g,就是卷積核。

爲了便於理解,舉一種簡單情況(選用離散數列進行演示,連續數列會更加麻煩):
f=[1,4,6,3,5,9,7],g=[1,2,1] 原函數:f = [1,4,6,3,5,9,7],\\ 卷積核:g = [1,-2,1]

接下來,卷積核從左向右移動,每三個元素通過卷積核得到結果,如:
1×1+4×(2)+6×1=114×1+6×(2)+3×1=55 1 \times 1 + 4 \times (-2) + 6 \times 1 = -1,得到第一個結果爲-1\\ 4 \times 1 + 6 \times (-2) + 3 \times 1 = -5,得到第一個結果爲-5\\ ……

146359712112112112112115526 \begin{matrix} 1&4&6&3&5&9&7\\\\ 1&-2&1&\\ \rightarrow&1&-2&1\\ &\rightarrow&1&-2&1\\ &&\rightarrow&1&-2&1\\ &&&\rightarrow&1&-2&1\\\\ &\downarrow&\downarrow&\downarrow&\downarrow&\downarrow\\ &-1&-5&5&2&-6&\qquad \end{matrix}

最終得到的數列就是卷積後的結果。

上面的例子是一維矩陣(數列)的卷積,對於二維、三維甚至更高維的矩陣,都可以這樣類比。

舉一個例子:
f=(148345128246)g=(1111) 原函數:f = \begin{pmatrix} 1&4&8&3\\ -4&5&-1&2\\ 8&-2&4&-6 \end{pmatrix} \\ 卷積核:g = \begin{pmatrix} 1&-1\\-1&1 \end{pmatrix}

同樣,卷積核需要逐個移動,例如先從左往右,再從上往下,遍歷每一塊元素:
(1445)×(1111)=1×1+4×(1)+(4)×(1)+5×1=9(4851)×(1111)=4×1+8×(1)+5×(1)+(1)×1=10 第一個元素: \begin{pmatrix} 1&4\\-4&5 \end{pmatrix} \times \begin{pmatrix} 1&-1\\-1&1 \end{pmatrix}\\ = 1 \times 1 + 4 \times (-1) + (-4) \times (-1) + 5 \times 1 = 9\\ \rightarrow第二個元素: \begin{pmatrix} 4&8\\5&-1 \end{pmatrix} \times \begin{pmatrix} 1&-1\\-1&1 \end{pmatrix}\\ = 4 \times 1 + 8 \times (-1) + 5 \times (-1) + (-1) \times 1 = -10\\ ……

最終結果:
(9108191213) \begin{pmatrix} 9&-10&8\\-19&12 &-13 \end{pmatrix}

動圖演示:
在這裏插入圖片描述
更高維的卷積都可以用這種方法推廣。

卷積核

上面的例子已經介紹了卷積核,卷積核非常神奇,圖像像素排列成的矩陣在通過卷積核可以實現銳化、模糊、邊緣、浮雕等效果,因此,我們可以使用卷積核提取關鍵信息。

下面是一些圖像處理常用卷積核:
(1/91/91/91/91/91/91/91/91/9)(111191111)Soble(101202101) 均值模糊: \begin{pmatrix} 1/9&1/9&1/9\\ 1/9&1/9&1/9\\ 1/9&1/9&1/9 \end{pmatrix}\\ 銳化: \begin{pmatrix} -1&-1&-1\\ -1&9&-1\\ -1&-1&-1 \end{pmatrix}\\ Soble邊緣檢測: \begin{pmatrix} -1&0&1\\ -2&0&2\\ -1&0&1 \end{pmatrix}

這裏筆者使用OpenCV2演示效果,代碼如下:

# !usr/bin/env python
# -*- coding: utf-8 -*-
# @Date: 2020/6/15
# @Author: Koorye

import cv2
import numpy as np

if __name__ == '__main__':
    img = cv2.imread('data/img/lena.jpg')
    cv2.imshow('Lena', img)

    blur = np.array([[1 / 9, 1 / 9, 1 / 9], [1 / 9, 1 / 9, 1 / 9], [1 / 9, 1 / 9, 1 / 9]], np.float32)
    sharp = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]], np.float32)
    soble = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], np.float32)

    blur_dst = cv2.filter2D(img, -1, kernel=blur)
    sharp_dst = cv2.filter2D(img, -1, kernel=sharp)
    soble_dst = cv2.filter2D(img, -1, kernel=soble)

    cv2.imshow('blur', blur_dst)
    cv2.imshow('sharp', sharp_dst)
    cv2.imshow('soble', soble_dst)

    cv2.waitKey(0)

運行結果:
在這裏插入圖片描述
通過修改卷積核的數值和尺寸,還可以得到不同效果的圖片。

全零填充

之前卷積的例子,在卷積之後都會丟失寬度(高度),原來7個元素的數列變成了5個元素,原來4x3的矩陣變成了3x2,這與原函數和卷積核的維度和尺寸有關。

要解決寬度(高度)的丟失問題,有一個解決思路,就是使用全零填充,即在邊緣加上0.

如:
f=[1,4,6,3,5,9,7],g=[1,2,1] 原函數:f = [1,4,6,3,5,9,7],\\ 卷積核:g = [1,-2,1]

卷積的結果是:1,5,5,2,61,-5,5,2,-6.

但如果使用全零填充,就變成:
f=[0,1,4,6,3,5,9,7,0],g=[1,2,1] 原函數:f = [0,1,4,6,3,5,9,7,0],\\ 卷積核:g = [1,-2,1]

卷積的結果是:2,1,5,5,2,6,52,1,-5,5,2,-6,-5.

通過全零填充,梳理(矩陣)的尺寸得以保留,這可以有效緩解網絡層數加深後數據量減少的問題。

批標準化

批標準化(Batch Normalization)是一種用於改善人工神經網絡的性能和穩定性的技術,簡稱BN算法。

批標準化和標準化類似,用於將數據規範到一定的範圍內,以便計算。

筆者非該專業,無法深入講解,僅在此簡單介紹其作用。

池化

池化是一種採樣方法,它可以提取數據特徵,減少數據量並緩解過擬合。下面介紹一下兩種池化方法:

均值池化

顧名思義,即取平均值。
首先將源數據分塊,然後取每塊的平均值,如:
(4682732984914325)(510.59.58.5) \begin{pmatrix} 4&6&|&8&2\\ 7&3&|&2&9\\ \text{—}&\text{—}&\text{—}&\text{—}&\text{—}\\ 8&4&|&9&1\\ 4&3&|&2&5 \end{pmatrix}\rightarrow \begin{pmatrix} 5&10.5\\9.5&8.5 \end{pmatrix}

最大值池化

最大值池化也很好理解,即取最大值:
(4682732984914325)(55.254.754.25) \begin{pmatrix} 4&6&|&8&2\\ 7&3&|&2&9\\ \text{—}&\text{—}&\text{—}&\text{—}&\text{—}\\ 8&4&|&9&1\\ 4&3&|&2&5 \end{pmatrix}\rightarrow \begin{pmatrix} 5&5.25\\4.75&4.25 \end{pmatrix}

失活

隨機失活(Dropout)是對具有深度結構的人工神經網絡進行優化的方法,在學習過程中通過將隱含層的部分權重或輸出隨機歸零,降低節點間的相互依賴性從而實現神經網絡的正則化,降低其結構風險。

如何實現呢?每次,我們可以選用神經層中的部分神經元,下次訓練時再選用其他部分,通過這樣的選取,可以有效緩解過擬合等問題。

圖例:

Dense
Dropout
Dense
b1
c1
c2
b2
a1
a2

接下來,Dropout層會隨機失活,例如,使b1失活,構成的神經網絡:

Dense
Dropout
Dense
b2
c1
c2
b1失活
a1
a2

通過每次隨機選擇神經元失活,就可以保持神經網絡的穩定性和活性。

CNN結構

有了上面的介紹,概括CNN卷積神經網絡的結構:
卷積(Convolutional) → 批標準化(BN) → 激活(Activation) → 池化(Pooling) → 失活(Dropout)* → 全連接(FC)

概括爲CBAPD.

簡單演示tensorflow2的keras搭建CNN神經網絡,以下是一個典型的解決多分類問題(如圖片內容分類)的代碼:

# !usr/bin/env python
# -*- coding: utf-8 -*-
# @Date: 2020/6/15
# @Author: Koorye

import tensorflow as tf
import numpy as np

if __name__ == '__main__':
	# 需要提供數據集
	# x_train, x_test, y_train, y_test = ...
	
    model = tf.keras.Sequential(
    	# 卷積層,filters指定卷積核數量,kernal_size指定卷積核尺寸
    	# padding指定是否使用全零填充
        tf.keras.layers.Conv2D(filters=6, kernal_size=(5, 5), padding='same'),
        # 批標準化
        tf.keras.layers.BatchNormalization(),
        # relu激活函數
        tf.keras.layers.Activation('relu'),
        # 池化,pool_size指定池尺寸,strides指定池間隔,默認與尺寸一致
        tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=2, padding='same'),
        # 隨機失活,指定每次失活20%的神經元
        tf.keras.layers.Dropout(0.2),
        # 數據平鋪成一維數組
        tf.keras.layers.Flatten(),
        # 全連接,128個神經元,relu激活函數
        tf.keras.layers.Dense(128, activation='relu'),
        # 隨機失活
        tf.keras.layers.Dropout(0.2),
        # 全連接,10個神經元,softmax激活函數,用於解決多分類問題
        tf.keras.layers.Dense(10, activation='softmax')
    )
	
	# 模型編譯,optimize指定adam優化器,loss指定損失函數爲均方差
    model.compile(optimize='adam', loss='mse')
	
	# 模型訓練,batch_size指定每次喂入的數據量,epochs指定訓練次數
	# validation_data指定驗證集,validation_freq指定多少次訓練進行一次驗證
    model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_test, y_test), validation_freq=1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章