深度学习模型中的权重初始化对模型的训练效果有很大的影响,对预训练模型的研究就是为了在大模型上先训练出较好的权重,然后再放到不同的小任务上微调。
对于不加载预训练的模型,仍然可以通过定义模型权重初始化的方式来使得模型获得较好的效果,以下介绍不同的权重初始化方法、适用场景及效果。
计算增益
对于线性
nonlinearity | gain |
---|---|
Linear / Identity | 1 1 1 |
Conv{1,2,3}D | 1 1 1 |
Sigmoid | 1 1 1 |
Tanh | 5 3 \frac{5}{3} 35 |
ReLU | 2 \sqrt{2} 2 |
Leaky Relu | 2 1 + negative_slope 2 \sqrt{\frac{2}{1 + \text{negative\_slope}^2}} 1+negative_slope22 |
SELU | 3 4 \frac{3}{4} 43 |
常数初始化
torch.nn.init.constant_(tensor, val)
按照常数val初始化tensor。
特别的,val为0和1分别有torch.nn.init.zeros_(tensor)
和torch.nn.init.ones_(tensor)
。
均匀分布初始化
torch.nn.init.uniform_(tensor, a=0.0, b=1.0)
按照
U
(
a
,
b
)
U(a,b)
U(a,b)的均匀分布初始化tensor。
正态分布初始化
torch.nn.init.normal_(tensor, mean=0.0, std=1.0)
按照
N
(
m
e
a
n
,
s
t
d
2
)
N(mean,std^2)
N(mean,std2)的均匀分布初始化tensor。
Xavier初始化
均匀分布(glorot初始化)
torch.nn.init.xavier_uniform_(tensor, gain=1.0)
按照
U
(
−
a
,
a
)
U(-a,a)
U(−a,a)的均匀分布初始化tensor,其中
a
=
g
a
i
n
×
6
f
a
n
_
i
n
+
f
a
n
_
o
u
t
a = gain \times \sqrt{\frac{6}{fan\_in + fan\_out}}
a=gain×fan_in+fan_out6
正态分布
torch.nn.init.xavier_normal_(tensor, gain=1.0)
按照
N
(
0
,
s
t
d
2
)
N(0,std^2)
N(0,std2)的均匀分布初始化tensor,其中
s
t
d
=
g
a
i
n
×
2
f
a
n
_
i
n
+
f
a
n
_
o
u
t
std = gain \times \sqrt{\frac{2}{fan\_in + fan\_out}}
std=gain×fan_in+fan_out2
Kaiming初始化
均匀分布
torch.nn.init.kaiming_uniform_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu')
按照
U
(
−
a
,
a
)
U(-a,a)
U(−a,a)的均匀分布初始化tensor,其中
a
=
g
a
i
n
×
3
f
a
n
_
m
o
d
e
a = gain \times \sqrt{\frac{3}{fan\_mode}}
a=gain×fan_mode3
正态分布
torch.nn.init.kaiming_normal_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu')
按照
N
(
0
,
s
t
d
2
)
N(0,std^2)
N(0,std2)的均匀分布初始化tensor,其中
s
t
d
=
g
a
i
n
f
a
n
_
m
o
d
e
std = \sqrt{\frac{gain}{fan\_mode}}
std=fan_modegain
具体应用
在pytorch中的torch.nn.init
模块中有多种初始化的方法,可以显式地定义,以下是一个例子:
def init_weights(self):
for m in self.modules():
if isinstance(m, GCNConv):
m.weight.data = init.xavier_uniform(
m.weight.data, gain=torch.nn.init.calculate_gain("relu")
)
if m.bias is not None:
m.bias.data = init.constant(m.bias.data, 0.0)
这个函数是模型类的成员函数,它表示的是检索这个类中的所有模块,如果有GCNConv
类的话,就将对应的weights
用xavier均匀分布的方法初始化,如果有bias
的话用常数来初始化bias
,在对象初始化的时候调用self.init_weights();
就可以了。
一些问答或tips
1. How to use torch.nn.init.calculate_gain?
2. How to Initialize Weights in PyTorch
3. Weight Initialization Techniques in Neural Networks
4. 网络权重初始化方法总结(上):梯度消失、梯度爆炸与不良的初始化
5. 网络权重初始化方法总结(下):Lecun、Xavier与He Kaiming
6.pytorch-nn.init模块文档