[深度学习] 权重初始化--Weight Initialization
深度學(xué)習(xí)中的weight initialization對(duì)模型收斂速度和模型質(zhì)量有重要影響!
- 在ReLU activation function中推薦使用Xavier Initialization的變種,暫且稱(chēng)之為He Initialization:
- 使用Batch Normalization Layer可以有效降低深度網(wǎng)絡(luò)對(duì)weight初始化的依賴(lài):
實(shí)驗(yàn)代碼請(qǐng)參見(jiàn)我的Github。
背景
深度學(xué)習(xí)模型訓(xùn)練的過(guò)程本質(zhì)是對(duì)weight(即參數(shù) W)進(jìn)行更新,這需要每個(gè)參數(shù)有相應(yīng)的初始值。有人可能會(huì)說(shuō):“參數(shù)初始化有什么難點(diǎn)?直接將所有weight初始化為0或者初始化為隨機(jī)數(shù)!” 對(duì)一些簡(jiǎn)單的機(jī)器學(xué)習(xí)模型,或當(dāng)optimization function是convex function時(shí),這些簡(jiǎn)單的方法確實(shí)有效。然而對(duì)于深度學(xué)習(xí)而言,非線性函數(shù)被瘋狂疊加,產(chǎn)生如本文題圖所示的non-convex function,如何選擇參數(shù)初始值便成為一個(gè)值得探討的問(wèn)題 --- 其本質(zhì)是初始參數(shù)的選擇應(yīng)使得objective function便于被優(yōu)化。事實(shí)上,在學(xué)術(shù)界這也是一個(gè)被actively研究的領(lǐng)域。
TLDR里已經(jīng)涵蓋了本文的核心要點(diǎn),下面在正文中,我們來(lái)深入了解一下前因后果。
初始化為0的可行性?
答案是不可行。 這是一道送分題 哈哈!為什么將所有W初始化為0是錯(cuò)誤的呢?是因?yàn)槿绻械膮?shù)都是0,那么所有神經(jīng)元的輸出都將是相同的,那在back propagation的時(shí)候同一層內(nèi)所有神經(jīng)元的行為也是相同的 --- gradient相同,weight update也相同。這顯然是一個(gè)不可接受的結(jié)果。
可行的幾種初始化方式
- pre-training
pre-training是早期訓(xùn)練神經(jīng)網(wǎng)絡(luò)的有效初始化方法,一個(gè)便于理解的例子是先使用greedy layerwise auto-encoder做unsupervised pre-training,然后再做fine-tuning。具體過(guò)程可以參見(jiàn)UFLDL的一個(gè)tutorial,因?yàn)檫@不是本文重點(diǎn),就在這里簡(jiǎn)略的說(shuō)一下:(1)pre-training階段,將神經(jīng)網(wǎng)絡(luò)中的每一層取出,構(gòu)造一個(gè)auto-encoder做訓(xùn)練,使得輸入層和輸出層保持一致。在這一過(guò)程中,參數(shù)得以更新,形成初始值(2)fine-tuning階段,將pre-train過(guò)的每一層放回神經(jīng)網(wǎng)絡(luò),利用pre-train階段得到的參數(shù)初始值和訓(xùn)練數(shù)據(jù)對(duì)模型進(jìn)行整體調(diào)整。在這一過(guò)程中,參數(shù)進(jìn)一步被更新,形成最終模型。
隨著數(shù)據(jù)量的增加以及activation function (參見(jiàn)我的另一篇文章) 的發(fā)展,pre-training的概念已經(jīng)漸漸發(fā)生變化。目前,從零開(kāi)始訓(xùn)練神經(jīng)網(wǎng)絡(luò)時(shí)我們也很少采用auto-encoder進(jìn)行pre-training,而是直奔主題做模型訓(xùn)練。不想從零開(kāi)始訓(xùn)練神經(jīng)網(wǎng)絡(luò)時(shí),我們往往選擇一個(gè)已經(jīng)訓(xùn)練好的在任務(wù)A上的模型(稱(chēng)為pre-trained model),將其放在任務(wù)B上做模型調(diào)整(稱(chēng)為fine-tuning)。
- random initialization
隨機(jī)初始化是很多人目前經(jīng)常使用的方法,然而這是有弊端的,一旦隨機(jī)分布選擇不當(dāng),就會(huì)導(dǎo)致網(wǎng)絡(luò)優(yōu)化陷入困境。下面舉幾個(gè)例子。
核心代碼見(jiàn)下方,完整代碼請(qǐng)參見(jiàn)我的Github。
data = tf.constant(np.random.randn(2000, 800)) layer_sizes = [800 - 50 * i for i in range(0,10)] num_layers = len(layer_sizes)fcs = [] # To store fully connected layers' output for i in range(0, num_layers - 1):X = data if i == 0 else fcs[i - 1]node_in = layer_sizes[i]node_out = layer_sizes[i + 1]W = tf.Variable(np.random.randn(node_in, node_out)) * 0.01 fc = tf.matmul(X, W)fc = tf.nn.tanh(fc)fcs.append(fc)這里我們創(chuàng)建了一個(gè)10層的神經(jīng)網(wǎng)絡(luò),非線性變換為tanh,每一層的參數(shù)都是隨機(jī)正態(tài)分布,均值為0,標(biāo)準(zhǔn)差為0.01。下圖給出了每一層輸出值分布的直方圖。
隨著層數(shù)的增加,我們看到輸出值迅速向0靠攏,在后幾層中,幾乎所有的輸出值都很接近0!回憶優(yōu)化神經(jīng)網(wǎng)絡(luò)的back propagation算法,根據(jù)鏈?zhǔn)椒▌t,gradient等于當(dāng)前函數(shù)的gradient乘以后一層的gradient,這意味著輸出值是計(jì)算gradient中的乘法因子,直接導(dǎo)致gradient很小,使得參數(shù)難以被更新!
讓我們將初始值調(diào)大一些:
W = tf.Variable(np.random.randn(node_in, node_out))均值仍然為0,標(biāo)準(zhǔn)差現(xiàn)在變?yōu)?,下圖是每一層輸出值分布的直方圖:
幾乎所有的值集中在-1或1附近,神經(jīng)元saturated了!注意到tanh在-1和1附近的gradient都接近0,這同樣導(dǎo)致了gradient太小,參數(shù)難以被更新。
- Xavier initialization
Xavier initialization可以解決上面的問(wèn)題!其初始化方式也并不復(fù)雜。Xavier初始化的基本思想是保持輸入和輸出的方差一致,這樣就避免了所有輸出值都趨向于0。注意,為了問(wèn)題的簡(jiǎn)便,Xavier初始化的推導(dǎo)過(guò)程是基于線性函數(shù)的,但是它在一些非線性神經(jīng)元中也很有效。讓我們?cè)囈幌?#xff1a;
W = tf.Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in)Woohoo!輸出值在很多層之后依然保持著良好的分布,這很有利于我們優(yōu)化神經(jīng)網(wǎng)絡(luò)!之前談到Xavier initialization是在線性函數(shù)上推導(dǎo)得出,這說(shuō)明它對(duì)非線性函數(shù)并不具有普適性,所以這個(gè)例子僅僅說(shuō)明它對(duì)tanh很有效,那么對(duì)于目前最常用的ReLU神經(jīng)元呢(關(guān)于不同非線性神經(jīng)元的比較請(qǐng)參考這里)?繼續(xù)做一下實(shí)驗(yàn):
W = tf.Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in) ...... fc = tf.nn.relu(fc)前面看起來(lái)還不錯(cuò),后面的趨勢(shì)卻是越來(lái)越接近0。幸運(yùn)的是,He initialization可以用來(lái)解決ReLU初始化的問(wèn)題。
- He initialization
He initialization的思想是:在ReLU網(wǎng)絡(luò)中,假定每一層有一半的神經(jīng)元被激活,另一半為0,所以,要保持variance不變,只需要在Xavier的基礎(chǔ)上再除以2:
W = tf.Variable(np.random.randn(node_in,node_out)) / np.sqrt(node_in/2) ...... fc = tf.nn.relu(fc)看起來(lái)效果非常好,推薦在ReLU網(wǎng)絡(luò)中使用!
Batch Normalization Layer
Batch Normalization是一種巧妙而粗暴的方法來(lái)削弱bad initialization的影響,其基本思想是:If you want it, just make it!
我們想要的是在非線性activation之前,輸出值應(yīng)該有比較好的分布(例如高斯分布),以便于back propagation時(shí)計(jì)算gradient,更新weight。Batch Normalization將輸出值強(qiáng)行做一次Gaussian Normalization和線性變換:
Batch Normalization中所有的操作都是平滑可導(dǎo),這使得back propagation可以有效運(yùn)行并學(xué)到相應(yīng)的參數(shù),。需要注意的一點(diǎn)是Batch Normalization在training和testing時(shí)行為有所差別。Training時(shí)和由當(dāng)前batch計(jì)算得出;在Testing時(shí)和應(yīng)使用Training時(shí)保存的均值或類(lèi)似的經(jīng)過(guò)處理的值,而不是由當(dāng)前batch計(jì)算。
隨機(jī)初始化,無(wú)Batch Normalization:
W = tf.Variable(np.random.randn(node_in, node_out)) * 0.01 ...... fc = tf.nn.relu(fc)隨機(jī)初始化,有Batch Normalization:
W = tf.Variable(np.random.randn(node_in, node_out)) * 0.01 ...... fc = tf.contrib.layers.batch_norm(fc, center=True, scale=True,is_training=True) fc = tf.nn.relu(fc)很容易看到,Batch Normalization的效果非常好,推薦使用!
參考資料
Xavier initialization是由Xavier Glorot et al.在2010年提出,He initialization是由Kaiming He et al.在2015年提出,Batch Normalization是由Sergey Ioffe et al.在2015年提出。
另有知乎網(wǎng)友在評(píng)論中提到了一些其他相關(guān)工作:https://arxiv.org/abs/1511.06422, https://arxiv.org/pdf/1702.08591.pdf
原文: https://www.leiphone.com/news/201703/3qMp45aQtbxTdzmK.html
總結(jié)
以上是生活随笔為你收集整理的[深度学习] 权重初始化--Weight Initialization的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: win10更新中断怎么办 win10更新
- 下一篇: TensorFlow和深度学习-无需博士