??
總結(jié)一下在曠視實(shí)習(xí)兩年來的煉丹經(jīng)驗(yàn),我主要做了一些 RL,圖像質(zhì)量,圖像分類,GAN 相關(guān)的任務(wù),日常大概占用 5 - 10 張卡。
有的同學(xué)在打比賽的時(shí)候,從頭到尾只維護(hù)若干份丹方(代碼),每次載入前一次的訓(xùn)練參數(shù),調(diào)一下丹方再煉,俗稱老丹。這樣會(huì)有幾個(gè)問題:某次引入一個(gè) bug,過了很久才發(fā)現(xiàn),然后不知道影響范圍;煉出一個(gè)金丹,但是不知道它是怎么來的;忘了自己的 baseline,不知道改動(dòng)是正面還是負(fù)面。要盡可能確保每一個(gè)丹有可復(fù)現(xiàn)性,實(shí)踐上建議丹方不應(yīng)該在煉丹后改動(dòng),煉新的丹時(shí),把舊的丹方復(fù)制一遍。得到的實(shí)驗(yàn)結(jié)果要開個(gè)文檔記下來以便日后總結(jié),避免遺忘。我經(jīng)常通過閱讀自己和別人的記錄來得到靈感。實(shí)驗(yàn)一致性上也要多做努力,理想狀態(tài)是有合理的基準(zhǔn)來測(cè)丹的性能,同一個(gè)丹方不應(yīng)該由于超參的微小改動(dòng)而有顯著結(jié)果差異。出現(xiàn)這種情況可能是數(shù)據(jù)太少或基準(zhǔn)設(shè)置不當(dāng)。對(duì)于新入行的同學(xué),不要試圖在玩具級(jí)別的數(shù)據(jù)集或任務(wù)上做靠譜的研究,比如 MNIST。不是每一個(gè)實(shí)驗(yàn)都要出一個(gè)金丹,實(shí)驗(yàn)是為了驗(yàn)證結(jié)論的。如果每個(gè)實(shí)驗(yàn)都要 8 張卡跑兩個(gè)星期,人力物力都耗不起。盡力把實(shí)驗(yàn)控制在單卡一天以內(nèi),理想狀態(tài)是半天得一次結(jié)論。理論上來說,水多加面面多加水(加數(shù)據(jù)加計(jì)算量)的做法無限漲點(diǎn)。建議先設(shè)一個(gè)目標(biāo),比如說就是在一天的訓(xùn)練時(shí)間下做對(duì)比實(shí)驗(yàn)。我的實(shí)踐經(jīng)驗(yàn)是,首先用小圖小模型,比如 128 x 128 輸入的 ResNet18;用 cProfile 來找性能瓶頸,比如我發(fā)現(xiàn)某個(gè)丹,煉的時(shí)候有一大半時(shí)間耗費(fèi)在等數(shù)據(jù),數(shù)據(jù)處理中一大半時(shí)間在調(diào)用 numpy 的 round 函數(shù),前期把精力集中在提高做實(shí)驗(yàn)的效率上。先把錦上添花的東西去掉,比如數(shù)據(jù)增廣,玄學(xué)學(xué)習(xí)率和超參,魔幻損失函數(shù),異形模型。如果世界上有一個(gè)非要加旋轉(zhuǎn)增廣和 1.96e-4 學(xué)習(xí)率 42 batchsize,配上四種混合損失函數(shù)才能煉好的丹,它應(yīng)該存在于靈能文明。可以先造一些盡量玩具的模型,驗(yàn)證代碼正確性。先確認(rèn)影響模型性能的組件。感性認(rèn)識(shí)就是,數(shù)據(jù)是否需要增加或增廣。模型是大了還是小了,再根據(jù)速度和精度期望開始尋找合適的模型。能用全卷積的任務(wù),少用全連接層,參數(shù)量小。基本模型上 ResNet, Unet 結(jié)構(gòu)還是主流。當(dāng)你的模型有 Batch Normalization,初始化通常不需要操心,激活函數(shù)默認(rèn) Relu 即可(某引用數(shù)萬的大佬說的)。一般順序是 Conv - BN - Relu。如果沒有 BN(很多任務(wù)上,BN降低訓(xùn)練難度,但是可能影響最終性能 ),試著要做一些數(shù)據(jù)歸一化。雖然有至少十種激活函數(shù),但在 Relu 外只推薦試一下 Swish。煉丹術(shù)只推薦 Momentum 和 Adam。在這些方面做嘗試意義不大,如果性能提升反倒可能說明模型不成熟。不推薦做人肉模型設(shè)計(jì),比如把某層卷積改大一點(diǎn),或者微調(diào)一下通道數(shù)。除非有特別 insight,不要自己亂設(shè)計(jì)新組件。超參上,learning rate 最重要,推薦了解 cosine learning rate 和 cyclic learning rate,其次是 batchsize 和 weight decay。當(dāng)你的丹還不錯(cuò)的時(shí)候,可以試著做數(shù)據(jù)增廣和改損失函數(shù)錦上添花了。- Bag of Tricks for Image Classification with Convolutional Neural Networks,trick 合集 1。
- Must Know Tips/Tricks in Deep Neural Networks,trick 合集 2。
- 33條神經(jīng)網(wǎng)絡(luò)訓(xùn)練秘技,trick 合集 3。
- 26秒單GPU訓(xùn)練CIFAR10,工程實(shí)踐。
- Batch Normalization,雖然玄學(xué),但是養(yǎng)活了很多煉丹師。
- Searching for Activation Functions,swish 激活函數(shù)。
https://www.zhihu.com/question/41631631/answer/859040970?
訓(xùn)練技巧對(duì)深度學(xué)習(xí)來說是非常重要的,作為一門實(shí)驗(yàn)性質(zhì)很強(qiáng)的科學(xué),同樣的網(wǎng)絡(luò)結(jié)構(gòu)使用不同的訓(xùn)練方法訓(xùn)練,結(jié)果可能會(huì)有很大的差異。這里我總結(jié)了近一年來的煉丹心得,分享給大家,也歡迎大家補(bǔ)充指正。
下面幾種方式,隨便選一個(gè),結(jié)果基本都差不多。但是一定要做。否則可能會(huì)減慢收斂速度,影響收斂結(jié)果,甚至造成Nan等一系列問題。下面的n_in為網(wǎng)絡(luò)的輸入大小,n_out為網(wǎng)絡(luò)的輸出大小,n為n_in或(n_in+n_out)*0.5http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdfHe初始化論文:https://arxiv.org/abs/1502.01852- uniform均勻分布初始化:
w = np.random.uniform(low=-scale, high=scale, size=[n_in,n_out]) - Xavier初始法,適用于普通激活函數(shù)(tanh,sigmoid):scale = np.sqrt(3/n)
- He初始化,適用于ReLU:scale = np.sqrt(6/n)
- normal高斯分布初始化:
w = np.random.randn(n_in,n_out) * stdev # stdev為高斯分布的標(biāo)準(zhǔn)差,均值設(shè)為0 - Xavier初始法,適用于普通激活函數(shù) (tanh,sigmoid):stdev = np.sqrt(n)
- He初始化,適用于ReLU:stdev = np.sqrt(2/n)
- svd初始化:對(duì)RNN有比較好的效果。參考論文:https://arxiv.org/abs/1312.6120
- zero-center ,這個(gè)挺常用的.
X -= np.mean(X, axis = 0) # zero-center
X /= np.std(X, axis = 0) # normalize - PCA whitening,這個(gè)用的比較少.
- 要做梯度歸一化,即算出來的梯度除以minibatch size
- clip c(梯度裁剪): 限制最大梯度,其實(shí)是value = sqrt(w1^2+w2^2….),如果value超過了閾值,就算一個(gè)衰減系系數(shù),讓value的值等于閾值: 5,10,15
- dropout對(duì)小數(shù)據(jù)防止過擬合有很好的效果,值一般設(shè)為0.5,小數(shù)據(jù)上dropout+sgd在我的大部分實(shí)驗(yàn)中,效果提升都非常明顯.因此可能的話,建議一定要嘗試一下。dropout的位置比較有講究, 對(duì)于RNN,建議放到輸入->RNN與RNN->輸出的位置.關(guān)于RNN如何用dropout,可以參考這篇論文:http://arxiv.org/abs/1409.2329
- adam,adadelta等,在小數(shù)據(jù)上,我這里實(shí)驗(yàn)的效果不如sgd, sgd收斂速度會(huì)慢一些,但是最終收斂后的結(jié)果,一般都比較好。如果使用sgd的話,可以選擇從1.0或者0.1的學(xué)習(xí)率開始,隔一段時(shí)間,在驗(yàn)證集上檢查一下,如果cost沒有下降,就對(duì)學(xué)習(xí)率減半. 我看過很多論文都這么搞,我自己實(shí)驗(yàn)的結(jié)果也很好. 當(dāng)然,也可以先用ada系列先跑,最后快收斂的時(shí)候,更換成sgd繼續(xù)訓(xùn)練.同樣也會(huì)有提升.據(jù)說adadelta一般在分類問題上效果比較好,adam在生成問題上效果比較好。
- 除了gate之類的地方,需要把輸出限制成0-1之外,盡量不要用sigmoid,可以用tanh或者relu之類的激活函數(shù).1. sigmoid函數(shù)在-4到4的區(qū)間里,才有較大的梯度。之外的區(qū)間,梯度接近0,很容易造成梯度消失問題。2. 輸入0均值,sigmoid函數(shù)的輸出不是0均值的。
- rnn的dim和embdding size,一般從128上下開始調(diào)整. batch size,一般從128左右開始調(diào)整.batch size合適最重要,并不是越大越好.
- word2vec初始化,在小數(shù)據(jù)上,不僅可以有效提高收斂速度,也可以可以提高結(jié)果.
- 盡量對(duì)數(shù)據(jù)做shuffle
- LSTM 的forget gate的bias,用1.0或者更大的值做初始化,可以取得更好的結(jié)果,來自這篇論文:http://jmlr.org/proceedings/papers/v37/jozefowicz15.pdf, 我這里實(shí)驗(yàn)設(shè)成1.0,可以提高收斂速度.實(shí)際使用中,不同的任務(wù),可能需要嘗試不同的值.
- Batch Normalization據(jù)說可以提升效果,不過我沒有嘗試過,建議作為最后提升模型的手段,參考論文:Accelerating Deep Network Training by Reducing Internal Covariate Shift
- 如果你的模型包含全連接層(MLP),并且輸入和輸出大小一樣,可以考慮將MLP替換成Highway Network,我嘗試對(duì)結(jié)果有一點(diǎn)提升,建議作為最后提升模型的手段,原理很簡(jiǎn)單,就是給輸出加了一個(gè)gate來控制信息的流動(dòng),詳細(xì)介紹請(qǐng)參考論文: http://arxiv.org/abs/1505.00387
- 來自@張馨宇的技巧:一輪加正則,一輪不加正則,反復(fù)進(jìn)行。
Ensemble是論文刷結(jié)果的終極核武器,深度學(xué)習(xí)中一般有以下幾種方式- 不同的參數(shù),通過cross-validation,選取最好的幾組
- 同樣的參數(shù),模型訓(xùn)練的不同階段,即不同迭代次數(shù)的模型。
- 不同的模型,進(jìn)行線性融合. 例如RNN和傳統(tǒng)模型.
作者:蕭瑟
https://www.zhihu.com/question/41631631/answer/94816420總結(jié)一下我遇到的小朋友常犯的錯(cuò):
1、一上來就自己動(dòng)手寫模型。建議首先用成熟的開源項(xiàng)目及其默認(rèn)配置(例如 Gluon 對(duì)經(jīng)典模型的各種復(fù)現(xiàn)、各個(gè)著名模型作者自己放出來的代碼倉庫)在自己的數(shù)據(jù)集上跑一遍,在等程序運(yùn)行結(jié)束的時(shí)間里仔細(xì)研究一下代碼里的各種細(xì)節(jié),最后再自己寫或者改代碼。2、訓(xùn) RNN 不加 gradient clipping,導(dǎo)致訓(xùn)練一段時(shí)間以后 loss 突然變成 Nan。3、tying input & output embedding(就是詞向量層和輸出 softmax 前的矩陣共享參數(shù),在語言模型或機(jī)器翻譯中常用)時(shí)學(xué)習(xí)率需要設(shè)置得非常小,不然容易 Nan。
4、在數(shù)據(jù)集很大的情況下,一上來就跑全量數(shù)據(jù)。建議先用 1/100、1/10 的數(shù)據(jù)跑一跑,對(duì)模型性能和訓(xùn)練時(shí)間有個(gè)底,外推一下全量數(shù)據(jù)到底需要跑多久。在沒有足夠的信心前不做大規(guī)模實(shí)驗(yàn)。5、只喜歡漂亮的模型結(jié)構(gòu),瞧不起調(diào)參數(shù)的論文/實(shí)驗(yàn)報(bào)告,看論文時(shí)經(jīng)常不看超參數(shù)設(shè)置等細(xì)節(jié)。舉個(gè)例子,現(xiàn)在還有相當(dāng)多的人不知道 BERT 的激活函數(shù)是 GELU 而不是 transformer 原論文中的 ReLU。在自己沒有太多資源實(shí)驗(yàn)的情況下,實(shí)驗(yàn)報(bào)告類文章簡(jiǎn)直是業(yè)界良心好不好!Regularizing and Optimizing LSTM Language Models(LSTM 的訓(xùn)練技巧)Massive Exploration of Neural Machine Translation Architectures(NMT 里各個(gè)超參的影響)Training Tips for the Transformer Model(訓(xùn)練 Transformer 時(shí)會(huì)發(fā)生的各種現(xiàn)象)RoBERTa: A Robustly Optimized BERT Pretraining Approach(BERT 預(yù)訓(xùn)練技巧,雖然跟大部分人沒啥關(guān)系)CV 我不算太熟,不過也可以勉強(qiáng)推薦幾篇:Training ImageNet in 1 Hour(大批量訓(xùn)練技巧)Bag of Tricks for Image Classification with Convolutional Neural Networks(各種訓(xùn)練技巧集大成)EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks(當(dāng)前對(duì)參數(shù)利用最有效的 CNN)有時(shí)受 batch size、sequence length 各種因素的影響,loss 很大(比如說好幾萬),對(duì)于這種數(shù)字人是沒有數(shù)感的,建議首先計(jì)算一下 per token loss(如果是多任務(wù),可以每個(gè)任務(wù)單獨(dú)算;類似地,某些 CV 任務(wù)可以計(jì)算 per pixel loss),心里有點(diǎn)感覺。脫離損失函數(shù)的形式談學(xué)習(xí)率沒有意義(例如單是對(duì) batch size 求和或者取平均這個(gè)差異就會(huì)使梯度差成百上千倍)。在確定初始學(xué)習(xí)率的時(shí)候,從一個(gè)很小的值(例如 1e-7)開始,然后每一步指數(shù)增大學(xué)習(xí)率(例如擴(kuò)大1.05 倍)進(jìn)行訓(xùn)練。訓(xùn)練幾百步應(yīng)該能觀察到損失函數(shù)隨訓(xùn)練步數(shù)呈對(duì)勾形,選擇損失下降最快那一段的學(xué)習(xí)率即可。7、Adam 可以解決一堆奇奇怪怪的問題(有時(shí) loss 降不下去,換 Adam 瞬間就好了),也可以帶來一堆奇奇怪怪的問題(比如單詞詞頻差異很大,當(dāng)前 batch 沒有的單詞的詞向量也被更新;再比如Adam和L2正則結(jié)合產(chǎn)生的復(fù)雜效果)。用的時(shí)候要膽大心細(xì),萬一遇到問題找各種魔改 Adam(比如 MaskedAdam, AdamW 啥的)搶救。8、subword 總是會(huì)很穩(wěn)定地漲點(diǎn),只管用就對(duì)了。
這一條放在最后,是因?yàn)楹芏嗳瞬话阉?dāng)一回事兒。可能是覺得這一條不需要寫代碼所以不重要?我見過太多人因?yàn)檫@條浪費(fèi)時(shí)間了,所以專門強(qiáng)調(diào)一下。有些指標(biāo)是有滯后性的,需要等訓(xùn)練一段時(shí)間才開始動(dòng)。很多人訓(xùn)練幾步看沒什么效果就把程序停掉開始 debug 了,但其實(shí)代碼毫無問題。如此反復(fù)好幾天甚至一兩周都在原地踏步,其實(shí)需要做的僅僅是讓程序自個(gè)兒安安靜靜地跑上幾個(gè)小時(shí)或者一天……https://www.zhihu.com/question/41631631/answer/862075836- 機(jī)器學(xué)習(xí)交流qq群955171419,加入微信群請(qǐng)掃碼: