一文帶你了解CNN(卷積神經(jīng)網(wǎng)絡(luò))
前言
在學(xué)計(jì)算機(jī)視覺(jué)的這段時(shí)間里整理了不少的筆記,想著就把這些筆記再重新整理出來(lái),然后寫成Blog和大家一起分享。目前的計(jì)劃如下(以下網(wǎng)絡(luò)全部使用Pytorch搭建):
專題一:計(jì)算機(jī)視覺(jué)基礎(chǔ)
- 介紹CNN網(wǎng)絡(luò)(計(jì)算機(jī)視覺(jué)的基礎(chǔ))
- 淺談VGG網(wǎng)絡(luò),介紹ResNet網(wǎng)絡(luò)(網(wǎng)絡(luò)特點(diǎn)是越來(lái)越深)
- 介紹GoogLeNet網(wǎng)絡(luò)(網(wǎng)絡(luò)特點(diǎn)是越來(lái)越寬)
- 介紹DenseNet網(wǎng)絡(luò)(一個(gè)看似十分NB但是卻實(shí)際上用得不多的網(wǎng)絡(luò))
- 整理期間還會(huì)分享一些自己正在參加的比賽的Baseline
專題二:GAN網(wǎng)絡(luò)
- 搭建普通的GAN網(wǎng)絡(luò)
- 卷積GAN
- 條件GAN
- 模式崩潰的問(wèn)題及網(wǎng)絡(luò)優(yōu)化
以上會(huì)有相關(guān)代碼實(shí)踐,代碼是基于Pytorch框架。話不多說(shuō),我們先進(jìn)行專題一的第一部分介紹,卷積神經(jīng)網(wǎng)絡(luò)。
一、CNN解決了什么問(wèn)題?
在CNN出現(xiàn)之前,對(duì)于圖像的處理一直都是一個(gè)很大的問(wèn)題,一方面因?yàn)閳D像處理的數(shù)據(jù)量太大,比如一張512 x 512的灰度圖,它的輸入?yún)?shù)就已經(jīng)達(dá)到了252144個(gè),更別說(shuō)1024x1024x3之類的彩色圖,這也導(dǎo)致了它的處理成本十分昂貴且效率極低。另一方面,圖像在數(shù)字化的過(guò)程中很難保證原有的特征,這也導(dǎo)致了圖像處理的準(zhǔn)確率不高。
而CNN網(wǎng)絡(luò)能夠很好的解決以上兩個(gè)問(wèn)題。對(duì)于第一個(gè)問(wèn)題,CNN網(wǎng)絡(luò)它能夠很好的將復(fù)雜的問(wèn)題簡(jiǎn)單化,將大量的參數(shù)降維成少量的參數(shù)再做處理。也就是說(shuō),在大部分的場(chǎng)景下,我們使用降維不會(huì)影響結(jié)果。比如在日常生活中,我們用一張1024x1024x3表示鳥(niǎo)的彩色圖和一張100x100x3表示鳥(niǎo)的彩色圖,我們基本上都能夠用肉眼辨別出這是一只鳥(niǎo)而不是一只狗。這也是卷積神經(jīng)網(wǎng)絡(luò)在圖像分類里的一個(gè)重要應(yīng)用?!緋s:卷積神經(jīng)網(wǎng)絡(luò)可以對(duì)一張圖片進(jìn)行是貓還是狗進(jìn)行分類。如果一張圖片里有貓有狗有雞,我們要分別識(shí)別出每個(gè)區(qū)域的動(dòng)物,并用顏色分割出來(lái),基礎(chǔ)的CNN網(wǎng)絡(luò)還能夠使用嗎?這是一個(gè)拓展思考,有興趣的讀者可以看一下FCN網(wǎng)絡(luò)。對(duì)比之下能夠更好的理解CNN網(wǎng)絡(luò)】
對(duì)于第二個(gè)問(wèn)題,CNN網(wǎng)絡(luò)利用了類似視覺(jué)的方式保留了圖像的特征,當(dāng)圖像做翻轉(zhuǎn)、旋轉(zhuǎn)或者變換位置的時(shí)候,它也能有效的識(shí)別出來(lái)是類似的圖像。
以上兩個(gè)問(wèn)題的解決,都是由于CNN網(wǎng)絡(luò)具有以下優(yōu)勢(shì)和特點(diǎn):局部區(qū)域連接、權(quán)值共享。在解釋這三個(gè)特點(diǎn)之前,我們先看一下CNN網(wǎng)絡(luò)的三大主要結(jié)構(gòu),卷積層、池化層(或者叫做匯聚層)、全連接層。
二、CNN網(wǎng)絡(luò)的結(jié)構(gòu)
2.1 卷積層 - 提取特征
卷積運(yùn)算
了解卷積層,我們先要了解一下卷積運(yùn)算。別看它叫做卷積,但是和嚴(yán)格意義上的數(shù)學(xué)卷積是不同的。深度學(xué)習(xí)所謂的卷積運(yùn)算是互相關(guān)( cross-correlation )運(yùn)算?!緦?shí)際上,經(jīng)過(guò)數(shù)學(xué)證明發(fā)現(xiàn)無(wú)論用嚴(yán)格卷積或互相關(guān)運(yùn)算,卷積層的輸出不會(huì)受太大影響。而互相關(guān)運(yùn)算比嚴(yán)格卷積運(yùn)算簡(jiǎn)潔的多,所以我們一般都采用互相關(guān)運(yùn)算來(lái)替代嚴(yán)格意義上的卷積運(yùn)算?!课覀円远S數(shù)據(jù)為例(高 x 寬),不考慮圖像的通道個(gè)數(shù),假設(shè)輸入的高度為3、寬度為3的二維張量,卷積核的高度和寬度都是2,而卷積核窗口的形狀由內(nèi)核的高度和寬度決定:
二維的互相關(guān)運(yùn)算。陰影部分是第一個(gè)輸出元素,以及用于計(jì)算這個(gè)輸出的輸入和核張量元素: 0 x 0 + 1x1 + 3x2 +4x3 = 19。由此可見(jiàn)互相關(guān)運(yùn)算就是一個(gè)乘積求和的過(guò)程。在二維互相關(guān)運(yùn)算中,卷積窗口從輸入張量的左上角開(kāi)始,從左到右、從上到下滑動(dòng)。這里我們?cè)O(shè)置步長(zhǎng)為1,即每次跨越一個(gè)距離。當(dāng)卷積窗口滑到新一個(gè)位置時(shí),包含在該窗口中的部分張量與卷積核張量進(jìn)行按元素相乘,得到的張量再求和得到一個(gè)單一的標(biāo)量值,由此我們得到了這一位置的輸出張量值。 【我們這里頻繁提到了張量,張量(Tensor)是一個(gè)多維數(shù)組,它是標(biāo)量、向量、矩陣的高維拓展?!?/p>
看了上面的內(nèi)容,可能有讀者開(kāi)始思考,如果這個(gè)輸入矩陣是 4x4,卷積核是3x3,步長(zhǎng)為1的時(shí)候,在向右移動(dòng)時(shí),我們發(fā)現(xiàn)如果要和卷積核進(jìn)行卷積操作,左便的輸入矩陣還缺少了一列;在行的方向也是如此。如果我們忽略邊緣的像素,我們可能就丟失了邊緣的細(xì)節(jié)。那么這種情況下我們?nèi)绾翁幚砟??這時(shí)我們可以進(jìn)行填充操作(padding),在用pytorch實(shí)現(xiàn)時(shí)我們可以在Convd函數(shù)中對(duì)padding進(jìn)行設(shè)置,這里我們可以設(shè)置padding=1,就能夠在行和列上向外擴(kuò)充一圈?!緋s:實(shí)際上當(dāng)處理比較大的圖片,且任務(wù)是分類任務(wù)時(shí),我們可以不用進(jìn)行padding。因?yàn)閷?duì)于大部分的圖像分類任務(wù),邊緣的細(xì)節(jié)是是無(wú)關(guān)緊要的,且邊緣的像素點(diǎn)相比于總的像素來(lái)講,占比是很小的,對(duì)于整個(gè)圖像分類的任務(wù)結(jié)果影響不大】
對(duì)于卷積操作,我們有一個(gè)統(tǒng)一的計(jì)算公式。且學(xué)會(huì)相關(guān)的計(jì)算對(duì)于了解感受野和網(wǎng)絡(luò)的搭建至關(guān)重要。學(xué)會(huì)相關(guān)的計(jì)算,我們?cè)诖罱ㄗ约旱木W(wǎng)絡(luò)或者復(fù)現(xiàn)別人的網(wǎng)絡(luò),才能夠確定好填充padding、步長(zhǎng)stride以及卷積核kernel size的參數(shù)大小。一般這里有一個(gè)統(tǒng)一的公式:
假設(shè)圖像的尺寸是 input x input,卷積核的大小是kernel,填充值為padding,步長(zhǎng)為stride,卷積后輸出的尺寸為output x output,則卷積后,尺寸的計(jì)算公式為:
ps:如果輸入的圖像尺寸是 mxn類型的,可以通過(guò)裁剪 or 插值轉(zhuǎn)換成 mxm or nxn類型的圖像;或者分別計(jì)算圖像的高和寬大小也可以,公式都是類似的。
權(quán)重共享
我們?cè)谇懊嬗刑岬竭^(guò)CNN網(wǎng)絡(luò)的一個(gè)特性是權(quán)重共享(share weights)也正是體現(xiàn)在通道處理的過(guò)程中。一般的神經(jīng)網(wǎng)絡(luò)層與層之間的連接是,每個(gè)神經(jīng)元與上一層的全部神經(jīng)元連接,這些連接線的權(quán)重獨(dú)立于其他的神經(jīng)元,所以假設(shè)上一層是m個(gè)神經(jīng)元,當(dāng)前層是n個(gè)神經(jīng)元,那么共有mxn個(gè)連接,也就有mxn個(gè)權(quán)重。權(quán)重矩陣是mxn的形式。那么CNN是如何呢?權(quán)重共享是什么意思?我們引入下面這樣一張圖來(lái)幫助我們理解:
我們先說(shuō)明上圖中各個(gè)模塊的矩陣格式及關(guān)系:
- 輸入矩陣格式:(樣本數(shù),圖像高度,圖像寬度,圖像通道數(shù))
- 輸出矩陣格式:(樣本數(shù),圖像高度、圖像寬度、圖像通道數(shù))
- 卷積核的格式:(卷積核高度、卷積核寬度、輸入通道數(shù)、輸出通道數(shù))
- 卷積核的輸入通道數(shù)(in depth)由輸入矩陣的通道數(shù)所決定。(紅色標(biāo)注)
- 輸出矩陣的通道數(shù)(out depth)由卷積核的輸出通道所決定。(綠色標(biāo)注)
- 輸出矩陣的高度和寬度,由輸入矩陣、卷積核大小、步長(zhǎng)、填充共同決定,具體計(jì)算公式見(jiàn)上文。
當(dāng)輸入一張大小為8x8x3的彩色圖時(shí),我們已經(jīng)提前設(shè)計(jì)好了卷積核后的輸出通道為5,即卷積核的個(gè)數(shù)為5【即五個(gè)偏置,一個(gè)卷積核一個(gè)偏置】(通道數(shù)的設(shè)計(jì)一般是實(shí)驗(yàn)后得到的較優(yōu)結(jié)果)。每個(gè)卷積核去和輸入圖像在通道上一一對(duì)應(yīng)進(jìn)行卷積操作(即互相關(guān)操作,除非刻意強(qiáng)調(diào),這里所說(shuō)的卷積都是互相關(guān),步長(zhǎng)為1,填充為0),得到了3個(gè)6x6的feature map。然后再將三個(gè)6x6的Feature map按照Eletwise相加進(jìn)行通道融合得到最終的feature map,大小為6x6(也就是將得到的三個(gè)矩陣逐元素相加,之后所有元素再加上該矩陣的偏置值,得到新的6x6矩陣)。權(quán)重共享也是體現(xiàn)在這個(gè)過(guò)程中。我們單獨(dú)提取出第一個(gè)卷積核,當(dāng)它的第一個(gè)通道(3x3)與輸入圖像的第一個(gè)通道(8x8)進(jìn)行卷積操作時(shí),按照普通的神經(jīng)網(wǎng)絡(luò)連接方式其權(quán)重矩陣是9 x 81。但是這里我們要注意,我們?cè)诖翱诨瑒?dòng)進(jìn)行卷積的操作權(quán)重是確定的,都是以輸入圖像的第一個(gè)通道為模板,卷積核的第一個(gè)通道3x3矩陣為權(quán)重值,然后得到卷積結(jié)果。這個(gè)過(guò)程中權(quán)重矩陣就是3x3,且多次應(yīng)用于每次計(jì)算中。權(quán)重的個(gè)數(shù)有9x81減少到3x3,極大的減少了參數(shù)的數(shù)量。綜合起來(lái),對(duì)于第一個(gè)卷積核來(lái)講,它的權(quán)重矩陣就是3x3x3+1,整個(gè)卷積過(guò)程的權(quán)重大小為3x3x3x5+5,而不是8x8x3x3x3x3x5。權(quán)重共享大大減少了模型的訓(xùn)練參數(shù)。權(quán)重共享意味著當(dāng)前隱藏層中的所有神經(jīng)元都在檢測(cè)圖像不同位置處的同一個(gè)特征,即檢測(cè)特征相同。因此也將輸入層到隱藏層的這種映射稱為特征映射。由上我們可以理解,從某種意義上來(lái)說(shuō),通道就是某種意義上的特征圖。輸出的同一張?zhí)卣鲌D上的所有元素共享一個(gè)卷積核,即共享一個(gè)權(quán)重。通道中某一處(特征圖上某一個(gè)神經(jīng)元)數(shù)值的大小就是當(dāng)前位置對(duì)當(dāng)前特征強(qiáng)弱的反應(yīng)。而為什么在CNN網(wǎng)絡(luò)中我們會(huì)增加通道數(shù)目,其實(shí)就是在增加通道的過(guò)程中區(qū)學(xué)習(xí)圖像的多個(gè)不同特征。
稀疏連接
通過(guò)上面對(duì)于卷積的過(guò)程以及權(quán)重共享的解釋,我們能夠總結(jié)出CNN的另一個(gè)特征。有心的讀者其實(shí)能夠自己總結(jié)出來(lái)。我們?cè)谏厦嫣岬竭^(guò),對(duì)于普通的神經(jīng)網(wǎng)絡(luò),隱藏層和輸入層之間的神經(jīng)元是采用全連接的方式。然而CNN網(wǎng)絡(luò)并不是如此。它的在局部區(qū)域創(chuàng)建連接,即稀疏連接。比如,對(duì)于一張輸入的單通道的8x8圖片,我們用3x3的卷積核和他進(jìn)行卷積,卷積核中的每個(gè)元素的值是和8x8矩陣中選取了3x3的矩陣做卷積運(yùn)算,然后通過(guò)滑動(dòng)窗口的方式,卷積核中的每個(gè)元素(也就是神經(jīng)元)只與上一層的所有神經(jīng)元中的9個(gè)進(jìn)行連接。相比于神經(jīng)元之間的全連接方式,稀疏連接極大程度上的減少了參數(shù)的數(shù)量,同時(shí)也一定程度上避免了模型的過(guò)擬合。這種算法的靈感是來(lái)自動(dòng)物視覺(jué)的皮層結(jié)構(gòu),其指的是動(dòng)物視覺(jué)的神經(jīng)元在感知外界物體的過(guò)程中起作用的只有一部分神經(jīng)元。在計(jì)算機(jī)視覺(jué)中,像素之間的相關(guān)性與像素之間的距離同樣相關(guān),距離較近的像素間相關(guān)性強(qiáng),距離較遠(yuǎn)則相關(guān)性比較弱,由此可見(jiàn)局部相關(guān)性理論也適用于計(jì)算機(jī)視覺(jué)的圖像處理。因此,局部感知(稀疏連接)采用部分神經(jīng)元接受圖像信息,再通過(guò)綜合全部的圖像信息達(dá)到增強(qiáng)圖像信息的目的。(至于我們?yōu)槭裁船F(xiàn)在經(jīng)常采用3x3卷積核,因?yàn)閷?shí)驗(yàn)結(jié)果告訴我們,3x3卷積核常常能達(dá)到更好的實(shí)驗(yàn)效果。)
總結(jié):標(biāo)準(zhǔn)的卷積操作
在進(jìn)行上面的解釋后,相信大家已經(jīng)對(duì)于什么是卷積,卷積的兩點(diǎn)特點(diǎn):稀疏鏈接和權(quán)重共享已經(jīng)有了了解。下面我們來(lái)總結(jié)一般意義的標(biāo)準(zhǔn)的卷積操作:當(dāng)輸入的feature map數(shù)量(即輸入的通道數(shù))是N,卷積層filter(卷積核)個(gè)數(shù)是M時(shí),則M個(gè)filter中,每一個(gè)filter都有N個(gè)channel,都要分別和輸入的N個(gè)通道做卷積,得到N個(gè)特征圖,然后將這N個(gè)feature map按Eletwise相加(即:進(jìn)行通道融合),再加上該filter對(duì)應(yīng)的偏置(一個(gè)filter對(duì)應(yīng)一個(gè)共享偏置),作為該卷積核所得的特征圖。同理,對(duì)其他M-1個(gè)filter也進(jìn)行以上操作。所以最終該層的輸出為M個(gè)feature map(即:輸出channel等于filter的個(gè)數(shù))??梢?jiàn),輸出的同一張?zhí)卣鲌D上的所有元素共享同一個(gè)卷積核,即共享一個(gè)權(quán)重。不同特征圖對(duì)應(yīng)的卷積核不同。
卷積的意義
如果用圖像處理上的專業(yè)術(shù)語(yǔ),我們可以將卷積叫做銳化。卷積其實(shí)是想要強(qiáng)調(diào)某些特征,然后將特征強(qiáng)化后提取出來(lái),不同卷積核關(guān)注圖片上不同的特征,比如有的更關(guān)注邊緣而有的更關(guān)注中心地帶等。當(dāng)完成幾個(gè)卷積層后(卷積 + 激活函數(shù) + 池化)【后面講解激活函數(shù)和池化】,如圖所示:
在CNN中,我們就是通過(guò)不斷的改變卷積核矩陣的值來(lái)關(guān)注不同的細(xì)節(jié),提取不同的特征。也就是說(shuō),在我們初始化卷積核的矩陣值(即權(quán)重參數(shù))后,我們通過(guò)梯度下降不斷降低loss來(lái)獲得最好的權(quán)重參數(shù),整個(gè)過(guò)程都是自動(dòng)調(diào)整的。
1x1卷積的重大意義
按照道理講,我是不該這么快就引入1x1卷積的,不過(guò)考慮到它在各種網(wǎng)絡(luò)中應(yīng)用的重要性并且也不難理解,就在這里提前和大家解釋一下1x1卷積是什么,作用是什么。
如果有讀者在理解完上文所提到的卷積后,可能會(huì)發(fā)出疑問(wèn):卷積的本質(zhì)不是有效的提取相鄰像素間的相關(guān)特征嗎?1x1卷積核的每個(gè)通道和上一層的通道進(jìn)行卷積操作的時(shí)候不是沒(méi)法識(shí)別相鄰元素了嗎?
其實(shí)不然,1x1卷積層的確是在高度和寬度的維度上失去了識(shí)別相鄰元素間的相互作用的能力,并且通過(guò)1x1卷積核后的輸出結(jié)果的高和寬與上一層的高和寬是相同的。但是,通道數(shù)目可能是不同的。而1x1卷積的唯一計(jì)算也正是發(fā)生在通道上。它通過(guò)改變1x1卷積核的數(shù)量,實(shí)現(xiàn)了多通道的線性疊加,使得不同的feature map進(jìn)行線性疊加。我們通過(guò)下圖來(lái)更好的認(rèn)識(shí)1x1卷積的作用:
上圖使用了2個(gè)通道的1x1卷積核與3個(gè)通道的3x3輸入矩陣進(jìn)行卷積操作。由圖可知,這里的輸入和輸出具有相同的高度和寬度,輸出的每個(gè)元素都是從輸入圖像的同一位置的元素的線性組合。我們可以將1x1卷積層看做是每個(gè)像素位置應(yīng)用的全連接層。同時(shí),我們發(fā)現(xiàn)輸出結(jié)果的通道數(shù)目發(fā)生了改變,這也是1x1卷積的一個(gè)重要應(yīng)用。可以對(duì)輸出通道進(jìn)行升維或者降維,并且不改變圖像尺寸的大小,有利于跨通道的信息交流的內(nèi)涵。降維之后我們可以使得參數(shù)數(shù)量變得更少,訓(xùn)練更快,內(nèi)存占用也會(huì)更少。如果是在GPU上訓(xùn)練,顯存就更加珍貴了。
卷積網(wǎng)絡(luò)的一個(gè)非常重要的應(yīng)用就是ResNet網(wǎng)絡(luò),而ResNet網(wǎng)絡(luò)結(jié)構(gòu),已經(jīng)應(yīng)用于各種大型網(wǎng)絡(luò)中,可以說(shuō)是隨處可見(jiàn)。這里先貼個(gè)ResNet中應(yīng)用了1x1卷積的殘差塊,后面會(huì)有一篇文章來(lái)解讀ResNet網(wǎng)絡(luò):ResNet paper download
2.2 激活函數(shù)
由前述可知,在CNN中,卷積操作只是加權(quán)求和的線性操作。若神經(jīng)網(wǎng)絡(luò)中只用卷積層,那么無(wú)論有多少層,輸出都是輸入的線性組合,網(wǎng)絡(luò)的表達(dá)能力有限,無(wú)法學(xué)習(xí)到非線性函數(shù)。因此CNN引入激活函數(shù),激活函數(shù)是個(gè)非線性函數(shù),常用于卷積層和全連接層輸出的每個(gè)神經(jīng)元,給神經(jīng)元引入了非線性因素,使網(wǎng)絡(luò)的表達(dá)能力更強(qiáng),幾乎可以逼近任意函數(shù),這樣的神經(jīng)網(wǎng)絡(luò)就可應(yīng)用到眾多的非線性模型中,我們可以用公式來(lái)定義隱藏層的每個(gè)神經(jīng)元輸出公式:
其中,\(b_l\)是該感知與連接的共享偏置,Wl是個(gè)nxn的共享權(quán)重矩陣,代表在輸入層的nxn的矩形區(qū)域的特征值。
當(dāng)激活函數(shù)作用于卷積層的輸出時(shí):
這里的σ是神經(jīng)元的激勵(lì)函數(shù),可以是Sigmoid、tanh、ReLU等函數(shù)。
2.3 池化層(下采樣) - 數(shù)據(jù)降維,避免過(guò)擬合
在CNN中,池化層通常在卷積或者激勵(lì)函數(shù)的后面,池化的方式有兩種,全最大池化或者平均池化,池化主要有三個(gè)作用:
- 一是降低卷積層對(duì)目標(biāo)位置的敏感度,即實(shí)現(xiàn)局部平移不變性,當(dāng)輸入有一定的平移時(shí),經(jīng)過(guò)池化后輸出不會(huì)發(fā)生改變。CNN通過(guò)引入池化,使得其特征提取不會(huì)因?yàn)槟繕?biāo)位置變化而受到較大的影響。
- 二是降低對(duì)空間降采樣表示的敏感性
- 三是能夠?qū)ζ溥M(jìn)行降維壓縮,以加快運(yùn)算速度 ,防止過(guò)擬合。
與卷積層類似的是,池化層運(yùn)算符有一個(gè)固定的窗口組成,該窗口也是根據(jù)步幅大小在輸入的所有區(qū)域上滑動(dòng),為固定的形狀窗口遍歷每個(gè)位置計(jì)算一個(gè)輸出。
輸出的張量高度為2,寬度為2,這四個(gè)元素為每個(gè)池化窗口中的最大值(stride=1,padding=0):
但是,不同于卷積層中的輸入與卷積核之間的互相關(guān)計(jì)算,池化層不包含參數(shù)。池化層的運(yùn)算符是確定性的,我們通常計(jì)算池化窗口中所有元素的最大值或平均值(些操作分別被稱為最大池化層和平均池化層),而不是像卷積層那樣將各通道的輸入在互相關(guān)操作后進(jìn)行eletwise特征融合,這也意味著池化層的輸出通道數(shù)和輸入通道數(shù)目是相同的。池化操作的計(jì)算一般形式為,設(shè)輸入圖像尺寸為WxHxC,寬x高x深度,卷積核的尺寸為FxF,S:步長(zhǎng),則池化后圖像的大小為:
2.4 全連接層 - 分類,輸出結(jié)果
我們剛給講了卷積層、池化層和激活函數(shù),這些在全連接層之前層的作用都是將原始數(shù)據(jù)映射到隱層特征空間來(lái)提取特征,而全連接層的作用就是將學(xué)習(xí)到的特征表示映射到樣本的標(biāo)記空間。換句話說(shuō),就是把特征正和島一起(高度提純特征),方便交給最后的分類器或者回歸。
我們也可以把全連接層的過(guò)程看做一個(gè)卷積過(guò)程,例如某個(gè)網(wǎng)絡(luò)在經(jīng)過(guò)卷積、ReLU激活后得到3x3x5的輸出,然后經(jīng)過(guò)全連接層轉(zhuǎn)換成1x4096的形式:
從上圖我們可以看出,我們用一個(gè)3x3x5的filter去卷積激活函數(shù)的輸出,得到的結(jié)果是全連接層的一個(gè)神經(jīng)元,因?yàn)槲覀冇?096個(gè)神經(jīng)元,我們實(shí)際上就是用一個(gè)3x3x5x4096的卷積層去卷積激活函數(shù)的輸出【不帶偏置】。因此全連接層中的每個(gè)神經(jīng)元都可以看成一個(gè)不帶偏置加權(quán)平均的多項(xiàng)式,我們可以簡(jiǎn)單寫成。
這一步卷積還有一個(gè)非常重要的作用,就是把分布式特征representation映射到樣本標(biāo)記空間,簡(jiǎn)單說(shuō)就是把特征整合到一起,輸出為一個(gè)值,這樣可以大大減少特征位置對(duì)分類帶來(lái)的影響。
從上面的圖,我們可以看出,貓?jiān)诓煌奈恢?,輸出的特征值相同,但是位置不同;?duì)于電腦來(lái)說(shuō),特征值相同,但是特征值位置不同,那分類結(jié)果可能是不一樣的。此時(shí)全連接層的作用就是,在展平后忽略其空間結(jié)構(gòu)特性,不管它在哪兒,只要它有這個(gè)貓,那么就能判別它是貓。這也說(shuō)明了它是一個(gè)跟全局圖像的問(wèn)題有關(guān)的問(wèn)題(例如:圖像是否包含一只貓呢)。這也說(shuō)明了全連接層的結(jié)構(gòu)不適合用于在方位上找patter的任務(wù),例如分割任務(wù)(后面的FCN就是將全連接層改成了卷積層)。不過(guò)全連接層有一個(gè)很大的缺點(diǎn),就是參數(shù)過(guò)于多。所以后面的像ResNet網(wǎng)絡(luò)、GoogLeNet都已經(jīng)采用全局平均池化取代全連接層來(lái)融合學(xué)到的特征。另外,參數(shù)多了也引發(fā)了另外一個(gè)問(wèn)題,模型復(fù)雜度提升,學(xué)習(xí)能力太好容易造成過(guò)擬合。
三、Pytorch實(shí)現(xiàn)LeNet網(wǎng)絡(luò)
LeNet模型是最早發(fā)布的卷積神經(jīng)網(wǎng)絡(luò)之一,它是由AT&T貝爾實(shí)驗(yàn)室的研究院Yann LeCun在1989年提出的,目的是識(shí)別圖像中的手寫數(shù)字,發(fā)表了第一篇通過(guò)反向傳播成功訓(xùn)練卷積神經(jīng)網(wǎng)絡(luò)的研究。我們現(xiàn)在通過(guò)pytorch來(lái)實(shí)現(xiàn):LeNet - Paper Download 。
LeNet它雖然很小,但是包含了深度學(xué)習(xí)的基本模塊。我們先對(duì)LeNet結(jié)構(gòu)進(jìn)行一個(gè)具體的分析,這也是我們搭建任何一個(gè)神經(jīng)網(wǎng)絡(luò)之前要提前知道的:
每個(gè)卷積塊中的基本單元是一個(gè)卷積層、一個(gè)Sigmod激活函數(shù)和平均池化層。(雖然ReLU函數(shù)和最大池化層很有效,但是當(dāng)時(shí)還沒(méi)有出現(xiàn))。每個(gè)卷積層使用5x5卷積核和一個(gè)Sigmoid激活函數(shù)。第一個(gè)卷積層有6個(gè)輸出通道,第二個(gè)卷積層有16個(gè)輸出通道。每個(gè)2x2赤化操作通過(guò)空間下采樣將維數(shù)減少4倍。卷積的輸出形狀由(批量大小,通道數(shù),高度,寬度)決定。LeNet中有三個(gè)全連接層,分別有120、84、10個(gè)輸出,因?yàn)槲覀冊(cè)趫?zhí)行手寫數(shù)字的分類任務(wù)(一共有0-9共10個(gè)數(shù)字),所以輸出層的10維對(duì)應(yīng)于最后輸出的結(jié)果的數(shù)量。
把上面的模型簡(jiǎn)化一下,網(wǎng)絡(luò)結(jié)構(gòu)大概就是這個(gè)樣子:
3.1 模型定義
import torch from torch import nn from d2l import torch as d2l class Reshape(torch.nn.Module): def forward(self, x): # 通過(guò)view函數(shù)把圖像展成標(biāo)準(zhǔn)的Tensor接收格式,即(樣本數(shù)量,通道數(shù),高,寬) return x.view(-1, 1, 28, 28) net = torch.nn.Sequential( Reshape(), # 第一個(gè)卷積塊,這里用到了padding=2 nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2), # 第二個(gè)卷積塊 nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(), nn.AvgPool2d(kernel_size=2, stride=2), # 稠密塊(三個(gè)全連接層) nn.Flatten(), nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(), nn.Linear(120, 84), nn.Sigmoid(), nn.Linear(84, 10))
X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32) for layer in net: X = layer(X) print(layer.__class__.__name__,'output shape: \t',X.shape)
輸出結(jié)果為:
3.2 模型訓(xùn)練(使用GPU訓(xùn)練)
我們用LeNet在Fashion-MNIST數(shù)據(jù)集上測(cè)試模型表現(xiàn)結(jié)果:
batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size) def evaluate_accuracy_gpu(net, data_iter, device=None): #@save """使用GPU計(jì)算模型在數(shù)據(jù)集上的精度。""" if isinstance(net, torch.nn.Module): net.eval() # 設(shè)置為評(píng)估模式 if not device: device = next(iter(net.parameters())).device # 正確預(yù)測(cè)的數(shù)量,總預(yù)測(cè)的數(shù)量 metric = d2l.Accumulator(2) for X, y in data_iter: if isinstance(X, list): X = [x.to(device) for x in X] else: X = X.to(device) y = y.to(device) metric.add(d2l.accuracy(net(X), y), y.numel()) return metric[0] / metric[1] #@save def train_ch6(net, train_iter, test_iter, num_epochs, lr, device): """用GPU訓(xùn)練模型。""" def init_weights(m): if type(m) == nn.Linear or type(m) == nn.Conv2d: nn.init.xavier_uniform_(m.weight) net.apply(init_weights) print('training on', device) net.to(device) optimizer = torch.optim.SGD(net.parameters(), lr=lr) loss = nn.CrossEntropyLoss() animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs], legend=['train loss', 'train acc', 'test acc']) timer, num_batches = d2l.Timer(), len(train_iter) for epoch in range(num_epochs): # 訓(xùn)練損失之和,訓(xùn)練準(zhǔn)確率之和,范例數(shù) metric = d2l.Accumulator(3) net.train() for i, (X, y) in enumerate(train_iter): timer.start() optimizer.zero_grad() X, y = X.to(device), y.to(device) y_hat = net(X) l = loss(y_hat, y) l.backward() optimizer.step() with torch.no_grad(): metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0]) timer.stop() train_l = metric[0] / metric[2] train_acc = metric[1] / metric[2] if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1: animator.add(epoch + (i + 1) / num_batches, (train_l, train_acc, None)) test_acc = evaluate_accuracy_gpu(net, test_iter) animator.add(epoch + 1, (None, None, test_acc)) print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, ' f'test acc {test_acc:.3f}') print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec ' f'on {str(device)}')
3.3 訓(xùn)練和評(píng)估模型
lr, num_epochs = 0.9, 10
train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
這個(gè)是我的訓(xùn)練結(jié)果,大概就醬紫,結(jié)束了結(jié)束了,累死我了。
到此這篇關(guān)于一文帶你了解CNN(卷積神經(jīng)網(wǎng)絡(luò))的文章就介紹到這了,更多相關(guān)CNN(卷積神經(jīng)網(wǎng)絡(luò))內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python英文文章詞頻統(tǒng)計(jì)(14份劍橋真題詞頻統(tǒng)計(jì))
這篇文章主要介紹了Python英文文章詞頻統(tǒng)計(jì)(14份劍橋真題詞頻統(tǒng)計(jì)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10教你怎么用python批量登錄帶有驗(yàn)證碼的網(wǎng)站
這篇文章主要介紹了教你怎么用python批量登錄帶有驗(yàn)證碼的網(wǎng)站,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python的小伙伴們有很好的幫助,需要的朋友可以參考下2021-04-04利用PyQt中的QThread類實(shí)現(xiàn)多線程
本文主要給大家分享的是python實(shí)現(xiàn)多線程及線程間通信的簡(jiǎn)單方法,非常的實(shí)用,有需要的小伙伴可以參考下2020-02-02python使用IPython調(diào)試debug程序
這篇文章主要為大家介紹了python使用IPython調(diào)試debug程序詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05python實(shí)現(xiàn)nao機(jī)器人身體軀干和腿部動(dòng)作操作
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)nao機(jī)器人身體軀干和腿部動(dòng)作操作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04pandas groupby + unstack的使用說(shuō)明
這篇文章主要介紹了pandas groupby + unstack的使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03