關(guān)于CNN,
第1部分:卷積神經(jīng)網(wǎng)絡(luò)的介紹
CNN是什么?:它們?nèi)绾喂ぷ鳎约叭绾卧?a href="http://www.1cnz.cn/tags/python/" target="_blank">Python中從頭開始構(gòu)建一個CNN。
在過去的幾年里,卷積神經(jīng)網(wǎng)絡(luò)(CNN)引起了人們的廣泛關(guān)注,尤其是因為它徹底的改變了計算機視覺領(lǐng)域。在這篇文章中,我們將以神經(jīng)網(wǎng)絡(luò)的基本背景知識為基礎(chǔ),探索什么是CNN,了解它們是如何工作的,并在Python中從頭開始構(gòu)建一個真正的CNN(僅使用numpy)。
準(zhǔn)備好了嗎?讓我們開看看吧
1. 動機
CNN的經(jīng)典用例是執(zhí)行圖像分類,例如查看寵物的圖像并判斷它是貓還是狗。這看起來是一個簡單的任務(wù),那為什么不使用一個普通的神經(jīng)網(wǎng)絡(luò)呢?
好問題!
原因1:圖像很大
現(xiàn)在用于計算機視覺問題的圖像通常是224x224或更大的。想象一下,構(gòu)建一個神經(jīng)網(wǎng)絡(luò)來處理224x224彩色圖像:包括圖像中的3個彩色通道(RGB),得到224×224×3 = 150,528個輸入特征!在這樣的網(wǎng)絡(luò)中,一個典型的隱含層可能有1024個節(jié)點,因此我們必須為第一層單獨訓(xùn)練150,528 x 1024 = 1.5 +億個權(quán)重。我們的網(wǎng)絡(luò)將是巨大的,幾乎不可能訓(xùn)練的。
我們也不需要那么多權(quán)重。圖像的好處是,我們知道像素在相鄰的上下文中最有用。圖像中的物體是由小的局部特征組成的,比如眼睛的圓形虹膜或一張紙的方角。從第一個隱藏層中的每個節(jié)點來說,查看每個像素看起來不是很浪費嗎?
原因二:立場可以改變
如果你訓(xùn)練一個網(wǎng)絡(luò)來檢測狗,你希望它能夠檢測狗,不管它出現(xiàn)在圖像的什么地方。想象一下,訓(xùn)練一個網(wǎng)絡(luò),它能很好地處理特定的狗的圖像,然后為它提供相同圖像的略微移位的版本。狗不會激活相同的神經(jīng)元,因此網(wǎng)絡(luò)會有完全不同的反應(yīng)!
我們很快就會看到CNN如何幫助我們解決這些問題。
2.數(shù)據(jù)集
在這篇文章中,我們將解決計算機視覺的“Hello,World!”:MNIST手寫數(shù)字分類問題。這很簡單:給定圖像,將其分類為數(shù)字。
MNIST數(shù)據(jù)集中的每個圖像都是28x28,并包含了一個以中心為中心的灰度數(shù)字。
說實話,一個正常的神經(jīng)網(wǎng)絡(luò)實際上可以很好地解決這個問題。你可以將每個圖像視為一個28x28 = 784維的向量,將其提供給一個784-dim的輸入層,堆疊幾個隱藏層,最后的輸出層包含10個節(jié)點,每個數(shù)字對應(yīng)一個節(jié)點。
因為MNIST數(shù)據(jù)集包含小圖像居中,所以我們不會遇到上述的大小或移動問題。然而,在這篇文章的整個過程中請記住,大多數(shù)現(xiàn)實世界中的圖像分類問題并沒有這么簡單。
那么,現(xiàn)在你已經(jīng)有足夠的積累了。讓我們正式進入CNN的世界!
3.卷積
什么是卷積神經(jīng)網(wǎng)絡(luò)?
它們基本上只是使用卷積層的神經(jīng)網(wǎng)絡(luò),即基于卷積數(shù)學(xué)運算的Conv層。Conv圖層由一組濾鏡組成,你可以將其看作是數(shù)字的二維矩陣。這里有一個例子3x3過濾器:
我們可以使用一個輸入圖像和一個過濾器通過將過濾器與輸入圖像進行卷積來生成一個輸出圖像。這包括
將過濾器覆蓋在圖像的某個位置上。
在過濾器中的值與其在圖像中的對應(yīng)值之間執(zhí)行元素級乘法。
總結(jié)所有元素產(chǎn)品。這個和是輸出圖像中目標(biāo)像素的輸出值。
對所有位置重復(fù)。
旁注:我們(以及許多CNN實現(xiàn))實際上在技術(shù)上使用的是互相關(guān)而不是卷積,但它們做的幾乎是一樣的。我不會在這篇文章中詳細討論它們之間的區(qū)別,因為這并不重要。
這四步描述有點抽象,我們來做個例子。看下這個微小的4x4灰度圖像和這個3x3濾鏡:
圖像中的數(shù)字表示像素強度,其中0為黑色,255為白色。我們將卷積輸入圖像和過濾器產(chǎn)生一個2x2輸出圖像:
3.1這有什么用?
讓我們縮小一下,在更高的層次上看這個。將圖像與過濾器進行卷積會做什么?我們可以從我們一直使用的例子3x3過濾器開始,它通常被稱為垂直Sobel過濾器:
Sobel過濾器是一種邊緣檢測器。垂直Sobel過濾器檢測垂直邊緣,水平Sobel過濾器檢測水平邊緣。輸出圖像現(xiàn)在很容易解釋:輸出圖像中的亮像素(高值像素)表示在原始圖像中有一個強邊緣。
你能看出為什么邊緣檢測圖像可能比原始圖像更有用嗎?回想一下我們的MNIST手寫數(shù)字分類問題。在MNIST上訓(xùn)練的CNN可以尋找數(shù)字1,例如,通過使用邊緣檢測過濾器并檢查圖像中心附近的兩個突出的垂直邊緣。通常,卷積有助于我們查找特定的本地化圖像特征(如邊緣),我們可以在以后的網(wǎng)絡(luò)中使用。
3.2填充
還記得以前將4x4輸入圖像與3x3濾波器卷積得到2x2輸出圖像嗎?通常,我們希望輸出圖像與輸入圖像的大小相同。為此,我們在圖像周圍添加零,這樣我們就可以在更多的地方覆蓋過濾器。一個3x3的過濾器需要1像素的填充:
這稱為“相同”填充,因為輸入和輸出具有相同的尺寸。不使用任何填充,這是我們一直在做的,并將繼續(xù)為這篇文章做,有時被稱為“有效”填充。
3.3 Conv層(Conv Layers)
現(xiàn)在我們知道了圖像卷積是如何工作的以及它為什么有用,讓我們看看它在CNN中的實際應(yīng)用。如前所述,CNN包括conv層,它使用一組過濾器將輸入圖像轉(zhuǎn)換為輸出圖像。conv層的主要參數(shù)是它擁有的過濾器的數(shù)量。
對于MNIST CNN,我們將使用一個帶有8個過濾器的小conv層作為網(wǎng)絡(luò)的初始層。這意味著它將把28x28的輸入圖像轉(zhuǎn)換成26x26x8的容量:
提醒:輸出是26x26x8,而不是28x28x8,因為我們使用了有效的填充,這將輸入的寬度和高度降低了2。
conv層中的4個過濾器每個都產(chǎn)生一個26x26的輸出,因此它們疊加在一起構(gòu)成一個26x26x8。所有這些都是因為3×3(過濾器大小) × 8(過濾器數(shù)量)= 72個權(quán)重!
3.4實施卷積
是時候把我們學(xué)到的東西寫進代碼里了!我們將實現(xiàn)conv層的前饋部分,它負責(zé)將過濾器與輸入圖像進行卷積以生成輸出卷。為了簡單起見,我們假設(shè)過濾器總是3x3(這并不是真的,5x5和7x7過濾器也很常見)。
讓我們開始實現(xiàn)一個conv層類:
Conv3x3類只接受一個參數(shù):過濾器的數(shù)量。在構(gòu)造函數(shù)中,我們存儲過濾器的數(shù)量,并使用NumPy的randn()方法初始化一個隨機過濾器數(shù)組。
注意:如果初始值過大或過小,訓(xùn)練網(wǎng)絡(luò)將無效。
接下來,實際的卷積:
iterate_regions()是一個輔助發(fā)生器的方法,收益率為我們所有有效3 x3的圖像區(qū)域。這對于以后實現(xiàn)該類的向后部分非常有用。
上面突出顯示了實際執(zhí)行卷積的代碼行。讓我們來分解一下:
我們有im_region,一個包含相關(guān)圖像區(qū)域的3x3數(shù)組。
我們有self.filters,一個3d數(shù)組。
我們做im_region * self.filters,它使用numpy的廣播機制以元素方式乘以兩個數(shù)組。結(jié)果是一個3d數(shù)組,其尺寸與self.filters相同。
我們np.sum()上一步的結(jié)果使用axis =(1,2),它產(chǎn)生一個長度為num_filters的1d數(shù)組,其中每個元素包含相應(yīng)過濾器的卷積結(jié)果。
我們將結(jié)果分配給輸出[i,j],其中包含輸出中像素(i,j)的卷積結(jié)果。
對輸出中的每個像素執(zhí)行上面的序列,直到得到最終的輸出卷為止!讓我們測試一下我們的代碼:
目前看起來不錯。
注意:在Conv3x3實現(xiàn)中,為了簡單起見,我們假設(shè)輸入是一個2d numpy數(shù)組,因為MNIST圖像就是這樣存儲的。這對我們有用,因為我們使用它作為我們網(wǎng)絡(luò)的第一層,但大多數(shù)cnn有更多的Conv層。如果我們要構(gòu)建一個更大的網(wǎng)絡(luò),需要多次使用Conv3x3,那么我們必須將輸入設(shè)置為3d numpy數(shù)組。
4. 池化
圖像中的相鄰像素往往具有相似的值,因此conv層通常也會為輸出中的相鄰像素生成相似的值。因此,conv層輸出中包含的大部分信息都是多余的。例如,如果我們使用邊緣檢測過濾器,并在某個位置找到一個強邊緣,那么我們很可能也會在距離原始位置1像素的位置找到一個相對較強的邊緣。然而,這些都是相同的邊緣!我們沒有發(fā)現(xiàn)任何新東西。
池化層解決了這個問題。他們所做的就是減少(通過猜測)在輸入中匯總值的輸入大小。池化層通常由一個簡單的操作完成,比如max、min或average。
為了執(zhí)行最大池化,我們在2x2塊中輸入了圖像(因為池的大小= 2),并將最大值放入對應(yīng)像素處的輸出圖像中。就是這樣!
它將輸入的寬度和高度除以它的大小。對于MNIST CNN,我們將在初始conv層之后放置一個池大小為2的最大池化層。池化層將26x26x8輸入轉(zhuǎn)換為13x13x8輸出:
4.1 Implementing Pooling(實施池)
我們將實現(xiàn)一個MaxPool2類與我們的conv類相同的方法從上一節(jié):
這個類的工作原理類似于我們之前實現(xiàn)的Conv3x3類。關(guān)鍵行再次突出顯示:要從給定的圖像區(qū)域找到最大值,我們使用np.amax(), numpy的array max方法。我們設(shè)置axis=(0,1),因為我們只想最大化前兩個維度(高度和寬度),而不是第三個維度(num_filters)。
我們來試試吧!
我們的MNIST CNN開始走到一起了!
5. Softmax
為了完成我們的CNN,我們需要賦予它實際預(yù)測的能力。我們將通過使用一個多類分類問題的標(biāo)準(zhǔn)最終層來實現(xiàn)這一點:Softmax層,這是一個使用Softmax激活函數(shù)的標(biāo)準(zhǔn)全連接(密集)層。
提醒:全連接層的每個節(jié)點都連接到上一層的每個輸出。如果你需要復(fù)習(xí)的話,我們在介紹神經(jīng)網(wǎng)絡(luò)時使用了全連接層圖層。
Softmax將任意實值轉(zhuǎn)換為概率。它背后的數(shù)學(xué)原理很簡單:給定一些數(shù)字,
取e(數(shù)學(xué)常數(shù))的每一次方。
把所有的指數(shù)(eee的冪)加起來。這個結(jié)果是分母。
用每個數(shù)的指數(shù)作為它的分子。
概率= Numerator/Denominator
寫得更妙的是,Softmax對nnn數(shù)字執(zhí)行以下轉(zhuǎn)換X1.。.Xn:
Softmax變換的輸出總是在[0,1][0,1][0,1][0,1]范圍內(nèi),并且加起來等于1,由此轉(zhuǎn)換成概率。
下面是一個使用數(shù)字-1、0、3和5的簡單例子:
5.1使用方法
我們將使用一個包含10個節(jié)點的softmax層,每個節(jié)點代表一個數(shù)字,作為CNN的最后一層。層中的每個節(jié)點都將連接到每個輸入層。應(yīng)用softmax變換后,以概率最高的節(jié)點表示的數(shù)字為CNN的輸出!
5.2交叉熵損失函數(shù)
你可能會想,為什么要把輸出轉(zhuǎn)化為概率呢?最高的產(chǎn)值不總是有最高的概率嗎?如果你這么做了,你絕對是對的。我們實際上不需要使用softmax來預(yù)測一個數(shù)字,而我們只需要從網(wǎng)絡(luò)中選擇輸出最高的數(shù)字即可!
softmax真正做的是幫助我們量化我們對預(yù)測的確定程度,這在訓(xùn)練和評估CNN時非常有用。更具體地說,使用softmax允許我們使用交叉熵損失函數(shù),它考慮到我們對每個預(yù)測的確定程度。下面是我們計算交叉熵損失函數(shù)的方法:
c在哪里是正確的類(在我們的例子中是正確的數(shù)字),Pc類c的預(yù)測概率,并在natural log中。一如既往的,損失越少越好。例如,在最好的情況下,我們會
在更現(xiàn)實的情況下,我們可能會有
我們將在稍后的文章中再次看到交叉熵損失函數(shù),所以請記住這一點!
5.3實施Softmax
你現(xiàn)在知道這個練習(xí),讓我們實現(xiàn)一個Softmax圖層類
這里沒有什么太復(fù)雜的。幾個亮點:
我們將輸入壓平(),使其更容易處理,因為我們不再需要它的形狀。
np.dot()將輸入和self相乘。按元素加權(quán),然后對結(jié)果求和。
np.exp()計算用于Softmax的指數(shù)。
我們現(xiàn)在已經(jīng)完成了CNN的整個轉(zhuǎn)發(fā)!放在一起:
運行cnn.py給我們輸出類似于:
這是有道理的:使用隨機權(quán)重初始化,你會期望CNN只會像隨機猜測一樣好。隨機猜測的話,10%的準(zhǔn)確率(因為有10類)和一個叉的損失?ln?(0.1) = 2.302 {- ln (0.1)} = 2.302?ln(0.1) = 2.302,這是我們得到的!
想自己嘗試或修改這段代碼嗎?在瀏覽器中運行CNN。它也可以在Github上使用。
6. 結(jié)論
以上就是對CNN的介紹!在這篇文章中,我們
為什么CNN在某些問題上可能更有用,比如圖像分類。
介紹MNIST手寫數(shù)字?jǐn)?shù)據(jù)集。
了解Conv層,它將過濾器與圖像進行卷積以產(chǎn)生更有用的輸出。
談到了池化層,它可以幫助刪除除最有用的功能之外的所有功能。
實現(xiàn)了一個Softmax層,因此我們可以使用交叉熵損失。
還有很多東西我們還沒有講到,比如如何訓(xùn)練CNN。本系列的第2部分將對CNN進行深入的一個訓(xùn)練,包括推導(dǎo)梯度和實施反向傳播。
編輯:jq
-
卷積神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
4文章
367瀏覽量
11863
原文標(biāo)題:深度學(xué)習(xí)其實并不難:卷積神經(jīng)網(wǎng)絡(luò)的簡單介紹
文章出處:【微信號:gh_f39db674fbfd,微信公眾號:尖刀視】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論