Pytorch 4.8 梯度爆炸和梯度消失以及解決的辦法


梯度爆炸/消失

梯度消失 : 參數更新過小,在每次更新時幾乎不會移動,導致模型無法學習。

%matplotlib inline  
import torch 
from d2l import torch as d2l 
# 梯度消失  參數更新過小,在每次更新時幾乎不會移動,導致模型無法學習
x = torch.arange(-8.0, 8.0, 0.1, requires_grad=True)
y = torch.sigmoid(x)
y.backward(torch.ones_like(x)) 
d2l.plot(x.detach().numpy(),[y.detach().numpy(),x.grad.numpy()],legend=["Sigmoid","Grad"],figsize=(4.5,2.5))

梯度爆炸 : 參數更新過大,破壞了模型的穩定收斂。

M = torch.normal(0, 1, size=(4,4))
print('一個矩陣 \n',M)
for i in range(100):
    M = torch.mm(M,torch.normal(0, 1, size=(4, 4)))

print('乘以100個矩陣后\n', M)
[out]:一個矩陣
 tensor([[ 0.7392, -0.7381,  0.1063,  0.5866],
        [-0.0302, -1.4010,  0.2725, -0.3175],
        [-1.9900, -1.1248,  1.7442,  1.3487],
        [-0.5263,  0.5572,  0.2403,  0.6967]])
乘以100個矩陣后
 tensor([[ 1.4398e+25, -4.8513e+24, -2.9295e+23, -2.8513e+24],
        [ 1.3503e+25, -4.5497e+24, -2.7475e+23, -2.6741e+24],
        [-1.8323e+25,  6.1736e+24,  3.7281e+23,  3.6285e+24],
        [-1.4487e+25,  4.8811e+24,  2.9476e+23,  2.8689e+24]])

具體的可以參考沐神D2l文章:http://zh.d2l.ai/chapter_multilayer-perceptrons/numerical-stability-and-init.html#id5

對於沐神所說的改變權重的順序或者重排列,不能夠改善梯度爆炸和梯度消失。這里是因為改變權重順序或者重排列只是讓我們的MLP換了另外一種線性表達,本質上還是線性。為了讓訓練更加穩定,我們有很多種方法可以限制梯度:

  1. 把梯度限制在一定的范圍內。
  2. 將乘法變成加法: ResNet , LSTM
  3. 歸一化: 梯度歸一化。梯度裁剪。
  4. 合理權重初始化和激活函數。

其中一個比較不錯的權重初始化的方式是Xavier。

Xavier初始化

解決(或至少減輕)上述問題的一種方法是進行參數初始化, 優化期間的注意和適當的正則化也可以進一步提高穩定性。
讓我們看看某些沒有非線性的全連接層輸出(例如,隱藏變量)\(o_i\) 的尺度分布。 對於該層 \(n_{in}\) 輸入 \(x_j\) 及其相關權重 \(w_{ij}\) ,輸出由下式給出

\[o_{i} = \sum_{j=1}^{n_\mathrm{in}} w_{ij} x_j \]

權重 \(w_{ij}\) 都是從同一分布中獨立抽取的。 此外,讓我們假設該分布具有零均值和方差 \(σ^2\) 。 請注意,這並不意味着分布必須是高斯的,只是均值和方差需要存在。 現在,讓我們假設層 \(x_j\) 的輸入也具有零均值和方差 \(γ^2\) , 並且它們獨立於 \(w_{ij}\) 並且彼此獨立。 在這種情況下,我們可以按如下方式計算 \(o_i\) 的平均值和方差:

\[\begin{split}\begin{aligned} E[o_i] & = \sum_{j=1}^{n_\mathrm{in}} E[w_{ij} x_j] \\&= \sum_{j=1}^{n_\mathrm{in}} E[w_{ij}] E[x_j] \\&= 0, \\ \mathrm{Var}[o_i] & = E[o_i^2] - (E[o_i])^2 \\ & = \sum_{j=1}^{n_\mathrm{in}} E[w^2_{ij} x^2_j] - 0 \\ & = \sum_{j=1}^{n_\mathrm{in}} E[w^2_{ij}] E[x^2_j] \\ & = n_\mathrm{in} \sigma^2 \gamma^2. \end{aligned}\end{split}\]

保持方差不變的一種方法是設置 \(n_{in}σ^2=1\) 。 現在考慮反向傳播過程,我們面臨着類似的問題,盡管梯度是從更靠近輸出的層傳播的。 使用與前向傳播相同的推斷,我們可以看到,除非 \(n_{out}σ^2=1\) , 否則梯度的方差可能會增大,其中 \(n_{out}\) 是該層的輸出的數量。 這使得我們進退兩難:我們不可能同時滿足這兩個條件。 相反,我們只需滿足:

\[\begin{aligned} \frac{1}{2} (n_\mathrm{in} + n_\mathrm{out}) \sigma^2 = 1 \text{ 或等價於 } \sigma = \sqrt{\frac{2}{n_\mathrm{in} + n_\mathrm{out}}}. \end{aligned}\]

通常,Xavier初始化從均值為零,方差 \(\sigma^2 = \frac{2}{n_\mathrm{in} + n_\mathrm{out}}\) 的高斯分布中采樣權重。我們也可以利用Xavier的直覺來選擇從均勻分布中抽取權重時的方差。 注意均勻分布 \(U(−a,a)\) 的方差為 \(\frac{a^2}{3}\) 。 將 \(\frac{a^2}{3}\) 代入到 \(\sigma^2\) 的條件中,將得到初始化值域:

\[U\left(-\sqrt{\frac{6}{n_\mathrm{in} + n_\mathrm{out}}}, \sqrt{\frac{6}{n_\mathrm{in} + n_\mathrm{out}}}\right) \]

盡管在上述數學推理中,“不存在非線性”的假設在神經網絡中很容易被違反, 但Xavier初始化方法在實踐中被證明是有效的。

最后做個總結的話就是:

  1. 需要用啟發式的初始化方法來確保初始梯度既不太大也不太小。
  2. ReLU激活函數緩解了梯度消失問題,這樣可以加速收斂。
  3. 隨機初始化是保證在進行優化前打破對稱性的關鍵。
  4. Xavier初始化表明,對於每一層,輸出的方差不受輸入數量的影響,任何梯度的方差不受輸出數量的影響。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM