高州新聞 頭條 今天seo推廣招聘
解讀
Abstract—摘要
翻譯
更深的神經(jīng)網(wǎng)絡(luò)往往更難以訓(xùn)練,我們?cè)诖颂岢鲆粋€(gè)殘差學(xué)習(xí)的框架,以減輕網(wǎng)絡(luò)的訓(xùn)練負(fù)擔(dān),這是個(gè)比以往的網(wǎng)絡(luò)要深的多的網(wǎng)絡(luò)。我們明確地將層作為輸入學(xué)習(xí)殘差函數(shù),而不是學(xué)習(xí)未知的函數(shù)。我們提供了非常全面的實(shí)驗(yàn)數(shù)據(jù)來證明,殘差網(wǎng)絡(luò)更容易被優(yōu)化,并且可以在深度增加的情況下讓精度也增加。在ImageNet的數(shù)據(jù)集上我們?cè)u(píng)測(cè)了一個(gè)深度152層(是VGG的8倍)的殘差網(wǎng)絡(luò),但依舊擁有比VGG更低的復(fù)雜度。殘差網(wǎng)絡(luò)整體達(dá)成了3.57%的錯(cuò)誤率,這個(gè)結(jié)果獲得了ILSVRC2015的分類任務(wù)第一名,我們還用CIFAR-10數(shù)據(jù)集分析了100層和1000層的網(wǎng)絡(luò)。
在一些計(jì)算機(jī)視覺識(shí)別方向的任務(wù)當(dāng)中,深度表示往往是重點(diǎn)。我們極深的網(wǎng)絡(luò)讓我們得到了28%的相對(duì)提升(對(duì)COCO的對(duì)象檢測(cè)數(shù)據(jù)集)。我們?cè)谏疃葰埐罹W(wǎng)絡(luò)的基礎(chǔ)上做了提交的版本參加ILSVRC和COCO2015的比賽,我們還獲得了ImageNet對(duì)象檢測(cè),Imagenet對(duì)象定位,COCO對(duì)象檢測(cè)和COCO圖像分割的第一名。
精讀
主要內(nèi)容
**背景:**神經(jīng)網(wǎng)絡(luò)的深度越深,越難以訓(xùn)練
**本文貢獻(xiàn):**本文展示了一種殘差學(xué)習(xí)框架,能夠簡(jiǎn)化使那些非常深的網(wǎng)絡(luò)的訓(xùn)練,該框架能夠?qū)幼鳛檩斎雽W(xué)習(xí)殘差函數(shù),而不是學(xué)習(xí)未知的函數(shù)。
**結(jié)果:**本文提供了全面的依據(jù)表明,這些殘差網(wǎng)絡(luò)更容易被優(yōu)化,而且可以在深度增加的情況下讓精度也增加。
**成績(jī):**2015年的ILSVRC分類任務(wù)上以及獲得了第一名的成績(jī),后來在ImageNet檢測(cè)、ImageNet定位、COCO檢測(cè)以及COCO分割上均獲得了第一名的成績(jī)。
Introduction—介紹
翻譯
深度卷積神經(jīng)網(wǎng)絡(luò)在圖像分類領(lǐng)域取得了一系列的突破 。 深度網(wǎng)絡(luò)很好的將一個(gè)端到端的多層模型中的低/中/高級(jí)特征以及分類器整合起來,特征的等級(jí)可以通過所堆疊層的數(shù)量(深度)來豐富。最近有結(jié)果顯示,模型的深度發(fā)揮著至關(guān)重要的作用,這樣導(dǎo)致了ImageNet競(jìng)賽的參賽模型都趨向于“非常深”——16 層 到30層 。許多其它的視覺識(shí)別任務(wù)的都得益于非常深的模型。
在深度的重要性的驅(qū)使下,出現(xiàn)了一個(gè)新的問題:訓(xùn)練一個(gè)更好的網(wǎng)絡(luò)是否和堆疊更多的層一樣簡(jiǎn)單呢?解決這一問題的障礙便是困擾人們很久的梯度消失/梯度爆炸,這從一開始便阻礙了模型的收斂。歸一初始化(normalized initialization)和中間歸一化(intermediate normalization)在很大程度上解決了這一問題,它使得數(shù)十層的網(wǎng)絡(luò)在反向傳播的隨機(jī)梯度下降(SGD)上能夠收斂。
當(dāng)深層網(wǎng)絡(luò)能夠收斂時(shí),一個(gè)退化問題又出現(xiàn)了:隨著網(wǎng)絡(luò)深度的增加,準(zhǔn)確率達(dá)到飽和(不足為奇)然后迅速退化。意外的是,這種退化并不是由過擬合造成的,并且在一個(gè)合理的深度模型中增加更多的層卻導(dǎo)致了更高的錯(cuò)誤率,我們的實(shí)驗(yàn)也證明了這點(diǎn)。
退化的出現(xiàn)(訓(xùn)練準(zhǔn)確率)表明了并非所有的系統(tǒng)都是很容易優(yōu)化的。讓我們來比較一個(gè)淺層的框架和它的深層版本。對(duì)于更深的模型,這有一種通過構(gòu)建的解決方案:恒等映射(identity mapping)來構(gòu)建增加的層,而其它層直接從淺層模型中復(fù)制而來。這個(gè)構(gòu)建的解決方案也表明了,一個(gè)更深的模型不應(yīng)當(dāng)產(chǎn)生比它的淺層版本更高的訓(xùn)練錯(cuò)誤率。實(shí)驗(yàn)表明,我們目前無法找到一個(gè)與這種構(gòu)建的解決方案相當(dāng)或者更好的方案(或者說無法在可行的時(shí)間內(nèi)實(shí)現(xiàn))。
本文中,我們提出了一種深度殘差學(xué)習(xí)框架來解決這個(gè)退化問題。我們明確的讓這些層來擬合殘差映射(residual mapping),而不是讓每一個(gè)堆疊的層直接來擬合所需的底層映射(desired underlying mapping)。假設(shè)所需的底層映射為 H(x)H(x),我們讓堆疊的非線性層來擬合另一個(gè)映射: F(x):=H(x)?xF(x):=H(x)?x。 因此原來的映射轉(zhuǎn)化為: F(x)+xF(x)+x。我們推斷殘差映射比原始未參考的映射(unreferenced mapping)更容易優(yōu)化。在極端的情況下,如果某個(gè)恒等映射是最優(yōu)的,那么將殘差變?yōu)? 比用非線性層的堆疊來擬合恒等映射更簡(jiǎn)單。
公式 F(x)+xF(x)+x 可以通過前饋神經(jīng)網(wǎng)絡(luò)的“shortcut連接”來實(shí)現(xiàn)(Fig.2)。Shortcut連接就是跳過一個(gè)或者多個(gè)層。在我們的例子中,shortcut 連接只是簡(jiǎn)單的執(zhí)行恒等映射,再將它們的輸出和堆疊層的輸出疊加在一起(Fig.2)。恒等的shortcut連接并不增加額外的參數(shù)和計(jì)算復(fù)雜度。完整的網(wǎng)絡(luò)仍然能通過端到端的SGD反向傳播進(jìn)行訓(xùn)練,并且能夠簡(jiǎn)單的通過公共庫(kù)(例如,Caffe)來實(shí)現(xiàn)而無需修改求解器(solvers)。
我們?cè)贗mageNet數(shù)據(jù)集上進(jìn)行了綜合性的實(shí)驗(yàn)來展示這個(gè)退化問題并評(píng)估了我們提出的方法。本文表明了: 1) 我們極深的殘差網(wǎng)絡(luò)是很容易優(yōu)化的,但是對(duì)應(yīng)的“plain”網(wǎng)絡(luò)(僅是堆疊了層)在深度增加時(shí)卻出現(xiàn)了更高的錯(cuò)誤率。 2) 我們的深度殘差網(wǎng)絡(luò)能夠輕易的由增加層來提高準(zhǔn)確率,并且結(jié)果也大大優(yōu)于以前的網(wǎng)絡(luò)。
CIFAR-10數(shù)據(jù)集上也出現(xiàn)了類似的現(xiàn)象,這表明了我們提出的方法的優(yōu)化難度和效果并不僅僅是對(duì)于一個(gè)特定數(shù)據(jù)集而言的。我們?cè)谶@個(gè)數(shù)據(jù)集上成功的提出了超過100層的訓(xùn)練模型,并探索了超過1000層的模型。
在ImageNet分類數(shù)據(jù)集上,極深的殘差網(wǎng)絡(luò)獲得了優(yōu)異的成績(jī)。我們的152層的殘差網(wǎng)絡(luò)是目前ImageNet尚最深的網(wǎng)絡(luò),并且別VGG網(wǎng)絡(luò)的復(fù)雜度還要低。在ImageNet測(cè)試集上,我們的組合模型(ensemble)的top-5錯(cuò)誤率僅為3.57%,并贏得了ILSVRC 2015分類競(jìng)賽的第一名。這個(gè)極深的模型在其他識(shí)別任務(wù)上同樣也具有非常好的泛化性能,這讓我們?cè)贗LSVRC & COCO 2015 競(jìng)賽的ImageNet檢測(cè)、ImageNet定位、COCO檢測(cè)以及COCO分割上均獲得了第一名的成績(jī)。這強(qiáng)有力的證明了殘差學(xué)習(xí)法則的通用性,因此我們將把它應(yīng)用到其他視覺甚至非視覺問題上。
精讀
背景
模型的深度發(fā)揮著至關(guān)重要的作用,這樣導(dǎo)致了ImageNet競(jìng)賽的參賽模型都趨向于“非常深”——16 層 到30層
問題一: 模型深度太大時(shí),會(huì)存在梯度消失/梯度爆炸的問題
**梯度消失/梯度爆炸概念:**二者問題問題都是因?yàn)榫W(wǎng)絡(luò)太深,網(wǎng)絡(luò)權(quán)值更新不穩(wěn)定造成的。本質(zhì)上是因?yàn)樘荻确聪騻鞑ブ械倪B乘效應(yīng)(小于1連續(xù)相乘多次)。梯度消失時(shí),越靠近輸入層的參數(shù)w越是幾乎紋絲不動(dòng);梯度爆炸時(shí),越是靠近輸入層的參數(shù)w越是上躥下跳。
**解決方法:**歸一初始化(normalized initialization)和中間歸一化(intermediate normalization)+BN,加快網(wǎng)絡(luò)收斂。
問題二: 隨著網(wǎng)絡(luò)深度的增加,準(zhǔn)確率達(dá)到飽和然后迅速退化
**網(wǎng)絡(luò)退化概念:**神經(jīng)網(wǎng)絡(luò)隨著層數(shù)加深,首先訓(xùn)練準(zhǔn)確率會(huì)逐漸趨于飽和;若層數(shù)繼續(xù)加深,反而訓(xùn)練準(zhǔn)確率下降,效果不好了,而這種下降不是由過擬合造成的(因?yàn)槿绻沁^擬合的話,訓(xùn)練時(shí)誤差應(yīng)該很低而測(cè)試時(shí)很高)。
Q:為啥會(huì)出現(xiàn)網(wǎng)絡(luò)退化?
由于非線性激活函數(shù)Relu的存在,每次輸入到輸出的過程都幾乎是不可逆的,這也造成了許多不可逆的信息損失。一個(gè)特征的一些有用的信息損失了,得到的結(jié)果肯定不盡人意。說通俗一點(diǎn)就是中間商賺差價(jià)。層數(shù)增多之后,信息在中間層損失掉了。
**解決方法:**深度殘差學(xué)習(xí)
(具體方法會(huì)在3.1章節(jié)講解)
結(jié)果:
(1)殘差網(wǎng)絡(luò)的結(jié)構(gòu)更利于優(yōu)化收斂
(2)解決了退化問題
(3)殘差網(wǎng)絡(luò)可以在擴(kuò)展網(wǎng)絡(luò)深度的同時(shí),提高網(wǎng)絡(luò)性能
Related Work—相關(guān)工作
Residual Representations—?dú)埐畋磉_(dá)
翻譯
殘差表達(dá)
在圖像識(shí)別中,VLAD是殘差向量對(duì)應(yīng)于字典進(jìn)行編碼的一種表達(dá)形式,Fisher Vector可以看做是VLAD 的一個(gè)概率版本。對(duì)于圖像檢索和分類它們都是強(qiáng)力的淺層表達(dá)。對(duì)于向量量化,殘差向量編碼比原始向量編碼更加有效。
在低級(jí)視覺和計(jì)算機(jī)圖形學(xué)中,為了求解偏微分方程(PDEs),通常使用Multigrid法將系統(tǒng)重新表達(dá)成多尺度的子問題來解決,每一個(gè)子問題就是解決粗細(xì)尺度之間的殘差問題。Multigrid的另外一種方式是分層基預(yù)處理,它依賴于代表著兩個(gè)尺度之間殘差向量的變量。實(shí)驗(yàn)證明 這些求解器比其他標(biāo)準(zhǔn)求解器的收斂要快得多,卻并沒有意識(shí)到這是該方法的殘差特性所致。這些方法表明了一個(gè)好的重新表達(dá)或者預(yù)處理能夠簡(jiǎn)化優(yōu)化問題**。**
精讀
主要內(nèi)容
(1)對(duì)于向量量化,殘差向量編碼比原始向量編碼更加有效。
(2)Multigrid的殘差特性使得求解器比其他標(biāo)準(zhǔn)求解器的收斂要快得多,表明了一個(gè)好的重新表達(dá)或者預(yù)處理能夠簡(jiǎn)化優(yōu)化問題。
Shortcut Connections—短路連接
翻譯
Shortcut連接
Shortcut連接已經(jīng)經(jīng)過了很長(zhǎng)的一段實(shí)踐和理論研究過程。訓(xùn)練多層感知器(MLPs)的一個(gè)早期實(shí)踐就是添加一個(gè)連接輸入和輸出的線性層。在Szegedy2015Going及Lee2015deeply中,將一些中間層直接與輔助分類器相連接可以解決梯度消失/爆炸問題。在 Szegedy2015Going中,一個(gè)“inception”層由一個(gè)shortcut分支和一些更深的分支組合而成。
與此同時(shí),“highway networks”將shortcut連接與門控函數(shù) 結(jié)合起來。這些門是數(shù)據(jù)相關(guān)并且是有額外參數(shù)的,而我們的恒等shortcuts是無參數(shù)的。當(dāng)一個(gè)門的shortcut是“closed”(接近于0)時(shí),highway網(wǎng)絡(luò)中的層表示非殘差函數(shù)。相反的,我們的模型總是學(xué)習(xí)殘差函數(shù);我們的恒等shortcuts從不關(guān)閉,在學(xué)習(xí)額外的殘差函數(shù)時(shí),所有的信息總是通過的。此外,highway網(wǎng)絡(luò)并不能由增加層的深度(例如, 超過100層)來提高準(zhǔn)確率。
精讀
主要內(nèi)容
(1)Shortcut連接已經(jīng)經(jīng)過了很長(zhǎng)的一段實(shí)踐和理論研究過程,證明是有效的。
(2)和highway networks(門控函數(shù))對(duì)比:當(dāng)一個(gè)門的shortcut是“closed”(接近于0)時(shí),highway networks中的層表示非殘差函數(shù)。相反的,我們的模型總是學(xué)習(xí)殘差函數(shù);我們的恒等shortcuts從不關(guān)閉,是無參數(shù)的,在學(xué)習(xí)額外的殘差函數(shù)時(shí),所有的信息總是通過的。此外,highway networks并不能由增加層的深度(例如,超過100層)來提高準(zhǔn)確率。
Deep Residual Learning—深度殘差學(xué)習(xí)
Residual Learning—?dú)埐顚W(xué)習(xí)
翻譯
我們將H(x)看作一個(gè)由部分堆疊的層(并不一定是全部的網(wǎng)絡(luò))來擬合的底層映射,其中x是這些層的輸入。假設(shè)多個(gè)非線性層能夠逼近復(fù)雜的函數(shù),這就等價(jià)于這些層能夠逼近復(fù)雜的殘差函數(shù),例如, H(x)?x(假設(shè)輸入和輸出的維度相同)。所以我們明確的讓這些層來估計(jì)一個(gè)殘差函數(shù):F(x)=H(x)?x而不是H(x)。因此原始函數(shù)變成了:F(x)+x。盡管這兩個(gè)形式應(yīng)該都能夠逼近所需的函數(shù)(正如假設(shè)),但是學(xué)習(xí)的難易程度并不相同。
這個(gè)重新表達(dá)的動(dòng)機(jī)是由退化問題這個(gè)反常的現(xiàn)象(Fig.1,左)。正如我們?cè)贗ntroduction中討論的,如果增加的層能以恒等映射來構(gòu)建,一個(gè)更深模型的訓(xùn)練錯(cuò)誤率不應(yīng)該比它對(duì)應(yīng)的淺層模型的更大。退化問題表明了,求解器在通過多個(gè)非線性層來估計(jì)恒等映射上可能是存在困難的。而伴隨著殘差學(xué)習(xí)的重新表達(dá),如果恒等映射是最優(yōu)的,那么求解器驅(qū)使多個(gè)非線性層的權(quán)重趨向于零來逼近恒等映射。
在實(shí)際情況下,恒等映射不太可能達(dá)到最優(yōu),但是我們的重新表達(dá)對(duì)于這個(gè)問題的預(yù)處理是有幫助的。如果最優(yōu)函數(shù)更趨近于恒等映射而不是0映射,那么對(duì)于求解器來說尋找關(guān)于恒等映射的擾動(dòng)比學(xué)習(xí)一個(gè)新的函數(shù)要容易的多。通過實(shí)驗(yàn)(Fig.7)表明,學(xué)習(xí)到的殘差函數(shù)通常只有很小的響應(yīng),說明了恒等映射提供了合理的預(yù)處理。
精讀
ResNet目的
我們選擇加深網(wǎng)絡(luò)的層數(shù),是希望深層的網(wǎng)絡(luò)的表現(xiàn)能比淺層好,或者是希望它的表現(xiàn)至少和淺層網(wǎng)絡(luò)持平(相當(dāng)于直接復(fù)制淺層網(wǎng)絡(luò)的特征)
以前方法
在正常的網(wǎng)絡(luò)中,應(yīng)該傳遞給下一層網(wǎng)絡(luò)的輸入是 H(x)=F(x),即直接擬合H(x)
本文改進(jìn)
在ResNet中,傳遞給下一層的輸入變?yōu)镠(x)=F(x)+x,即擬合殘差F(x)=H(x)-x
**殘差模塊:**一條路不變(恒等映射);另一條路負(fù)責(zé)擬合相對(duì)于原始網(wǎng)絡(luò)的殘差,去糾正原始網(wǎng)絡(luò)的偏差,而不是讓整體網(wǎng)絡(luò)去擬合全部的底層映射,這樣網(wǎng)絡(luò)只需要糾正偏差。
本質(zhì)
(1)加了殘差結(jié)構(gòu)后,給了輸入x一個(gè)多的選擇。若神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)到這層的參數(shù)是冗余的時(shí)候,它可以選擇直接走這條“跳接”曲線(shortcut connection),跳過這個(gè)冗余層,而不需要再去擬合參數(shù)使得H(x)=F(x)=x
(2)加了恒等映射后,深層網(wǎng)絡(luò)至少不會(huì)比淺層網(wǎng)絡(luò)更差。
(3)而在Resnet中,只需要把F(x)變?yōu)?即可,輸出變?yōu)镕(x)+x=0+x=x很明顯,將網(wǎng)絡(luò)的輸出優(yōu)化為0比將其做一個(gè)恒等變換要容易得多。
Q:為什么H(x)=F(x)+x中F(x)為0才有效?
模型在訓(xùn)練過程中,F(x)是訓(xùn)練出來的,如果F(x)對(duì)于提高模型的訓(xùn)練精度無作用,自然梯度下降算法就調(diào)整該部分的參數(shù),使該部分的效果趨近于0.這樣整個(gè)模型就不會(huì)出現(xiàn)深度越深反而效果越差的情況了。
3.2. Identity Mapping by Shortcuts—通過短路連接進(jìn)行恒等映射
翻譯
我們?cè)诙询B層上采取殘差學(xué)習(xí)算法。一個(gè)構(gòu)建塊如Fig.2所示。本文中的構(gòu)建塊定義如下(Eq.1):y=F(x,{Wi})+x.
其中x和y分別表示層的輸入和輸出。函數(shù)F(x,{Wi})代表著學(xué)到的殘差映射。Fig.2中的例子包含兩層,F=W2σ(W1x),其中 σ代表ReLU,為了簡(jiǎn)化省略了偏置項(xiàng)。F+x操作由一個(gè)shortcut連接和元素級(jí)(element-wise)的加法來表示。在加法之后我們?cè)賵?zhí)行另一個(gè)非線性操作(例如, σ(y),如Fig.2。
Eq.1中的shortcut連接沒有增加額外的參數(shù)和計(jì)算復(fù)雜度。這不僅是一個(gè)很有吸引力的做法,同時(shí)在對(duì)“plain”網(wǎng)絡(luò)和殘差網(wǎng)絡(luò)進(jìn)行比較時(shí)也是非常重要的。我們可以在參數(shù)、深度、寬度以及計(jì)算成本都相同的基礎(chǔ)上對(duì)兩個(gè)網(wǎng)絡(luò)進(jìn)行公平的比較(除了可以忽略不計(jì)的元素級(jí)的加法)。
在Eq.1中,x和F的維度必須相同。如果不相同(例如, 當(dāng)改變了輸入/輸出的通道),我們可以通過shortcut連接執(zhí)行一個(gè)線性映射Ws來匹配兩者的維度(Eq.2):y=F(x,{Wi})+Wsx.
在Eq.1中同樣可以使用方陣Ws。但我們的實(shí)驗(yàn)表明,恒等映射已足夠解決退化問題,并且是經(jīng)濟(jì)的,因此Ws只是用來解決維度不匹配的問題。
殘差函數(shù)F的形勢(shì)是靈活可變的。本文實(shí)驗(yàn)中涉及到的函數(shù)FF是兩層或者三層的(Fig.5),當(dāng)然更多層也是可行的。但是如果F只含有一層,Eq.1就和線性函數(shù):y=W1x+x一致,因此并不具有任何優(yōu)勢(shì)。
我們還發(fā)現(xiàn)不僅是對(duì)于全連接層,對(duì)于卷積層也是同樣適用的。函數(shù)F(x,{Wi})可以表示多個(gè)卷積層,在兩個(gè)特征圖的通道之間執(zhí)行元素級(jí)的加法。
精讀
Shortcuts Connection的兩種方式:
(1)shortcuts同等維度映射,F(x)與x相加就是就是逐元素相加
- y=F(x,Wi)+x
- F=W2σ(W1x)
其中 x 和 y 分別表示層的輸入和輸出。函數(shù) F(x,Wi)代表著學(xué)到的殘差映射,σ 代表ReLU
這種方式通過shortcuts直接傳遞輸入x,不會(huì)引入額外的參數(shù)也不會(huì)增加模塊的計(jì)算復(fù)雜性,因此可以公平地將殘差網(wǎng)絡(luò)和plain網(wǎng)絡(luò)作比較。
(2)如果兩者維度不同(改變了輸入/輸出的通道),需要給x執(zhí)行一個(gè)線性映射來匹配維度
- y=F(x,Wi)+Wsx.
- F=W2σ(W1x)
這種方式的目的僅僅是為了保持x與F(x)之間的維度一致,所以通常只在相鄰殘差塊之間通道數(shù)改變時(shí)使用,絕大多數(shù)情況下僅使用第一種方式。
用卷積層進(jìn)行殘差學(xué)習(xí):以上的公式表示為了簡(jiǎn)化,都是基于全連接層的,實(shí)際上當(dāng)然可以用于卷積層。加法隨之變?yōu)閷?duì)應(yīng)channel間的兩個(gè)feature map逐元素相加。
3.3. Network Architectures—網(wǎng)絡(luò)架構(gòu)
翻譯
我們?cè)诙鄠€(gè)plain網(wǎng)絡(luò)和殘差網(wǎng)絡(luò)上進(jìn)行了測(cè)試,并都觀測(cè)到了一致的現(xiàn)象。接下來我們將在ImageNet上對(duì)兩個(gè)模型進(jìn)行討論。
Plain網(wǎng)絡(luò)
我們的plain網(wǎng)絡(luò)結(jié)構(gòu)(Fig.3,中)主要受VGG網(wǎng)絡(luò) (Fig.3,左)的啟發(fā)。
卷積層主要為3*3的濾波器,并遵循以下兩點(diǎn)要求:(i) 輸出特征尺寸相同的層含有相同數(shù)量的濾波器;(ii) 如果特征尺寸減半,則濾波器的數(shù)量增加一倍來保證每層的時(shí)間復(fù)雜度相同。我們直接通過stride 為2的卷積層來進(jìn)行下采樣。在網(wǎng)絡(luò)的最后是一個(gè)全局的平均pooling層和一個(gè)1000 類的包含softmax的全連接層。加權(quán)層的層數(shù)為34,如Fig.3(中)所示。
值得注意的是,我們的模型比VGG網(wǎng)絡(luò)(Fig.3,左)有更少的濾波器和更低的計(jì)算復(fù)雜度。我們34層的結(jié)構(gòu)含有36億個(gè)FLOPs(乘-加),而這僅僅只有VGG-19 (196億個(gè)FLOPs)的18%。
殘差網(wǎng)絡(luò)
在以上plain網(wǎng)絡(luò)的基礎(chǔ)上,我們插入shortcut連接(Fig.3,右),將網(wǎng)絡(luò)變成了對(duì)應(yīng)的殘差版本。如果輸入和輸出的維度相同時(shí),可以直接使用恒等shortcuts (Eq.1)(Fig.3中的實(shí)線部分)。當(dāng)維度增加時(shí)(Fig.3中的虛線部分),考慮兩個(gè)選項(xiàng):
(A) shortcut仍然使用恒等映射,在增加的維度上使用0來填充,這樣做不會(huì)增加額外的參數(shù);
(B) 使用Eq.2的映射shortcut來使維度保持一致(通過1*1的卷積)。
對(duì)于這兩個(gè)選項(xiàng),當(dāng)shortcut跨越兩種尺寸的特征圖時(shí),均使用stride為2的卷積。
Fig.3 對(duì)應(yīng)于ImageNet的網(wǎng)絡(luò)框架舉例。 左:VGG-19模型 (196億個(gè)FLOPs)作為參考。中:plain網(wǎng)絡(luò),含有34個(gè)參數(shù)層(36 億個(gè)FLOPs)。右:殘差網(wǎng)絡(luò),含有34個(gè)參數(shù)層(36億個(gè)FLOPs)。虛線表示的shortcuts增加了維度。Table 1展示了更多細(xì)節(jié)和其它變體。
Table 1 對(duì)應(yīng)于ImageNet的結(jié)構(gòu)框架。括號(hào)中為構(gòu)建塊的參數(shù)(同樣見Fig.5),數(shù)個(gè)構(gòu)建塊進(jìn)行堆疊。下采樣由stride為2的conv3_1、conv4_1和conv5_1 來實(shí)現(xiàn)。
精讀
下面將以ImageNet數(shù)據(jù)集為例,將plain網(wǎng)絡(luò)和殘差網(wǎng)絡(luò)作對(duì)比討論。
Plain網(wǎng)絡(luò)
plain網(wǎng)絡(luò)結(jié)構(gòu)主要受VGG網(wǎng)絡(luò)的啟發(fā)。 卷積層主要為3*3的卷積核,直接通過stride為2的卷積層來進(jìn)行下采樣。在網(wǎng)絡(luò)的最后是一個(gè)全局的平均pooling層和一個(gè)1000類的包含softmax的全連接層。加權(quán)層的層數(shù)為34。
兩條設(shè)計(jì)準(zhǔn)則:
(i)同樣輸出大小的特征圖,有著相同數(shù)量的卷積核;
(ii)如果特征圖大小減半,為了保證相同的時(shí)間復(fù)雜度,卷積核個(gè)數(shù)加倍。
與VGG對(duì)比:
我們的模型比VGG有更少的卷積核和更低的計(jì)算復(fù)雜度。我們34層的結(jié)構(gòu)含有36億個(gè)FLOPs(乘-加),而這僅僅只有VGG-19 (196億個(gè)FLOPs)的18%。
殘差網(wǎng)絡(luò)
在plain網(wǎng)絡(luò)的基礎(chǔ)上,加入shortcuts連接,就變成了相應(yīng)的殘差網(wǎng)絡(luò)
如上圖,實(shí)線代表維度一樣,直接相加 。虛線代表維度不一樣(出現(xiàn)了下采樣,步長(zhǎng)為2的卷積),使用殘差網(wǎng)絡(luò)
調(diào)整維度的方法有兩種:
(1)zero-padding:對(duì)多出來的通道padding補(bǔ)零填充,這種方法不會(huì)引入額外的參數(shù);
(2)線性投影變換:用1*1卷積升維,是需要學(xué)習(xí)的參數(shù),精度比zero-padding更好,但是耗時(shí)更長(zhǎng),占用更多內(nèi)存。
這兩種方法都使用stride為2的卷積。
3.4. Implementation—實(shí)現(xiàn)
翻譯
針對(duì)ImageNet的網(wǎng)絡(luò)實(shí)現(xiàn)遵循了Krizhevsky2012ImageNet和Simonyan2014Very。調(diào)整圖像的大小使它的短邊長(zhǎng)度隨機(jī)的從[256,480]中采樣來增大圖像的尺寸。 從一張圖像或者它的水平翻轉(zhuǎn)圖像中隨機(jī)采樣一個(gè)224*224的crop,每個(gè)像素都減去均值。圖像使用標(biāo)準(zhǔn)的顏色增強(qiáng)。我們?cè)诿恳粋€(gè)卷積層之后,激活層之前均使用batch normalization(BN)。我們根據(jù)He2014spatial來初始化權(quán)值然后從零開始訓(xùn)練所有plain/殘差網(wǎng)絡(luò)。
我們使用的mini-batch的尺寸為256。學(xué)習(xí)率從0.1開始,每當(dāng)錯(cuò)誤率平穩(wěn)時(shí)將學(xué)習(xí)率除以10,整個(gè)模型進(jìn)行60?104次迭代訓(xùn)練。我們將權(quán)值衰減設(shè)置為0.0001,a 動(dòng)量為0.9。根據(jù) Ioffe2015Batch,我們并沒有使用Dropout。
在測(cè)試中,為了進(jìn)行比較,我們采取標(biāo)準(zhǔn)的10-crop測(cè)試。
為了達(dá)到最佳的結(jié)果,我們使用Simonyan2014Very及He2014spatial中的全卷積形式,并在多個(gè)尺度的結(jié)果上取平均分(調(diào)整圖像的大小使它的短邊長(zhǎng)度分別為{224,256,384,480,640})。
精讀
方法
(1)圖像分別隨機(jī)被壓縮到256到480之間,之后做圖像增強(qiáng)
(2)輸出處理過程:用224 * 224 隨機(jī)裁出一個(gè)小圖,在做水平的鏡像來做圖像增強(qiáng)(不同尺度維度),10個(gè)小圖匯總成一個(gè)大圖(可使用多尺度裁剪和結(jié)果融合)。
(3)每個(gè)卷積層后面或者激活層之前都使用BN
參數(shù): mini-batch為256,學(xué)習(xí)率為0.1,訓(xùn)練60萬的迭代次數(shù),正則化0.0001,動(dòng)量是0.9。沒有使用dropout(BN和dropout不能混合使用,單獨(dú)使用效果更佳,原因:方差偏移)
Experiments—實(shí)驗(yàn)
ImageNet Classification—ImageNet分類
本文在1000類的ImageNet2012數(shù)據(jù)集上對(duì)我們的方法進(jìn)行評(píng)估。訓(xùn)練集包含128萬張圖像,驗(yàn)證集包含5萬張圖像。我們?cè)?0萬張測(cè)試圖像上進(jìn)行測(cè)試,并對(duì)top-1和top-5 的錯(cuò)誤率進(jìn)行評(píng)估。
Plain網(wǎng)絡(luò)
翻譯
我們首先評(píng)估了18層和34層的plain網(wǎng)絡(luò)。34層的網(wǎng)絡(luò)如圖Fig.3(中)所示。18層的結(jié)構(gòu)很相似,具體細(xì)節(jié)參見Table 1。
Table 2中展示的結(jié)果表明了34層的網(wǎng)絡(luò)比18層的網(wǎng)絡(luò)具有更高的驗(yàn)證錯(cuò)誤率。為了揭示產(chǎn)生這種現(xiàn)象的原因,在Fig.4(左)中我們比較了整個(gè)訓(xùn)練過程中的訓(xùn)練及驗(yàn)證錯(cuò)誤率。從結(jié)果中我們觀測(cè)到了明顯的退化問題——在整個(gè)訓(xùn)練過程中34 層的網(wǎng)絡(luò)具有更高的訓(xùn)練錯(cuò)誤率,即使18層網(wǎng)絡(luò)的解空間為34層解空間的一個(gè)子空間。
我們認(rèn)為這種優(yōu)化上的困難不太可能是由梯度消失所造成的。因?yàn)檫@些plain網(wǎng)絡(luò)的訓(xùn)練使用了BN,這能保證前向傳遞的信號(hào)是具有非零方差的。我們同樣驗(yàn)證了在反向傳遞階段的梯度由于BN而具有良好的范式,所以在前向和反向階段的信號(hào)不會(huì)存在消失的問題。事實(shí)上34層的plain網(wǎng)絡(luò)仍然具有不錯(cuò)的準(zhǔn)確率(Table 3),這表明了求解器在某種程度上也是有效的。我們推測(cè),深層的plain網(wǎng)絡(luò)的收斂率是指數(shù)衰減的,這可能會(huì)影響訓(xùn)練錯(cuò)誤率的降低。這種優(yōu)化困難的原因我們將在以后的工作中進(jìn)行研究。
精讀
首先進(jìn)行的實(shí)驗(yàn)是18層和34層的plain網(wǎng)絡(luò),實(shí)驗(yàn)結(jié)果如下表所示,產(chǎn)生了一種退化現(xiàn)象:在訓(xùn)練過程中34層的網(wǎng)絡(luò)比18層的網(wǎng)絡(luò)有著更高的訓(xùn)練錯(cuò)誤率。
(細(xì)線:訓(xùn)練集上的誤差; 粗線:測(cè)試集上的誤差)
殘差網(wǎng)絡(luò)
翻譯
接下來我們對(duì)18層和34層的殘差網(wǎng)絡(luò)ResNets進(jìn)行評(píng)估。如Fig.3 (右)所示,ResNets的基本框架和plain網(wǎng)絡(luò)的基本相同,除了在每一對(duì)3*3的濾波器上添加了一個(gè)shortcut連接。在Table 2以及Fig.4(右)的比較中,所有的shortcuts都是恒等映射,并且使用0對(duì)增加的維度進(jìn)行填充(選項(xiàng) A)。因此他們并沒有增加額外的參數(shù)。
我們從Table 2和Fig.4中觀測(cè)到以下三點(diǎn):
第一,與plain網(wǎng)絡(luò)相反,34層的ResNet比18層ResNet的結(jié)果更優(yōu)(2.8%)。更重要的是,34 層的ResNet在訓(xùn)練集和驗(yàn)證集上均展現(xiàn)出了更低的錯(cuò)誤率。這表明了這種設(shè)置可以很好的解決退化問題,并且我們可以由增加的深度來提高準(zhǔn)確率。
第二,與對(duì)應(yīng)的plain網(wǎng)絡(luò)相比,34層的ResNet在top-1 錯(cuò)誤率上降低了3.5% (Table 2),這得益于訓(xùn)練錯(cuò)誤率的降低(Fig.4 右 vs 左)。這也驗(yàn)證了在極深的網(wǎng)絡(luò)中殘差學(xué)習(xí)的有效性。
最后,我們同樣注意到,18層的plain網(wǎng)絡(luò)和殘差網(wǎng)絡(luò)的準(zhǔn)確率很接近 (Table 2),但是ResNet 的收斂速度要快得多。(Fig.4 右 vs 左)。
如果網(wǎng)絡(luò)“并不是特別深” (如18層),現(xiàn)有的SGD能夠很好的對(duì)plain網(wǎng)絡(luò)進(jìn)行求解,而ResNet能夠使優(yōu)化得到更快的收斂。
精讀
接著對(duì)18層和34層的殘差網(wǎng)絡(luò)進(jìn)行評(píng)估,為了保證變量的一致性,其基本框架結(jié)構(gòu)和plain網(wǎng)絡(luò)的結(jié)構(gòu)相同,只是在每一對(duì)卷積層上添加了shortcuts連接來實(shí)現(xiàn)殘差結(jié)構(gòu),對(duì)于維度不匹配的情況,使用0來填充維度(即3.3介紹過的方法1),因此也并沒有添加額外的參數(shù)。訓(xùn)練結(jié)果如下圖所示
【Table 2 ImageNet驗(yàn)證集上的Top-1錯(cuò)誤率 (%, 10-crop testing)】
結(jié)論
(1)與plain網(wǎng)絡(luò)相反,34層的resnet網(wǎng)絡(luò)比18層的錯(cuò)誤率更低,表明可以通過增加深度提高準(zhǔn)確率,解決了退化問題。
(2)與plain網(wǎng)絡(luò)相比,層次相同的resnet網(wǎng)絡(luò)上錯(cuò)誤率更低,表明殘差網(wǎng)絡(luò)在深層次下仍然有效。
(3)對(duì)于18層的plain網(wǎng)絡(luò),它和殘差網(wǎng)絡(luò)的準(zhǔn)確率很接近,但是殘差網(wǎng)絡(luò)的收斂速度要更快。
Identity vs. Projection Shortcuts—恒等 vs 映射 Shortcuts
翻譯
我們已經(jīng)驗(yàn)證了無參數(shù)的恒等shortcuts是有助于訓(xùn)練的。接下來我們研究映射shortcut(Eq.2)。在Table 3中,我們比較了三種選項(xiàng):
(A) 對(duì)增加的維度使用0填充,所有的shortcuts是無參數(shù)的(與Table 2 和 Fig.4 (右)相同);
(B) 對(duì)增加的維度使用映射shortcuts,其它使用恒等shortcuts;
? 所有的都是映射shortcuts。
Table 3表明了三種選項(xiàng)的模型都比對(duì)于的plain模型要好。B略好于A,我們認(rèn)為這是因?yàn)锳中的0填充并沒有進(jìn)行殘差學(xué)習(xí)。C略好于B,我們把這個(gè)歸結(jié)于更多的(13個(gè))映射shortcuts所引入的參數(shù)。在A、B、C三個(gè)結(jié)果中細(xì)小的差距也表明了映射shortcuts對(duì)于解決退化問題并不是必需的。所以我們?cè)诒疚慕酉聛淼膬?nèi)容中,為了減少?gòu)?fù)雜度和模型尺寸,并不使用選項(xiàng)C的模型。恒等shortcuts因其無額外復(fù)雜度而對(duì)以下介紹的瓶頸結(jié)構(gòu)尤為重要。
精讀
無參數(shù)的恒等shortcuts肯定是有助于提高訓(xùn)練效果的,針對(duì)映射shortcuts,有三種方法可供選擇:
(1)ResNet - 34 A: 所有的shortcut都使用恒等映射,也就是多出來的通道補(bǔ)0,沒有額外的參
(2)ResNet - 34 B: 對(duì)需要調(diào)整維度的使用卷積映射shortcut來實(shí)現(xiàn),不需要調(diào)整維度的使用恒等shortcut,升維的時(shí)候使用1 * 1卷積
(3)ResNet - 34 C: 所有的shortcut都使用1 * 1卷積(效果最好,但引入更多的參數(shù),不經(jīng)濟(jì))
下面的表格中表明了三種選項(xiàng)的模型都比plain模型要好,按效果好壞排序?yàn)镃>B>A,
【Table 3 在ImageNet驗(yàn)證集上的錯(cuò)誤率 (%, 10-crop testing)】
B比A好,因?yàn)锳在升維的時(shí)候用padding補(bǔ)零,丟失了shortcut學(xué)習(xí),沒有進(jìn)行殘差學(xué)習(xí)
C比B好,因?yàn)镃的13個(gè)非下采樣殘差模塊的shortcut都有參數(shù),模型能力比較強(qiáng)
但是ABC都差不多,說明恒等映射的shortcut可以解決退化問題
Deeper Bottleneck Architectures—深度瓶頸結(jié)構(gòu)
翻譯
接下來我們介紹更深的模型??紤]到訓(xùn)練時(shí)間的限制,我們將構(gòu)建塊修改成瓶頸的設(shè)計(jì)。對(duì)于每一個(gè)殘差函數(shù)F,我們使用了三個(gè)疊加層而不是兩個(gè)(Fig.5)。 這三層分別是11、33 和11 的卷積,11 的層主要負(fù)責(zé)減少然后增加(恢復(fù))維度,剩下的3*3的層來減少輸入和輸出的維度。Fig.5展示了一個(gè)例子,這兩種設(shè)計(jì)具有相似的時(shí)間復(fù)雜度。
無參數(shù)的恒等shortcuts對(duì)于瓶頸結(jié)構(gòu)尤為重要。如果使用映射shortcuts來替代Fig.5(右)中的恒等shortcuts,將會(huì)發(fā)現(xiàn)時(shí)間復(fù)雜度和模型尺寸都會(huì)增加一倍,因?yàn)閟hortcut連接了兩個(gè)高維端,所以恒等shortcuts對(duì)于瓶頸設(shè)計(jì)是更加有效的。
50層 ResNet:我們將34層網(wǎng)絡(luò)中2層的模塊替換成3層的瓶頸模塊,整個(gè)模型也就變成了50層的ResNet (Table 1)。對(duì)于增加的維度我們使用選項(xiàng)B來處理。整個(gè)模型含有38億個(gè)FLOPs。
101層和152層 ResNets:我們使用更多的3層模塊來構(gòu)建101層和152層的ResNets (Table 1)。值得注意的是,雖然層的深度明顯增加了,但是152層ResNet的計(jì)算復(fù)雜度(113億個(gè)FLOPs)仍然比VGG-16(153 億個(gè)FLOPs)和VGG-19(196億個(gè)FLOPs)的小很多。
50/101/152層ResNets比34層ResNet的準(zhǔn)確率要高得多(Table 3 和4)。而且我們并沒有觀測(cè)到退化問題。所有的指標(biāo)都證實(shí)了深度帶來的好處。 (Table 3 和4)。
精讀
接下來介紹層次更多的模型,對(duì)于每一個(gè)殘差塊,不再使用兩層卷積,而是使用三層卷積來實(shí)現(xiàn),如下圖所示。
50層的殘差網(wǎng)絡(luò): 將其34層的殘差網(wǎng)絡(luò)的2個(gè)卷積層替換成了3個(gè)bottleneck殘差塊,就變成了50層殘差網(wǎng)絡(luò),下采樣使用的是1 * 1 的卷積
【Table 4 單一模型在ImageNet驗(yàn)證集上的錯(cuò)誤率(%)(除了 ++ 是在驗(yàn)證集上的結(jié)果)
結(jié)論
50/101/152層的resnet比34層resnet的準(zhǔn)確率要高很多,解決了深層的退化問題。同時(shí)即使是152層resnet的計(jì)算復(fù)雜度仍然比VGG-16和VGG-19要小。
Comparisons with State-of-the-art Methods—與最優(yōu)秀方法的比較
翻譯
在Table 4中我們比較了目前最好的單模型結(jié)果。我們的34層ResNets取得了非常好的結(jié)果,152層的ResNet的單模型top-5驗(yàn)證錯(cuò)誤率僅為 4.49%,甚至比先前組合模型的結(jié)果還要好 (Table 5)。我們將6個(gè)不同深度的ResNets合成一個(gè)組合模型(在提交結(jié)果時(shí)只用到2個(gè)152層的模型)。這在測(cè)試集上的top-5錯(cuò)誤率僅為3.57% (Table 5),這一項(xiàng)在ILSVRC 2015 上獲得了第一名的成績(jī)。
精讀
將6個(gè)不同深度的ResNets合成一個(gè)組合模型(在提交結(jié)果時(shí)只用到2個(gè)152層的模型)。這在測(cè)試集上的top-5錯(cuò)誤率僅為3.57% (Table 5),這一項(xiàng)在ILSVRC 2015 上獲得了第一名的成績(jī)。
【Table 5 組合模型在ImageNet測(cè)試集上的top-5錯(cuò)誤率】
4.2. CIFAR-10 and Analysis— CIFAR-10和分析
翻譯
我們?cè)诎?萬張訓(xùn)練圖像和1萬張測(cè)試圖像的10類CIFAR-10數(shù)據(jù)集上進(jìn)行了更多的研究。我們?cè)谟?xùn)練集上進(jìn)行訓(xùn)練,在測(cè)試集上進(jìn)行驗(yàn)證。我們關(guān)注的是驗(yàn)證極深模型的效果,而不是追求最好的結(jié)果,因此我們只使用簡(jiǎn)單的框架如下。
Plain網(wǎng)絡(luò)和殘差網(wǎng)絡(luò)的框架如 Fig.3(中/右)所示。網(wǎng)絡(luò)的輸入是3232的減掉像素均值的圖像。第一層是33的卷積層。然后我們使用6n個(gè)3*3的卷積層的堆疊,卷積層對(duì)應(yīng)的特征圖有三種:{32,16,8},每一種卷積層的數(shù)量為2n 個(gè),對(duì)應(yīng)的濾波器數(shù)量分別為{16,32,64}。使用strde為2的卷積層進(jìn)行下采樣。在網(wǎng)絡(luò)的最后是一個(gè)全局的平均pooling層和一個(gè)10類的包含softmax的全連接層。一共有6n+2個(gè)堆疊的加權(quán)層。
權(quán)重的衰減設(shè)置為0.0001,動(dòng)量為0.9,采用了He2015Delving中的權(quán)值初始化以及BN,但是不使用Dropout,mini-batch的大小為128,模型在2塊GPU 上進(jìn)行訓(xùn)練。學(xué)習(xí)率初始為0.1,在第32000和48000次迭代時(shí)將其除以10,總的迭代次數(shù)為64000,這是由45000/5000的訓(xùn)練集/驗(yàn)證集分配所決定的。我們?cè)谟?xùn)練階段遵循Lee2015deeply中的數(shù)據(jù)增強(qiáng)法則:在圖像的每條邊填充4個(gè)像素,然后在填充后的圖像或者它的水平翻轉(zhuǎn)圖像上隨機(jī)采樣一個(gè)3232 的crop。在測(cè)試階段,我們只使用原始3232的圖像進(jìn)行評(píng)估。
我們比較了n={3,5,7,9},也就是20、32、44以及56層的網(wǎng)絡(luò)。Fig.6(左) 展示了plain網(wǎng)絡(luò)的結(jié)果。深度plain網(wǎng)絡(luò)隨著層數(shù)的加深,訓(xùn)練錯(cuò)誤率也變大。這個(gè)現(xiàn)象與在ImageNet(Fig.4, 左)和MNIST上的結(jié)果很相似,表明了優(yōu)化上的難度確實(shí)是一個(gè)很重要的問題。
Fig.6(中)展示了ResNets的效果。與ImageNet(Fig.4, 右)中類似,我們的ResNets能夠很好的克服優(yōu)化難題,并且隨著深度加深,準(zhǔn)確率也得到了提升。
我們進(jìn)一步探索了n=18,也就是110層的ResNet。在這里,我們發(fā)現(xiàn)0.1的初始學(xué)習(xí)率有點(diǎn)太大而不能很好的收斂。所以我們剛開始使用0.01的學(xué)習(xí)率,當(dāng)訓(xùn)練錯(cuò)誤率在80%以下(大約400次迭代)之后,再將學(xué)習(xí)率調(diào)回0.1繼續(xù)訓(xùn)練。剩余的學(xué)習(xí)和之前的一致。110層的ResNets很好的收斂了 (Fig.6, 中)。它與其他的深層窄模型,如FitNet和 Highway (Table 6)相比,具有更少的參數(shù),然而卻達(dá)到了最好的結(jié)果 (6.43%, Table 6)。
精讀
**CIFAR-10 數(shù)據(jù)集:**50w的訓(xùn)練集,10w的測(cè)試集,一共10個(gè)類別
對(duì)比plain網(wǎng)絡(luò)和殘差網(wǎng)絡(luò)的做法
(1)輸入的圖像為32*32的像素,此時(shí)的圖像做了預(yù)處理(每個(gè)像素減去均值)
(2)第一個(gè)卷積層為33 ,使用6n的卷積層,分別都是33的,feature map為(3232/1616/ 8*8)。一共有6n+2的卷積層(最后一層為池化層:1 +2n,2n,2n,1)
(3)卷積核個(gè)數(shù)分別為16/32/64,feature map個(gè)數(shù)減半,channel數(shù)翻倍
Q:為什么下采樣之后feature map尺寸減半,通道個(gè)數(shù)翻倍?
因?yàn)槌鼗瘯?huì)讓長(zhǎng)寬方向減半,卷積核個(gè)數(shù)對(duì)應(yīng)通道加倍(詳情見《MobileNet》)
下采樣用的是步長(zhǎng)為2的卷積,最后加一個(gè)全局池化,10個(gè)神經(jīng)元的全連接層和softmax
(1)殘差是由2層神經(jīng)網(wǎng)絡(luò)(每一個(gè)shortcut都由3 * 3的卷積組成)來擬合的,總共有6n,所以一共有3n的shortcut。
(2)下采樣是由0補(bǔ)充(下采樣的殘差和不帶殘差的計(jì)算量是一樣的)
(3)訓(xùn)練過程中的正則化為0.0001 ,動(dòng)量化為0.9 ,論文中提出的權(quán)重進(jìn)行初始化,使用了BN沒有使用dropout,批次處理為128,起始的學(xué)習(xí)率為0.1,在3.2w和4.8w迭代時(shí)除以10,最終在6.4w終止訓(xùn)練
(4)把訓(xùn)練集劃分為4.5w訓(xùn)練和5k的驗(yàn)證,使用圖像增強(qiáng)方法,分別在圖像外邊補(bǔ)4個(gè)pixel,再用32 *32 的圖像進(jìn)行剪裁(水平翻轉(zhuǎn)的圖像增強(qiáng))。測(cè)試的時(shí)候,直接使用32 * 32的圖像進(jìn)行測(cè)試即可
【圖6:CIFAR-10培訓(xùn)。虛線表示訓(xùn)練錯(cuò)誤,粗體表示測(cè)試錯(cuò)誤。左:plain。plain-110的誤差大于60%,不顯示。中間:ResNets。右圖:ResNets110層和1202層。】
Analysis of Layer Responses—分析每一層的網(wǎng)絡(luò)的響應(yīng)分布
翻譯
Fig.7展示了層響應(yīng)的標(biāo)準(zhǔn)方差(std)。 響應(yīng)是每一個(gè)3*3卷積層的BN之后、非線性層(ReLU/addition)之前的輸出。對(duì)于ResNets,這個(gè)分析結(jié)果也揭示了殘差函數(shù)的響應(yīng)強(qiáng)度。Fig.7表明了ResNets的響應(yīng)比它對(duì)應(yīng)的plain網(wǎng)絡(luò)的響應(yīng)要小。這些結(jié)果也驗(yàn)證了我們的基本動(dòng)機(jī)(Sec3.1),即殘差函數(shù)比非殘差函數(shù)更接近于0。從Fig.7中ResNet-20、56和110的結(jié)果,我們也注意到,越深的ResNet的響應(yīng)幅度越小。當(dāng)使用更多層是,ResNets中單個(gè)層對(duì)信號(hào)的改變?cè)缴佟?/p>
精讀
殘差網(wǎng)絡(luò)是修正輸入。響應(yīng)的標(biāo)準(zhǔn)差如下圖:
【圖7:CIFAR- 10層響應(yīng)的標(biāo)準(zhǔn)偏差(std)。響應(yīng)為BN后和非線性前各33層的輸出。頂部:圖層按原來的順序顯示。底部:響應(yīng)按降序排列。】
方法
BN處理,均值已被調(diào)整為0。標(biāo)準(zhǔn)差衡量數(shù)據(jù)的離散程度(標(biāo)準(zhǔn)差越大,表明響應(yīng)越大) 響應(yīng)是每一層都是3 * 3的卷積層,介于BN后和激活之前。
結(jié)論
(1)ResNets的響應(yīng)比它對(duì)應(yīng)的plain網(wǎng)絡(luò)的響應(yīng)要小
(2)殘差函數(shù)比非殘差函數(shù)更接近于0
(3)越深的ResNet的響應(yīng)幅度越小
(4)越靠近起始層,輸出越大
Exploring Over 1000 layers—過深層網(wǎng)絡(luò)
翻譯
我們探索了一個(gè)超過1000層的極其深的模型。我們?cè)O(shè)置n=200,也就是1202層的網(wǎng)絡(luò)模型,按照上述進(jìn)行訓(xùn)練。我們的方法對(duì)103103層的模型并不難優(yōu)化,并且達(dá)到了<0.1%的訓(xùn)練錯(cuò)誤率(Fig.6, 右),它的測(cè)試錯(cuò)誤率也相當(dāng)?shù)?7.93%, Table 6)。
但是在這樣一個(gè)極其深的模型上,仍然存在很多問題。1202層模型的測(cè)試結(jié)果比110層的結(jié)果要差,盡管它們的訓(xùn)練錯(cuò)誤率差不多。我們認(rèn)為這是過擬合導(dǎo)致的。這樣一個(gè)1202層的模型對(duì)于小的數(shù)據(jù)集來說太大了(19.4M)。在這個(gè)數(shù)據(jù)集上應(yīng)用了強(qiáng)大的正則化方法,如maxout或者 dropout,才獲得了最好的結(jié)果。
本文中,我們并沒有使用maxout/dropout,只是簡(jiǎn)單的通過設(shè)計(jì)深層窄模型來進(jìn)行正則化,而且不用擔(dān)心優(yōu)化的難度。但是通過強(qiáng)大的正則化或許能夠提高實(shí)驗(yàn)結(jié)果,我們會(huì)在以后進(jìn)行研究。
精讀
取n等于200 ,也就是1202的殘差卷積網(wǎng)絡(luò)(6 * 200 + 2),和之前的訓(xùn)練方式一樣,誤差小于0.1,表明了沒有退化,沒優(yōu)化困難。
但測(cè)試集的性能沒有110層的好,文中表明這是過擬合了(模型太深參數(shù)過多,對(duì)于這個(gè)小數(shù)據(jù)集沒有必要)
此論文沒有使用maxout或者是dropout來正則化,因?yàn)楹诵娜蝿?wù)是為了解決退化問題。
4.3. Object Detection on PASCAL and MS COCO—PASCAL和MS COCO上的對(duì)象檢測(cè)
翻譯
我們的方法在其它識(shí)別任務(wù)上展現(xiàn)出了很好的泛化能力。Table 7和8展示了在PASCAL VOC 2007 和 2012以及 COCO上的目標(biāo)檢測(cè)結(jié)果。我們使用Faster R-CNN作為檢測(cè)方法。在這里,我們比較關(guān)注由ResNet-101 替換VGG-16所帶來的的提升。使用不同網(wǎng)絡(luò)進(jìn)行檢測(cè)的實(shí)現(xiàn)是一樣的,所以檢測(cè)結(jié)果只能得益于更好的網(wǎng)絡(luò)。最值得注意的是,在COCO數(shù)據(jù)集上,我們?cè)贑OCO的標(biāo)準(zhǔn)指標(biāo)(mAP@[.5, .95])上比先前的結(jié)果增加了6.0%,這相當(dāng)于28%的相對(duì)提升。而這完全得益于所學(xué)到的表達(dá)。
基于深度殘差網(wǎng)絡(luò),我們?cè)贗LSVRC & COCO 2015競(jìng)賽的ImageNet檢測(cè)、ImageNet定位、COCO檢測(cè)以及COCO分割上獲得了第一名。
精讀
【Table 7 在PASCAL VOC 2007/2012測(cè)試集上使用Faster R-CNN的目標(biāo)檢測(cè) mAP (%)。有關(guān)更好的結(jié)果,請(qǐng)參見附錄。】
【Table 8 在COCO 驗(yàn)證集上使用Faster R-CNN的目標(biāo)檢測(cè) mAP (%)?!?/p>
基于深度殘差網(wǎng)絡(luò),我們?cè)贗LSVRC & COCO 2015競(jìng)賽的ImageNet檢測(cè)、ImageNet定位、COCO檢測(cè)以及COCO分割上獲得了第一名。
論文十問
Q1:論文試圖解決什么問題?
該論文主要解決的深層神經(jīng)網(wǎng)絡(luò)的訓(xùn)練問題。隨著網(wǎng)絡(luò)的深度的增加,模型的效果反而變差了,論文提出了殘差學(xué)習(xí)的方式來訓(xùn)練深層的神經(jīng)網(wǎng)絡(luò)。
Q2:這是否是一個(gè)新的問題?
不是新問題,是優(yōu)化問題
Q3:這篇文章要驗(yàn)證一個(gè)什么科學(xué)假設(shè)?
研究深度模型中的退化問題,累積的非線性層可能難以學(xué)習(xí)到線性映射
Q4:有哪些相關(guān)研究?如何歸類?誰是這一課題在領(lǐng)域內(nèi)值得關(guān)注的研究員?
- 為了求解偏微分方程(PDEs),通常使用Multigrid法將系統(tǒng)重新表達(dá)成多尺度的子問題來解決。數(shù)學(xué)類問題。
- 附錄部分,作者針對(duì)ResNet在目標(biāo)檢測(cè)、目標(biāo)定位上的應(yīng)用進(jìn)行了研究。
Q5:論文中提到的解決方案之關(guān)鍵是什么?
ResNet 其實(shí)就是通過shortcut connections,將x直接傳遞到后面的層,使得網(wǎng)絡(luò)可以很容易的學(xué)習(xí)恒等變換,從而解決網(wǎng)絡(luò)退化的問題,同時(shí)也使得學(xué)習(xí)效率更高。
Q6:論文中的實(shí)驗(yàn)是如何設(shè)計(jì)的?
1.ImageNet2012:
- 首先對(duì)plain網(wǎng)絡(luò)和殘差網(wǎng)絡(luò)分別訓(xùn)練,對(duì)比它們不同層在訓(xùn)練集和測(cè)試集的誤差,以及是否退化。
- 然后恒等 vs 映射 Shortcuts
- 接著加深深度,對(duì)改進(jìn)后的殘差網(wǎng)絡(luò)訓(xùn)練和評(píng)估錯(cuò)誤率
- 最后和VGG、GoogLeNet等優(yōu)秀方法對(duì)比
2.CIFAR-10:
- 首先對(duì)plain網(wǎng)絡(luò)和殘差網(wǎng)絡(luò)分別訓(xùn)練,對(duì)比它們不同層在訓(xùn)練集和測(cè)試集的誤差,以及是否退化。
- 然后研究更深的模型
3.PASCAL和MS COCO:
和VGG對(duì)比
Q7:用于定量評(píng)估的數(shù)據(jù)集是什么?代碼有沒有開源?
ImageNet2012、CIFAR-10、PASCAL VOC 2007,2012、COCO
開源
Q8:論文中的實(shí)驗(yàn)及結(jié)果有沒有很好地支持需要驗(yàn)證的科學(xué)假設(shè)?
支持了,解決了退化的問題,也取得了第一。
Q9:這篇論文到底有什么貢獻(xiàn)?
1.研究深度模型中的退化問題,提出了ResNet網(wǎng)絡(luò)
2.提出了殘差學(xué)習(xí),助力深度模型的學(xué)習(xí),且沒有增加學(xué)習(xí)的參數(shù)
3.ResNet為目標(biāo)檢測(cè)和目標(biāo)定位提供了優(yōu)化思路
Q10:下一步呢?有什么工作可以繼續(xù)深入?
1.網(wǎng)絡(luò)收斂率問題需要繼續(xù)探究。 plain層我們推測(cè),深層的plain網(wǎng)絡(luò)的收斂率是指數(shù)衰減的,這可能會(huì)影響訓(xùn)練錯(cuò)誤率的降低。這種優(yōu)化困難的原因我們將在以后的工作中進(jìn)行研究。
2.解決過深層退化問題。 ResNet在1202層的優(yōu)化不再明顯反而還出現(xiàn)了退化。
代碼復(fù)現(xiàn)
源代碼比較復(fù)雜,感興趣的同學(xué)可以上官網(wǎng)學(xué)習(xí):
https://github.com/pytorch/vision/tree/master/torchvision
本篇是簡(jiǎn)化版本
一、BasicBlock模塊
BasicBlock結(jié)構(gòu)圖如圖所示:
BasicBlock是基礎(chǔ)版本,主要用來構(gòu)建ResNet18和ResNet34網(wǎng)絡(luò),里面只包含兩個(gè)卷積層,使用了兩個(gè) 3*3 的卷積,通道數(shù)都是64,卷積后接著 BN 和 ReLU。
右邊的曲線就是Shortcut Connections,將輸入x加到輸出。
代碼:
'''-------------一、BasicBlock模塊-----------------------------'''
# 用于ResNet18和ResNet34基本殘差結(jié)構(gòu)塊
class BasicBlock(nn.Module):def __init__(self, inchannel, outchannel, stride=1):super(BasicBlock, self).__init__()self.left = nn.Sequential(nn.Conv2d(inchannel, outchannel, kernel_size=3, stride=stride, padding=1, bias=False),nn.BatchNorm2d(outchannel),nn.ReLU(inplace=True), #inplace=True表示進(jìn)行原地操作,一般默認(rèn)為False,表示新建一個(gè)變量存儲(chǔ)操作nn.Conv2d(outchannel, outchannel, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(outchannel))self.shortcut = nn.Sequential()#論文中模型架構(gòu)的虛線部分,需要下采樣if stride != 1 or inchannel != outchannel:self.shortcut = nn.Sequential(nn.Conv2d(inchannel, outchannel, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(outchannel))def forward(self, x):out = self.left(x) #這是由于殘差塊需要保留原始輸入out += self.shortcut(x)#這是ResNet的核心,在輸出上疊加了輸入xout = F.relu(out)return out
二、Bottleneck 模塊
Bottleneck結(jié)構(gòu)圖如圖所示:
Bottleneck主要用在ResNet50及以上的網(wǎng)絡(luò)結(jié)構(gòu),與BasicBlock不同的是這里有 3 個(gè)卷積,分別為 11,33,11大小的卷積核,分別用于壓縮維度、卷積處理、恢復(fù)維度。
這里的通道數(shù)是變化的,11卷積層的作用就是用于改變特征圖的通數(shù),使得可以和恒等映射x相疊加,另外這里的1*1卷積層改變維度的很重要的一點(diǎn)是可以降低網(wǎng)絡(luò)參數(shù)量,這也是為什么更深層的網(wǎng)絡(luò)采用BottleNeck而不是BasicBlock的原因。
**注意:**這里outchannel / 4是因?yàn)锽ottleneck層輸出通道都是輸入的4倍
代碼:
'''-------------二、Bottleneck模塊-----------------------------'''
# 用于ResNet50及以上的殘差結(jié)構(gòu)塊
class Bottleneck(nn.Module):def __init__(self, inchannel, outchannel, stride=1):super(Bottleneck, self).__init__()self.left = nn.Sequential(nn.Conv2d(inchannel, int(outchannel / 4), kernel_size=1, stride=stride, padding=0, bias=False),nn.BatchNorm2d(int(outchannel / 4)),nn.ReLU(inplace=True),nn.Conv2d(int(outchannel / 4), int(outchannel / 4), kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(int(outchannel / 4)),nn.ReLU(inplace=True),nn.Conv2d(int(outchannel / 4), outchannel, kernel_size=1, stride=1, padding=0, bias=False),nn.BatchNorm2d(outchannel),)self.shortcut = nn.Sequential()if stride != 1 or inchannel != outchannel:self.shortcut = nn.Sequential(nn.Conv2d(inchannel, outchannel, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(outchannel))def forward(self, x):out = self.left(x)y = self.shortcut(x)out += self.shortcut(x)out = F.relu(out)return out
三、ResNet主體
介紹了上述BasicBlock基礎(chǔ)塊和BotteNeck結(jié)構(gòu)后,我們就可以搭建ResNet結(jié)構(gòu)了。
5種不同層數(shù)的ResNet結(jié)構(gòu)圖如圖所示:
代碼:
ResNet18
'''----------ResNet18----------'''
class ResNet_18(nn.Module):def __init__(self, ResidualBlock, num_classes=10):super(ResNet_18, self).__init__()self.inchannel = 64self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(64),nn.ReLU(),)self.layer1 = self.make_layer(ResidualBlock, 64, 2, stride=1)self.layer2 = self.make_layer(ResidualBlock, 128, 2, stride=2)self.layer3 = self.make_layer(ResidualBlock, 256, 2, stride=2)self.layer4 = self.make_layer(ResidualBlock, 512, 2, stride=2)self.fc = nn.Linear(512, num_classes)def make_layer(self, block, channels, num_blocks, stride):strides = [stride] + [1] * (num_blocks - 1) # strides=[1,1]layers = []for stride in strides:layers.append(block(self.inchannel, channels, stride))self.inchannel = channelsreturn nn.Sequential(*layers)def forward(self, x): # 3*32*32out = self.conv1(x) # 64*32*32out = self.layer1(out) # 64*32*32out = self.layer2(out) # 128*16*16out = self.layer3(out) # 256*8*8out = self.layer4(out) # 512*4*4out = F.avg_pool2d(out, 4) # 512*1*1out = out.view(out.size(0), -1) # 512out = self.fc(out)return out
ResNet34
'''----------ResNet34----------'''
class ResNet_34(nn.Module):def __init__(self, ResidualBlock, num_classes=10):super(ResNet_34, self).__init__()self.inchannel = 64self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(64),nn.ReLU(),)self.layer1 = self.make_layer(ResidualBlock, 64, 3, stride=1)self.layer2 = self.make_layer(ResidualBlock, 128, 4, stride=2)self.layer3 = self.make_layer(ResidualBlock, 256, 6, stride=2)self.layer4 = self.make_layer(ResidualBlock, 512, 3, stride=2)self.fc = nn.Linear(512, num_classes)def make_layer(self, block, channels, num_blocks, stride):strides = [stride] + [1] * (num_blocks - 1) # strides=[1,1]layers = []for stride in strides:layers.append(block(self.inchannel, channels, stride))self.inchannel = channelsreturn nn.Sequential(*layers)def forward(self, x): # 3*32*32out = self.conv1(x) # 64*32*32out = self.layer1(out) # 64*32*32out = self.layer2(out) # 128*16*16out = self.layer3(out) # 256*8*8out = self.layer4(out) # 512*4*4out = F.avg_pool2d(out, 4) # 512*1*1out = out.view(out.size(0), -1) # 512out = self.fc(out)return out
ResNet50
'''---------ResNet50--------'''
class ResNet_50(nn.Module):def __init__(self, ResidualBlock, num_classes=10):super(ResNet_50, self).__init__()self.inchannel = 64self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(64),nn.ReLU(),)self.layer1 = self.make_layer(ResidualBlock, 256, 3, stride=1)self.layer2 = self.make_layer(ResidualBlock, 512, 4, stride=2)self.layer3 = self.make_layer(ResidualBlock, 1024, 6, stride=2)self.layer4 = self.make_layer(ResidualBlock, 2048, 3, stride=2)self.fc = nn.Linear(512 * 4, num_classes)# **************************def make_layer(self, block, channels, num_blocks, stride):strides = [stride] + [1] * (num_blocks - 1) # strides=[1,1]layers = []for stride in strides:layers.append(block(self.inchannel, channels, stride))self.inchannel = channelsreturn nn.Sequential(*layers)def forward(self, x): # 3*32*32out = self.conv1(x) # 64*32*32out = self.layer1(out) # 64*32*32out = self.layer2(out) # 128*16*16out = self.layer3(out) # 256*8*8out = self.layer4(out) # 512*4*4out = F.avg_pool2d(out, 4) # 512*1*1# print(out.size())out = out.view(out.size(0), -1) # 512out = self.fc(out)return out
四、完整代碼
import torch
import torch.nn as nn
import torch.nn.functional as F'''-------------一、BasicBlock模塊-----------------------------'''
# 用于ResNet18和ResNet34基本殘差結(jié)構(gòu)塊
class BasicBlock(nn.Module):def __init__(self, inchannel, outchannel, stride=1):super(BasicBlock, self).__init__()self.left = nn.Sequential(nn.Conv2d(inchannel, outchannel, kernel_size=3, stride=stride, padding=1, bias=False),nn.BatchNorm2d(outchannel),nn.ReLU(inplace=True), #inplace=True表示進(jìn)行原地操作,一般默認(rèn)為False,表示新建一個(gè)變量存儲(chǔ)操作nn.Conv2d(outchannel, outchannel, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(outchannel))self.shortcut = nn.Sequential()#論文中模型架構(gòu)的虛線部分,需要下采樣if stride != 1 or inchannel != outchannel:self.shortcut = nn.Sequential(nn.Conv2d(inchannel, outchannel, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(outchannel))def forward(self, x):out = self.left(x) #這是由于殘差塊需要保留原始輸入out += self.shortcut(x)#這是ResNet的核心,在輸出上疊加了輸入xout = F.relu(out)return out'''-------------二、Bottleneck模塊-----------------------------'''
# 用于ResNet50及以上的殘差結(jié)構(gòu)塊
class Bottleneck(nn.Module):def __init__(self, inchannel, outchannel, stride=1):super(Bottleneck, self).__init__()self.left = nn.Sequential(nn.Conv2d(inchannel, int(outchannel / 4), kernel_size=1, stride=stride, padding=0, bias=False),nn.BatchNorm2d(int(outchannel / 4)),nn.ReLU(inplace=True),nn.Conv2d(int(outchannel / 4), int(outchannel / 4), kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(int(outchannel / 4)),nn.ReLU(inplace=True),nn.Conv2d(int(outchannel / 4), outchannel, kernel_size=1, stride=1, padding=0, bias=False),nn.BatchNorm2d(outchannel),)self.shortcut = nn.Sequential()if stride != 1 or inchannel != outchannel:self.shortcut = nn.Sequential(nn.Conv2d(inchannel, outchannel, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(outchannel))def forward(self, x):out = self.left(x)y = self.shortcut(x)out += self.shortcut(x)out = F.relu(out)return out'''-------------ResNet18---------------'''
class ResNet_18(nn.Module):def __init__(self, ResidualBlock, num_classes=10):super(ResNet_18, self).__init__()self.inchannel = 64self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(64),nn.ReLU(),)self.layer1 = self.make_layer(ResidualBlock, 64, 2, stride=1)self.layer2 = self.make_layer(ResidualBlock, 128, 2, stride=2)self.layer3 = self.make_layer(ResidualBlock, 256, 2, stride=2)self.layer4 = self.make_layer(ResidualBlock, 512, 2, stride=2)self.fc = nn.Linear(512, num_classes)def make_layer(self, block, channels, num_blocks, stride):strides = [stride] + [1] * (num_blocks - 1) # strides=[1,1]layers = []for stride in strides:layers.append(block(self.inchannel, channels, stride))self.inchannel = channelsreturn nn.Sequential(*layers)def forward(self, x): # 3*32*32out = self.conv1(x) # 64*32*32out = self.layer1(out) # 64*32*32out = self.layer2(out) # 128*16*16out = self.layer3(out) # 256*8*8out = self.layer4(out) # 512*4*4out = F.avg_pool2d(out, 4) # 512*1*1out = out.view(out.size(0), -1) # 512out = self.fc(out)return out'''-------------ResNet34---------------'''
class ResNet_34(nn.Module):def __init__(self, ResidualBlock, num_classes=10):super(ResNet_34, self).__init__()self.inchannel = 64self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(64),nn.ReLU(),)self.layer1 = self.make_layer(ResidualBlock, 64, 3, stride=1)self.layer2 = self.make_layer(ResidualBlock, 128, 4, stride=2)self.layer3 = self.make_layer(ResidualBlock, 256, 6, stride=2)self.layer4 = self.make_layer(ResidualBlock, 512, 3, stride=2)self.fc = nn.Linear(512, num_classes)def make_layer(self, block, channels, num_blocks, stride):strides = [stride] + [1] * (num_blocks - 1) # strides=[1,1]layers = []for stride in strides:layers.append(block(self.inchannel, channels, stride))self.inchannel = channelsreturn nn.Sequential(*layers)def forward(self, x): # 3*32*32out = self.conv1(x) # 64*32*32out = self.layer1(out) # 64*32*32out = self.layer2(out) # 128*16*16out = self.layer3(out) # 256*8*8out = self.layer4(out) # 512*4*4out = F.avg_pool2d(out, 4) # 512*1*1out = out.view(out.size(0), -1) # 512out = self.fc(out)return out'''-------------ResNet50---------------'''
class ResNet_50(nn.Module):def __init__(self, ResidualBlock, num_classes=10):super(ResNet_50, self).__init__()self.inchannel = 64self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(64),nn.ReLU(),)self.layer1 = self.make_layer(ResidualBlock, 256, 3, stride=1)self.layer2 = self.make_layer(ResidualBlock, 512, 4, stride=2)self.layer3 = self.make_layer(ResidualBlock, 1024, 6, stride=2)self.layer4 = self.make_layer(ResidualBlock, 2048, 3, stride=2)self.fc = nn.Linear(512 * 4, num_classes)# **************************def make_layer(self, block, channels, num_blocks, stride):strides = [stride] + [1] * (num_blocks - 1) # strides=[1,1]layers = []for stride in strides:layers.append(block(self.inchannel, channels, stride))self.inchannel = channelsreturn nn.Sequential(*layers)def forward(self, x): # 3*32*32out = self.conv1(x) # 64*32*32out = self.layer1(out) # 64*32*32out = self.layer2(out) # 128*16*16out = self.layer3(out) # 256*8*8out = self.layer4(out) # 512*4*4out = F.avg_pool2d(out, 4) # 512*1*1# print(out.size())out = out.view(out.size(0), -1) # 512out = self.fc(out)return outdef ResNet18():return ResNet_18(BasicBlock)def ResNet34():return ResNet_34(BasicBlock)def ResNet50():return ResNet_50(Bottleneck)
本篇到這里就結(jié)束啦,有什么問題,歡迎大家留言討論~