卷積神經網路的原理及Python實現

郝hai發表於2024-05-25

卷積神經網路(Convolutional Neural Networks)是一種深度學習模型或類似於人工神經網路的多層感知器,常用來分析視覺影像。卷積神經網路(Convolutional Neural Network,CNN)是一種在計算機視覺領域取得了巨大成功的深度學習模型,該演算法的靈感來自於人腦的一部分,即視覺皮層。視覺皮層是人腦的一部分,負責處理來自外界的視覺資訊。它有不同的層,每一層都有自己的功能,即每一層從影像或任何視覺中提取一些資訊,最後將從每一層接收到的所有資訊組合起來,對影像/視覺進行解釋或分類。同樣,CNN有各種濾波器,每個濾波器從影像中提取一些資訊,例如邊緣、不同種類的形狀(垂直、水平、圓形),然後將所有這些組合起來識別影像。在過去的幾年中,CNN已經在影像識別、目標檢測、影像生成和許多其他領域取得了顯著的進展,成為了計算機視覺和深度學習研究的重要組成部分。

卷積神經網路的原理及Python實現

一、影像原理

在瞭解卷積神經網路前,我們先來看看影像在計算機中的表示。RGB影像是一種在計算機視覺和影像處理領域廣泛使用的彩色影像表示方法。RGB代表紅色(Red)、綠色(Green)和藍色(Blue),這是三種基本的顏色,透過不同的組合可以生成各種顏色。每個畫素在RGB影像中透過這三種顏色的不同強度值來表示,通常這些值的範圍是從0到255(8位表示)。在計算機中,RGB影像通常儲存為一個三維陣列或矩陣:第一個維度和第二個維度對應於影像的畫素位置(行和列)。第三個維度有三個元素,分別對應紅色、綠色和藍色通道的值。例如,一個800x600的RGB影像可以表示為一個800x600x3的陣列。

RGB影像 R G B

上面RGB這幅圖的本質是一個4003003的一個矩陣PI 400, 300, 3,說明這個影像有400列,300行,以及在色彩上有三個分量。每個分量單獨拿出來都是一個400300(1)的矩陣。如你所見,它們並不是彩色的,而是一幅灰度影像,對於一副8bit的影像來說,矩陣元素的取值範圍是從0-255(0 - 2^8-1),矩陣中的元素對應我們所說的畫素(pixel),其值即該畫素的灰度值,數值越大,畫素的顏色越‘白/淺’;數值越小,畫素的顏色越’黑/深‘
對於影像每個分量來說,它只是灰度,談論色彩沒有意義,它是“黑白”的!(用黑白來描述灰度影像並不準確,用深淺可能更準確一些,但也不嚴謹。所以我加上了引號。你要願意把通道設成紅色綠色紫色黃色都行。在影像顯示時,我們把影像的R分量放進紅色通道里,B分量放進藍色通道里,G分量放進綠色通道里。經過一系列處理,顯示在螢幕上的就是我們所看到的彩色影像了。
所以說,通道和一幅影像根本就沒關係!數字影像是矩陣,矩陣只描述其空間位置和在色彩上的分量,哪有通道了?通道是什麼?CHANNEL!圖片中有channel這個概念嗎?有個回答說通道類似顏料,這個意思就有點接近了。想要什麼顏色,對應的通道里的灰度值就大一點就行了。

計算機影像 RGB顏色模型 三維陣列

二、卷積神經網路的原理

用CNN卷積神經網路識別圖片,一般需要的步驟有:

(1) 卷積層(Convolutional Layer)初步提取特徵
(2) 池化層(Pooling Layer)提取主要特徵
(3) 全連線層(Fully Connected Layer)將各部分特徵彙總
(4) 產生分類器(classifier),進行預測識別

2.1 卷積層工作原理

卷積層的作用:就是提取圖片每個小部分裡具有的特徵
假定我們有一個尺寸為 6∗6 的影像,每一個畫素點裡都儲存著影像的資訊。我們再定義一個卷積核(相當於權重),用來從影像中提取一定的特徵。卷積核與數字矩陣對應位相乘再相加,得到卷積層輸出結果。

(429 = 18x1+54x0+51x1+55x0+121x1+75x0+35x1+24x0+204x1)
卷積核的取值在沒有以往學習的經驗下,可由函式隨機生成,再逐步訓練調整。當所有的畫素點都至少被覆蓋一次後,就可以產生一個卷積層的輸出(下圖的步長為1)

機器一開始並不知道要識別的部分具有哪些特徵,是透過與不同的卷積核相作用得到的輸出值,相互比較來判斷哪一個卷積核最能表現該圖片的特徵——比如我們要識別影像中的某種特徵(比如曲線),也就是說,這個卷積核要對這種曲線有很高的輸出值,對其他形狀(比如三角形)則輸出較低。卷積層輸出值越高,就說明匹配程度越高,越能表現該圖片的特徵

卷積層具體工作過程:
比如我們設計的一個卷積核如下左,想要識別出來的曲線如下右:

卷積核 漫畫老鼠

現在我們用上面的卷積核,來識別這個簡化版的圖片——一隻漫畫老鼠。當機器識別到老鼠的屁股的時候,真實區域數字矩陣與卷積核相乘作用後,輸出較大:6600;而用同一個卷積核,來識別老鼠的耳朵的時候,輸出則很小:0 。

老鼠屁股 老鼠耳朵

我們就可以認為:現有的這個卷積核儲存著曲線的特徵,匹配識別出來了老鼠的屁股是曲線的。我們則還需要其他特徵的卷積核,來匹配識別出來老鼠的其他部分。卷積層的作用其實就是透過不斷的改變卷積核,來確定能初步表徵圖片特徵的有用的卷積核是哪些,再得到與相應的卷積核相乘後的輸出矩陣

2.2 池化層工作原理

池化層的輸入就是卷積層輸出的原資料與相應的卷積核相乘後的輸出矩陣
池化層的目的:

  • 為了減少訓練引數的數量,降低卷積層輸出的特徵向量的維度
  • 減小過擬合現象,只保留最有用的圖片資訊,減少噪聲的傳遞
    最常見的兩種池化層的形式:
  • 最大池化:max-pooling——選取指定區域內最大的一個數來代表整片區域
  • 均值池化:mean-pooling——選取指定區域內數值的平均值來代表整片區域(Average Pooling)

舉例說明兩種池化方式:(池化步長為2,選取過的區域,下一次就不再選取)

在 4∗4 的數字矩陣裡,以步長 2∗2 選取區域,比如上左將區域[1,2,3,4]中最大的值4池化輸出;上右將區域[1,2,3,4]中平均值5/2池化輸出。

2.3 全連線層工作原理

卷積層和池化層的工作就是提取特徵,並減少原始影像帶來的引數。然而,為了生成最終的輸出,我們需要應用全連線層來生成一個等於我們需要的類的數量的分類器。全連線層的工作原理和之前的神經網路學習很類似,我們需要把池化層輸出的張量重新切割成一些向量,乘上權重矩陣,加上偏置值,然後對其使用ReLU啟用函式,用梯度下降法最佳化引數既可。

2.4 CNN的結構組成

上面我們已經知道了卷積(convolution)、池化(pooling)以及填白(padding)是怎麼進行的,接下來我們就來看看CNN的整體結構,它包含了3種層(layer):
Convolutional layer(卷積層–CONV):由濾波器filters和啟用函式構成。 一般要設定的超引數包括filters的數量、大小、步長,以及padding是“valid”還是“same”。當然,還包括選擇什麼啟用函式。
Pooling layer (池化層–POOL):這裡裡面沒有引數需要我們學習,因為這裡裡面的引數都是我們設定好了,要麼是Maxpooling,要麼是Averagepooling。 需要指定的超引數,包括是Max還是average,視窗大小以及步長。 通常,我們使用的比較多的是Maxpooling,而且一般取大小為(2,2)步長為2的filter,這樣,經過pooling之後,輸入的長寬都會縮小2倍,channels不變。
Fully Connected layer(全連線層–FC):這個前面沒有講,是因為這個就是我們最熟悉的傢伙,就是我們之前學的神經網路中的那種最普通的層,就是一排神經元。因為這一層是每一個單元都和前一層的每一個單元相連線,所以稱之為“全連線”。 這裡要指定的超引數,無非就是神經元的數量,以及啟用函式。

老鼠屁股 老鼠耳朵

三、卷積神經網路的Python實現

使用Keras庫構建和訓練一個簡單神經網路模型來處理鳶尾花(Iris)資料集的示例程式碼的詳細解釋:

3.1 匯入Keras庫和相關模組

from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.utils import to_categorical
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt 

3.2 模型的設定

  • Sequential:用於建立一個按順序新增層的神經網路模型。
  • Dense:用於建立一個全連線層。
  • Activation:用於指定層的啟用函式。
    有兩種方式來設定模型:
    方式一:將網路層例項列表直接傳遞給Sequential建構函式。
    方式二:先建立一個Sequential模型,然後使用add()方法依次新增各層。

3.3 Iris資料集的匯入和切分及標準化

iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) 
#load\_iris**:匯入鳶尾花資料集,train\_test\_split**:將資料集劃分為訓練集和測試集,測試集佔30%
#StandardScaler:對訓練集和測試集進行標準化處理
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

#to\_categorical:將分類標籤轉換為獨熱編碼(One-Hot Encoding)
y_train = to_categorical(y_train, 3)
y_test = to_categorical(y_test, 3)

3.4 建立神經網路模型三部曲

#建立模型
model = Sequential([
    Dense(10, input_shape=(4,)),
    Activation('sigmoid'),
    Dense(10),
    Activation('relu'),
    Dense(10),
    Activation('tanh'),
    Dense(3),
    Activation('softmax')
])

# 編譯模型
model.compile(loss='categorical_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

#compile:指定損失函式為categorical_crossentropy,最佳化器為rmsprop,評估標準為accuracy

# 訓練模型
history = model.fit(X_train, y_train, epochs=100, batch_size=5, verbose=1)
#fit:使用訓練集資料和標籤訓練模型,指定訓練的輪數(epochs)

3.5 模型評價與預測

#evaluate:在測試集上評估模型的效能,列印測試集上的損失函式和預測準確率。
loss, accuracy = model.evaluate(X_test, y_test, verbose=0)
print(f'Test loss: {loss:.4f}')
print(f'Test accuracy: {accuracy:.4f}')

#predict:對測試集進行預測,列印預測結果及其形狀
predictions = model.predict(X_test)
print(predictions)
print(predictions.shape)
3.6 視覺化展示
#使用matplotlib.pyplot繪製訓練過程中的準確率和損失函式變化圖
plt.plot(history.history['accuracy'])
plt.plot(history.history['loss'])
plt.title('Model accuracy and loss')
plt.xlabel('Epoch')
plt.legend(['Accuracy', 'Loss'], loc='upper left')
plt.show()

3.7 程式展示

#全部程式碼
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.utils import to_categorical
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

# 匯入Iris資料集
iris = load_iris()
X = iris.data
y = iris.target

# 劃分資料集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 資料標準化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 因變數轉換為啞變數
y_train = to_categorical(y_train, 3)
y_test = to_categorical(y_test, 3)

# 建立神經網路模型
model = Sequential([
    Dense(10, input_shape=(4,)),
    Activation('sigmoid'),
    Dense(10),
    Activation('relu'),
    Dense(10),
    Activation('tanh'),
    Dense(3),
    Activation('softmax')
])

# 編譯模型
model.compile(loss='categorical_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

# 訓練模型
history = model.fit(X_train, y_train, epochs=100, batch_size=5, verbose=1)

# 模型評價
loss, accuracy = model.evaluate(X_test, y_test, verbose=0)
print(f'Test loss: {loss:.4f}')
print(f'Test accuracy: {accuracy:.4f}')

# 模型預測
predictions = model.predict(X_test)
print(predictions)
print(predictions.shape)

# 視覺化展示
plt.plot(history.history['accuracy'])
plt.plot(history.history['loss'])
plt.title('Model accuracy and loss')
plt.xlabel('Epoch')
plt.legend(['Accuracy', 'Loss'], loc='upper left')
plt.show()

這段程式碼展示瞭如何使用Keras構建一個簡單的神經網路模型,從資料預處理到模型訓練、評估和預測的完整流程。

總結

卷積網路在本質上是一種輸入到輸出的對映,它能夠學習大量的輸入與輸出之間的對映關係,而不需要任何輸入和輸出之間的精確的數學表示式,只要用已知的模式對卷積網路加以訓練,網路就具有輸入輸出對之間的對映能力。CNN一個非常重要的特點就是頭重腳輕(越往輸入權值越小,越往輸出權值越多),呈現出一個倒三角的形態,這就很好地避免了BP神經網路中反向傳播的時候梯度損失得太快。
卷積神經網路CNN主要用來識別位移、縮放及其他形式扭曲不變性的二維圖形。由於CNN的特徵檢測層透過訓練資料進行學習,所以在使用CNN時,避免了顯式的特徵抽取,而隱式地從訓練資料中進行學習;再者由於同一特徵對映面上的神經元權值相同,所以網路可以並行學習,這也是卷積網路相對於神經元彼此相連網路的一大優勢。卷積神經網路以其區域性權值共享的特殊結構在語音識別和影像處理方面有著獨特的優越性,其佈局更接近於實際的生物神經網路,權值共享降低了網路的複雜性,特別是多維輸入向量的影像可以直接輸入網路這一特點避免了特徵提取和分類過程中資料重建的複雜度。

參考資料

  1. 【深度學習】5:CNN卷積神經網路原理
  2. 【深度學習】一文搞懂卷積神經網路(CNN)的原理(超詳細)
  3. 深度學習:卷積神經網路(基礎知識+iris實現)

相關文章