當前位置:
首頁 > 知識 > 僅使用NumPy完成卷積神經網路CNN的搭建

僅使用NumPy完成卷積神經網路CNN的搭建

現有的Caffe、TensorFlow等工具箱已經很好地實現CNN模型,但這些工具箱需要的硬體資源比較多,不利於初學者實踐和理解。因此,本文教大家如何僅使用NumPy來構建卷積神經網路(Convolutional Neural Network , CNN)模型,具體實現了卷積層、ReLU激活函數層以及最大池化層(max pooling),代碼簡單,講解詳細。

目前網路上存在很多編譯好的機器學習、深度學習工具箱,在某些情況下,直接調用已經搭好的模型可能是非常方便且有效的,比如Caffe、TensorFlow工具箱,但這些工具箱需要的硬體資源比較多,不利於初學者實踐和理解。因此,為了更好的理解並掌握相關知識,最好是能夠自己編程實踐下。本文將展示如何使用NumPy來構建卷積神經網路(Convolutional Neural Network , CNN)。

CNN是較早提出的一種神經網路,直到近年來才變得火熱,可以說是計算機視覺領域中應用最多的網路。一些工具箱中已經很好地實現CNN模型,相關的庫函數已經完全編譯好,開發人員只需調用現有的模塊即可完成模型的搭建,避免了實現的複雜性。但實際上,這樣會使得開發人員不知道其中具體的實現細節。有些時候,數據科學家必須通過一些細節來提升模型的性能,但這些細節是工具箱不具備的。在這種情況下,唯一的解決方案就是自己編程實現一個類似的模型,這樣你對實現的模型會有最高級別的控制權,同時也能更好地理解模型每步的處理過程。

本文將僅使用NumPy實現CNN網路,創建三個層模塊,分別為卷積層(Conv)、ReLu激活函數和最大池化(max pooling)。

一、讀取輸入圖像

以下代碼將從skimage Python庫中讀取已經存在的圖像,並將其轉換為灰度圖:

讀取圖像是第一步,下一步的操作取決於輸入圖像的大小。將圖像轉換為灰度圖如下所示:

二、準備濾波器

以下代碼為第一個卷積層Conv準備濾波器組(Layer 1,縮寫為l1,下同):

根據濾波器的數目和每個濾波器的大小來創建零數組。上述代碼創建了2個3x3大小的濾波器,(2,3,3)中的元素數字分別表示2:濾波器的數目(num_filters)、3:表示濾波器的列數、3:表示濾波器的行數。由於輸入圖像是灰度圖,讀取後變成2維圖像矩陣,因此濾波器的尺寸選擇為2維陣列,捨去了深度。如果圖像是彩色圖(具有3個通道,分別為RGB),則濾波器的大小必須為(3,3,3),最後一個3表示深度,上述代碼也要更改,變成(2,3,3,3)。

濾波器組的大小由自己指定,但沒有給定濾波器中具體的數值,一般採用隨機初始化。下列一組值可以用來檢查垂直和水平邊緣:

三、卷積層(Conv Layer)

構建好濾波器後,接下來就是與輸入圖像進行卷積操作。下面代碼使用conv函數將輸入圖像與濾波器組進行卷積:

conv函數只接受兩個參數,分別為輸入圖像、濾波器組:

該函數首先確保每個濾波器的深度等於圖像通道的數目,代碼如下。if語句首先檢查圖像與濾波器是否有一個深度通道,若存在,則檢查其通道數是否相等,如果匹配不成功,則報錯。

此外,濾波器的大小應該是奇數,且每個濾波器的大小是相等的。這是根據下面兩個if條件語塊來檢查的。如果條件不滿足,則程序報錯並退出。

上述條件都滿足後,通過初始化一個數組來作為濾波器的值,通過下面代碼來指定濾波器的值:

由於沒有設置步幅(stride)或填充(padding),默認為步幅設置為1,無填充。那麼卷積操作後得到的特徵圖大小為(img_rows-filter_rows+1, image_columns-filter_columns+1, num_filters),即輸入圖像的尺寸減去濾波器的尺寸後再加1。注意到,每個濾波器都會輸出一個特徵圖。

循環遍歷濾波器組中的每個濾波器後,通過下面代碼更新濾波器的狀態:

如果輸入圖像不止一個通道,則濾波器必須具有同樣的通道數目。只有這樣,卷積過程才能正常進行。最後將每個濾波器的輸出求和作為輸出特徵圖。下面的代碼檢測輸入圖像的通道數,如果圖像只有一個通道,那麼一次卷積即可完成整個過程:

上述代碼中conv_函數與之前的conv函數不同,函數conv只接受輸入圖像和濾波器組這兩個參數,本身並不進行卷積操作,它只是設置用於conv_函數執行卷積操作的每一組輸入濾波器。下面是conv_函數的實現代碼:

每個濾波器在圖像上迭代卷積的尺寸相同,通過以下代碼實現:

之後,在圖像區域矩陣和濾波器之間對位相乘,並將結果求和以得到單值輸出:

輸入圖像與每個濾波器卷積後,通過conv函數返回特徵圖。下圖顯示conv層返回的特徵圖(由於l1卷積層的濾波器參數為(2,3,3),即2個3x3大小的卷積核,最終輸出2個特徵圖):

卷積後圖像

卷積層的後面一般跟著激活函數層,本文採用ReLU激活函數。

四、ReLU激活函數層

ReLU層將ReLU激活函數應用於conv層輸出的每個特徵圖上,根據以下代碼行調用ReLU激活函數:

ReLU激活函數(ReLU)的具體實現代碼如下:

ReLU思想很簡單,只是將特徵圖中的每個元素與0進行比較,若大於0,則保留原始值。否則將其設置為0。ReLU層的輸出如下圖所示:

ReLU層輸出圖像

激活函數層後面一般緊跟池化層,本文採用最大池化(max pooling)。

五 、最大池化層

ReLU層的輸出作為最大池化層的輸入,根據下面的代碼行調用最大池化操作:

最大池化函數(max pooling)的具體實現代碼如下:

該函數接受3個參數,分別為ReLU層的輸出,池化掩膜的大小和步幅。首先也是創建一個空數組,用來保存該函數的輸出。數組大小根據輸入特徵圖的尺寸、掩膜大小以及步幅來確定。

對每個輸入特徵圖通道都進行最大池化操作,返回該區域中最大的值,代碼如下:

池化層的輸出如下圖所示,這裡為了顯示讓其圖像大小看起來一樣,其實池化操作後圖像尺寸遠遠小於其輸入圖像。

池化層輸出圖像

六、層堆疊

以上內容已經實現CNN結構的基本層——conv、ReLU以及max pooling,現在將其進行堆疊使用,代碼如下:

從代碼中可以看到,l2表示第二個卷積層,該卷積層使用的卷積核為(3,5,5),即3個5x5大小的卷積核(濾波器)與第一層的輸出進行卷積操作,得到3個特徵圖。後續接著進行ReLU激活函數以及最大池化操作。將每個操作的結果可視化,如下圖所示:

l2層處理過程可視化圖像

從代碼中可以看到,l3表示第三個卷積層,該卷積層使用的卷積核為(1,7,7),即1個7x7大小的卷積核(濾波器)與第二層的輸出進行卷積操作,得到1個特徵圖。後續接著進行ReLU激活函數以及最大池化操作。將每個操作的結果可視化,如下圖所示:

l3層處理過程可視化圖像

神經網路的基本結構是前一層的輸出作為下一層的輸入,比如l2層接收l1層的輸出,l3層接收來l2層的輸出,代碼如下:

七、完整代碼

全部代碼已經上傳至Github上,每層的可視化是使用Matplotlib庫實現。

地址:https://github.com/ahmedfgad/NumPyCNN?spm=a2c4e.11153940.blogcont585741.15.3c951357xsKixt

譯者:海棠,審校:Uncle_LLD。

- 加入人工智慧學院系統學習 -


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 AI講堂 的精彩文章:

Python 如何快速入門?
重磅《美國機器智能國家戰略》

TAG:AI講堂 |