task03 Pytorch模型定义
task03 Pytorch模型定义
2022/6/19 雾切凉宫
先引入必要的包
import os
import numpy as np
import collections
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
1. 模型定义方式
定义方法 | 特点 | 使用方式 |
---|---|---|
sequential:direct list | 直接按顺序定义模型 | 直接传入变量 |
sequential:ordered dict | 类似字典构建,但是有序定义模型 | 直接传入变量 |
ModuleList | 可以逐个定义模型层,但需要实例化 | 先实例化再使用 |
ModuleDict | 重写前馈函数时需要用层名遍历 | 先实例化再使用 |
P.S.实例化指的是需要继承nn.Module类,并重写构造函数(init)和前馈函数(forward)
1.1 sequential方法
1.1.1 sequential:direct list
直接按模型层序一一排列,定义好直接就可以前向传播运算。
优点是方便快捷
缺点是不方便定义复杂模型
net1 = nn.Sequential(nn.Linear(784, 256),nn.ReLU(),nn.Linear(256, 10),
)
print(net1)
Sequential((0): Linear(in_features=784, out_features=256, bias=True)(1): ReLU()(2): Linear(in_features=256, out_features=10, bias=True)
)
输入纬度:784->256->10
总共三层:两层全连接一层ReLU激活函数
1.1.2 sequential:ordered dict
ordered dict形式定义模型:
每一层的定义都在一个tuple中,tuple包含两个元素:第一个是该层的名字(自定义),第二个是层结点的定义
net2 = nn.Sequential(collections.OrderedDict([("fcl", nn.Linear(784, 256)),("relu1", nn.ReLU()),("fc2", nn.Linear(256, 10))
]))
print(net2)
以上定义了一个同1.1.1方式的模型,区别在于每一层有了自定义的名字。
P.S.虽然是字典形式,但是却有顺序,我觉得可以理解为带一个注释参数的list,模型的层序严格按照定义的层序
下面是模型的前馈运算,可见模型一定义就可以运算,不需要实例化
a = torch.rand(4,784)
out1 = net1(a)
out2 = net2(a)
print(out1.shape,out2.shape)
torch.Size([4, 10]) torch.Size([4, 10])
1.2 ModuleList方法
ModuleList方法与sequential方法最大的不同在于模型定义后需要实例化。自己重写构造函数(init)和前馈函数(forward)
net3 = nn.ModuleList([nn.Linear(784, 256), nn.ReLU()])
net3.append(nn.Linear(256, 10))
print(net3)
ModuleList((0): Linear(in_features=784, out_features=256, bias=True)(1): ReLU()(2): Linear(in_features=256, out_features=10, bias=True)
)
moduleList并不会实际定义一个网络,只是将不同模块存储。
所以通常moduleList的使用是这样的:
先进行类的继承与方法重写:
class Net3(nn.Module):def __init__(self):super().__init__()self.modulelist = nn.ModuleList([nn.Linear(784, 256), nn.ReLU()])self.modulelist.append(nn.Linear(256, 10))def forward(self, x):for layer in self.modulelist:x = layer(x)return x
以上定义了一个Net3的网络继承nn.Module,包括了一个构造函数,完成了对ModuleList的定义
一个前向传播函数,并定义了参数如何在各层之间传播
net = Net3()
out = net(a)
print(out.shape)
torch.Size([4, 10])
以上实现了模型的计算,先实例化网络类,再传入数据,就能够完成前向计算!
1.3 ModuleDict方法
在定义上与ModuleList方法大体相似,不同的是可以为每一层命名
net4 = nn.ModuleDict({"linear":nn.Linear(784,256),"act":nn.ReLU(),})
net4["output"] = nn.Linear(256, 10)
print(net4)
使用上与ModuleList有一定区别。
在forward上,因为字典没法直接遍历,要自己写每一层前向传播的过程,个人感觉区别就是可以给每一层设个名字然后用名字编写forward前馈函数。。。
class Net4(nn.Module):def __init__(self):super().__init__()self.ModuleDict= nn.ModuleDict({"linear":nn.Linear(784,256),"act":nn.ReLU(),})self.ModuleDict["output"] = nn.Linear(256, 10)def forward(self, x):x = self.ModuleDict["linear"](x)x = self.ModuleDict["act"](x)x = self.ModuleDict["output"](x)return x
net4 = Net4()
out = net4(a)
print(out.shape)
torch.Size([4, 10])
1.4 总结
- sequential 简单直白,模型定义完了,直接就可以运算,不用定义forward
- ModuleList 不能够直接用来运算,需要实例化,自定义forward。可以批量定义一个复杂的多层网络
- ModulaDict 与ModuleList类似,需要实例化、定义forward,不过可以给每层网络自定义名字,并用名字来调用各层的方法。
2. 利用模型块快速搭建网络
以U-Net为例,学习如何构建模型块,以及如何利用模型块快速搭建复杂模型。
2.1 U-Net简介
U-Net是分割 (Segmentation) 模型的杰作,在以医学影像为代表的诸多领域有着广泛的应用。U-Net模型结构如下图所示,通过残差连接结构解决了模型学习中的退化问题,使得神经网络的深度能够不断扩展。
2.2 U-Net模型块分析
结合上图,不难发现U-Net模型具有非常好的对称性。模型从上到下分为若干层,每层由左侧和右侧两个模型块组成,每侧的模型块与其上下模型块之间有连接;同时位于同一层左右两侧的模型块之间也有连接,称为“Skip-connection”。此外还有输入和输出处理等其他组成部分。由于模型的形状非常像英文字母的“U”,因此被命名为“U-Net”。
组成U-Net的模型块主要有如下几个部分:
1)每个子块内部的两次卷积(Double Convolution)
2)左侧模型块之间的下采样连接,即最大池化(Max pooling)
3)右侧模型块之间的上采样连接(Up sampling)
4)输出层的处理
除模型块外,还有模型块之间的横向连接,输入和U-Net底部的连接等计算,这些单独的操作可以通过forward函数来实现。
下面我们用PyTorch先实现上述的模型块,然后再利用定义好的模型块构建U-Net模型。
2.3 模型块代码实现
2.3.1 双层卷积模块
in_channels**–(卷积conv2d)–>mid_channels–(batchNorm2/ReLU)–>mid_channelss–(卷积conv2d)–>out_channels–(batchNorm2/ReLU)–>**out_channels
class DoubleConv(nn.Module):"""(convolution => [BN] => ReLU) * 2"""def __init__(self, in_channels, out_channels, mid_channels=None):super().__init__()if not mid_channels:mid_channels = out_channelsself.double_conv = nn.Sequential(nn.Conv2d(in_channels, mid_channels, kernel_size=3, padding=1, bias=False),nn.BatchNorm2d(mid_channels),nn.ReLU(inplace=True),nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1, bias=False),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True))def forward(self, x):return self.double_conv(x)
2.3.2 降采样模块
in_channels**–(MaxPools2d池化降维)–>**复用双层卷积
class Down(nn.Module):"""Downscaling with maxpool then double conv"""def __init__(self, in_channels, out_channels):super().__init__()self.maxpool_conv = nn.Sequential(nn.MaxPool2d(2),DoubleConv(in_channels, out_channels))def forward(self, x):return self.maxpool_conv(x)
2.3.3 上采样模块
forward中实现了图中copy and crop的功能
class Up(nn.Module):"""Upscaling then double conv"""def __init__(self, in_channels, out_channels, bilinear=True):super().__init__()# if bilinear, use the normal convolutions to reduce the number of channelsif bilinear:self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)self.conv = DoubleConv(in_channels, out_channels, in_channels // 2)else:self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2)self.conv = DoubleConv(in_channels, out_channels)def forward(self, x1, x2):x1 = self.up(x1)# input is CHWdiffY = x2.size()[2] - x1.size()[2]diffX = x2.size()[3] - x1.size()[3]x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2,diffY // 2, diffY - diffY // 2])# if you have padding issues, see# https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a# https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bdx = torch.cat([x2, x1], dim=1)return self.conv(x)
2.3.4 输出模块
不会被复用
最后进行一次两次卷积将维数调整到需要的维数
class OutConv(nn.Module):def __init__(self, in_channels, out_channels):super(OutConv, self).__init__()self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)def forward(self, x):return self.conv(x)
2.4 模型块组装U-Net
class UNet(nn.Module):def __init__(self, n_channels, n_classes, bilinear=True):super(UNet, self).__init__()self.n_channels = n_channelsself.n_classes = n_classesself.bilinear = bilinearself.inc = DoubleConv(n_channels, 64)self.down1 = Down(64, 128)self.down2 = Down(128, 256)self.down3 = Down(256, 512)factor = 2 if bilinear else 1self.down4 = Down(512, 1024 // factor)self.up1 = Up(1024, 512 // factor, bilinear)self.up2 = Up(512, 256 // factor, bilinear)self.up3 = Up(256, 128 // factor, bilinear)self.up4 = Up(128, 64, bilinear)self.outc = OutConv(64, n_classes)def forward(self, x):x1 = self.inc(x)x2 = self.down1(x1)x3 = self.down2(x2)x4 = self.down3(x3)x5 = self.down4(x4)x = self.up1(x5, x4)x = self.up2(x, x3)x = self.up3(x, x2)x = self.up4(x, x1)logits = self.outc(x)return logits
unet = UNet(3, 1)
3. 模型修改
3.1 修改模型层
比如说我们想要一个5分类的任务,需要最后一层输出5个变量。
只需要取出原模型的最后一层重新实例化最后一层即可。
import copy
unet1 = copy.deepcopy(unet)
unet1.outc = OutConv(64,5)
b = torch.rand(1,3,224,224)
out_unet1 = unet1(b)
print(out_unet1.shape)
torch.Size([1, 5, 224, 224])
可以看见batchsize与图片大小均没有变化,channel数发生了变化,变成了5
3.2 添加额外输入
class UNet_more_input(nn.Module):def __init__(self, n_channels, n_classes, bilinear=True):super(UNet_more_input, self).__init__()self.n_channels = n_channelsself.n_classes = n_classesself.bilinear = bilinearself.inc = DoubleConv(n_channels, 64)self.down1 = Down(64, 128)self.down2 = Down(128, 256)self.down3 = Down(256, 512)factor = 2 if bilinear else 1self.down4 = Down(512, 1024 // factor)self.up1 = Up(1024, 512 // factor, bilinear)self.up2 = Up(512, 256 // factor, bilinear)self.up3 = Up(256, 128 // factor, bilinear)self.up4 = Up(128, 64, bilinear)self.outc = OutConv(64, n_classes)def forward(self, x, add_variable):x1 = self.inc(x)x2 = self.down1(x1)x3 = self.down2(x2)x4 = self.down3(x3)x5 = self.down4(x4)x = self.up1(x5, x4)x = self.up2(x, x3)x = self.up3(x, x2)x = self.up4(x, x1)x = x + add_variable #修改点logits = self.outc(x)return logits
unet2 = UNet_more_input(3,1)
c = torch.rand(1, 224, 224)
out = unet2(b,c)
print(out.shape)
torch.Size([1, 1, 224, 224])
总结:在forward处添加变量,并加入各层运算中
3.3 添加额外输出
class UNet_more_output(nn.Module):def __init__(self, n_channels, n_classes, bilinear=True):super(UNet_more_output, self).__init__()self.n_channels = n_channelsself.n_classes = n_classesself.bilinear = bilinearself.inc = DoubleConv(n_channels, 64)self.down1 = Down(64, 128)self.down2 = Down(128, 256)self.down3 = Down(256, 512)factor = 2 if bilinear else 1self.down4 = Down(512, 1024 // factor)self.up1 = Up(1024, 512 // factor, bilinear)self.up2 = Up(512, 256 // factor, bilinear)self.up3 = Up(256, 128 // factor, bilinear)self.up4 = Up(128, 64, bilinear)self.outc = OutConv(64, n_classes)def forward(self, x):x1 = self.inc(x)x2 = self.down1(x1)x3 = self.down2(x2)x4 = self.down3(x3)x5 = self.down4(x4)x = self.up1(x5, x4)x = self.up2(x, x3)x = self.up3(x, x2)x = self.up4(x, x1)logits = self.outc(x)return logits, x5 #修改点
unet3 = UNet_more_output(3,1)
out ,more_out= unet3(b)
print(out.shape,more_out.shape)
torch.Size([1, 1, 224, 224]) torch.Size([1, 512, 14, 14])
总结:在return处添加更多输出
4. 模型保存与读取
unet(b)
unet.state_dict()
#保存&读取整个模型
torch.save(unet, "./unet.pth")
torch.load("./unet.pth")
#保存&读取模型权重
torch.save(unet.state_dict(),"./unet_weight.pth")
loaded_weight = torch.load("./unet_weight.pth")
unet.load_state_dict(loaded_weight)
<All keys matched successfully>
task03 Pytorch模型定义相关推荐
- 深入浅出PyTorch - Pytorch模型定义
深入浅出PyTorch 模型部署及定义 使用seqtoseq模型预测时序数据 Pytorch模型定义 深入浅出PyTorch 1.数据集 1.1数据读入 1.2数据集预处理 2模块化搭建模型 1.数据 ...
- PyTorch学习笔记(五):模型定义、修改、保存
往期学习资料推荐: 1.Pytorch实战笔记_GoAI的博客-CSDN博客 2.Pytorch入门教程_GoAI的博客-CSDN博客 本系列目录: PyTorch学习笔记(一):PyTorch环境安 ...
- PyTorch:模型定义
PyTorch模型定义的方式 模型在深度学习中扮演着重要的角色,好的模型极大地促进了深度学习的发展进步,比如CNN的提出解决了图像.视频处理中的诸多问题,RNN/LSTM模型解决了序列数据处理的问题, ...
- pytorch如何定义损失函数_对比PyTorch和TensorFlow的自动差异和动态模型
使用自定义模型类从头开始训练线性回归,比较PyTorch 1.x和TensorFlow 2.x之间的自动差异和动态模型子类化方法, 这篇简短的文章重点介绍如何在PyTorch 1.x和TensorFl ...
- TensorFlow与PyTorch模型部署性能比较
TensorFlow与PyTorch模型部署性能比较 前言 2022了,选 PyTorch 还是 TensorFlow?之前有一种说法:TensorFlow 适合业界,PyTorch 适合学界.这种说 ...
- 基于C++的PyTorch模型部署
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 引言 PyTorch作为一款端到端的深度学习框架,在1.0版本之后 ...
- 快速上手笔记,PyTorch模型训练实用教程(附代码)
机器之心发布 作者:余霆嵩 前言 自 2017 年 1 月 PyTorch 推出以来,其热度持续上升,一度有赶超 TensorFlow 的趋势.PyTorch 能在短时间内被众多研究人员和工程师接受并 ...
- PyTorch模型的保存加载以及数据的可视化
文章目录 PyTorch模型的保存和加载 模块和张量的序列化和反序列化 模块状态字典的保存和载入 PyTorch数据的可视化 TensorBoard的使用 总结 PyTorch模型的保存和加载 在深度 ...
- Pytorch模型迁移和迁移学习,导入部分模型参数
Pytorch模型迁移和迁移学习 目录 Pytorch模型迁移和迁移学习 1. 利用resnet18做迁移学习 2. 修改网络名称并迁移学习 3.去除原模型的某些模块 1. 利用resnet18做迁移 ...
最新文章
- 单元测试——第六周作业
- Flutter开发之HTTP网络请求:Http库(27)
- 【机器视觉】 dev_inspect_ctrl算子
- 如何检查字符串是否包含特定的单词? [英]How do I check if a string contains a specific word?
- 【问答集锦】联邦学习让隐私保护和海量数据学习兼得!
- Snowflake Snow Snowflakes--POJ 3349
- 苗族php动态网页设计作业
- CnPack应用总结
- 【图像加密解密】基于matlab GUI混沌序列图像加密解密(含相关性检验)【含Matlab源码 1862期】
- python计算消费额_11、Python 数据分析-用户消费行为分析
- python3D绘图Axes3D函数详解
- Python股票数据爬虫解读
- 浏览器引擎 Chromium
- SHA 256算法是什么?哈希算法有哪些特点,主要应用在哪里?
- 网页报错404原因及解决方法
- XYQ加密算法——动态可逆加密算法。
- word2010中奇偶页不同页眉页脚设置
- DNSPod十问深创投刘辉:产业互联网是烧钱做慈善吗?
- Sphinx武林秘籍(下)
- IoT物联网——各大厂质量保障实践汇总(智能硬件其他篇)