深度學習中的weight initialization對模型收斂速度和模型質量有重要影響!php
import numpy as np
W = np.random.randn(node_in, node_out) / np.sqrt(node_in / 2)
import tensorflow as tf
# put this before nonlinear transformation
layer = tf.contrib.layers.batch_norm(layer, center=True, scale=True,
is_training=True)
實驗代碼請參見個人Github。html
深度學習模型訓練的過程本質是對weight(即參數 W)進行更新,這須要每一個參數有相應的初始值。有人可能會說:「參數初始化有什麼難點?直接將全部weight初始化爲0或者初始化爲隨機數!」 對一些簡單的機器學習模型,或當optimization function是convex function時,這些簡單的方法確實有效。然而對於深度學習而言,非線性函數被瘋狂疊加,產生如本文題圖所示的non-convex function,如何選擇參數初始值便成爲一個值得探討的問題 --- 其本質是初始參數的選擇應使得objective function便於被優化。事實上,在學術界這也是一個被actively研究的領域。node
TLDR裏已經涵蓋了本文的核心要點,下面在正文中,咱們來深刻了解一下來龍去脈。python
答案是不可行。 這是一道送分題 哈哈!爲何將全部W初始化爲0是錯誤的呢?是由於若是全部的參數都是0,那麼全部神經元的輸出都將是相同的,那在back propagation的時候同一層內全部神經元的行爲也是相同的 --- gradient相同,weight update也相同。這顯然是一個不可接受的結果。git
pre-training是早期訓練神經網絡的有效初始化方法,一個便於理解的例子是先使用greedy layerwise auto-encoder作unsupervised pre-training,而後再作fine-tuning。具體過程能夠參見UFLDL的一個tutorial,由於這不是本文重點,就在這裏簡略的說一下:(1)pre-training階段,將神經網絡中的每一層取出,構造一個auto-encoder作訓練,使得輸入層和輸出層保持一致。在這一過程當中,參數得以更新,造成初始值(2)fine-tuning階段,將pre-train過的每一層放回神經網絡,利用pre-train階段獲得的參數初始值和訓練數據對模型進行總體調整。在這一過程當中,參數進一步被更新,造成最終模型。github
隨着數據量的增長以及activation function (參見個人另外一篇文章) 的發展,pre-training的概念已經漸漸發生變化。目前,從零開始訓練神經網絡時咱們也不多采用auto-encoder進行pre-training,而是直奔主題作模型訓練。不想從零開始訓練神經網絡時,咱們每每選擇一個已經訓練好的在任務A上的模型(稱爲pre-trained model),將其放在任務B上作模型調整(稱爲fine-tuning)。算法
隨機初始化是不少人目前常用的方法,然而這是有弊端的,一旦隨機分佈選擇不當,就會致使網絡優化陷入困境。下面舉幾個例子。網絡
核心代碼見下方,完整代碼請參見個人Github。app
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)
這裏咱們建立了一個10層的神經網絡,非線性變換爲tanh,每一層的參數都是隨機正態分佈,均值爲0,標準差爲0.01。下圖給出了每一層輸出值分佈的直方圖。dom
隨着層數的增長,咱們看到輸出值迅速向0靠攏,在後幾層中,幾乎全部的輸出值都很接近0!回憶優化神經網絡的back propagation算法,根據鏈式法則,gradient等於當前函數的gradient乘之後一層的gradient,這意味着輸出值是計算gradient中的乘法因子,直接致使gradient很小,使得參數難以被更新!
讓咱們將初始值調大一些:
W = tf.Variable(np.random.randn(node_in, node_out))
均值仍然爲0,標準差如今變爲1,下圖是每一層輸出值分佈的直方圖:
幾乎全部的值集中在-1或1附近,神經元saturated了!注意到tanh在-1和1附近的gradient都接近0,這一樣致使了gradient過小,參數難以被更新。
Xavier initialization能夠解決上面的問題!其初始化方式也並不複雜。Xavier初始化的基本思想是保持輸入和輸出的方差一致,這樣就避免了全部輸出值都趨向於0。注意,爲了問題的簡便,Xavier初始化的推導過程是基於線性函數的,可是它在一些非線性神經元中也頗有效。讓咱們試一下:
W = tf.Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in)
Woohoo!輸出值在不少層以後依然保持着良好的分佈,這頗有利於咱們優化神經網絡!以前談到Xavier initialization是在線性函數上推導得出,這說明它對非線性函數並不具備普適性,因此這個例子僅僅說明它對tanh頗有效,那麼對於目前最經常使用的ReLU神經元呢(關於不一樣非線性神經元的比較請參考這裏)?繼續作一下實驗:
W = tf.Variable(np.random.randn(node_in, node_out)) / np.sqrt(node_in)
......
fc = tf.nn.relu(fc)
前面看起來還不錯,後面的趨勢倒是愈來愈接近0。幸運的是,He initialization能夠用來解決ReLU初始化的問題。
He initialization的思想是:在ReLU網絡中,假定每一層有一半的神經元被激活,另外一半爲0,因此,要保持variance不變,只須要在Xavier的基礎上再除以2:
W = tf.Variable(np.random.randn(node_in,node_out)) / np.sqrt(node_in/2)
......
fc = tf.nn.relu(fc)
看起來效果很是好,推薦在ReLU網絡中使用!
Batch Normalization是一種巧妙而粗暴的方法來削弱bad initialization的影響,其基本思想是:If you want it, just make it!
咱們想要的是在非線性activation以前,輸出值應該有比較好的分佈(例如高斯分佈),以便於back propagation時計算gradient,更新weight。Batch Normalization將輸出值強行作一次Gaussian Normalization和線性變換:
Batch Normalization中全部的操做都是平滑可導,這使得back propagation能夠有效運行並學到相應的參數,。須要注意的一點是Batch Normalization在training和testing時行爲有所差異。Training時和由當前batch計算得出;在Testing時和應使用Training時保存的均值或相似的通過處理的值,而不是由當前batch計算。
隨機初始化,無Batch Normalization:
W = tf.Variable(np.random.randn(node_in, node_out)) * 0.01
......
fc = tf.nn.relu(fc)
隨機初始化,有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年提出。
另有知乎網友在評論中提到了一些其餘相關工做:https://arxiv.org/abs/1511.06422, https://arxiv.org/pdf/1702.08591.pdf
原文: https://www.leiphone.com/news/201703/3qMp45aQtbxTdzmK.html