3.5 模型初始化

3.5 模型初始化

3.5 模型初始化#

在深度学习模型的训练中,权重的初始值极为重要。一个好的初始值,会使模型收敛速度提高,使模型准确率更精确。一般情况下,我们不使用全0初始值训练网络。为了利于训练和减少收敛时间,我们需要对模型进行合理的初始化。PyTorch也在torch.nn.init中为我们提供了常用的初始化方法。

通过本章学习,你将学习到以下内容:

常见的初始化函数

初始化函数的使用

torch.nn.init内容#

通过访问torch.nn.init的官方文档链接 ,我们发现torch.nn.init提供了以下初始化方法:

1 . torch.nn.init.uniform_(tensor, a=0.0, b=1.0)

2 . torch.nn.init.normal_(tensor, mean=0.0, std=1.0)

3 . torch.nn.init.constant_(tensor, val)

4 . torch.nn.init.ones_(tensor)

5 . torch.nn.init.zeros_(tensor)

6 . torch.nn.init.eye_(tensor)

7 . torch.nn.init.dirac_(tensor, groups=1)

8 . torch.nn.init.xavier_uniform_(tensor, gain=1.0)

9 . torch.nn.init.xavier_normal_(tensor, gain=1.0)

10 . torch.nn.init.kaiming_uniform_(tensor, a=0, mode='fan__in', nonlinearity='leaky_relu')

11 . torch.nn.init.kaiming_normal_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu')

12 . torch.nn.init.orthogonal_(tensor, gain=1)

13 . torch.nn.init.sparse_(tensor, sparsity, std=0.01)

14 . torch.nn.init.calculate_gain(nonlinearity, param=None)

关于计算增益如下表:

nonlinearity

gain

Linear/Identity

1

Conv{1,2,3}D

1

Sigmod

1

Tanh

5/3

ReLU

sqrt(2)

Leaky Relu

sqrt(2/1+neg_slop^2)

我们可以发现这些函数除了calculate_gain,所有函数的后缀都带有下划线,意味着这些函数将会直接原地更改输入张量的值。

torch.nn.init使用#

我们通常会根据实际模型来使用torch.nn.init进行初始化,通常使用isinstance()来进行判断模块(回顾3.4模型构建)属于什么类型。

import torch

import torch.nn as nn

conv = nn.Conv2d(1,3,3)

linear = nn.Linear(10,1)

isinstance(conv,nn.Conv2d) # 判断conv是否是nn.Conv2d类型

isinstance(linear,nn.Conv2d) # 判断linear是否是nn.Conv2d类型

True

False

对于不同的类型层,我们就可以设置不同的权值初始化的方法。

# 查看随机初始化的conv参数

conv.weight.data

# 查看linear的参数

linear.weight.data

tensor([[[[ 0.1174, 0.1071, 0.2977],

[-0.2634, -0.0583, -0.2465],

[ 0.1726, -0.0452, -0.2354]]],

[[[ 0.1382, 0.1853, -0.1515],

[ 0.0561, 0.2798, -0.2488],

[-0.1288, 0.0031, 0.2826]]],

[[[ 0.2655, 0.2566, -0.1276],

[ 0.1905, -0.1308, 0.2933],

[ 0.0557, -0.1880, 0.0669]]]])

tensor([[-0.0089, 0.1186, 0.1213, -0.2569, 0.1381, 0.3125, 0.1118, -0.0063, -0.2330, 0.1956]])

# 对conv进行kaiming初始化

torch.nn.init.kaiming_normal_(conv.weight.data)

conv.weight.data

# 对linear进行常数初始化

torch.nn.init.constant_(linear.weight.data,0.3)

linear.weight.data

tensor([[[[ 0.3249, -0.0500, 0.6703],

[-0.3561, 0.0946, 0.4380],

[-0.9426, 0.9116, 0.4374]]],

[[[ 0.6727, 0.9885, 0.1635],

[ 0.7218, -1.2841, -0.2970],

[-0.9128, -0.1134, -0.3846]]],

[[[ 0.2018, 0.4668, -0.0937],

[-0.2701, -0.3073, 0.6686],

[-0.3269, -0.0094, 0.3246]]]])

tensor([[0.3000, 0.3000, 0.3000, 0.3000, 0.3000, 0.3000, 0.3000, 0.3000, 0.3000,0.3000]])

初始化函数的封装#

人们常常将各种初始化方法定义为一个initialize_weights()的函数并在模型初始后进行使用。

def initialize_weights(model):

for m in model.modules():

# 判断是否属于Conv2d

if isinstance(m, nn.Conv2d):

torch.nn.init.zeros_(m.weight.data)

# 判断是否有偏置

if m.bias is not None:

torch.nn.init.constant_(m.bias.data,0.3)

elif isinstance(m, nn.Linear):

torch.nn.init.normal_(m.weight.data, 0.1)

if m.bias is not None:

torch.nn.init.zeros_(m.bias.data)

elif isinstance(m, nn.BatchNorm2d):

m.weight.data.fill_(1)

m.bias.data.zeros_()

这段代码流程是遍历当前模型的每一层,然后判断各层属于什么类型,然后根据不同类型层,设定不同的权值初始化方法。我们可以通过下面的例程进行一个简短的演示:

# 模型的定义

class MLP(nn.Module):

# 声明带有模型参数的层,这里声明了两个全连接层

def __init__(self, **kwargs):

# 调用MLP父类Block的构造函数来进行必要的初始化。这样在构造实例时还可以指定其他函数

super(MLP, self).__init__(**kwargs)

self.hidden = nn.Conv2d(1,1,3)

self.act = nn.ReLU()

self.output = nn.Linear(10,1)

# 定义模型的前向计算,即如何根据输入x计算返回所需要的模型输出

def forward(self, x):

o = self.act(self.hidden(x))

return self.output(o)

mlp = MLP()

print(mlp.hidden.weight.data)

print("-------初始化-------")

mlp.apply(initialize_weights)

# 或者initialize_weights(mlp)

print(mlp.hidden.weight.data)

tensor([[[[ 0.3069, -0.1865, 0.0182],

[ 0.2475, 0.3330, 0.1352],

[-0.0247, -0.0786, 0.1278]]]])

"-------初始化-------"

tensor([[[[0., 0., 0.],

[0., 0., 0.],

[0., 0., 0.]]]])

注意:

我们在初始化时,最好不要将模型的参数初始化为0,因为这样会导致梯度消失,从而影响模型的训练效果。因此,我们在初始化时,可以使用其他初始化方法或者将模型初始化为一个很小的值,如0.01,0.1等。

相关数据

【创见固态硬盘专区】报价 评测 导购 图片(Transcend)创见固态硬盘大全
联机原理#
软件生命周期模型——瀑布模型

友情链接