ResNet网络详解

article/2025/9/18 3:56:57

ResNet

ResNet在2015年由微软实验室提出,斩获当年lmageNet竞赛中分类任务第一名,目标检测第一名。获得coco数据集中目标检测第一名,图像分割第一名。

ResNet亮点

1.超深的网络结构(突破1000层)
2.提出residual模块
3.使用Batch Normalization加速训练(丢弃dropout)

网络一定是越深越好吗?

一般来说,网络越深,咱们能获取的信息越多,而且特征也越丰富。我们思考一个问题,我们一直加深我们的网络,取得的效果一定越好吗?

在这里插入图片描述

看到这两幅图我们看到,网络并不是深度越深效果越好,那么是什么原因导致的呢?在ResNet论文中,提出了两个问题,一个是随着网络深度的增加,梯度消失或梯度爆炸问题;另一个是退化问题。为了让更深的网络也能训练出好的效果,何恺明提出了ResNet网络。

在这里插入图片描述

残差结构

在这里插入图片描述

左边的残差结构用于ResNet-34,右边的残差结构用于ResNet-50/101/152。残差结构可以用表达式F(x)=f(x)+x表示。左边的残差结构很简单,主线f(x)是两个3x3的卷积,最后与x合并。右边多了两个1x1的卷积,用来降维和升维(减少参数量)。

ResNet网络结构

在这里插入图片描述

我们着重分析一下ResNet-34结构,可以看到是由多个残差结构堆叠而成:

在这里插入图片描述

为什么会有实线和虚线之分呢?从网络参数图上可以看到,经过一个类型的第一个残差结构后,图像的大小为原来的一半,我们拿第一条虚线举例:输入图像为56x56x64,输出为28x28x128,所以分支需要一个1x1卷积来将输入图处理成输出大小。

请添加图片描述

右侧虚线残差结构的主分支上第一个1x1卷积层的步距是2,第二个3x3卷积层步距是1。但在pytorch官方实现过程中是第一个1x1卷积层的步距是1,第二个3x3卷积层步距是2,这样能够在imagenet的top1上提升大概0.5%的准确率。

Batch Normalization

Batch Normalization是google团队在2015年论文《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》提出的。通过该方法能够加速网络的收敛并提升准确率。我们在图像预处理过程中通常会对图像进行标准化处理,这样能够加速网络的收敛,假设对于Conv1来说输入的就是满足某一分布的特征矩阵,但对于Conv2而言经过Conv1卷积后输入的feature map就不一定满足某一分布规律了。而我们Batch Normalization的目的就是使我们的feature map满足均值为0,方差为1的分布规律。下图是一个示例:

在这里插入图片描述

我们需要知道的是将bn层放在卷积层(Conv)和激活层(例如Relu)之间,且卷积层不要使用偏置bias,如图所示:

请添加图片描述

ResNet实现

1.建立模型:
import torch.nn as nn
import torchclass BasicBlock(nn.Module):expansion = 1def __init__(self, in_channel, out_channel, stride=1, downsample=None, **kwargs):super(BasicBlock, self).__init__()self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,kernel_size=3, stride=stride, padding=1, bias=False)self.bn1 = nn.BatchNorm2d(out_channel)self.relu = nn.ReLU()self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,kernel_size=3, stride=1, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(out_channel)self.downsample = downsampledef forward(self, x):identity = xif self.downsample is not None:identity = self.downsample(x)out = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)out += identityout = self.relu(out)return outclass Bottleneck(nn.Module):expansion = 4def __init__(self, in_channel, out_channel, stride=1, downsample=None,groups=1, width_per_group=64):super(Bottleneck, self).__init__()width = int(out_channel * (width_per_group / 64.)) * groupsself.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=width,kernel_size=1, stride=1, bias=False)  # squeeze channelsself.bn1 = nn.BatchNorm2d(width)# -----------------------------------------self.conv2 = nn.Conv2d(in_channels=width, out_channels=width, groups=groups,kernel_size=3, stride=stride, bias=False, padding=1)self.bn2 = nn.BatchNorm2d(width)# -----------------------------------------self.conv3 = nn.Conv2d(in_channels=width, out_channels=out_channel*self.expansion,kernel_size=1, stride=1, bias=False)  # unsqueeze channelsself.bn3 = nn.BatchNorm2d(out_channel*self.expansion)self.relu = nn.ReLU(inplace=True)self.downsample = downsampledef forward(self, x):identity = xif self.downsample is not None:identity = self.downsample(x)out = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)out = self.relu(out)out = self.conv3(out)out = self.bn3(out)out += identityout = self.relu(out)return outclass ResNet(nn.Module):def __init__(self,block,blocks_num,num_classes=1000,include_top=True,groups=1,width_per_group=64):super(ResNet, self).__init__()self.include_top = include_topself.in_channel = 64self.groups = groupsself.width_per_group = width_per_groupself.conv1 = nn.Conv2d(3, self.in_channel, kernel_size=7, stride=2,padding=3, bias=False)self.bn1 = nn.BatchNorm2d(self.in_channel)self.relu = nn.ReLU(inplace=True)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)self.layer1 = self._make_layer(block, 64, blocks_num[0])self.layer2 = self._make_layer(block, 128, blocks_num[1], stride=2)self.layer3 = self._make_layer(block, 256, blocks_num[2], stride=2)self.layer4 = self._make_layer(block, 512, blocks_num[3], stride=2)if self.include_top:self.avgpool = nn.AdaptiveAvgPool2d((1, 1))  # output size = (1, 1)self.fc = nn.Linear(512 * block.expansion, num_classes)for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')def _make_layer(self, block, channel, block_num, stride=1):downsample = Noneif stride != 1 or self.in_channel != channel * block.expansion:downsample = nn.Sequential(nn.Conv2d(self.in_channel, channel * block.expansion, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(channel * block.expansion))layers = []layers.append(block(self.in_channel,channel,downsample=downsample,stride=stride,groups=self.groups,width_per_group=self.width_per_group))self.in_channel = channel * block.expansionfor _ in range(1, block_num):layers.append(block(self.in_channel,channel,groups=self.groups,width_per_group=self.width_per_group))return nn.Sequential(*layers)def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.relu(x)x = self.maxpool(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)if self.include_top:x = self.avgpool(x)x = torch.flatten(x, 1)x = self.fc(x)return xdef resnet34(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnet34-333f7ec4.pthreturn ResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)def resnet50(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnet50-19c8e357.pthreturn ResNet(Bottleneck, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)def resnet101(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnet101-5d3b4d8f.pthreturn ResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes, include_top=include_top)def resnext50_32x4d(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pthgroups = 32width_per_group = 4return ResNet(Bottleneck, [3, 4, 6, 3],num_classes=num_classes,include_top=include_top,groups=groups,width_per_group=width_per_group)def resnext101_32x8d(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pthgroups = 32width_per_group = 8return ResNet(Bottleneck, [3, 4, 23, 3],num_classes=num_classes,include_top=include_top,groups=groups,width_per_group=width_per_group)
2.训练模型:
import os
import sys
import jsonimport torch
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms, datasets
from tqdm import tqdmfrom model import resnet34def main():device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")print("using {} device.".format(device))data_transform = {"train": transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])# transforms.ConvertImageDtype('RGB')]),"val": transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])}train_dataset = datasets.ImageFolder(root='./train',transform=data_transform["train"])train_num = len(train_dataset)flower_list = train_dataset.class_to_idxcla_dict = dict((val, key) for key, val in flower_list.items())json_str = json.dumps(cla_dict, indent=4)with open('class_indices.json', 'w') as json_file:json_file.write(json_str)batch_size = 16nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8])  # number of workersprint('Using {} dataloader workers every process'.format(nw))train_loader = torch.utils.data.DataLoader(train_dataset,batch_size=batch_size, shuffle=True,num_workers=nw)validate_dataset = datasets.ImageFolder(root='./val',transform=data_transform["val"])val_num = len(validate_dataset)validate_loader = torch.utils.data.DataLoader(validate_dataset,batch_size=batch_size, shuffle=False,num_workers=nw)print("using {} images for training, {} images for validation.".format(train_num, val_num))net = resnet34(num_classes=36)net.to(device)# define loss functionloss_function = nn.CrossEntropyLoss()# construct an optimizerparams = [p for p in net.parameters() if p.requires_grad]optimizer = optim.Adam(params, lr=0.0001)epochs = 15best_acc = 0.0save_path = './resNet34.pth'train_steps = len(train_loader)for epoch in range(epochs):# trainnet.train()running_loss = 0.0train_bar = tqdm(train_loader, file=sys.stdout)for step, data in enumerate(train_bar):images, labels = dataoptimizer.zero_grad()logits = net(images.to(device))loss = loss_function(logits, labels.to(device))loss.backward()optimizer.step()# print statisticsrunning_loss += loss.item()train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,epochs,loss)# validatenet.eval()acc = 0.0  # accumulate accurate number / epochwith torch.no_grad():val_bar = tqdm(validate_loader, file=sys.stdout)for val_data in val_bar:val_images, val_labels = val_dataoutputs = net(val_images.to(device))# loss = loss_function(outputs, test_labels)predict_y = torch.max(outputs, dim=1)[1]acc += torch.eq(predict_y, val_labels.to(device)).sum().item()val_bar.desc = "valid epoch[{}/{}]".format(epoch + 1,epochs)val_accurate = acc / val_numprint('[epoch %d] train_loss: %.3f  val_accuracy: %.3f' %(epoch + 1, running_loss / train_steps, val_accurate))if val_accurate > best_acc:best_acc = val_accuratetorch.save(net.state_dict(), save_path)print('Finished Training')if __name__ == '__main__':main()

http://chatgpt.dhexx.cn/article/0YLJ8SLx.shtml

相关文章

1 通俗易懂解释Resnet50

通俗易懂Resnet50网络结构分析 1 Why(该网络要解决什么样的问题)1.1 什么叫梯度消失和梯度爆炸 2 How(如何解决该问题)2.1 直观解释2.2 残差是什么2.3 网络结构 3 what 结果怎么样 1 Why(该网络要解决什么样的问题) 理论上网络越来越深,获取的信息越多,…

ResNet50网络结构

代码: import keras keras.utils.plot_model(keras.applications.ResNet50(include_topTrue,input_shape(224,224,3),weightsNone), to_fileimage_model.png, show_shapesTrue) ResNet50的标准输入为224x224,avg_pool(-3层)及之…

resnet18与resnet50

ResNet18的18层代表的是带有权重的 18层,包括卷积层和全连接层,不包括池化层和BN层。 Resnet论文给出的结构图 参考ResNet详细解读 结构解析: 首先是第一层卷积使用7∗77∗7大小的模板,步长为2,padding为3。之后进行…

长文解析Resnet50的算法原理

大家好啊,我是董董灿。 恭喜你发现宝藏了。收藏起来吧。 前言 从打算写图像识别系列文章开始已经快2个月了,目前写了有9篇文章,几乎涵盖了Renset50这一CNN网络95%的算法。 今天整理了下,修复一些笔误和表述错误,整…

【pytorch】ResNet18、ResNet20、ResNet34、ResNet50网络结构与实现

文章目录 ResNet主体BasicBlockResNet18ResNet34ResNet20 Bottleneck BlockResNet50 ResNet到底解决了什么问题 选取经典的早期Pytorch官方实现代码进行分析 https://github.com/pytorch/vision/blob/9a481d0bec2700763a799ff148fe2e083b575441/torchvision/models/resnet.py 各…

神经网络学习小记录20——ResNet50模型的复现详解

神经网络学习小记录20——ResNet50模型的复现详解 学习前言什么是残差网络什么是ResNet50模型ResNet50网络部分实现代码图片预测 学习前言 最近看yolo3里面讲到了残差网络,对这个网络结构很感兴趣,于是了解到这个网络结构最初的使用是在ResNet网络里。 …

彻底搞懂ResNet50

pytorch实现resnet50代码如下: (1)一个block实现,如1x1,64,3x3,64,1x1,256。这段代码中,1x1的卷积核只是为了改变输出通道数,3x3的卷积可能改变卷…

【ResNet】Pytorch从零构建ResNet50

Pytorch从零构建ResNet 第一章 从零构建ResNet18 第二章 从零构建ResNet50 文章目录 Pytorch从零构建ResNet前言一、Res50和Res18的区别?1. 残差块的区别2. ResNet50具体结构 二、ResNet分步骤实现三、完整例子测试总结 前言 ResNet 目前是应用很广的网络基础框架&…

ResNet介绍

ResNet介绍 1 简要概括 ResNet(Residual Neural Network)由微软研究院的Kaiming He等四名华人提出,通过使用ResNet Unit成功训练出了152层的神经网络,并在ILSVRC2015比赛中取得冠军,在top5上的错误率为3.57%&#xff0…

resnet 20 和resnet 56

resnet是什么 在论文中,存在resnet20和resnet56,之前没注意,现在仔细了解后才发觉和标准的ResNet有差异,可参考resnet-50 vs resnet-56(或者18 vs 20)的明显区别在哪,性能差的好多?…

ResNet详解

1.什么是ResNet? ResNet 网络是在 2015年 由微软实验室中的何凯明等几位大神提出,斩获当年ImageNet竞赛中分类任务第一名,目标检测第一名。获得COCO数据集中目标检测第一名,图像分割第一名。 2.网络中的亮点 1.超深的网络结构&a…

关于ResNet50的解读

说起ResNet必然要提起He大佬,这真是神一样的存在,这不,不久前又有新的突破RegNet,真是厉害啊。 ResNet开篇之作在此,后面又出了各种变形啥的,ResNeXt,inception-ResNet等等吧,He大佬…

【深度学习】resnet-50网络结构

最近许多目标检测网络的backbone都有用到resnet-50的部分结构,于是找到原论文,看了一下网络结构,在这里做一个备份,需要的时候再来看看。 整体结构 layer0 首先是layer0,这部分在各个网络都一样,如图&…

一张图看懂Resnet50与Resnet101算法

直接上流程图,算法很清晰。 仅包括卷积层和全连接层,不包括池化层,正好50层。 相比于ResNet_50,ResNet_101就是在上图第3个大虚线框多了17个bottleneck,17*350101,说白了就是将下图复制17个加入上图的第3个…

什么是Resnet50模型?

1 深度残差网络 随着CNN的不断发展,为了获取深层次的特征,卷积的层数也越来越多。一开始的 LeNet 网络只有 5 层,接着 AlexNet 为 8 层,后来 VggNet 网络包含了 19 层,GoogleNet 已经有了 22 层。但仅仅通过增加网络层…

resnet-50介绍(一)

这篇文章讲解的是使用Tensorflow实现残差网络resnet-50. 侧重点不在于理论部分,而是在于代码实现部分。在github上面已经有其他的开源实现,如果希望直接使用代码运行自己的数据,不建议使用本人的代码。但是如果希望学习resnet的代码实现思路&…

ResNet50 网络结构搭建(PyTorch)

ResNet50是一个经典的特征提取网络结构,虽然Pytorch已有官方实现,但为了加深对网络结构的理解,还是自己动手敲敲代码搭建一下。需要特别说明的是,笔者是以熟悉网络各层输出维度变化为目的的,只对建立后的网络赋予伪输入…

ResNet-50网络理解

本文主要针对ResNet-50对深度残差网络进行一个理解和分析 ResNet已经被广泛运用于各种特征提取应用中,当深度学习网络层数越深时,理论上表达能力会更强,但是CNN网络达到一定的深度后,再加深,分类性能不会提高&#xff…

庖丁解牛-Resnet50 深度剖析,细致讲解,深入理解

背景介绍 ResNet-50侧边输出形状 假设输入为352,则 output2 256x88x88 output3 512x44x44 output4 1024x22x22 output5 2048x11x11 VGG-16侧边输出形状 假设输入为352,则 output1 64x320x320 output2 128x160x160 output3 256x88x88 output4 512x44x44 output5 512x22…

Resnet-50网络结构详解

解决的问题: 梯度消失,深层网络难训练。 因为梯度反向传播到前面的层,重复相乘可能使梯度无穷小。结果就是,随着网络的层数更深,其性能趋于饱和,甚至迅速下降。 关于为什么残差结构(即多了一…