在深度學習中,為了有效地訓練深度神經(jīng)網(wǎng)絡,有一些值得我們強烈推薦的做法。在本文中,我將介紹一些最常用的方法,從高質(zhì)量訓練數(shù)據(jù)的重要性,到超參數(shù)的選擇,再到更快的做出 DNN 原型的通用技巧。這些方法的大多數(shù)由學術(shù)界和工業(yè)界的研究驗證過,并且在諸如 Yann LeCun 等人寫的《Efficient BackProp》和 Yoshua Bengio 的《Practical Recommendations for Deep Architectures》中也給出了數(shù)學和實驗證明。
你會注意到,我沒有在這篇文章中提到任何數(shù)學證明。在這里建議的所有要點,更多地應該被看作是 DNN 的最佳訓練方法中獲得的總結(jié)。為了更深入地了解,我強烈建議您最后看一遍上面提到的研究論文和后面提到的參考文獻。
訓練數(shù)據(jù)
許多機器學習從業(yè)者習慣于在任何深度神經(jīng)網(wǎng)絡(DNN)中使用原始(raw)訓練數(shù)據(jù)。為什么不這樣做呢,任何 DNN(大概)仍會給出好的結(jié)果,對吧?但是,說出「給出正確的數(shù)據(jù)類型,一個十分簡單的模型會比一個復雜的 DNN 更快地給出更好的結(jié)果」(雖然,這可能會有例外)并不是很守舊派的。因此,無論你是在做計算機視覺,還是在做自然語言處理或統(tǒng)計建模等,你都應該嘗試預處理您的原始數(shù)據(jù)。你可以采取以下幾個方法來獲得更好的訓練數(shù)據(jù):
盡可能大的數(shù)據(jù)集(DNN 對數(shù)據(jù)的需求是相當大的:越多越好)
刪除所有具有損壞數(shù)據(jù)的訓練樣本(短文本、高失真圖像、虛假輸出標簽、具有大量空值的特征等)
數(shù)據(jù)增強——創(chuàng)建新樣本(如果是圖像,可以重新縮放、添加噪聲等)
選擇適當?shù)募せ詈瘮?shù)
激活函數(shù)在任何神經(jīng)網(wǎng)絡中都是重要組成部分之一。激活將大家非常期望的非線性效果引入到了模型中。多年來,sigmoid 激活函數(shù)一直是最好的選擇。但是 sigmoid 函數(shù)本質(zhì)上有兩個缺陷:
1.sigmoid 尾部的飽和(會進一步導致梯度消失問題)
2.sigmoid 不是以 0 為中心的。
一個更好的選擇是 tanh 函數(shù)——在數(shù)學上,tanh 只是一個重新縮放和移位的 sigmoid,tanh(x) = 2*sigmoid(x) - 1。雖然 tanh 仍然可能遭受梯度消失問題,但好消息是 tanh 是以零為中心的。因此,使用 tanh 為激活函數(shù)可以更快地收斂。我使用中也發(fā)現(xiàn)使用 tanh 作為激活函數(shù)通常比使用 sigmoid 函數(shù)好。
你可以根據(jù)具體任務進一步探索其它選擇,如已經(jīng)表現(xiàn)出可以改善一些問題的 ReLU,SoftSign 等函數(shù)。
隱含單元和隱含層的數(shù)量
使用比最佳隱含單元數(shù)更多的數(shù)量通常是安全的。因為,任何正則化方法在一定程度上都可以處理多余的單元。而另一方面,使用比最佳隱含單元數(shù)更少的數(shù)量時,發(fā)生欠擬合的概率更高一些。
此外,當采用無監(jiān)督學習預訓練的表示(pre-trained representations,在后面部分中描述)時,隱含單元數(shù)的最佳數(shù)量通常要更大一些。因為,在各種表示中(對于特定的監(jiān)督任務),預訓練表示可能會包含大量的無關(guān)信息。通過增加隱含單元的數(shù)量,模型將具有足夠支持從預訓練表示中過濾出最合適的信息的靈活性。
選擇最佳隱含層數(shù)是相對簡單的。正如 Yoshua Bengio 在 Quora 上提到的:「你只需要繼續(xù)添加層,直到測試錯誤不再改善為止」。
權(quán)重初始化
始終使用小隨機數(shù)(random numbers)初始化權(quán)重,以打破不同單元之間的對稱性。但是權(quán)重應該多小呢?推薦的上限是多少?使用什么概率分布來生成隨機數(shù)?此外,當使用 sigmoid 激活函數(shù)時,如果權(quán)重被初始化為非常大的數(shù),則 sigmoid 函數(shù)將會飽和(尾部區(qū)域),導致死亡神經(jīng)元(dead neurons)。如果權(quán)重非常小,則梯度也會很小。因此,最好在中間范圍選擇權(quán)重,并且使它們圍繞平均值均勻分布。
幸運的是,目前已經(jīng)有很多關(guān)于初始權(quán)重的適當值的研究,這對于有效的收斂是非常重要的。為了初始化得到均勻分布的權(quán)重,uniform distribution 可能是最好的選擇之一。此外,如論文(Glorot and Bengio, 2010)所示,具有更多傳入連接(fan_in)的單元應具有相對較小的權(quán)重。
由于所有這些深入的實驗,現(xiàn)在我們有一個測量公式,可以直接用于權(quán)重初始化;例如從~ Uniform(-r, r) 范圍獲得權(quán)重,對于 tanh 作為激活函數(shù)的時候,r=sqrt(6/(fan_in+fan_out));而對于 sigmoid 作為激活函數(shù)的時候,r=4*(sqrt(6/fan_in+fan_out)),其中 fan_in 是上一層的大小,fan_out 是下一層的大小。
訓練速率
這可能是最重要的超參數(shù)之一,決定了整個學習過程。如果設置的學習速率太小,你的模型可能需要幾年才能收斂;如果學習速率太大,在開始訓練幾個樣本之后,你的損失值(loss)可能會迅速增加。一般來說,0.01 的學習速率是安全的,但這不應被視為一個嚴格的規(guī)則;因為最佳學習速率應該根據(jù)具體任務來調(diào)整。
相比之下,在每個 epoch 之后選擇固定的學習率(learning rate)或者逐漸降低學習率(learning rate)是另一個選擇。雖然這可能有助于訓練得更快,但需要人工確定新的學習率。一般來說,學習率可以在每個 epoch 后減半——這幾類策略在幾年前相當普遍。
幸運的是,現(xiàn)在我們有更好的基于動量(momentum based methods)方法來改變學習率,就是基于誤差函數(shù)的曲率。這種方法也可以幫助我們?yōu)槟P椭械母鱾€參數(shù)設置不同的學習率;使得一些參數(shù)可能以相對較慢或較快的速率學習。
近期大量針對優(yōu)化方法的研究也產(chǎn)生了自適應學習率(adaptive learning rate)方法?,F(xiàn)在,我們有很多可選擇的方法,從老牌的動量方法(Momentum Method)到 Adagrad、Adam(我最喜歡的方法)、RMSProp 等。像 Adagrad 或 Adam 這樣的方法有效地避免了手動選擇初始學習速率,并且模型能在一定的時間內(nèi)順利地收斂(當然,如果選擇好的初始速率會進一步幫助模型收斂)。
超參數(shù)微調(diào):旋轉(zhuǎn)的網(wǎng)格搜索——擁抱隨機搜索
網(wǎng)格搜索(Grid Search)是經(jīng)典的機器學習方法。但是,在尋找 DNN 的最佳超參數(shù)時,網(wǎng)格搜索并不高效。主要是因為嘗試不同的 DNN 超參數(shù)組合所花費的時間太長。隨著超參數(shù)的數(shù)量不斷增加,網(wǎng)格搜索所需的計算也呈指數(shù)增長。
這里有兩種方法:
1. 根據(jù)經(jīng)驗手動調(diào)整一些常用的超參數(shù),如學習率、層數(shù)(number of layer)等。
2. 使用隨機搜索/隨機抽樣(Random Search/Random Sampling)來選擇最優(yōu)超參數(shù)。超參數(shù)的組合通常從可行域的均勻分布中選擇。還可以加入先驗知識以進一步減少搜索空間(例如學習速率不應該太大或太小)。經(jīng)證明,隨機搜索比網(wǎng)格搜索更有效率。
學習方法
老牌的隨機梯度下降(Stochastic Gradient Descent)可能不像 DNN 一樣有效(這不是一個嚴格的規(guī)則),因此最近很多人正研究開發(fā)更靈活的優(yōu)化算法。例如:Adagrad、Adam、AdaDelta、RMSProp 等。這些復雜的方法除了提供自適應學習率之外,還對不同的模型參數(shù)應用不同的速率,使得收斂曲線更加平滑。將學習率、層數(shù)等作為超參數(shù)是很好的,建議在訓練數(shù)據(jù)的子集上進行嘗試。
使權(quán)重的維度以 2 的指數(shù)冪級增加
即使用最新的硬件資源處理最新的深度學習模型時,內(nèi)存管理仍然是以字節(jié)衡量的;所以,盡量將參數(shù)的大小設置為 2 的冪指數(shù),如 64、128、512、1024。這可能有助于分割矩陣、權(quán)重等,從而略微提高學習效率。這個現(xiàn)象在使用 GPU 時變得更加顯著。
無監(jiān)督預訓練
無論你是否用 NLP、機器視覺(Computer Vision)、語音識別等技術(shù),無監(jiān)督預訓練總能幫助有監(jiān)督模型和無監(jiān)督模型的訓練。詞向量(Word Vector)在 NLP 中無處不在;對于有監(jiān)督二分類問題,你可以使用 ImageNet 的數(shù)據(jù)集以無監(jiān)督的方式預訓練模型;或者對于說話者消歧模型(speaker disambiguation model),可以進一步利用語音樣本的信息訓練模型。
Mini-Batch vs. 隨機學習
訓練模型的主要目的是學習得到適當?shù)膮?shù),從而產(chǎn)生從輸入到輸出的最佳映射(mapping)。不管是否使用批處理(batch)、Mini-Batch 或隨機學習(stochastic learning),這些參數(shù)都會因訓練樣本的不同而有所調(diào)整。在使用隨機學習方法時,在每個訓練樣本之后調(diào)整權(quán)重梯度,因此將噪聲引入梯度。這具有非常理想的效果;即在訓練期間引入噪聲,模型變得不太容易過度擬合。
然而,現(xiàn)在計算機的計算能力大大提高,使得隨機學習方法的效率可能相對較低。隨機學習可能浪費了很大一部分資源。如果我們能夠計算矩陣與矩陣的乘法(Matrix-Matrix multiplication),那么為什么要局限于使用迭代相加的向量與向量的乘法?因此,為了實現(xiàn)更大的吞吐量(throughput)/更快的學習,建議使用 Mini-Batch 而不是隨機學習。
但是,選擇適當?shù)呐幚泶笮∫簿哂邢嗤闹匾?因此我們也可以保留一些噪音(通過減少批的數(shù)據(jù)量實現(xiàn)),并有效利用計算機的計算能力。同樣的,一個批的樣本量控制在 16 到 128 之間也是一個不錯的選擇(2 的指數(shù)冪)。通常,一旦你找到更重要的超參數(shù)(或手動或隨機搜索),批處理的大小是選定的。然而,有些情況下(如在線學習/online learning),模型的訓練數(shù)據(jù)是數(shù)據(jù)流(stream),這時求助于隨機學習是一個很好的選擇。
重排訓練樣本
信息論中有這樣的話——「學習發(fā)生的極小概率事件比學習發(fā)生的大概率事件更有信息」。類似地,隨機排列訓練樣本的順序(不同的迭代或批處理中)將導致更快的收斂。當訓練樣本的順序不同時,模型的結(jié)果會有輕微的提升。
作為正則化的 dropout
考慮到要學習數(shù)百萬的參數(shù),正則化成為防止 DNN 過度擬合的必然要求。你也可以繼續(xù)使用 L1/L2 正則化,但是 dropout 是更好的檢查 DNN 過擬合的方法。dropout 在實現(xiàn)方法上比較瑣碎,它通常能更快地學習模型。默認值 0.5 是一個好的選擇,但是這也取決于具體的任務。如果模型較不復雜,則 0.2 的 dropout 也可能就足夠了。
在測試階段,應該相應地標準化權(quán)重,同時暫緩使用舍棄方法,如論文《Dropout: A Simple Way to Prevent Neural Networks from Overfitting》中所做的那樣。賦予模型舍棄正則化方法,經(jīng)過一定的訓練時間錯誤肯定會下降。
訓練的迭代數(shù)
「用多個迭代(epoch)來訓練深度學習模型將產(chǎn)生更好的結(jié)果」——但是我們?nèi)绾瘟炕付嗌佟?原來,有一個簡單的策略 - 只要對訓練模型設置固定數(shù)量的訓練樣本或迭代,比如 20,000 個樣本或 1 個迭代。在每組訓練樣本訓練完成后,將測試誤差與訓練誤差進行比較,如果它們之間的差距正在減小,則繼續(xù)訓練。除此之外,在每個這樣的集合之后,保存這組數(shù)據(jù)訓練模型的參數(shù)(以便從多個模型中選擇)。
可視化
有一千種可能使得訓練的深度學習模型出錯。我們都有過這樣的經(jīng)歷,當模型訓練了幾個小時或幾天后,在訓練完成后我們才意識到模型存在一些問題。為了避免這種問題——總是可視化訓練過程。最明顯的步驟是打印/保存損失(loss)函數(shù)值的日志、訓練誤差或測試誤差等。
除此之外,另一個好的做法是在訓練一定樣本后或在 epoch 之間使用可視化庫繪制權(quán)重的直方圖。這可能有助于跟蹤深度學習模型中的一些常見問題,例如梯度消失(Vanishing Gradient)、梯度爆炸(Exploding Gradient)等。
多核計算機,GPU 集群
隨著 GPU、提供向量化操作的庫(library)、具有更強計算能力的計算機的出現(xiàn),這些可能是深度學習成功的最重要的因素。如果你足夠耐心,你可以嘗試在你的筆記本電腦上運行 DNN(這時你甚至不能打開 10 個 Chrome 瀏覽器標簽),并需要等待很長時間才能得到結(jié)果。要么你有非常好的硬件(很昂貴)與至少多個 CPU 核和幾百個 GPU 核。GPU 已經(jīng)徹底改變了深度學習研究(難怪 Nvidia 的股票井噴式漲價),主要是因為 GPU 能夠更大規(guī)模地執(zhí)行矩陣操作。
因此,以前在正常的機器上花幾個星期的訓練,由于并行(parallelization)技術(shù),將訓練的時間減少到幾天甚至幾個小時。
使用具有 GPU 計算和自動微分支持的庫
幸運的是,對于快速訓練,我們有一些很好的庫,如 Theano、Tensorflow、Keras 等。幾乎所有這些深度學習庫提供對 GPU 計算和自動微分(Automatic Differentiation)的支持。所以,你不必深入了解 GPU 的核心編程(除非你想,絕對有趣);你也不必編寫自己的微分代碼,這在真正復雜的模型中可能會有點費力(雖然你應該能夠做到這一點)。TensorFlow 能進一步支持在分布式架構(gòu)上訓練模型。
以上并不是訓練 DNN 的詳盡列表。它只包括了最常見的做法,上面已經(jīng)去掉了如數(shù)據(jù)標準化、批規(guī)范化/層規(guī)范化、梯度檢查(Gradient Check)等概念。