pytorch学习笔记——3.5Pytorch中网络参数的初始化方法

摘要:

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

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

         下面我们列出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)
)

  • 10
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是一个简单的 ACGAN 生成对抗网络训练 Pytorch 代码,可以生成指定数字的手写数字图片: ```python import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader from torch.autograd import Variable import numpy as np # 定义生成器和判别器的网络结构 class Generator(nn.Module): def __init__(self, nz, ngf, nc, num_classes): super(Generator, self).__init__() self.num_classes = num_classes self.fc = nn.Sequential( nn.Linear(nz + num_classes, 1024), nn.BatchNorm1d(1024), nn.ReLU(True), nn.Linear(1024, 7 * 7 * 128), nn.BatchNorm1d(7 * 7 * 128), nn.ReLU(True), ) self.conv = nn.Sequential( nn.ConvTranspose2d(128, 64, 4, 2, 1), nn.BatchNorm2d(64), nn.ReLU(True), nn.ConvTranspose2d(64, nc, 4, 2, 1), nn.Tanh(), ) def forward(self, z, labels): c = np.zeros((z.shape[0], self.num_classes)) c[range(z.shape[0]), labels] = 1 c = torch.from_numpy(c).float() if z.is_cuda: c = c.cuda() z = torch.cat([z, c], 1) out = self.fc(z) out = out.view(out.size(0), 128, 7, 7) out = self.conv(out) return out class Discriminator(nn.Module): def __init__(self, ndf, nc, num_classes): super(Discriminator, self).__init__() self.num_classes = num_classes self.conv = nn.Sequential( nn.Conv2d(nc, 64, 4, 2, 1), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(64, 128, 4, 2, 1), nn.BatchNorm2d(128), nn.LeakyReLU(0.2, inplace=True), ) self.fc = nn.Sequential( nn.Linear(128 * 7 * 7 + num_classes, 1024), nn.BatchNorm1d(1024), nn.LeakyReLU(0.2, inplace=True), nn.Linear(1024, 1), nn.Sigmoid(), ) def forward(self, x, labels): out = self.conv(x) out = out.view(out.size(0), -1) c = np.zeros((out.shape[0], self.num_classes)) c[range(out.shape[0]), labels] = 1 c = torch.from_numpy(c).float() if x.is_cuda: c = c.cuda() out = torch.cat([out, c], 1) out = self.fc(out) return out # 定义训练函数 def train(dataloader, discriminator, generator, optimizer_d, optimizer_g, criterion, num_epochs, nz, num_classes): for epoch in range(num_epochs): for i, (images, labels) in enumerate(dataloader): batch_size = images.size(0) images = Variable(images) labels = Variable(labels) real_labels = Variable(torch.ones(batch_size)) fake_labels = Variable(torch.zeros(batch_size)) if images.is_cuda: real_labels = real_labels.cuda() fake_labels = fake_labels.cuda() labels = labels.cuda() images = images.cuda() # 训练判别器 optimizer_d.zero_grad() outputs = discriminator(images, labels) real_loss = criterion(outputs, real_labels) real_loss.backward() z = Variable(torch.randn(batch_size, nz)) if z.is_cuda: z = z.cuda() fake_labels_ = Variable(torch.LongTensor(np.random.randint(0, num_classes, batch_size))) if fake_labels_.is_cuda: fake_labels_ = fake_labels_.cuda() fake_images = generator(z, fake_labels_) outputs = discriminator(fake_images, fake_labels_) fake_loss = criterion(outputs, fake_labels) fake_loss.backward() optimizer_d.step() # 训练生成器 optimizer_g.zero_grad() z = Variable(torch.randn(batch_size, nz)) if z.is_cuda: z = z.cuda() fake_labels_ = Variable(torch.LongTensor(np.random.randint(0, num_classes, batch_size))) if fake_labels_.is_cuda: fake_labels_ = fake_labels_.cuda() fake_images = generator(z, fake_labels_) outputs = discriminator(fake_images, fake_labels_) g_loss = criterion(outputs, real_labels) g_loss.backward() optimizer_g.step() # 打印训练信息 if (i + 1) % 100 == 0: print('Epoch [%d/%d], Step [%d/%d], d_loss: %.4f, g_loss: %.4f' % (epoch + 1, num_epochs, i + 1, len(dataloader), (real_loss + fake_loss).data[0], g_loss.data[0])) # 定义超参数 batch_size = 128 num_epochs = 200 nz = 100 ngf = 64 ndf = 64 nc = 1 num_classes = 10 lr = 0.0002 beta1 = 0.5 # 加载 MNIST 数据集 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(mean=(0.5,), std=(0.5,)) ]) train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True) train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 初始化生成器和判别器 generator = Generator(nz, ngf, nc, num_classes) discriminator = Discriminator(ndf, nc, num_classes) if torch.cuda.is_available(): generator.cuda() discriminator.cuda() # 定义损失函数和优化器 criterion = nn.BCELoss() optimizer_g = optim.Adam(generator.parameters(), lr=lr, betas=(beta1, 0.999)) optimizer_d = optim.Adam(discriminator.parameters(), lr=lr, betas=(beta1, 0.999)) # 训练模型 train(train_dataloader, discriminator, generator, optimizer_d, optimizer_g, criterion, num_epochs, nz, num_classes) ``` 这个代码可以生成指定数字的手写数字图片,你可以通过修改 `fake_labels_` 的值来指定要生成的数字。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学不来我就死

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值