pytorch常用组件和模型搭建

pytorch模型搭建

torch.nn还是torch.nn.functional?

原文
torch.nn 中大多数 layer 在 torch.nn.funtional 中都有一个与之对应的函数。二者的区别在于:

torch.nn 中实现 layer 的都是一个特殊的, 会自动提取可学习的参数。

nn.functional 中的函数,更像是纯函数,由 def function( ) 定义,只是进行简单的数学运算而已。即 functional 中的函数是一个确定的不变的运算公式,输入数据产生输出就ok。而深度学习中会有很多权重是在不断更新的,不可能每进行一次 forward 就用新的权重重新来定义一遍函数来进行计算,所以说就会采用类的方式,以确保能在参数发生变化时仍能使用我们之前定好的运算步骤。

当所需的函数不含有需要学习的参数在train和test阶段运行方法一致时,无论用torch.nn.X 还是torch.nn.functional.X 都可以,并且既可以现在 init中声明,也可以直接在forward中使用:(不具备可学习参数的层,将它们用函数代替,这样可以不用放在构造函数中进行初始化。)
如: torch.nn.functional.relu, torch.nn.ReLU

train和test阶段运行方法不一致时,尽量用 torch.nn,避免了手动控制的麻烦
如 batch normalization 和 dropout

有可学习参数时,使用torch.nn
如卷积层和全连接层

maxpool2d

ceil_model参数:
在这里插入图片描述

小例子:包括conv2d,maxpool, sigmoid激活

线性层linear略
以下分别对这三个组件构建了对应的类,并且将组件对图片的处理结果用tensorboard展示
具体用到什么组件的详细信息可以去官网查询:pytorch.org

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10('./data', train=False, transform=torchvision.transforms.ToTensor(), download=True)

dataloader = DataLoader(dataset, batch_size=64)

# tensorboard --logdir=p6

class CONV(nn.Module):
    def __init__(self):
        super(CONV, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)

    def forward(self, x):
        x = self.conv1(x)
        return x


class POOL(nn.Module):
    def __init__(self):
        super(POOL, self).__init__()
        self.maxpool = nn.MaxPool2d(kernel_size=3, ceil_mode=False)

    def forward(self, x):
        output = self.maxpool(x)
        return output


class ACT(nn.Module):
    def __init__(self):
        super(ACT, self).__init__()
        self.sigmoid = nn.Sigmoid()
        # self.relu = nn.Relu()

    def forward(self, x):
        output = self.sigmoid(x)
        return output


model1 = CONV()
model2 = POOL()
model3 = ACT()

writer = SummaryWriter('./p6')

step = 0
for data in dataloader:
    imgs, targets = data
    writer.add_images('input', imgs, step)
    output1 = model1(imgs)
    # 由于add_images只能接收3通道,这里就把它展平了一下
    # 与add_image区分,add_image只能接收单一图片,但add_images可以传入batch_size个图片,参数形状为[B,C,H,W]
    output1 = torch.reshape(output1, (-1,3,30,30))
    writer.add_images('conv', output1, step)
    output2 = model2(imgs)
    writer.add_images('maxpool', output2, step)
    output3 = model3(imgs)
    writer.add_images('sigmoid', output3, step)
    step += 1

writer.close()

一个小demo

按照下面的图搭建网络,验证网络结构是否正确,并用tensorboard查看网络结构
在这里插入图片描述
使用的库为:

import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.tensorboard import SummaryWriter

没有用sequential的情况

class cifar10(nn.Module):
    def __init__(self):
        super(cifar10, self).__init__()
        self.conv1 = Conv2d(3, 32, 5, padding=2)
        self.maxpool1 = MaxPool2d(2)
        self.conv2 = Conv2d(32, 32, 5, padding=2)
        self.maxpool2 = MaxPool2d(2)
        self.conv3 = Conv2d(32, 64, 5, padding=2)
        self.maxpool3 = MaxPool2d(2)
        self.flatten = Flatten()
        # 在不知道某层参数个数的情况下,可以将forward只写到那一层,然后看输出的shape,比如下面线性层的输入
        self.linear1 = Linear(1024, 64)
        self.linear2 = Linear(64, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = self.maxpool1(x)
        x = self.conv2(x)
        x = self.maxpool2(x)
        x = self.conv3(x)
        x = self.maxpool3(x)
        x = self.flatten(x)
        x = self.linear1(x)
        x = self.linear2(x)
        return x


# 测试时,可以生成一个batch的数据形式,传入模型调整错误
img = torch.rand((64, 3, 32, 32))
model = cifar10()
output = model(img)
print(output.shape)
# output shape:[64,10]

有sequential

可以发现在forward中的代码会减少很多,sequential的功能可以类比transforms.Compose
这里用tensorboard的add_graph,可以实现模型结构可视化
对于参数错误:例如线性层参数计算错误,写成2048,无论用不用sequential,报错位置都不在当前文件,因此debug的时候需要逐层去看,当然用sequential并不影响,而且更简洁。


class cifar10_seq(nn.Module):
    def __init__(self):
        super(cifar10_seq, self).__init__()
        self.seq = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10),
        )

    def forward(self, x):
        x = self.seq(x)
        return x


# tensorboard --logdir=p7
writer = SummaryWriter('./p7')
model1 = cifar10_seq()
writer.add_graph(model1, img)

writer.close()

训练过程

定义损失函数,实例化模型,定义优化器(包括对什么参数优化,学习率多少,优化器的其他参数等)
每个batch先计算损失并清零梯度 -> 求梯度 -> 根据梯度更新权重

dataset = torchvision.datasets.CIFAR10('./data', train=False, transform=torchvision.transforms.ToTensor(), download=True)
dataloader = DataLoader(dataset, batch_size=64)

# 训练阶段:
# 定义损失函数,实例化模型,定义优化器(包括对什么参数优化,学习率多少,优化器的其他参数等)
loss = nn.CrossEntropyLoss()
model2 = cifar10_seq()
optim = torch.optim.SGD(model2.parameters(), lr=0.01)

# 迭代周期
for epoch in range(3):
    # 统计损失
    running_loss = 0.0
    for data in dataloader:
        imgs, targets = data
        outputs = model2(imgs)
        result_loss = loss(outputs, targets)
        # 在梯度更新之前需要清零上一轮的梯度
        optim.zero_grad()
        # 得到梯度
        result_loss.backward()
        # 根据梯度更新权重
        optim.step()
        # 所有batch的loss累加
        running_loss += result_loss
    print('epoch %d, running loss %f' % (epoch, running_loss))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值