摘要:

对于搭建的网络,一般情况下我们使用默认的参数初始化就可以获得比较稳定的结果,但我们如果了解常用的参数初始化方法并加以使用,在某些情况下可以提高模型的精度。

一、常用的参数初始化方法:

         下面我们列出nn模块中的init模块下常用的参数初始化类,功能如下:

常用的参数初始化方法的功能
方法(类)功能
torch.nn.init.uniform_(tensor, a=0, b=1)从均匀分布U(a, b)中采样,填充输入的张量或变量
torch.nn.init.normal_(tensor, mean=0.0, std=1.0) 从给定的均值和标准差的正态分布 中生成值,初始化张量
torch.nn.init.constant_(tensor, val)用常数 val 的值填充输入的张量或变量
 torch.nn.init.eye_(tensor)将二维张量初始化为单位矩阵
torch.nn.init.xavier_normal_(tensor, gain=1.0)使用Glorot 初始化方法正态分布生成值,生成随机数填充张量
torch.nn.init,dirac(tensor)使用Dirac data函数来填充{3,4,5}维输入张量或变量,在卷积层尽可能多的保存输入通道特性
torch.nn.init.xavier_uniform_(tensor, gain=1.0)使用Glorat初始化方法均匀分布生成值,生成随机数填充张量
torch.nn.init.kaiming_uniform_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu')使用HE初始化方法均匀分布生成值,生成随机数填充张量
torch.nn.init.kaiming_normal_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu')使用HE初始化方法正态分布生成值,生成随机数填充张量
torch.nn.init.orthogonal_(tensor, gain=1)使用正交矩阵填充张量

        下面我们用具体的示例介绍如何使用这些初始化方法,并对模型参数进行初始化。


二、参数初始化方法应用实例:

         在本节我们介绍两种参数初始化的方法:第一种是针对某一层的权重进行初始化,第二种是针对一个网络的权重进行初始化。

        首先导入需要使用的模块和库,代码如下:

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

        1.针对某一层的权重进行初始化

         以一个卷积层为例,我们首先使用Conv2d()函数定义一个从3个特征映射到16个特征映射的卷积层,并且卷积核大小为3*3,然后使用标准正态分布的随机数进行初始化,代码如下:

#以一个卷积层为例,先定义一个从3个特征映射到16个特征映射的卷积层,(3*3卷积核)然后使用标准正态分布的随机数进行初始化

#针对一个层进行权重初始化
conv1 = torch.nn.Conv2d(3,16,(3*3))
#使用标准正态分布初始化权重
torch.manual_seed(1)#随机数初始化种子
torch.nn.init.normal_(conv1.weight,mean=0,std=1)#表示生成的随机数用来替换蟑螂conv1.weight的原始数据

#使用直方图可视化conv1.weight的分布情况
plt.figure(figsize=(8,6))
plt.hist(conv1.weight.data.numpy().reshape((-1,1)),bins=30)
plt.show()

在上面的代码中,我们使用conv1.weight获得了conv1卷积层初始的权重参数,在使用torch.nn.init.normal_()函数时,第一个参数conv1.weight表示表示生成的随机数用来替换conv1.weight的原始数据,参数mean=0,std=1表示均值为0,标准差为1。

        在将conv1.weight初始化后,我们将其中的权重参数分布使用plt方法初始化,得到如下的直方图,说明生成的初始化数据符合正态分布。

        在上面的代码中,我们初始化了conv1的卷积核的权重,通过conv1.bias可以获取该层的偏置参数,代码如下:

conv1.bias#获取该层的偏置参数

结果如下,可见初始偏置参数:

Parameter containing:
tensor([ 0.0597, -0.0097,  0.0147,  0.0448,  0.0054,  0.0041,  0.0205, -0.0350,
         0.0092,  0.0280, -0.0312, -0.0527, -0.0417, -0.0563, -0.0028,  0.0337],
       requires_grad=True)

下面我们通过torch.nn.init.constant()函数使用常量0.1来进行偏置的初始化,代码如下:

#使用指定const值初始化偏置

torch.nn.init.constant_(conv1.bias,val=0.1)

 结果如下,说明conv1偏置参数的每个元素都已经初始化为0.1:

Parameter containing:
tensor([0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000,
        0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000],
       requires_grad=True)

  2.针对一个网络的权重进行初始化

        首先,我们定义一个简单的测试网络TestNet()网络类,代码如下:

#首先建立一个测试网络
class TestNet(nn.Module):
    def __init__(self):
        super(TestNet,self).__init__()
        self.conv1 = nn.Conv2d(3,16,3)
        self.hidden = nn.Sequential(
                                    nn.Linear(100,100),
                                    nn.ReLU(),
                                    nn.Linear(100,50),
                                    nn.ReLU(),)
        self.cla = nn.Linear(50,10)
    #定义网络的前向传播路径
    def forward(self,x):
        x = self.conv1(x)
        x = x.view(x.shape[0],-1)
        x = self.hidden(x)
        output = self.cla(x)
        return output
#输出网络结构
testnet = TestNet()
print(testnet)

结果为(网络结构):

TestNet(
  (conv1): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1))
  (hidden): Sequential(
    (0): Linear(in_features=100, out_features=100, bias=True)
    (1): ReLU()
    (2): Linear(in_features=100, out_features=50, bias=True)
    (3): ReLU()
  )
  (cla): Linear(in_features=50, out_features=10, bias=True)
)

 在上述定义的网络结构中,一共有4个包含参数的层,分别是1个卷积层和3个全连接层。

        下面我们尝试对不同类型层的参数使用不同的方法进行参数初始化,方法是定义一个函数,对不同类型的层使用不同的初始化方法,下面我们就定义一个init_weights()函数来实现这个功能,代码如下:(若是卷积层,使用正态分布初始化;若是全连接层没使用均匀分布初始化)

#针对不同类型的层使用不同的初始化方法
def init_weights(m):
    #如果是卷积层
    if type(m) == nn.Conv2d:
        torch.nn.init.normal_(m.weight,mean=0,std=0.5)
    #如果是全连接层
    if type(m) == nn.Linear:
        torch.nn.init.uniform_(m.weight,a=-0.1,b=0.1)
        m.bias.data.fill_(0.01)

        最后,我们在网络TestNet中,对定义好的函数使用apply方法即可,testnet的参数初始化代码如下:

#使用网络的apply方法进行权重初始化
torch.manual_seed(1)
testnet.apply(init_weights)

 结果为:

TestNet(
  (conv1): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1))
  (hidden): Sequential(
    (0): Linear(in_features=100, out_features=100, bias=True)
    (1): ReLU()
    (2): Linear(in_features=100, out_features=50, bias=True)
    (3): ReLU()
  )
  (cla): Linear(in_features=50, out_features=10, bias=True)
)

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐