CNN14. Residual Networks (ResNets)
1. 梯度彌散與梯度爆炸
1.1 梯度消失(梯度彌散, vanishing gradient)與梯度爆炸(exploding gradient)
參考 深度神經(jīng)網(wǎng)絡(luò)中的梯度丟失和梯度爆炸
1.1.1 梯度不穩(wěn)定
梯度丟失和梯度爆炸統(tǒng)稱(chēng)為梯度不穩(wěn)定谓晌。它們產(chǎn)生的原因是類(lèi)似的啸驯。為了說(shuō)明梯度丟失是如何產(chǎn)生的客冈,我們將把問(wèn)題簡(jiǎn)化,以鏈?zhǔn)椒▌t為例來(lái)進(jìn)行說(shuō)明。
1.1.2 簡(jiǎn)化問(wèn)題——鏈?zhǔn)椒▌t
讓我們考慮下面這個(gè)簡(jiǎn)單的深度神經(jīng)網(wǎng)絡(luò)苛谷,它的每一層都只包含一個(gè)神經(jīng)元赊锚,一共有三個(gè)隱藏層:
這個(gè)等式也反映了反向傳播的工作模式:它從輸出層開(kāi)始,逐層計(jì)算偏導(dǎo)數(shù)酱床,直到輸入層為止羊赵。然后,利用這些計(jì)算出來(lái)的偏導(dǎo)數(shù),更新對(duì)應(yīng)的權(quán)重和偏置昧捷,從而達(dá)到反向傳播的目的闲昭。
但是,我們發(fā)現(xiàn)靡挥,隨著層數(shù)的加深序矩,梯度的計(jì)算公式會(huì)依賴(lài)于越來(lái)越多每一層的參數(shù),這些參數(shù)的影響層層累加跋破,最終就導(dǎo)致了梯度爆炸與梯度消失簸淀。
1.1.3 梯度消失(即梯度彌散, vanishing gradient)
Sigmoid函數(shù)常常會(huì)引發(fā)梯度不穩(wěn)定問(wèn)題,所以我們以此為研究對(duì)象毒返。
它的圖像如下:
它的導(dǎo)函數(shù)圖像如下:
該函數(shù)的導(dǎo)數(shù)最大值為0.25租幕,且當(dāng)取值的絕對(duì)值變大時(shí),輸出會(huì)變小拧簸。
由于我們初始化權(quán)重值的時(shí)候一般從標(biāo)準(zhǔn)正態(tài)分布中采樣劲绪,所以權(quán)重w的絕對(duì)值通常小于1,因此我們可以得到:
再由于公式
最終計(jì)算結(jié)果將會(huì)呈指數(shù)級(jí)變小,這也就是梯度丟失產(chǎn)生的原因弟劲。
1.1.4 梯度爆炸
梯度爆炸產(chǎn)生的原因和梯度丟失正好相反祷安。當(dāng)我們選取的權(quán)重值較大時(shí),將大于1兔乞。當(dāng)累乘這些項(xiàng)的時(shí)候汇鞭,計(jì)算結(jié)果將呈指數(shù)級(jí)增長(zhǎng)。
2. resnet學(xué)習(xí)
2.1 提出背景
ResNet最根本的動(dòng)機(jī)就是所謂的“退化”問(wèn)題庸追,即當(dāng)模型的層次加深時(shí)霍骄,錯(cuò)誤率卻提高了。
自AlexNet以來(lái)淡溯,state-of-the-art的CNN結(jié)構(gòu)都在不斷地變深读整。AlexNet只有5個(gè),而到了VGG和GoogLeNet已經(jīng)有有19個(gè)和22個(gè)卷積層咱娶。
然而米间,我們不能通過(guò)簡(jiǎn)單地疊加層的方式來(lái)增加網(wǎng)絡(luò)的深度。梯度消失問(wèn)題的存在膘侮,使深度網(wǎng)絡(luò)的訓(xùn)練變得相當(dāng)困難屈糊。“梯度消失”問(wèn)題指的是即當(dāng)梯度在被反向傳播到前面的層時(shí)琼了,重復(fù)的相乘可能會(huì)使梯度變得無(wú)限小逻锐。因此,隨著網(wǎng)絡(luò)深度的不斷增加,其性能會(huì)逐漸趨于飽和昧诱,甚至還會(huì)開(kāi)始下降晓淀。
在ResNet出現(xiàn)之前,研究人員們發(fā)現(xiàn)了幾個(gè)用于處理梯度消失問(wèn)題的方法盏档,比如凶掰,在中間層添加輔助損失(auxiliary loss)作為額外的監(jiān)督。但沒(méi)有一種方法能夠一次性徹底解決這一問(wèn)題妆丘。
最后锄俄,有人提出了resNet局劲,大大改善了這一情況勺拣。
ResNet的基本思想是引入了能夠跳過(guò)一層或多層的“shortcut connection”,如上圖所示鱼填。圖中“彎彎的弧線“就是所謂的”shortcut connection“药有,也就是identity mapping。
resNet的作者認(rèn)為:
- 增加網(wǎng)絡(luò)的層不應(yīng)該降低網(wǎng)絡(luò)的性能苹丸,因?yàn)槲覀兛梢詫ⅰ昂愕茸儞Q(identity mapping)”簡(jiǎn)單地疊加在網(wǎng)絡(luò)上愤惰,而且所得到的輸出架構(gòu)也會(huì)執(zhí)行相同的操作。這就暗示了更深層的模型的訓(xùn)練錯(cuò)誤率不應(yīng)該高于與之對(duì)應(yīng)的淺層模型赘理。
- 他們還作出了這樣的假設(shè):與其讓它們直接適應(yīng)所需的底層映射宦言,還是讓堆疊的層適應(yīng)一個(gè)殘差映射要簡(jiǎn)單一些。上圖所示的殘差塊能夠明確地使它完成這一點(diǎn)商模。
另外奠旺,resNet還采用了reLU方式激活,reLU函數(shù)在取值變大時(shí)不會(huì)發(fā)生梯度變小的情況施流,所以也緩解了梯度消失响疚。
所以說(shuō),ResNet的優(yōu)越之處有兩個(gè):identity mapping和reLU激活
2.2 兩種block設(shè)計(jì)
這兩種結(jié)構(gòu)分別取自ResNet34(左圖)和ResNet50/101/152(右圖)瞪醋。
一般稱(chēng)整個(gè)結(jié)構(gòu)為一個(gè)”building block“忿晕,而右圖又稱(chēng)為”bottleneck design”。
右圖的目的就是為了降低參數(shù)的數(shù)目:第一個(gè)1x1的卷積把256維channel降到64維银受,然后在最后通過(guò)1x1卷積恢復(fù)践盼。
使用bottleneck的結(jié)構(gòu)整體上用的參數(shù)數(shù)目為
1x1x256x64 + 3x3x64x64 + 1x1x64x256 = 69632
。然而不使用bottleneck的話(huà)就是兩個(gè)3x3x256的卷積宾巍,參數(shù)數(shù)目: 3x3x256x256x2 = 1179648
宏侍,差了16.94倍。對(duì)于常規(guī)ResNet蜀漆,可以用于34層或者更少的網(wǎng)絡(luò)中谅河。而對(duì)于Bottleneck Design的ResNet通常用于更深的如101這樣的網(wǎng)絡(luò)中,目的是減少計(jì)算和參數(shù)量(實(shí)用目的)。
2.3 兩種Shortcut Connection方式
有人會(huì)問(wèn)绷耍,如果F(x)和x的channel個(gè)數(shù)不同怎么辦吐限,因?yàn)镕(x)和x是按照channel維度相加的,channel不同怎么相加呢褂始?
針對(duì)channel個(gè)數(shù)是否相同诸典,要分成兩種情況考慮。我們先看下圖崎苗,有實(shí)線和虛線兩種連接方式:
-
實(shí)線的Connection部分(”第一個(gè)粉色矩形和第三個(gè)粉色矩形“)都是執(zhí)行3x3x64的卷積狐粱,他們的channel個(gè)數(shù)一致,所以采用計(jì)算方式:
y=F(x)+x -
虛線的Connection部分(”第一個(gè)綠色矩形和第三個(gè)綠色矩形“)分別是3x3x64和3x3x128的卷積操作胆数,他們的channel個(gè)數(shù)不同(64和128)肌蜻,所以采用計(jì)算方式:
y=F(x)+Wx
其中W是卷積操作,用來(lái)調(diào)整x的channel維度的
2.4 resnet各層架構(gòu)
上面一共提出了5種深度的ResNet必尼,分別是18蒋搜,34,50判莉,101和152豆挽。resNet-101僅僅指卷積或者全連接層加起來(lái)有101層,而激活層或者Pooling層并沒(méi)有計(jì)算在內(nèi)券盅,其它resNet都以此類(lèi)推帮哈。
所有的網(wǎng)絡(luò)都分成5部分,分別是:conv1锰镀,conv2_x娘侍,conv3_x,conv4_x互站。私蕾。
這里我們關(guān)注50-layer和101-layer這兩列,可以發(fā)現(xiàn)胡桃,它們唯一的不同在于conv4_x——ResNet50有6個(gè)block踩叭,而ResNet101有23個(gè)block。這里相差了17個(gè)block翠胰,也就是17 x 3 = 51層容贝。
3. resnet訓(xùn)練imageNet(由于數(shù)據(jù)集過(guò)大,未完成)
3.1. 安裝java jdk
參考How To Install Java with Apt-Get on Debian 8
3.2. 確認(rèn)系統(tǒng)版本
cmd執(zhí)行命令
uname -a
我得知我的系統(tǒng)是ubuntu之景,因此安裝采用ubuntu的教程
3.2. 安裝bazel
3.3. 下載數(shù)據(jù)集
參考Inception in TensorFlow
按照參考網(wǎng)址里的Getting Started做即可斤富,需要事先安裝bazel,而上文的1-3就是安裝bazel的過(guò)程锻狗。
由于實(shí)驗(yàn)室虛擬機(jī)的下載速度太慢满力,我轉(zhuǎn)而使用CIFAR作為訓(xùn)練數(shù)據(jù)集
4. resnet訓(xùn)練cifar-10
由于時(shí)間有限焕参,難度較大,我只是用了網(wǎng)上https://github.com/tensorflow/models/tree/master/official/resnet提供的模型跑了一遍油额,并記錄了結(jié)果叠纷。嘗試過(guò)自己修改代碼,但發(fā)現(xiàn)官方提供的代碼框架太大潦嘶,難以分析涩嚣。希望日后能補(bǔ)足這個(gè)部分......
4.1 添加環(huán)境變量
需要把models的文件路徑添加到環(huán)境變量,否則可能遇到ImportError: No module named official.resnet.
之類(lèi)的問(wèn)題掂僵。
export PYTHONPATH="$PYTHONPATH:/path/to/models" # 比如"$PYTHONPATH:/root/Desktop/models"
4.1 下載并解壓cifar-10-data
python cifar10_download_and_extract.py --data_dir ~
4.2 開(kāi)始訓(xùn)練
python cifar10_main.py --data_dir ~
訓(xùn)練到后期航厚,training準(zhǔn)確率到99%以上,由于overfitting锰蓬,evaluate準(zhǔn)確率有92%左右幔睬。
training
evaluating
可以看到,測(cè)試準(zhǔn)確率是略低于訓(xùn)練準(zhǔn)確率的互妓。
4.3 各種問(wèn)題與解決方法
4.3.1 問(wèn)題:AttributeError: module 'tensorflow' has no attribute 'data'
參考
AttributeError: module 'tensorflow' has no attribute 'data'
Yes, as @blairjordan mentions,
tf.contrib.data
has been upgraded to justtf.data
in TensorFlow v1.4. So you need to make sure you're using v1.4.
原因
新舊版本的接口不同溪窒,函數(shù)調(diào)用不同
解決方案1
更改調(diào)用函數(shù)的方式 或者 安裝新版的tensorflow(v1.4或v1.7)
conda create -n tf1.7 python=3.6
conda install tensorflow-gpu=1.7
為什么解決方案1可行
我最開(kāi)始有疑惑坤塞,安裝tensorflow-gpu要求事先安裝好相應(yīng)版本的cudatoolkit和cudnn冯勉。正是因?yàn)樘摂M機(jī)預(yù)先安裝的cuda和cudnn版本不高,我才只能安裝低版本的tf摹芙。但當(dāng)我運(yùn)行conda install tensorflow-gpu=1.7
后灼狰,發(fā)現(xiàn)conda現(xiàn)在會(huì)自動(dòng)幫你安裝相應(yīng)版本的cuda和cudnn依賴(lài)。如下圖:
所以就可以放心地安裝高版本的tensorflow了浮禾,以后也不用再糾結(jié)于cuda和cudnn的安裝交胚,只要gpu能支持,就可以順利安裝盈电。
參考2
The arguments accepted by the Dataset.map() transformation have also changed:
dataset.map(..., output_buffer_size=B) is now dataset.map(...).prefetch(B).
I'd check that you have the latest version. In my case, I still need to use the old tf.contrib.data.
解決方案2(未證實(shí))
采用舊的函數(shù)調(diào)用蝴簇,比如data.map.prefetch的調(diào)用改為data.map 。
這個(gè)方法只是一個(gè)思路匆帚,未證實(shí)熬词,因?yàn)槲乙呀?jīng)用解決方案1解決問(wèn)題。我也不在此深究了吸重。
參考
- 梯度不穩(wěn)定
- resNet
- resNet實(shí)現(xiàn)