【DL碎片1】神經(jīng)網(wǎng)絡(luò)參數(shù)初始化的學(xué)問

我們已經(jīng)知道,神經(jīng)網(wǎng)絡(luò)的參數(shù)主要是權(quán)重(weights):W, 和偏置項(xiàng)(bias):b。
訓(xùn)練神經(jīng)網(wǎng)絡(luò)的時(shí)候需先給定一個(gè)初試值,才能夠訓(xùn)練,然后一點(diǎn)點(diǎn)地更新,但是不同的初始化方法,訓(xùn)練的效果可能會(huì)截然不同。本文主要記錄一下不同的初始化的方法,以及相應(yīng)的效果。

筆者正在學(xué)習(xí)的Andrew Ng的DeepLearning.ai提供了相應(yīng)的模型框架和數(shù)據(jù),我們這里要自己設(shè)置的就是不同的初值。

數(shù)據(jù)可視化之后是這樣的:


數(shù)據(jù)集

我們需要做的就是把上面的紅點(diǎn)和藍(lán)點(diǎn)分類。

一、直接把參數(shù)都初始化為0

這是大家可以想到的最簡單的方法,也確實(shí)很多其他的地方都采用0初值,那神經(jīng)網(wǎng)絡(luò)中這樣做是否可行呢?
在python中,可以用np.zeros((維度)) 來給一個(gè)向量/矩陣賦值0,
于是,對(duì)于L層神經(jīng)網(wǎng)絡(luò),可這樣進(jìn)行0-initialization:

for l in range(1,L): #總共L層,l為當(dāng)前層
    W = np.zeros((num_of_dim[l],num_of_dim[l-1])) # W的維度是(當(dāng)前層單元數(shù),上一層單元數(shù))
    b = np.zeros((num_of_dim[l],1)) # b的維度是(當(dāng)前層單元數(shù),1)

通過這樣的初值,我們r(jià)un一下模型,得到的cost-iteration曲線以及在訓(xùn)練集、測(cè)試集上面的準(zhǔn)確率如下:


可以發(fā)現(xiàn),壓根就沒訓(xùn)練!得到的模型跟瞎猜沒有區(qū)別。

為什么呢?

我們看看神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)圖:

3層神經(jīng)網(wǎng)絡(luò)

這是一個(gè)3層神經(jīng)網(wǎng)絡(luò),可以看出,神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)是十分對(duì)稱的,不管有幾層。
當(dāng)我們把所有的參數(shù)都設(shè)成0的話,那么上面的每一條邊上的權(quán)重就都是0,那么神經(jīng)網(wǎng)絡(luò)就還是對(duì)稱的,對(duì)于同一層的每個(gè)神經(jīng)元,它們就一模一樣了。
這樣的后果是什么呢?我們知道,不管是哪個(gè)神經(jīng)元,它的前向傳播和反向傳播的算法都是一樣的,如果初始值也一樣的話,不管訓(xùn)練多久,它們最終都一樣,都無法打破對(duì)稱(fail to break the symmetry),那每一層就相當(dāng)于只有一個(gè)神經(jīng)元,最終L層神經(jīng)網(wǎng)絡(luò)就相當(dāng)于一個(gè)線性的網(wǎng)絡(luò),如Logistic regression,線性分類器對(duì)我們上面的非線性數(shù)據(jù)集是“無力”的,所以最終訓(xùn)練的結(jié)果就瞎猜一樣。

因此,我們決不能把所有參數(shù)初始化為0,同樣也不能初始化為任何相同的值,因?yàn)槲覀儽仨殹?strong>打破對(duì)稱性”!

二、隨機(jī)初始化

好,不用0,咱們隨機(jī)給一批值總可以吧。確實(shí)可以!咱們看看:
【下面的演示會(huì)試試多種參數(shù)或超參數(shù),為了方便大家看,我分4步:①②③④】

①隨機(jī)初始化

python中,隨機(jī)初始化可以用 np.random.randn(維度) 來隨機(jī)賦值:
于是前面的代碼改成:

for l in range(1,L): #總共L層,l為當(dāng)前層
    W = np.random.randn(num_of_dim[l],num_of_dim[l-1]) # W的維度是(當(dāng)前層單元數(shù),上一層單元數(shù))
    b = np.zeros((num_of_dim[l],1)) # b的維度是(當(dāng)前層單元數(shù),1)

這里有三點(diǎn)需要說明一下:

  1. b不用隨機(jī)初始化,因?yàn)閣隨機(jī)之后,已經(jīng)打破對(duì)稱,b就一個(gè)常數(shù),無所謂了
  2. random.rand()是在0~1之間隨機(jī),random.randn()是標(biāo)準(zhǔn)正態(tài)分布中隨機(jī),有正有負(fù)
  3. np.zeros(())這里是兩個(gè)括號(hào),random.randn()是一個(gè)括號(hào),奇怪的很,就記著吧

那看看run出來的效果如何呢:


效果明顯比0初始化要好多了,cost最后降的也比較低,準(zhǔn)確率也不錯(cuò),92%。給分類效果可視化:


我們接著試試,如果把隨機(jī)初始化的值放大一點(diǎn)會(huì)出現(xiàn)什么:

②放大版隨機(jī)初始化

for l in range(1,L): #總共L層,l為當(dāng)前層
    W = np.random.randn(num_of_dim[l],num_of_dim[l-1])*10 # W的維度是(當(dāng)前層單元數(shù),上一層單元數(shù))
    b = np.zeros((num_of_dim[l],1)) # b的維度是(當(dāng)前層單元數(shù),1)

上面的代碼中,我們給W最后多乘以10,run的效果:
【注意啊,乘以10不一定就是變大,因?yàn)槲覀兊膚的隨機(jī)取值可正可負(fù),所以乘以10之后,正數(shù)更大,負(fù)數(shù)更小】


咦~~ 真o心 ~~

準(zhǔn)確率明顯降低了許多,到86%。

為什么把隨機(jī)初始化的值放大就不好了呢?

我們看看神經(jīng)網(wǎng)絡(luò)中常用的sigmoid函數(shù):

sigmoid function

這家伙,中間的斜率大,兩邊的斜率小還趨于零。所以當(dāng)我們把隨機(jī)的值乘以10了之后,我們的初值會(huì)往兩邊跑,那么我們的梯度下降就會(huì)顯著變慢,可能迭代半天,才下降一點(diǎn)點(diǎn)。

這就是問題的癥結(jié)。

我們上面的實(shí)驗(yàn),可以從圖的橫坐標(biāo)看出,都是設(shè)定的一樣的迭代次數(shù)(iteration number):15000次,因此,在相同的迭代次數(shù)下,放大版的隨機(jī)初始化的模型的學(xué)習(xí)就像一個(gè)“笨學(xué)生”,沒別人學(xué)的多,因此效果就更差。

為了驗(yàn)證我說的,我們可以試試吧迭代次數(shù)加大,看看我說的是不是對(duì)的:

③增大迭代次數(shù)

測(cè)試了好久。。。
然后打臉了。。。

不過還是值得玩味~~

我把迭代次數(shù)顯示設(shè)為60000,也就是增大了4,5倍,結(jié)果cost function后來下降十分十分緩慢,最后效果還不如之前的。然后我再把迭代次數(shù)增加到了160000,相當(dāng)于比一開始增大了10倍多,結(jié)果....


可以看到,cost基本從20000次迭代之后就穩(wěn)定了,怎么都降不下去了,實(shí)際上是在降低,但是十分十分十分X10地緩慢。難道這就是傳說中的梯度消失???
所以結(jié)果并沒有我想象地把迭代次數(shù)加大,就可以解決這個(gè)問題,實(shí)際上,可以看到,在訓(xùn)練集上準(zhǔn)確度確實(shí)上升了,所以說明確實(shí)模型有所改進(jìn),只不過改進(jìn)的太緩慢,相當(dāng)于沒有改進(jìn)。

仔細(xì)分析了一下,由于W太大或者太小,導(dǎo)致激活函數(shù)對(duì)w的倒數(shù)趨于零,那么計(jì)算cost對(duì)w的導(dǎo)數(shù)也會(huì)趨于零,所以下降如此緩慢也是可以理解。

好,放大的效果如此差,我們縮小試試?

④縮小版隨機(jī)初始化

還是回到迭代14000次,這次把w除以10看看:

嘿~縮小結(jié)果甚至更差!連圈圈都沒有了。

上面這個(gè)圖,說明學(xué)習(xí)到的模型太簡單了,因?yàn)槲覀儼?strong>w都除以10,實(shí)際上就接近0了,深度學(xué)習(xí)中我們認(rèn)為參數(shù)越大,模型越復(fù)雜;參數(shù)越小,模型越簡單。所以除以10之后,參數(shù)太小了,模型就too simple了,效果當(dāng)然不好。

最后再試一次吧,再多的話大家都煩了我也煩了。

上面乘以10和除以10,效果都很差,那我們?cè)囈粋€(gè)中間的,比如:除以3(真的是隨便試試)


好了好了,終于提高了!這個(gè)準(zhǔn)確率是目前的最高水平了!

可見,只要找到一個(gè)恰當(dāng)?shù)闹祦砜s小,是可以提高準(zhǔn)確率的。但是,這里除以三是我拍腦門出來的,不能每次都這么一個(gè)個(gè)地試吧,有沒有一個(gè)穩(wěn)健的,通用的方法呢?

有!接著看:

三、何氏初試法(He Initialization)(不知道是不是何,我音譯的)

上面試了各種方法,放大縮小都不好,無法把握那個(gè)度。還好,總有大神為我們鋪路,論文He et al., 2015.中提出了一種方法,我們稱之為He Initialization,它就是在我們隨機(jī)初始化了之后,乘以

這樣就避免了參數(shù)的初始值過大或者過小,因此可以取得比較好的效果,代碼也很簡單,用np.sqrt()來求平方根:

for l in range(1,L): #總共L層,l為當(dāng)前層
    W = np.random.randn(num_of_dim[l],num_of_dim[l-1])**np.sqrt(2/num_of_dim[l-1]) # W的維度是(當(dāng)前層單元數(shù),上一層單元數(shù))
    b = np.zeros((num_of_dim[l],1)) # b的維度是(當(dāng)前層單元數(shù),1)

取得的效果如下:


嘖嘖嘖,看這效果,看這優(yōu)美的損失曲線,看著卓越的準(zhǔn)確率... ...

以后就用你了,He Initialization !

其實(shí)吧,He Initialization是推薦針對(duì)使用ReLU激活函數(shù)的神經(jīng)網(wǎng)絡(luò)使用的,不過對(duì)其他的激活函數(shù),效果也不錯(cuò)。

還有其他的類似的一些好的初始化方法,例如:

推薦給sigmoid的Xavier Initialization:隨機(jī)化之后乘以

總結(jié)一下:

  • 神經(jīng)網(wǎng)絡(luò)不可用0來初始化參數(shù)!
  • 隨機(jī)賦值是為了打破對(duì)稱性,使得不同的神經(jīng)元可以有不同的功能
  • 推薦在初始化的時(shí)候使用He Initialization

我的其他[深度學(xué)習(xí)筆記]文章:
【DL筆記1】Logistic回歸:最基礎(chǔ)的神經(jīng)網(wǎng)絡(luò)
【DL筆記2】神經(jīng)網(wǎng)絡(luò)編程原則&Logistic Regression的算法解析
如果覺得寫的不錯(cuò),隨手點(diǎn)個(gè)贊吧!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容