pytorch实现resnet50,pytorch实现resnet18
ResNet代表residualneuralnetwork,主要解决网络过深导致的梯度分散、梯度爆炸、网络退化等问题(即网络层越深,在数据集上的性能越差)。
00-1010数据集训练中残差结构18层实现简介
目录
Net和VGG网络已经证明,更深的网络可以抽象出表达能力更强的特征,从而获得更强的分类能力。在深度网络中,随着网络深度的增加,各层输出特征图的分辨率主要是高度和宽度越来越小,而深度逐渐增加。
深度的增加理论上可以提高网络的表达能力,但对于优化来说,梯度会消失。在深度网络中,梯度在反向传播中从输出端到数据端逐层传播。在传播过程中,梯度的累积相乘使得近数据段接近于零,使得网络的训练失效。
为了解决梯度消失的问题,可以在网络中加入BatchNorm,用ReLU代替激活函数,在一定程度上缓解了梯度消失的问题。
深度增加的另一个问题是深度网络的退化。即在现有网络的基础上,增加网络的深度。理论上,只有训练到最佳情况,新网络的性能才不会低于浅层网络。因为,只要把新加的层学习成身份映射就行了。换句话说,浅网络的解空间是深网络的解空间的子集。但是因为退化问题,更深的网络不一定比浅的网络更好。
剩余模块的思想是使网络实现这种身份映射。如图所示,残差结构在两层卷积的基础上增加了一个并行分支。在将输入直接添加到最终的ReLU激活函数之前,如果两层卷积改变了大量输入的分辨率和通道数,为了能够相加,可以在相加的分支上使用1x1卷积来匹配大小。
简述
NET网络有两种残差块,一种是两个3x3卷积,另一种是由三个卷积网络1x1,3x3,1x1串联而成的残差块。
PyTorch实现:
类残差_1(nn。模块):
r
18层、34层剩余区块
1.使用类似于VGG的33卷积层设计;
2.首先使用两个输出通道数相同的3卷积层,后面是一个批量归一化和ReLU激活函数;
3.在最终ReLU激活函数之前添加穿过卷积层的路径;
4.如果要匹配卷积输出的大小和通道数,可以在增加的交叉通道上使用11卷积;
def __init__(self,input_channels,num_channels,use_1x1conv=False,strides=1):
r
参数:
Input_channels:输入的通道数
num_channels:输出的通道数
Use_1x1conv:你需要用1x1卷积来控制大小?
第一个卷积的步长
超级()。__init__()
# 33卷积,步长控制是否降低分辨率。
self.conv1=nn。Conv2d(输入通道,
数量_通道,
内核大小=3,
填充=1,
步幅=步幅)
# 33卷积,不改变分辨率
self.conv2=nn。Conv2d(通道数,
数量_通道,
内核大小=3,
填充=1)
#使用1x1卷积转换输入分辨率和通道。
如果使用_1x1conv:
self.conv3=nn。Conv2d(输入通道,
num_channels,
kernel_size=1,
stride=strides)
else:
self.conv3 = None
# 批量规范化层
self.bn1 = nn.BatchNorm2d(num_channels)
self.bn2 = nn.BatchNorm2d(num_channels)
def forward(self, X):
Y = F.relu(self.bn1(self.conv1(X)))
Y = self.bn2(self.conv2(Y))
if self.conv3:
X = self.conv3(X)
# print(X.shape)
Y += X
return F.relu(Y)
class Residual_2(nn.Module):r"""
50-layer, 101-layer, 152-layer 残差块
1. 首先使用1x1卷积,ReLU激活函数;
2. 然后用3×3卷积层,在接一个批量规范化,ReLU激活函数;
3. 再接1x1卷积层;
4. 加入跨过卷积层的通路,加到最后的ReLU激活函数前;
5. 如果要匹配卷积后的输出的尺寸和通道数,可以在加入的跨通路上使用1×1卷积;
"""
def __init__(self, input_channels, num_channels, use_1x1conv=False, strides=1):
r"""
parameters:
input_channels: 输入的通道上数
num_channels: 输出的通道数
use_1x1conv: 是否需要使用1x1卷积控制尺寸
stride: 第一个卷积的步长
"""
super().__init__()
# 1×1卷积,strides控制分辨率是否缩小
self.conv1 = nn.Conv2d(input_channels,
num_channels,
kernel_size=1,
padding=1,
stride=strides)
# 3×3卷积,不改变分辨率
self.conv2 = nn.Conv2d(num_channels,
num_channels,
kernel_size=3,
padding=1)
# 1×1卷积,strides控制分辨率是否缩小
self.conv3 = nn.Conv2d(input_channels,
num_channels,
kernel_size=1,
padding=1)
# 使用 1x1 卷积变换输入的分辨率和通道
if use_1x1conv:
self.conv3 = nn.Conv2d(input_channels,
num_channels,
kernel_size=1,
stride=strides)
else:
self.conv3 = None
# 批量规范化层
self.bn1 = nn.BatchNorm2d(num_channels)
self.bn2 = nn.BatchNorm2d(num_channels)
def forward(self, X):
Y = F.relu(self.bn1(self.conv1(X)))
Y = F.relu(self.bn2(self.conv2(Y)))
Y = self.conv3(Y)
if self.conv3:
X = self.conv3(X)
# print(X.shape)
Y += X
return F.relu(Y)
ResNet有不同的网络层数,比较常用的是50-layer,101-layer,152-layer。他们都是由上述的残差模块堆叠在一起实现的。
以18-layer为例,层数是指:首先,conv_1 的一层7x7卷积,然后conv_2~conv_5四个模块,每个模块两个残差块,每个残差块有两层的3x3卷积组成,共4×2×2=16层,最后是一层分类层(fc),加总一起共1+16+1=18层。
18-layer 实现
首先定义由残差结构组成的模块:
# ResNet模块def resnet_block(input_channels, num_channels, num_residuals, first_block=False):
r"""残差块组成的模块"""
blk = []
for i in range(num_residuals):
if i == 0 and not first_block:
blk.append(Residual_1(input_channels,
num_channels,
use_1x1conv=True,
strides=2))
else:
blk.append(Residual_1(num_channels, num_channels))
return blk
定义18-layer的最开始的层:
# ResNet的前两层:# 1. 输出通道数64, 步幅为2的7x7卷积层
# 2. 步幅为2的3x3最大汇聚层
conv_1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
定义残差组模块:
# ResNet模块conv_2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
conv_3 = nn.Sequential(*resnet_block(64, 128, 2))
conv_4 = nn.Sequential(*resnet_block(128, 256, 2))
conv_5 = nn.Sequential(*resnet_block(256, 512, 2))
ResNet 18-layer模型:
net = nn.Sequential(conv_1, conv_2, conv_3, conv_4, conv_5,nn.AdaptiveAvgPool2d((1, 1)),
nn.Flatten(),
nn.Linear(512, 10))
# 观察模型各层的输出尺寸
X = torch.rand(size=(1, 1, 224, 224))
for layer in net:
X = layer(X)
print(layer.__class__.__name__,output shape:\t, X.shape)
输出:
Sequential output shape: torch.Size([1, 64, 56, 56])
Sequential output shape: torch.Size([1, 64, 56, 56])
Sequential output shape: torch.Size([1, 128, 28, 28])
Sequential output shape: torch.Size([1, 256, 14, 14])
Sequential output shape: torch.Size([1, 512, 7, 7])
AdaptiveAvgPool2d output shape: torch.Size([1, 512, 1, 1])
Flatten output shape: torch.Size([1, 512])
Linear output shape: torch.Size([1, 10])
在数据集训练
def load_datasets_Cifar10(batch_size, resize=None):trans = [transforms.ToTensor()]
if resize:
transform = trans.insert(0, transforms.Resize(resize))
trans = transforms.Compose(trans)
train_data = torchvision.datasets.CIFAR10(root="../data", train=True, transform=trans, download=True)
test_data = torchvision.datasets.CIFAR10(root="../data", train=False, transform=trans, download=True)
print("Cifar10 下载完成...")
return (torch.utils.data.DataLoader(train_data, batch_size, shuffle=True),
torch.utils.data.DataLoader(test_data, batch_size, shuffle=False))
def load_datasets_FashionMNIST(batch_size, resize=None):
trans = [transforms.ToTensor()]
if resize:
transform = trans.insert(0, transforms.Resize(resize))
trans = transforms.Compose(trans)
train_data = torchvision.datasets.FashionMNIST(root="../data", train=True, transform=trans, download=True)
test_data = torchvision.datasets.FashionMNIST(root="../data", train=False, transform=trans, download=True)
print("FashionMNIST 下载完成...")
return (torch.utils.data.DataLoader(train_data, batch_size, shuffle=True),
torch.utils.data.DataLoader(test_data, batch_size, shuffle=False))
def load_datasets(dataset, batch_size, resize):
if dataset == "Cifar10":
return load_datasets_Cifar10(batch_size, resize=resize)
else:
return load_datasets_FashionMNIST(batch_size, resize=resize)
train_iter, test_iter = load_datasets("", 128, 224) # Cifar10
到此这篇关于PyTorch详解经典网络ResNet实现流程的文章就介绍到这了,更多相关PyTorch ResNet内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。