梯度爆炸與梯度消失
![梯度消失梯度爆炸-Gradient Clip](http://p2.ttnews.xyz/loading.gif)
實際現象: 當我們使用sigmoid function作為激活函數時,隨著神經網絡的隱藏層數增加,訓練誤差反而增大,造成了深度網絡的不穩定。
梯度彌散: 靠近輸出層的hidden layer 梯度大,參數更新更快,所以很快就會收斂。而靠近輸入層的hidden layer梯度小,參數更新慢,幾乎和初始狀態一樣,隨機分佈。
梯度爆炸: 當前面hidden layer的梯度通過訓練變大,而後面的梯度將會指數級增大。
現象原因: sigmoid函數會將[+∞,-∞]的輸入壓縮到[0,1],導致當輸入更新時,輸出的更新會很小。在這種情況下,就會隨著隱藏層數的增加,反向傳遞時,數值更新將會越來越小。
解決方法:
- Relu函數代換Sigmoid函數。
- 逐層貪婪預訓練,如同訓練自編碼器的過程,每次只訓練一層參數。由於得到的參數將會是局部最優,所以需要對整個網絡再進行調優。
- 梯度減切Gradient Clip。設置一個梯度減切的閾值,如果在更新梯度的時候,梯度超過這個閾值,則會將其限制在這個範圍之內,防止梯度爆炸。
- 正則。對參數加入正則規範,限制參數範數過大。
- 加入batch normalization層。
- 加入殘差結構。
- LSTM層由於有記憶,可以緩解梯度消失的發生。
Gradient Clip
簡述
該方法簡單,但是粗暴,閾值人為定義。設置上界閾值,面對梯度爆炸,設置下界閾值,也可以用於梯度消失。
梯度爆炸解釋
在一個只有一個隱藏節點的網絡中,損失函數和權值w偏置b構成error surface,宛如一堵牆,如下圖所示:
![梯度消失梯度爆炸-Gradient Clip](http://p2.ttnews.xyz/loading.gif)
損失函數每次迭代都是每次一小步,但是當遇到這堵牆時,在牆上的某點計算梯度,梯度會瞬間增大,指向某處不理想的位置。如果我們將大梯度縮放,就可以把該梯度的誤導控制在可接受範圍內,如虛線箭頭所示。
算法步驟
- 設置梯度閾值threshold
- 求出梯度的L2範數||g||。
- 比較||g||與threshold的大小。
- 如果||g||大於threshold,則求threshold/||g||得到縮放因子。
- 將梯度乘上縮放因子得到最終的梯度。
效果實驗
無gradient clip:模型在2000次迭代出發生了梯度爆炸。
有gradient clip:可以發現clip_gradient在前期有效了控制了梯度爆炸的影響,使得最終的loss能下降到滿意的結果
Tensorflow and Pytorch GradientClip
Tensorflow
<code># 1. 計算局部範數(快)
tf.clip_by_norm(grads, clip_norm=5)
# 2. 計算全局範數(慢)
tf.clip_by_global_norm(grads, clip_norm=5)
# 計算所有梯度的平方和global_norm,
# 如果梯度平方和global_norm 超過我們指定的clip_norm,
# 那麼就對梯度進行縮放;否則就按照原本的計算結果,/<code>
Pytorch
<code># 這個函數計算的是全局梯度範數
torch.nn.utils.clip_grad_norm(parameters=model.parameters(), max_norm=5, norm_type=2)
# parameters: an iterable of Variables that will have gradients normalized
# max_norm: max norm of the gradients(閾值設定)
# norm_type: type of the used p-norm. Can be'inf'for infinity norm(定義範數類型)/<code>
Keras
<code>from keras import optimizers
# 所有參數梯度將被裁剪,讓其l2範數最大為1:g * 1 / max(1, l2_norm)
sgd = optimizers.SGD(lr=0.01, clipnorm=1.)
# 所有參數d 梯度將被裁剪到數值範圍內:
# 最大值0.5
# 最小值-0.5
sgd = optimizers.SGD(lr=0.01, clipvalue=0.5)/<code>
閱讀更多 量子AI 的文章