目錄
- 為什么要初始化
- 公式推導
- 初始化方法
- 引入激活函數
-
初始化方法分類
一、為什么要初始化
在深度學習中,神經網絡的權重初始化方法(weight initialization)對模型的收斂速度和性能有着至關重要的影響。簡單而言:神經網絡其實就是對權重參數w的不停迭代更新,以期達到較好的性能。但隨着層數的增多,極易出現梯度消失或者梯度爆炸。因此,對權重w的初始化則顯得至關重要,一個好的權重初始化雖然不能完全解決梯度消失和梯度爆炸的問題,但是對於處理這兩個問題是有很大的幫助的,並且十分有利於模型性能和收斂速度。
一般地,假定輸入的每個特征是服從均值為0,方差為1的分布(一般輸入到神經網絡的數據都是要做歸一化的,就是為了達到這個條件)。為了使網絡中的信息更好的傳遞,每一層的特征的方差應該盡可能相等,如果保證這個特征的方差是相等的呢。我們可以從初始化的權重值入手。
二、公式推導
為了使網絡中的信息更好的傳遞,每一層的特征的方差應該盡可能相等,基於此,可以分析每一層的網絡初始化的權重應該滿足哪些條件。首先來做一個公式推導:

在這里假定了x的均值為0,對於初始化的權重通常均值也是選擇0,因此上面的式子可以轉換成
![]()
又因為x中每個特征我們都假定方差為1,因此上面的式子可以改寫成
![]()
現在要使得var(s)=1,則有
![]()

為了確保量綱和期望一致,我們將方差轉換成標准差,因此要確保標准差為1/√n
三、初始化方法
現在我們來看看每種方法初始化時我們該如何設置方差能保證輸入的分布狀態不變。
3.1 均勻分布
對於均勻分布U(a,b),其期望和方差分別為
![]()
假定均勻分布為
![]()
在這里d為神經元的個數,則有期望和方差為
![]()
根據代入到下面表達式中,
![]()
可以得到:
![]()
因此為了保證最終的方差為1,因此方差需要乘以3,標准差則需要乘以√3。因此一般均勻分布的初始化值可以選擇
![]()
在在xavier uniform init(也稱glorot uniform,是2010年Xavier glorot發明的),在tensorflow中有對飲的API: tf.glorot_uniform_initializer()方法中初始化值為如下,在一個二維矩陣中din,dout分別表示矩陣的第一個維度和第二個維度。
![]()
1)舉例說明——tf.random_uniform_initializer()

2)舉例說明——tf.glorot_uniform_initializer()

3.2 正態分布
正態分布會直接給出期望和標准差,所以這個不用多說。為了保證var(s)=1,我們需要讓var(w)=1/d,則標准差為1/√d。
同樣還是從兩個方面來展示,第一個隨機取值,設置方差為:1/√d,xavier uniform init內部有定義,其標准差為:

1)舉例說明——tf.random_normal_initializer()

2)舉例說明——tf.glorot_normal_initializer()

3.3 常數初始化
常數初始化時期望為常數值n,方差為0。
1)舉例說明——tf.zeros_initializer()

2)舉例說明——tf.ones_initializer()

3)舉例說明——tf.constant_initializer()

從上面實驗可以看出,初始權重為0時,mean和VAR為0,無法有效計算;當取1或者常數時候,會較大變化。
四、引入激活函數
上面都是在線性運算的情況下的結果,但實際應用中都是要引入激活函數的,這樣神經網絡才具有更強的表達能力。如果引入激活函數會怎么樣?為了觀看效果,我們將網絡層數設置為100層,分別采用tf.random_normal_initializer()和tf.glorot_normal_initializer()。
1-1)舉例說明——tf.random_normal_initializer(),不加激活函數

1-2)舉例說明——tf.random_normal_initializer(),加tanh函數

1-3)舉例說明——tf.random_normal_initializer(),加relu函數

2-1)舉例說明——tf.glorot_normal_initializer(),不加激活函數

2-2)舉例說明——tf.glorot_normal_initializer(),加tanh函數

2-3)舉例說明——tf.glorot_normal_initializer(),加relu函數

3)舉例說明——tf.random_normal_initializer(stddev = (2/512)**0.5),加relu函數

實驗說明:
1、2-3實驗說明relu函數並不適用tf.glorot_normal_initializer(),1-3實驗說明初始化的tf.random_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)原型結合也不好,3實驗說明調整后的tf.random_normal_initializer有較好的效果。對於relu激活函數時,正態分布的標准差通常為

2、實驗出現NAN,表明有指數爆炸發生。
五、初始化方法分類
- 隨機初始化
- Xavier初始化:tf.glorot_normal_initializer()
- Kaiming初始化(he初始化):其實就是上一節中實驗3的部分:tf.random_normal_initializer(stddev = (2/512)**0.5)。
附件一:第三節實驗
import tensorflow as tf tf.reset_default_graph() #重置圖:刷新tensorflow的舊變量 x = tf.get_variable("x",shape = [256,512],initializer=tf.random_normal_initializer()) w = tf.get_variable("w",shape = [512,512],initializer=tf.glorot_normal_initializer) a = tf.matmul(x,w) mean,var = tf.nn.moments(a,axes = [0,1]) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(sess.run(mean)) print(sess.run(var))
附件二:第四章實驗3
import tensorflow as tf tf.reset_default_graph() #重置圖:刷新tensorflow的舊變量 x = tf.get_variable("x",shape = [512,512],initializer=tf.random_normal_initializer()) for i in range(100): with tf.variable_scope(str(i)): w = tf.get_variable("w",shape = [512,512],initializer=tf.random_normal_initializer(stddev = (2/512)**0.5)) x = tf.nn.relu(tf.matmul(x,w)) mean,var = tf.nn.moments(x,axes = [0,1]) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(sess.run(mean)) print(sess.run(var))
參考:
【1】初始化方法:https://www.cnblogs.com/jiangxinyang/p/11574049.html
【2】從最基本的方法到xavier、he初始化方法一路走來的歷程:https://zhuanlan.zhihu.com/p/86602524
