天天看點

幹貨 | 算法工程師入門第一期——羅恒講深度學習

雷鋒網(公衆号:雷鋒網)按:本文為大牛講堂算法工程師入門課程第一篇。地平線資深算法工程師羅恒、穆黎森、黃李超将分别帶來深度學習、增強學習、物體檢測的相關課程。本期地平線資深算法研究員羅恒将為大家帶來深度學習簡介,包括神經網絡曆史回顧和神經網絡訓練等内容。

幹貨 | 算法工程師入門第一期——羅恒講深度學習

▼ 

整個神經網絡,從曆史上就可以把很多東西搞清楚,比如它是怎麼變過來的。我認為神經網絡其實是變得越來越簡單,越來越好用的。現在神經網絡常用的東西已經很固定了,你不用再加任何東西就能用。但有些時候你覺得這個東西應該work,但它不work,這種情況該怎麼辦。是以盡管現在很多東西已經純标準化,但了解這些對于你找問題找錯誤,還是很重要。是以這次主要講兩個東西,優化和正則化。絕大多數情況,正則化不是問題,我們隻關心優化問題,往往你發現需要做正則化的時候多半是資料問題。

神經網絡經曆了三次研究熱潮。第一次是60年代,感覺器出來後很多人認為離人工智能已經很近了。但馬上有人寫了本書叫《感覺器》,說它不能解決異或問題,這個時候大家一下子又不感興趣了。到80年代,bp算法出來,又開始變得火熱起來。但當時人們認為多層神經網絡優化困難,又對它失去了信心。直到很多年後,2006年出來了deep

belief

nets。學術界又開始慢慢對神經網絡有興趣,等到神經網絡在語音識别和物體識别上取得突破後,神經網絡的第三次熱潮又開始了,一直持續到現在。

感覺器已經有了現代神經網絡的原型,輸入特征與參數w連接配接,權重累加之後進入神經元,通過激活函數輸出。與現在的網絡的差別主要有兩點,第一是資料要經過人工編碼形成特征;第二是網絡的輸出是離散的二值。前者導緻了相當一段時間,人們認為什麼是好的特征應該由專家來設計,有了好的特征之後再解決分類問題,從這個角度上看,svm也隻是個特殊的感覺器。

關于第二點,輸出的離散的,這個帶來一個問題,就是從輸入到輸出不是一個連續的光滑的,這個其實是限制使用梯度優化網絡的最大障礙。

幹貨 | 算法工程師入門第一期——羅恒講深度學習

很快,minsky和papert的《感覺器》裡面證明了上面的感覺器不能解決異或等一大類問題,這本書是以也造成了神經網絡研究的第一次低潮。有趣的是,其實也就是在《感覺器》裡面,作者指出如果在網絡中能夠增加一些額外的類似感覺器的單元,那麼就能解決那些不能解決的問題。

這類神經元後來被hinton稱之為隐藏單元(hidden

units),在傳統的感覺器中,輸出神經元是可見的,根據訓練資料,我們知道輸出單元應當是什麼樣的狀态,而隐藏單元的狀态則不可知。就像之前提到的,如果隐藏單元的輸出是離散的,那麼根據輸入特征,得到對應的輸出就需要考慮隐藏單元的各種可能狀态,那麼就是一個組合優化問題,求解困難。

80年代,bp算法的成功的主要原因,就是改變激活函數為光滑連續的函數(可導),這樣一來,對于一個含有隐藏單元的神經網絡,從輸入x到輸入y也是一個關于所有連接配接參數w的光滑連續的函數。那麼使用鍊式法則求導,我們就可以得到網絡所有參數的梯度,也就是說我們現在知道按梯度方向調整參數w就可以使得給定輸入資料x改變網絡的輸出大小,不斷地修正,就可以使得網絡的行為去拟合訓練資料。之後,bp算法大獲成功,神經網絡迎來了第二次的研究熱潮。

80年代到90年代,大量的研究人員使用bp算法訓練神經網絡,但是大家發現優化十分困難,最常見的失敗就是無論怎麼調整參數,訓練的loss就是不降。由于神經網絡是優化一個非線性函數,那麼意味着理論上存在局部極小點,是以,每當loss不降,大家都是自然而然地認為這是遇到了局部極小點,同時理論上層數越多的神經網絡非線性越強會有更多的局部極小,現實的觀察也發現更深的網絡往往結果更差,進而大量的研究者對神經網絡失去信心,神經網絡進入第二次低潮。90年代末開始的svm相關研究以及後來對凸優化的癡迷,也都是在這個大背景下發生的。

進入2000年之後,hinton發現使用一些非監督方法對多層神經網絡做初始化之後再使用bp算法,能夠成功地訓練并得到更好的結果。再後來,發現直接使用bp算法進行監督訓練就能在很多很多問題上得到非常好的結果。那麼為什麼90年代的時候沒有成功呢?一個是當時訓練資料相對很少,而且當時的機器訓練起來很慢;另外一個是當時訓練優化方法不太先進,是以有時在訓練的時候梯度會出一些問題。

幹貨 | 算法工程師入門第一期——羅恒講深度學習

上面的圖是一個四隐藏層的神經網絡訓練在mnist上面(激活函數是tanh),大家可以看到訓練一開始,最頂層的神經元的激活值迅速減小,那麼意味着從這一層往後傳遞的梯度也會迅速減小,同時也可以觀察到loss會基本保持不變(最後一層的激活函數接近0,那麼無論什麼樣的輸入到這一層之後都差不多,自然也就無法正确分類降低loss)。

但是随着訓練的進行,頂層的激活又從0開始慢慢變大,loss最後又開始降。也就是在優化的時候,本來以為是掉到某一個坑裡(局部極小),無論把w怎麼改變,你的loss都沒辦法降下來。但實際情況是你在一個很平的高原上,你沿各個方向走,這個loss都差不多。現在我們知道使用适當的參數初始化、使用沒有飽和的激活函數(如relu)、使用batch

normalization都可以、使用一些自适應學習率方法(如adam,rmsprop)都可以緩解上面這種情況,當然更重要的一點是使用gpu。

曆史講完了,接下來講講算法工程師日常工作面臨的問題。我有一堆資料,品質差不多,我要拿到這些資料去訓練一個模型,讓這個模型能夠投入使用。至于訓練模型,我們現在工具已經很完備了,資料整理好之後梳理好指令,機器去跑,拿到一個結果,就最好了。但通常呢,會發現結果不好,結果不好有兩種情況,一種是我剛才說的,模型在訓練集上表現不好,也就是對應我們要講的第一個問題,優化問題。也就是你拿到一個資料,你第一件事情你不要考慮測試集,你就考慮訓練集,我要讓我這個模型在訓練上能做的足夠好,是以這個實際上是一個優化問題。通常我們絕大多數困難都在這個問題。

當這個問題解決之後,可能又開始第二個問題。就是我在訓練集上做的很好,但是在驗證集上做的不好,這個就是overfitting,overfitting有很多種情況,從學術上講比如說訓練資料中包含一些噪聲。我們日常中當你發現你的loss很低,但是在你的驗證集結果不好,通常是你的訓練集和你的測試集不一樣。這個不一樣可能有很多種原因,比如是不同的時間采集的,采集資料的政策發生了變化等等。這時首先需要做的是通過可視化對資料的分布有直覺上的認識,解決資料本身的問題。最簡單的一種可視化辦法,比如說你是一個二分類,你現在資料你就把它全部過一遍,二分類隻有一個輸出,每個訓練的資料給它分一個數,你把這個數從大到小排一遍,驗證集也可以得到一個數,也從大到小排一遍。

然後你就從大到小随機抽一些采樣,就會發現你資料的問題在哪。不斷地做這個過程,不斷地改進新的資料集,這個将會是你的最大的收益。也就是改你的資料擴大你的資料集,使你的資料覆寫的種類更全,收益可能是幾十個百分點的,而調整你的優化政策可能隻是幾個百分點的收益,正則化方法可能隻是千分位上的收益。

是以,了解神經網絡背後的優化過程,了解你的資料才是最重要的。具體的可視化、資料采樣的方法往往需要結合問題本身發揮創造力。當訓練、驗證資料大緻滿足需求之後,接下來要做的就是訓練網絡,不斷減小訓練集上的loss。如今有大量的開源工具,對于一些主流的任務,通常可以友善的找到适合的網絡結構以及相應的超參數。

大家隻要結合自己的計算資源上的限制對這些網絡做些适當的剪裁就可以,這裡就不展開了。下面介紹一些訓練過程中常見的情況以及如何調整。訓練中常見的困難是loss不降,常見的情況是輸入資料從下往上傳輸的時候,某一層的表示完全相同(比如某層的激活函數為0),這樣學習自然就無法進行了。

是以在訓練的過程中檢視激活函數的相關統計資訊是個好習慣。常見的情況,比如到softmax的連接配接矩陣w迅速變小,這有可能是由于資料類别分布非常不均衡導緻的,這時候做些采樣以及适當改變mini-batch的大小可能會有緩解。除了考慮資料樣本的均衡之外,也可以适當地改變這層連接配接矩陣的參數初始化。當網絡中間某層的激活函數總是輸出0,這種時候loss的下降也會停止。

這時候可以考慮幾個方面,首先在這個激活函數之前是否有batch

normalization,如果沒有最好加上試試(對于現在的前向網絡,最好保證除softmax之外的激活函數之前都有bn),如果有bn也可以進一步檢查eps是否設的過大,可以适當調小試試;其次也可以檢查一下是否relu造成的,這時候也可以試着改變這一層的bias和bn的beta的初始化(初始化成某個正數,比如+1);第三,如果改變了原始的網絡結構,那麼也最好避免表示的瓶頸(這一層的隐單元個數不要比之前層的隐單元個數少得過多)。

如果是從輸入開始的第一層就激活為0,那麼就要檢查資料的預處理和相應參數初始化。一種很簡便的方式,則是讓輸入資料先通過一個batch

normalization層,然後再連接配接後面的w。訓練集上的loss能夠正常的下降之後,那麼接下來就需要看驗證集上的表現了。如果我們是不計代價地獲得驗證集的表現,那麼就像yann

lecun給的建議一樣,首先應當通過不斷地增加網絡的大小使得出現overfitting(訓練集的loss越來越低,而驗證集的loss降低到某個程度之後不變甚至開始變高)。

說到這裡,插一句。神經網絡是非常靈活強大的模型,也就是說隻要模型的大小足夠,那麼應當可以完美地拟合訓練資料。如果當你發現沒有辦法完美拟合訓練集,假如優化過程沒有問題,那麼很大的可能性是訓練資料中存在自相沖突的資料,比如同樣一張圖在訓練集出現多次,并且每次的label又各自不同。語言模型往往很難完美拟合訓練集也是類似的原因,就是不同的詞卻有相同的(或極相似的的)上下文。提升驗證集的效果最直接效果最好的辦法就是在訓練集中增加更多的各式各樣的與驗證集類的資料。

這個聽上去像廢話,這裡強調一下是希望大家時刻記住條件允許的時候,這總是應該最先考慮的努力方向;其次,依據關注的問題不同,各式各樣的資料增強往往對結果也會帶來很大的提升。除去上面兩種,那麼接下來可以考慮各種正則化方法。先講兩種比較容易被大家忽視的正則化。

首先,盡可能在每輪的訓練中徹底地shuffle訓練資料,這會帶來一定的正則化效果(特别是在到處有batch

normalization的網絡,充分的shuffle可以避免某些資料總是出現在同一個mini-batch),其次,在訓練效率和問題本身允許的情況下,盡量嘗試更小的mini-batch。小的mini-batch可以使得sgd的過程中産生很多對模型推廣有益的噪聲。此外,dropout、weight

decay都應該嘗試,也可以适當的調整他們的參數。這些的調整,對于驗證集的結果提升往往比較有限。

最後,對于那些離散的長尾輸入資料(比如一些語言相關的輸入),也可以考慮在輸入層的參數上加入l1正則化。

本文作者:大牛講堂

繼續閱讀