👨🎓作者简介:一位即将上大四,正专攻机器学习的保研er
🌌上期文章:机器学习&&深度学习------Dropout
📚订阅专栏:机器学习&&深度学习
希望文章对你们有所帮助
这一部分包括了很多概率论和数学的知识,而书上的推导很少,这边会做个比较细致的讨论,数学基础不行就去补,不能拖,深入浅出的感觉是最让人感到心情愉悦的。
数值稳定性和模型初始化
梯度消失和梯度爆炸
一个具有L层、输入x和输出o的深层网络。每一层l由f定义,变换的参数权重为W^(l)^,其隐藏变量为h^(l)^(令h^(0)^=x)。则我们的网络可以定义为:
h ( l ) = f l ( h ( l − 1 ) ) 因此 o = f L ○ . . . ○ f 1 ( x ) h^{(l)}=f_l(h^{(l-1)})因此o=f_L○...○f_1(x) h(l)=fl(h(l−1))因此o=fL○...○f1(x)
若所有隐藏向量和输入都是向量,我们可以将o关于任何一组参数W^{(l)}^的梯度写为:
∂ h ( L − 1 ) h ( L ) ⋅ . . . ⋅ ∂ h ( l ) h ( l + 1 ) ∂ w ( l ) h ( l ) \partial_h(L-1)h^{(L)}·...·\partial_h(l)h^{(l+1)}\partial_w(l)h^{(l)} ∂h(L−1)h(L)⋅...⋅∂h(l)h(l+1)∂w(l)h(l)
换言之,该梯度是一个L-l个矩阵M^(L)^·...·M^(l+1)^与梯度向量v^{l}^的乘积。
这么多的乘积放在一起会出现严重的问题:可能会造成梯度的不稳定。要么是梯度爆炸:参数更新过大,破坏了模型的稳定收敛;要么是梯度消失:参数更新过小,在每次更新时几乎不会移动,导致模型无法学习。
梯度消失
sigmoid就是一个造成梯度消失的常见原因,我们可以绘制sigmoid函数以及它的导数函数观察:
python
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(gradient=torch.ones_like(x)) # 参与的参数是非标量的时候,就需要指定gradient为和x形状相同的全1向量(矩阵)
d2l.plot(x.detach().numpy(), [y.detach().numpy(), x.grad.numpy()],
legend=['sigmoid', 'gradient'], figsize=(4.5, 2.5))
d2l.plt.show()
如上图,当sigmoid函数的输入很大或者很小时梯度会消失。此外,当反向传播通过许多层时,除非函数的输入接近于0,否则整个成绩的梯度都可能会消失。因此,更稳定的ReLU系列函数已经成为从业者的默认选择(虽然在神经科学的角度看起来不太合理)。
梯度爆炸
梯度爆炸可能同样令人烦恼。 为了更好地说明这一点,我们生成100个高斯随机矩阵,并将它们与某个初始矩阵相乘。 对于我们选择的尺度(方差σ^2^=1),矩阵乘积发生爆炸。当这种情况是由于深度网络的初始化所导致时,我们没有机会让梯度下降优化器收敛。
python
import torch
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)
一个矩阵
tensor([[ 2.2266, 0.1844, -0.1071, -0.7712],
[-0.1580, -0.3028, -0.9375, -0.2922],
[ 0.0616, -1.1593, 1.8516, 1.6285],
[ 0.2703, -0.5483, -0.6187, -1.2804]])
乘以100个矩阵后
tensor([[ 1.3260e+25, -6.2655e+25, 1.2841e+25, 1.5429e+25],
[ 1.5770e+24, -7.4518e+24, 1.5273e+24, 1.8351e+24],
[ 8.5330e+23, -4.0321e+24, 8.2638e+23, 9.9294e+23],
[ 5.7656e+24, -2.7244e+25, 5.5837e+24, 6.7091e+24]])
让训练更加稳定
而如何让我们的训练更加稳定呢?也就是要避免掉梯度消失和梯度爆炸问题。
目标 :让梯度值在合理范围内,如[1e-6,1e3]
将乘法变加法 :ResNet,LSTM
归一化 :梯度归一化,梯度裁剪
合理的权重和激活函数(这是我们的重点)
参数初始化
减轻上面问题的一种方法就是进行参数初始化,优化期间的注意以及适当的正则化也可以使得训练更加的稳定。
讨论(各种概率论思维推导)
我们现在做一个假设:
(1)假设w都是独立同分布的,那么:
E [ w i , j t ] = 0 , D [ w i , j t ] = γ t 2 E[w_{i,j}^t]=0,D[w_{i,j}^t]=γ_t^2 E[wi,jt]=0,D[wi,jt]=γt2
(2)h^t-1^独立于w^t^(也就是层的权重与输入是无关的)
我们大胆假设此时没有激活函数,那么
h t = W t h t − 1 ,这里 W t ∈ R n t × n t − 1 h^t=W^th^{t-1},这里W^t∈R^{n_t×n_{t-1}} ht=Wtht−1,这里Wt∈Rnt×nt−1
则容易推出:
E [ h i t ] = E [ ∑ j w i , j t h j t − 1 ] = ∑ j E [ w i , j ] E [ h j t − 1 ] = 0 (独立同分布的推广) E[h_i^t]=E[\sum_jw_{i,j}^th_j^{t-1}]=\sum_jE[w_{i,j}]E[h_j^{t-1}]=0(独立同分布的推广) E[hit]=E[j∑wi,jthjt−1]=j∑E[wi,j]E[hjt−1]=0(独立同分布的推广)
此时我们分别计算正向方差与反向方差,并且让他们都相同。
正向方差
D [ h i t ] = E [ ( h i t ) 2 ] − E [ h i t ] 2 = E [ ( ∑ j w i , j t h j t − 1 ) 2 ] (前面假设过独立同分布那么 E [ h i t ] = 0 ) = E [ ∑ j ( w i , j t ) 2 ( h j t − 1 ) 2 + ∑ j ≠ k w i , j t w i , k t h j t − 1 h k t − 1 ] (这里就是 ( a + b + c + . . . ) 2 的计算方式) 由于独立同分布,所以 ∑ j ≠ k w i , j t w i , k t h j t − 1 h k t − 1 = 0 ,则 上式 = ∑ j E [ ( w i , j t ) 2 ] E [ ( h j t − 1 ) 2 ] = ∑ j ( E [ ( w i , j t ) 2 ] − E [ w i , j t ] 2 ) ( E [ ( h j t − 1 ) 2 ] − E [ h j t − 1 ] 2 ) (构造出 D ) = ∑ j D [ w i , j t ] D [ h j t − 1 ] = n t − 1 γ t 2 D [ h j t − 1 ] D[h_i^t]=E[(h_i^t)^2]-E[h_i^t]^2=E[(\sum_jw_{i,j}^th_j^{t-1})^2](前面假设过独立同分布那么E[h_i^t]=0)\\ =E[\sum_j(w_{i,j}^t)^2(h_j^{t-1})^2+\sum_{j≠k}w_{i,j}^tw_{i,k}^th_j^{t-1}h_k^{t-1}](这里就是(a+b+c+...)^2的计算方式)\\ 由于独立同分布,所以\sum_{j≠k}w_{i,j}^tw_{i,k}^th_j^{t-1}h_k^{t-1}=0,则\\ 上式=\sum_jE[(w_{i,j}^t)^2]E[(h_j^{t-1})^2]\\ =\sum_j(E[(w_{i,j}^t)^2]-E[w_{i,j}^t]^2)(E[(h_j^{t-1})^2]-E[h_j^{t-1}]^2)(构造出D)\\ =\sum_jD[w_{i,j}^t]D[h_j^{t-1}]=n_{t-1}γ_t^2D[h_j^{t-1}] D[hit]=E[(hit)2]−E[hit]2=E[(j∑wi,jthjt−1)2](前面假设过独立同分布那么E[hit]=0)=E[j∑(wi,jt)2(hjt−1)2+j=k∑wi,jtwi,kthjt−1hkt−1](这里就是(a+b+c+...)2的计算方式)由于独立同分布,所以j=k∑wi,jtwi,kthjt−1hkt−1=0,则上式=j∑E[(wi,jt)2]E[(hjt−1)2]=j∑(E[(wi,jt)2]−E[wi,jt]2)(E[(hjt−1)2]−E[hjt−1]2)(构造出D)=j∑D[wi,jt]D[hjt−1]=nt−1γt2D[hjt−1]
我们让t层输入的反差与输出的方差都是相同的,那么可以推出:
n t − 1 γ t 2 = 1 (其中 n t − 1 代表第 t 层输入的规模) n_{t-1}γ_t^2=1(其中n_{t-1}代表第t层输入的规模) nt−1γt2=1(其中nt−1代表第t层输入的规模)
其他层也是同理的。
反向方差
而反向和正向的情况就类似了,可以这么推导:
∂ l ∂ h t − 1 = ∂ l ∂ h t W t \frac{\partial l}{\partial h^{t-1}}=\frac{\partial l}{\partial h^t}W^t ∂ht−1∂l=∂ht∂lWt
分别取转置,得:
( ∂ l ∂ h t − 1 ) T = ( W t ) T ( ∂ l ∂ h t ) T (\frac{\partial l}{\partial h^{t-1}})^T=(W^t)^T(\frac{\partial l}{\partial h^t})^T (∂ht−1∂l)T=(Wt)T(∂ht∂l)T
依旧假设:
E [ ∂ l ∂ h i t − 1 ] = 0 E[\frac{\partial l}{\partial h_i^{t-1}}]=0 E[∂hit−1∂l]=0
则
D [ ∂ l ∂ h i t − 1 ] = n t γ t 2 D [ ∂ l ∂ h j t ] D[\frac{\partial l}{\partial h_i^{t-1}}]=n_tγ_t^2D[\frac{\partial l}{\partial h_j^t}] D[∂hit−1∂l]=ntγt2D[∂hjt∂l]
这时我们可以推出:
n t γ t 2 = 1 (其中 n t 代表第 t 层输出的规模) n_tγ_t^2=1(其中n_t代表第t层输出的规模) ntγt2=1(其中nt代表第t层输出的规模)
其他层也是同理的。
照着上面的方式推下去,我们最终整合起来的结论是
n t − 1 γ t 2 = 1 和 n t γ t 2 = 1 n_{t-1}γ_t^2=1和n_tγ_t^2=1 nt−1γt2=1和ntγt2=1
显然我们要满足上面的式子,当且仅当:
n t − 1 = n t n_{t-1}=n_t nt−1=nt
这并不容易满足,因为我们很难说对于一层中,我们的输入和输出的规模(神经元的数量)是相同的。
接下来就会谈到Xavier初始化,将会用另外一种方式来解决这一问题。
默认初始化
在前面的学习中,我们初始化权重值的方式都是使用正态分布来。而如果我们不指定初始化方法的话,框架会使用默认的随机初始化方法(比如Linear就会提供,具体原理可以自行去了解),简单问题用默认初始化还是很有效的。
Xavier初始化
回到之前的讨论,我们已知很难同时满足
n t − 1 γ t 2 = n t γ t 2 = 1 n_{t-1}γ_t^2=n_tγ_t^2=1 nt−1γt2=ntγt2=1
我们推广到每一层,即为:
n i n σ 2 = n o u t σ 2 = 1 n_{in}\sigma^2=n_{out}\sigma^2=1 ninσ2=noutσ2=1
虽然难以满足输入和输出规模相同,但是我们可以先将两个式子相加并调整:
σ 2 ( n i n + n o u t ) / 2 = 1 → σ = 2 ( n i n + n o u t ) \sigma^2(n_{in}+n_{out})/2=1→\sigma=\sqrt\frac{2}{(n_{in}+n_{out})} σ2(nin+nout)/2=1→σ=(nin+nout)2
对于上面的式子,我们就可以有两种采样方式:
(1)Xavier初始化从均值为0,方差为
σ 2 = 2 n i n + n o u t \sigma^2=\frac{2}{n_{in}+n_{out}} σ2=nin+nout2
的高斯分布中采样权重,即为
正态分布 N ( 0 , 2 n i n + n o u t ) 正态分布N(0,\sqrt\frac{2}{n_{in}+n_{out}}) 正态分布N(0,nin+nout2 )
(2)从均匀分布从抽取权重时的方差,我们先注意一个定理:
均匀分布 U ( − a , a ) 的方差为 a 2 3 均匀分布U(-a,a)的方差为\frac{a^2}{3} 均匀分布U(−a,a)的方差为3a2
此时我们将其带入到σ^2^的条件中,将得到初始化值域:
均匀分布 U ( − 6 n i n + n o u t , 6 n i n + n o u t ) 均匀分布U(-\sqrt\frac{6}{n_{in}+n_{out}},\sqrt\frac{6}{n_{in}+n_{out}}) 均匀分布U(−nin+nout6 ,nin+nout6 )