神經網絡構建好,訓練不出好的效果怎么辦?明明說好的擬合任意函數(一般連續)(為什么?可以參考Neural Network and Deep Learning
),說好的足夠多的數據(Occam's razor),仔細設計的神經網絡都可以得到比其他算法更好的準確率和泛化性呢(當然不是我說的),怎么感覺不出來呢?
很直觀,因為神經網絡可以隨意設計,先驗假設較少,參數多,超參數更多,那模型的自由度就非常高了,精心設計對于新手就變得較難了。這里講一些最簡單的trick,肯定不全面,歡迎大家留言補充。因為我也是新手!
下面介紹一些值得注意的部分,有些簡單解釋原理,具體細節不能面面俱到,請參考專業文章
- 主要來源
CS224D Lecture 6
Debugging Neural Networks
A Practical Guide to Training Restricted Boltzmann Machines
My Neural Network isn't working! What should I do?
Neural Network and Deep Learning
TensorFlow實戰
那我們直接從拿到一個問題決定用神經網絡說起。一般而言,
首先選定你要采用的結構,如一對一,固定窗口,數據維度粒度,MLP,RNN或者CNN等
非線性選擇,sigmoid,tanh,ReLU,或者一些變體,一般tanh比sigmoid效果好一點(簡單說明下,兩者很類似,tanh是rescaled的sigmoid,sigmoid輸出都為正數,根據BP規則,某層的神經元的權重的梯度的符號和后層誤差的一樣,也就是說,如果后一層的誤差為正,則這一層的權重全部都要降低,如果為負,則這一層梯度全部為負,權重全部增加,權重要么都增加,要么都減少,這明顯是有問題的;tanh是以0為對稱中心的,這會消除在權重更新時的系統偏差導致的偏向性。當然這是啟發式的,并不是說tanh一定比sigmoid的好),ReLU也是很好的選擇,最大的好處是,當tanh和sigmoid飽和時都會有梯度消失的問題,ReLU就不會有這個問題,而且計算簡單,當然它會產生dead neurons,下面會具體說。
-
Gradient Check,如果你覺得網絡feedforward沒什么問題,那么GC可以保證BP的過程沒什么bug。值得提的是,如果feedforward有問題,但是得到的誤差是差不多的,GC也會感覺是對的。大多情況GC可幫你找到很多問題!步驟如下
步驟
那如果GC失敗,可能網絡某些部分有問題,也有可能整個網絡都有問題了!你也不知道哪出錯了,那怎么辦呢?構建一個可視化過程監控每一個環節,這可以讓你清楚知道你的網絡的每一地方是否有問題!!這里還有一個trick,先構建一個簡單的任務(比如你做MNIST數字識別,你可以先識別0和1,如果成功可以再加入更多識別數字);然后從簡單到復雜逐步來檢測你的model,看哪里有問題。舉個例子吧,先用固定的data通過單層softmax看feedforward效果,然后BP效果,然后增加單層單個neuron unit看效果;增加一層多個;增加bias。。。。。直到構建出最終的樣子,系統化的檢測每一步! -
參數初始化也是重要滴!其主要考慮點在于你的激活函數的取值范圍和梯度較大的范圍!
隱層的bias一般初始化為0就可以;輸出層的bias可以考慮用reverse activation of mean targets或者mean targets(很直觀對不對)
weights初始化一般較小的隨機數,比如Uniform,Gaussion
parameter initial
更放心一點,可視化每一層feedforward輸出的取值范圍,梯度范圍,通過修改使其落入激活函數的中間區域范圍(梯度類似線性);如果是ReLU則保證不要輸出大多為負數就好,可以給bias一點正直的噪聲等。當然還有一點就是不能讓神經元輸出一樣,原因很簡單 -
優化算法,一般用mini-batch SGD,絕對不要用full batch gradient(慢)。一般情況下,大數據集用2nd order batch method比如L-BFGS較好,但是會有大量額外計算2nd過程;小數據集,L-BFGS或共軛梯度較好。(Large-batch L-BFGS extends the reach of L-BFGS Le et al. ICML 2001 )
mini-batch好處主要有:可以用矩陣計算加速并行;引入的隨機性可以避免困在局部最優值;并行化計算多個梯度等。在此基礎上一些改進也是很有效的(因為SGD真的敏感),比如Momentum,他的意圖就是在原先的跟新基礎上增加一點摩擦力,有點向加速度對速度的作用,如果多次更新梯度都往一個方向,說明這個方向是對的,這時候增加跟新的步長,突然有一個方向,只會較少影響原來的方向,因為可以較少的數據帶來的誤差。當你使用momentum時可以適當減小global learning rate
momentum -
學習率,跑過神經網絡的都知道這個影響還蠻大。一般就是要么選用固定的lr,要么隨著訓練讓lr逐步變小
方案一:當驗證誤差不再下降時,lr減小為原來的0.5
方案二:采用理論上可以保證收斂的減小比例,O(1/t),t是迭代次數
方案三:最好用自適應的學習率,比如Adagrad(Duchi et al. 2010)等
簡要說明一下,Adagrad非常適合數據出現頻度不一樣的模型,比如word2vec,你肯定希望出現非常少的詞語權重更新非常大,讓它們遠離常規詞,學習到向量空間中距離度量的意義,出現非常多的詞(the,very,often)每次更新比較小。
adagrad
按照上面式子,如果進入一個local optimum,參數可能無法更新時,可以考慮每隔一段epoch,reset sum項 看看你的模型有沒有能力過擬合!(training error vs. validation error)
如果沒有,想辦法讓它過擬合!(r u kidding?! 哈哈),一般而言,當參數多于training數據時,模型是有能力記住數據的,總歸先保證模型的能力么
如果過擬合了,那么就可以進一步優化啦,一般深度學習breakthrough的方法都是來自于更好的regularization method,解決過擬合很多方法在此就不多論述了。比如減小模型(layers, units);L1,L2正則(weight decay);early stop(按照數據集大小,每隔一段epoch(比如小數據集每隔5epoch,大的每隔(1/3epoch))保存模型,最后選擇validation error 最小的模型);sparsity constraints on hidden activation;Dropout;data
augumentation (CNN 一些變化不變性要注意)等
大體流程如上,再引一篇大神之作,Practical Recommendations for Gradient-Based Training of Deep Architectures Y. Bengio(2012),額外提到的有unsupervised預訓練。其實數據不夠時也可以找類似任務做遷移學習,fine-tuning等。
最后,可以看到一個網絡那么多的超參數,怎么去選這些超參數呢?文章也說了:Random hyperparameter search!
以上提的多是supervised learning,對于unsupervised learning可以做fine tuning
接下來按一些模塊具體列舉下,歡迎補充!!
標準化(Normalization)
很多machine learning模型都需要,在此不多論述,神經網絡假設inputs/outputs服從近似均值為0方差為1分布。主要為了公平對待每個特征;使優化過程變得平穩;消除量綱影響等
z-score; min-max; decimal scaling等
- scale控制特征的重要性:大scale的output特征產生更大的error;大的scale的input的特征可以主導網絡對此特征更敏感,產生大的update
- 一些特征本來取值范圍很小需要格外注意,避免產生NaNs
- 就算沒有標準化你的網絡可以訓練的話,那可能前幾層也是做類似的事情,無形增加了網絡的復雜程度
- 通常都是把所有inputs的特征獨立地按同樣的規則標準化,如果對任務有特殊需求,某些特征可以特別對待
檢查結果(Results Check)
有點類似于在模型中按一個監控系統(預處理,訓練,預測過程中都要),這個步驟可以幫助你發現你的模型在哪里出了問題,最好可以找到可視化的方法,一目了然,比如圖像方面就很直觀了。
- 需要注意的是,你需要理解你設定的error的意義,就算訓練過程error在不斷減少,也需要來和真實的error比較,雖然training error減少了,但是可能還不夠,真實世界中需要更小的error,說明模型學習的還不夠
- 當在training過程中work后,再去看在validation集上的效果
- 再更新網絡結構前,最好確保每一個環節都有“監控”,不要盲目做無用功
預處理(Pre-Processing Data)
現實中同樣的數據可以有不同的表達方式,比如移動的汽車,你從不同角度位置去觀察,它做的都是同樣的事情。你應該確保從南面觀察和從西面觀察的同樣的數據,應該是相似的!
- 神經網絡假設數據的分布空間是連續的
- 減少數據表示多樣性帶來的誤差;間接減少了網絡前幾層做沒必要的“等同”映射帶來的復雜度
正則化(Regularization)
增加Dropout,隨機過程,噪聲,data augumentation等。就算數據足夠多,你認為不可能over-fitting,那么最好還是有正則,如dropout(0.99)
- 一方面緩解過擬合,另一方面引入的隨機性,可以平緩訓練過程,加速訓練過程,處理outliers
- Dropout可以看做ensemble,特征采樣,相當于bagging很多子網絡;訓練過程中動態擴展擁有類似variation的輸入數據集。(在單層網絡中,類似折中Naiive bayes(所有特征權重獨立)和logistic regression(所有特征之間有關系);
- 一般對于越復雜的大規模網絡,Dropout效果越好,是一個強regularizer!
- 最好的防止over-fitting就是有大量不重復數據
Batch Size太大
太大的batch size會減gradient descend的隨機性,對模型的精度產生負面影響。
如果可以容忍訓練時間過長,最好開始使用盡量小的batch size(16,8,1)
- 大的batch size需要更多的epoch來達到較好的水平
- 原因1:幫助訓練過程中跳出local minima
- 原因2:使訓練進入較為平緩的local minima,提高泛化性
學習率lr
去掉gradient clipping(一般默認有),訓練過程中,找到最大的,使模型error不會爆掉的lr,然后用稍微小一點的lr訓練
- 一般數據中的outliers會產生大的error,進而大的gradient,得到大的weight update,會使最優的lr比較難找
- 預處理好數據(去除outliers),lr設定好一般無需clipping
- 如果error explode,那么加gradient clipping只是暫時緩解,原因還是數據有問題
最后一層的激活函數
限制輸出的范圍,一般不用任何激活
需要仔細考慮輸入是什么,標準化之后的輸出的取值范圍,如果輸出有正有負,你用ReLU,sigmoid明顯不行;多分類任務一般用softmax(相當于對輸出歸一化為概率分布)
- 激活只是一個映射,理論上都可以
- 如果輸出沒有error明顯也不行,那就沒有gradient,模型也學不到什么
- 一般用tanh,產生一個問題就是梯度在-1或1附近非常小,神經元飽和學習很慢,容易產生梯度消息,模型產生更多接近-1或1的值
Bad Gradient(Dead Neurons)
使用ReLU激活函數,由于其在小于零范圍梯度為0,可能會影響模型性能,甚至模型不會在更新
當發現模型隨著epoch進行,訓練error不變化,可能所以神經元都“死”了。這時嘗試更換激活函數如leaky ReLU,ELU,再看訓練error變化
- 使用ReLU時需要給參數加一點噪聲,打破完全對稱避免0梯度,甚至給biases加噪聲
- 相對而言對于sigmoid,因為其在0值附近最敏感,梯度最大,初始化全為0就可以啦
- 任何關于梯度的操作,比如clipping, rounding, max/min都可能產生類似的問題
- ReLU相對Sigmoid優點:單側抑制;寬闊的興奮邊界;稀疏激活性;解決梯度消失
初始化權重
一般說隨機初始化為一些小的數,沒那么簡單,一些網絡結構需要一些特定的初始化方法,初始化不好很可能得不到文章上的效果!可以去嘗試一些流行的找到有用的初始化
- 太小:信號傳遞逐漸縮小難以產生作用
- 太大:信號傳遞逐漸放大導致發散和失效
- 比較流行的有 'he', 'lecun', 'Xavier'(讓權重滿足0均值,2/(輸入節點數+輸出節點數))
- biases一般初始化為0就可以
- 每一層初始化都很重要
網絡太深
都說深度網絡精度更高,但深度不是盲目堆起來的,一定要在淺層網絡有一定效果的基礎上,增加深度。深度增加是為了增加模型的準確率,如果淺層都學不到東西,深了也沒效果。
開始一般用3-8層,當效果不錯時,為了得到更高的準確率,再嘗試加深網絡
- 所以的優化方法在淺層也有用,如果效果不好,絕對不是深度不夠
- 訓練和預測過程隨著網絡加深變慢
Hidden neurons的數量
最好參考researcher在相似的任務上結構,一般256-1024
太多:訓練慢,難去除噪聲(over-fitting)
太少:擬合能力下降
- 考慮真實變量有多少信息量需要傳遞,然后再稍微增加一點(考慮dropout;冗余表達;估計的余地)
- 分類任務:初始嘗試5-10倍類別個數
- 回歸任務:初始嘗試2-3倍輸入/輸出特征數
- 這里直覺很重要
- 最終影響其實不大,只是訓練過程比較慢,多嘗試
loss function
多分類任務一般用cross-entropy不用MSE
- 多分類一般用softmax,在小于0范圍內梯度很小,加一個log可以改善此問題
- 避免MSE導致的學習速率下降,學習速率受輸出誤差控制(自己推一下就知道了)
AE降維
對中間隱層使用L1正則,通過懲罰系數控制隱含節點稀疏程度
SGD
不穩定算法,設定不同的學習速率,結果差距大,需要仔細調節
一般希望開始大,加速收斂,后期小,穩定落入局部最優解。
也可采用自適應的算法,Adam,Adagrad,Adadelta等減輕調參負擔(一般使用默認值就可以)
- 對于SGD需要對學習率,Momentum,Nesterov等進行復雜調參
- 值得一提是神經網絡很多局部最優解都可能達到較好的效果,而全局最優解反而是容易過擬合的解
CNN的使用
神經網絡是特征學習方法,其能力取決隱層,更多的連接意味著參數爆炸的增長,模型復雜直接導致很多問題。比如嚴重過擬合,過高的計算復雜度。
CNN其優越的性能十分值得使用,參數數量只和卷積核大小,數量有關,保證隱含節點數量(與卷積步長相關)的同時,大量降低了參數的數量!當然CNN更多用于圖像,其他任務靠你自己抽象啦,多多嘗試!
這里簡單介紹一些CNN的trick
- pooling或卷積尺寸和步長不一樣,增加數據多樣性
- data augumentation,避免過擬合,提高泛化,加噪聲擾動
- weight regularization
- SGD使用decay的訓練方法
- 最后使用pooling(avgpooling)代替全連接,減少參數量
- maxpooling代替avgpooling,避免avgpooling帶來的模糊化效果
- 2個3x3代替一個5x5等,減少參數,增加非線性映射,使CNN對特征學習能力強
- 3x3,2x2窗口
- 預訓練方法等
- 數據預處理后(PCA,ZCA)喂給模型
- 輸出結果窗口ensemble
- 中間節點作為輔助輸出節點,相當于模型融合,同時增加反向傳播的梯度信號,提供了額外的正則化
- 1x1卷積,夸通道組織信息,提高網絡表達,可對輸出降維,低成本,性價比高,增加非線性映射,符合Hebbian原理
- NIN增加網絡對不同尺度的適應性,類似Multi-Scale思想
- Factorization into small convolution,7x7用1x7和7x1代替,節約參數,增加非線性映射
- BN減少Internal Covariance Shift問題,提高學習速度,減少過擬合,可以取消dropout,增大學習率,減輕正則,減少光學畸變的數據增強
- 模型遇到退化問題考慮shortcut結構,增加深度
- 等等
RNN使用
小的細節和其他很像,簡單說兩句個人感覺的其他方面吧,其實RNN也是shortcut結構
- 一般用LSTM結構防止BPTT的梯度消失,GRU擁有更少的參數,可以優先考慮
- 預處理細節,padding,序列長度設定,罕見詞語處理等
- 一般語言模型的數據量一定要非常大
- Gradient Clipping
- Seq2Seq結構考慮attention,前提數據量大
- 序列模型考率性能優良的CNN+gate結構
- 一般生成模型可以參考GAN,VAE,產生隨機變量
- RL的框架結合
- 數據量少考慮簡單的MLP
- 預測采用層級結構降低訓練復雜度
- 設計采樣方法,增加模型收斂速度
- 增加多級shortcut結構
今天就到這了,歡迎補充,個人水平實在有限。