- 本文譯自:Russell Stewart's Blog -> Introduction to debugging neural networks
- 同步發(fā)布于個(gè)人博客,轉(zhuǎn)載注明出處擎椰。
題目:調(diào)試神經(jīng)網(wǎng)絡(luò)簡介
以下建議主要針對神經(jīng)網(wǎng)絡(luò)的初學(xué)者杀怠,它是基于我的經(jīng)驗(yàn)對工業(yè)界和斯坦福的神經(jīng)網(wǎng)絡(luò)新手給出的建議实抡。神經(jīng)網(wǎng)基本上比大多數(shù)程序更難調(diào)試飞涂,因?yàn)榇蠖鄶?shù)神經(jīng)網(wǎng)絡(luò)錯(cuò)誤不會(huì)導(dǎo)致類型錯(cuò)誤或運(yùn)行時(shí)間錯(cuò)誤器一。他們只是導(dǎo)致神經(jīng)網(wǎng)絡(luò)難以收斂障涯。特別是當(dāng)你剛接觸這個(gè)的時(shí)候宪躯,它可能會(huì)讓你非常沮喪乔宿!但是一個(gè)有經(jīng)驗(yàn)的神經(jīng)網(wǎng)絡(luò)訓(xùn)練者將能夠系統(tǒng)地克服這些困難,盡管存在著大量似是而非的錯(cuò)誤消息:性能錯(cuò)誤:你的神經(jīng)網(wǎng)絡(luò)沒有訓(xùn)練好访雪。對于缺乏經(jīng)驗(yàn)的人來說详瑞,這種信息是令人生畏的掂林。但對有經(jīng)驗(yàn)的,這是一個(gè)非常好的錯(cuò)誤信息坝橡。這意味著樣板代碼已經(jīng)偏離了正確道路泻帮,是時(shí)候去深挖一下原因了!
如何應(yīng)對NaN
到目前為止计寇,我從學(xué)生那里得到的最常見的第一個(gè)問題是锣杂,“為什么我出現(xiàn)了 NaNs ?”番宁。有時(shí)候元莫,這個(gè)問題的答案很復(fù)雜。但大多數(shù)情況是贝淤,NaNs 在前100輪迭代中就出現(xiàn)了柒竞,這時(shí)候這個(gè)答案就非常簡單:你的學(xué)習(xí)率設(shè)置的太高了。當(dāng)學(xué)習(xí)率非常高時(shí)播聪,在訓(xùn)練的前100輪迭代中就會(huì)出現(xiàn)NaNs朽基。嘗試不斷的把學(xué)習(xí)率除以3,直到在前100輪迭代中不再出現(xiàn)NaNs离陶。一旦這樣做起作用了稼虎,你就會(huì)得到一個(gè)很好的初始學(xué)習(xí)率。根據(jù)我的經(jīng)驗(yàn)招刨,最好的有效學(xué)習(xí)率一般在你得到NaNs的學(xué)習(xí)率的1-10倍以下霎俩。
如果你是在超過100輪迭代之后才出現(xiàn)的NaNs,還有2個(gè)其他的常見原因沉眶。** 1)**如果你訓(xùn)練的是RNN打却,請確保使用的是“梯度剪裁(clip gradient )”,這可以把全局的梯度二范數(shù)(L2)限制在一定的范圍內(nèi)谎倔。RNN傾向于在訓(xùn)練早期產(chǎn)生梯度柳击,其中10%或者更少的batch會(huì)出現(xiàn)學(xué)習(xí)尖峰,這些尖峰上的梯度值非常大片习。如果沒有限制幅度捌肴,這些尖峰就可能導(dǎo)致NaNs。 2)如果你自己編寫了任何自定義的layer藕咏,那么這個(gè)問題很可能是由這些自定義的layer中一些除零錯(cuò)誤引發(fā)的状知。還有一個(gè)眾所周知的產(chǎn)生NaNs的layer就是softmax層。 softmax的計(jì)算在分子和分母中都含有指數(shù)函數(shù)exp(x)孽查,當(dāng)inf除以inf時(shí)就可能會(huì)產(chǎn)生NaNs饥悴。所以要確保你使用的是一個(gè)穩(wěn)定版本的softmax實(shí)現(xiàn)。
當(dāng)神經(jīng)網(wǎng)絡(luò)不再學(xué)習(xí)的時(shí)候怎么辦
當(dāng)你不再碰到NaNs的時(shí)候,很可能就會(huì)遇到這樣一種情況铺坞,你的網(wǎng)絡(luò)順利地訓(xùn)練了幾千輪起宽,但是訓(xùn)練的loss值卻在前幾百個(gè)回合后不再減小。如果你是初次構(gòu)建代碼庫的話济榨,基本上不會(huì)說需要等待超過2000輪迭代。這不是因?yàn)樗芯W(wǎng)絡(luò)都能在2000次迭代內(nèi)開始學(xué)習(xí)绿映,而是因?yàn)槟阍诰幋a中引入bug的幾率很高擒滑,與其等待長時(shí)間的迭代,不如早早的進(jìn)入調(diào)試模式〔嫦遥現(xiàn)在你應(yīng)該不斷縮小問題的范圍丐一,直到你的網(wǎng)絡(luò)可以在2000次迭代內(nèi)開始學(xué)習(xí)。幸運(yùn)的是淹冰,有2個(gè)不錯(cuò)的維度來降低復(fù)雜度:
1)把訓(xùn)練集的樣本量減小到10库车。任何一個(gè)可用的網(wǎng)絡(luò)通常都能在幾百次迭代后過擬合十個(gè)樣本。但是很多編碼bug則會(huì)阻止這種情況發(fā)生樱拴。如果你的網(wǎng)絡(luò)仍然不能過度擬合訓(xùn)練集的10個(gè)樣本柠衍,請?jiān)俅未_認(rèn)數(shù)據(jù)和標(biāo)簽是否是正確對應(yīng)的。嘗試將batch size設(shè)為1來檢查batch計(jì)算中的錯(cuò)誤晶乔。在代碼中加入一些log輸出以確保是以你期望的方式運(yùn)行的珍坊。一般來說,通過暴力排查總會(huì)找到這些錯(cuò)誤正罢。一旦網(wǎng)絡(luò)可以擬合10個(gè)樣本了阵漏,繼續(xù)嘗試擬合100個(gè)。如果現(xiàn)在可以正常訓(xùn)練了但不如預(yù)期翻具,則可以進(jìn)入下一步了履怯。
2)解決你感興趣的問題的最簡單版本。如果你正在做句子翻譯裆泳,嘗試首先為目標(biāo)語言構(gòu)建一個(gè)語言模型叹洲。當(dāng)上一步成功了,只給出三個(gè)源語言的單詞晾虑,嘗試著去預(yù)測翻譯的第一個(gè)詞疹味。如果你打算從圖像中檢測物體,訓(xùn)練回歸網(wǎng)絡(luò)之前試著去分類圖像中有多少個(gè)物體帜篇。在獲得一個(gè)確保網(wǎng)絡(luò)可以解決的好的子問題糙捺,以及花費(fèi)最少的時(shí)間來使用代碼掛接數(shù)據(jù)之間存在著平衡點(diǎn)。創(chuàng)造力可以起到幫助作用笙隙。
為一個(gè)新的想法擴(kuò)展網(wǎng)絡(luò)的小技巧就是慢慢地縮小上述兩步中所做的簡化洪灯。這是坐標(biāo)上升法的一種形式,而且十分有用竟痰。一開始签钩,你可以證明這個(gè)網(wǎng)絡(luò)可以記住少量的樣本掏呼,然后可以證明它在一個(gè)簡化版的子問題中可以在驗(yàn)證集上具有泛化能力。慢慢提升難度铅檩,穩(wěn)步前進(jìn)憎夷。這并不像第一次Karpathy的風(fēng)格那么有趣,但至少它是有用的昧旨。有些時(shí)候你會(huì)發(fā)現(xiàn)有些問題本身十分困難拾给,難以在2000次迭代內(nèi)完成學(xué)習(xí)。這很棒兔沃!但是它很少需要以前那種難度級別問題迭代次數(shù)的十倍以上蒋得。如果真需要這么多次迭代,可以嘗試尋找一個(gè)中間的復(fù)雜度乒疏。
調(diào)整超參數(shù)
既然你的網(wǎng)絡(luò)現(xiàn)在開始學(xué)習(xí)東西了额衙,你可能覺得很好。但你可能發(fā)現(xiàn)它不能解決這個(gè)問題中最困難的版本怕吴。超參數(shù)的調(diào)整就是其中的關(guān)鍵窍侧。也許有人僅僅下載了一個(gè)CNN包然后在上面跑自己的數(shù)據(jù)集,并告訴你超參數(shù)的調(diào)整并不會(huì)帶來改變械哟。你要認(rèn)識(shí)到他們在用已有的框架解決已有的問題疏之。如果你在使用新架構(gòu)解決新問題,則必須調(diào)試超參數(shù)來獲得一個(gè)良好的配置暇咆。你最好是為你的特定問題閱讀一個(gè)超參數(shù)教程锋爪,但為了完整性我會(huì)在這里列出一些基本的想法:
- 可視化是關(guān)鍵。不要害怕花時(shí)間在整個(gè)訓(xùn)練過程中去寫一些好用的可視化工具爸业。如果你的可視化方法還是簡單觀察終端中的loss值變化其骄,那你該考慮一下升級了。
- 權(quán)值初始化很重要扯旷。一般來說拯爽,大一點(diǎn)幅度的初始權(quán)值會(huì)好一些,但太大了就會(huì)導(dǎo)致NaN钧忽。因此初始權(quán)值需要和學(xué)習(xí)率一起調(diào)整毯炮。
- 確保權(quán)值看起來是“健康的”。要了解這是什么意思耸黑,我推薦用ipython notebook打開現(xiàn)有網(wǎng)絡(luò)的權(quán)值桃煎。花一些時(shí)間來熟悉在標(biāo)準(zhǔn)數(shù)據(jù)集(如ImageNet或Penn Tree Bank)上訓(xùn)練的成熟網(wǎng)絡(luò)中的組件的權(quán)值直方圖應(yīng)該是什么樣子大刊。
- 神經(jīng)網(wǎng)絡(luò)不是輸入尺度不變的为迈,尤其當(dāng)它使用SGD訓(xùn)練而不是其他的二階方法訓(xùn)練時(shí),因?yàn)镾GD不是一個(gè)尺度不變的方法。在確定縮放尺度之前葫辐,花點(diǎn)時(shí)間來嘗試多次縮放輸入數(shù)據(jù)和輸出標(biāo)簽搜锰。
- 在訓(xùn)練結(jié)束之前減小學(xué)習(xí)率總能帶來提升。最佳的decay策略是:在k個(gè)epoch后耿战,每n個(gè)epoch之后將學(xué)習(xí)率除以1.5蛋叼,其中k > n。
- 使用超參數(shù)配置文件昆箕。雖然在你開始嘗試不同的值之前把超參數(shù)放在代碼中也是ok的鸦列。我通過命令行參數(shù)加載的方式使用json文件,就像 Russell91/TensorBox 中一樣鹏倘,但是具體的形式并不重要。避免總是要去重構(gòu)你的代碼顽爹,因?yàn)槟菍⑹浅瑓?shù)加載的糟糕問題纤泵。重構(gòu)引入了bugs,花費(fèi)你的訓(xùn)練周期镜粤,這種情況能夠被避免直到你有一個(gè)你覺得不錯(cuò)的網(wǎng)絡(luò)捏题。
- 隨機(jī)的搜索超參數(shù),如果可以的話肉渴。隨機(jī)搜索可以產(chǎn)生你想不到的超參數(shù)組合公荧, 并且能減少很大工作量一旦你已經(jīng)訓(xùn)練形成了對于給定超參數(shù)會(huì)帶來什么樣的影響的直覺。
總結(jié)
調(diào)試神經(jīng)網(wǎng)絡(luò)可能比調(diào)試傳統(tǒng)程序更費(fèi)精力同规,因?yàn)閹缀跛绣e(cuò)誤都被投射到整個(gè)網(wǎng)絡(luò)表現(xiàn)的單一維度循狰。盡管如此,二分查找仍然起作用券勺。通過交替1)調(diào)整問題的難度绪钥,和2)使用少量的訓(xùn)練樣本,你可以快速解決最初的問題关炼。然后超參數(shù)調(diào)整和長時(shí)間的等待就可以解決你剩下的問題了程腹。
(注:感謝您的閱讀,希望本文對您有所幫助儒拂。如果覺得不錯(cuò)歡迎分享轉(zhuǎn)載寸潦,但請先點(diǎn)擊 這里 獲取授權(quán)。本文由 版權(quán)印 提供保護(hù)社痛,禁止任何形式的未授權(quán)違規(guī)轉(zhuǎn)載见转,謝謝!)