pytorch日积月累8-权值初始化

1.梯度消亡和梯度爆炸

image-20200821111326572

  • ${D}({X} \times {Y})={D}({X}) \times {D}({Y})+{D}({X}) \times[E({Y})]^{2}+{D}({Y}) \times[{E}({X})]^{2}$
  • 若$E({X})=0, {E}({Y})=0$,则有$\mathrm{D}(\mathrm{X} \times \mathrm{Y})=\mathrm{D}(\mathrm{X}) \times \mathrm{D}(\mathrm{Y})$

已知$H_1$层输出的结果$\mathrm{H}_{11}=\sum_{i=0}^{n} X_{i} \times W_{1 i}$,根据$\quad \mathrm{D}(\mathrm{X} \times \mathrm{Y})=\mathrm{D}(\mathrm{X}) \times \mathrm{D}(\mathrm{Y})$,可以得到:

可以发现对于神经网络,每一层的标准差都变为原来的$\sqrt{n}$倍。

1
2
3
4
5
def initialize(self):
for m in self.modules():
if isinstance(m, nn.Linear):#采用恰当的权值初始化方法
nn.init.normal_(m.weight.data, std=np.sqrt(1/self.neural_num))
# normal: mean=0, std=1

2.Xavier初始化

带有激活函数时如何进行初始化:

方差一致性:保持数据尺度维持在恰当范围,通常方差为1

激活函数:饱和函数,如Sigmoid,Tanh

1
2
3
4
5
#利用公式进行的初始化方法
a = np.sqrt(6 / (self.neural_num + self.neural_num))
tanh_gain = nn.init.calculate_gain('tanh')
a *= tanh_gain
nn.init.uniform_(m.weight.data, -a, a)
1
2
3
#nn模块中的Xavier初始化方法
tanh_gain = nn.init.calculate_gain('tanh')
nn.init.xavier_uniform_(m.weight.data, gain=tanh_gain)

3.Kaiming初始化

方差一致性:保持数据尺度维持在恰当范围,通常方差为1

激活函数:ReLU及其变种

1
nn.init.normal_(m.weight.data, std=np.sqrt(2 / self.neural_num))
1
nn.init.kaiming_normal_(m.weight.data)

计算方差变化尺度:

1
2
3
nn.init.calculate_gain(nonlinearity, param=None)
#nonlinearity: 激活函数名称
#param: 激活函数的参数,如Leaky ReLU的negative_slop
1
2
3
4
5
6
x = torch.randn(10000)
out = torch.tanh(x)
gain = x.std() / out.std()
print('gain:{}'.format(gain))
tanh_gain = nn.init.calculate_gain('tanh')
print('tanh_gain in PyTorch:', tanh_gain)#1.666667表示方差每次会减少1.6左右