ResNet网络结构详解与模型的搭建

article/2025/9/16 5:39:57

ResNET(Deep Residual Learning for Image Recognition )

ResNet网络是在2015年由微软实验室提出,斩获当年ImageNet竞赛中分类任务第一名,目标检测第一名。获得COCO数据集中目标检测第一名,图像分割第一名。下图是ResNet34层模型的结构简图。
在这里插入图片描述
在ResNet网络中有如下几个亮点:

  1. 提出residual结构(残差结构),并搭建超深的网络结构(突破1000层)
  2. 使用batch normalization 加速训练(丢弃dropout)
    在ResNet网络提出之前,传统的卷积神经网络都是通过将一系列卷积层与下采样层进行堆叠得到的。但是当堆叠到一定网络深度时,就会出现两个问题。1)梯度消失或梯度爆炸。 2)退化问题(degradation problem)。在ResNet论文中说通过数据的预处理以及在网络中使用BN(Batch Normalization)层能够解决梯度消失或者梯度爆炸问题。如果不了解BN层可参考这个链接。但是对于退化问题(随着网络层数的加深,效果还会变差,如下图所示)并没有很好的解决办法。

在这里插入图片描述
所以ResNet论文提出了residual结构(残差结构)来减轻退化问题。下图是使用residual结构的卷积网络,可以看到随着网络的不断加深,效果并没有变差,反而变的更好了。

在这里插入图片描述
接着,我们就来分析下论文中的残差结构(residual),下图是论文中给出的两种残差结构。左边的残差结构是针对层数较少网络,例如ResNet18层和ResNet34层网络。右边是针对网络层数较多的网络,例如ResNet101,ResNet152等。为什么深层网络要使用右侧的残差结构呢。因为,右侧的残差结构能够减少网络参数与运算量。同样输入一个channel为256的特征矩阵,如果使用左侧的残差结构需要大约1170648个参数,但如果使用右侧的残差结构只需要69632个参数。明显搭建深层网络时,使用右侧的残差结构更合适。

在这里插入图片描述
我们先对左侧的残差结构(针对ResNet18/34)进行一个分析。如下图所示,该残差结构的主分支是由两层3x3的卷积层组成,而残差结构右侧的连接线是shortcut分支也称捷径分支(注意为了让主分支上的输出矩阵能够与我们捷径分支上的输出矩阵进行相加,必须保证这两个输出特征矩阵有相同的shape)。如果刚刚仔细观察了ResNet34网络结构图的同学,应该能够发现图中会有一些虚线的残差结构。在原论文中作者只是简单说了这些虚线残差结构有降维的作用,并在捷径分支上通过1x1的卷积核进行降维处理。而下图右侧给出了详细的虚线残差结构,注意下每个卷积层的步距stride,以及捷径分支上的卷积核的个数(与主分支上的卷积核个数相同)。

在这里插入图片描述
接着我们再来分析下针对ResNet50/101/152的残差结构,如下图所示。在该残差结构当中,主分支使用了三个卷积层,第一个是1x1的卷积层用来压缩channel维度,第二个是3x3的卷积层,第三个是1x1的卷积层用来还原channel维度(注意主分支上第一层卷积层和第二次卷积层所使用的卷积核个数是相同的,第三次是第一层的4倍)。该残差结构所对应的虚线残差结构如下图右侧所示,同样在捷径分支上有一层1x1的卷积层,它的卷积核个数与主分支上的第三层卷积层卷积核个数相同,注意每个卷积层的步距。

在这里插入图片描述
下面这幅图是原论文给出的不同深度的ResNet网络结构配置,注意表中的残差结构给出了主分支上卷积核的大小与卷积核个数,表中的xN表示将该残差结构重复N次。那到底哪些残差结构是虚线残差结构呢。

在这里插入图片描述
对于我们ResNet18/34/50/101/152,表中conv3_x, conv4_x, conv5_x所对应的一系列残差结构的第一层残差结构都是虚线残差结构。因为这一系列残差结构的第一层都有调整输入特征矩阵shape的使命(将特征矩阵的高和宽缩减为原来的一半,将深度channel调整成下一层残差结构所需要的channel)。为了方便理解,下面给出了ResNet34的网络结构图,图中简单标注了一些信息。

在这里插入图片描述
对于我们ResNet50/101/152,其实在conv2_x所对应的一系列残差结构的第一层也是虚线残差结构。因为它需要调整输入特征矩阵的channel,根据表格可知通过3x3的max pool之后输出的特征矩阵shape应该是[56, 56, 64],但我们conv2_x所对应的一系列残差结构中的实线残差结构它们期望的输入特征矩阵shape是[56, 56, 256](因为这样才能保证输入输出特征矩阵shape相同,才能将捷径分支的输出与主分支的输出进行相加)。所以第一层残差结构需要将shape从[56, 56, 64] --> [56, 56, 256]。注意,这里只调整channel维度,高和宽不变(而conv3_x, conv4_x, conv5_x所对应的一系列残差结构的第一层虚线残差结构不仅要调整channel还要将高和宽缩减为原来的一半)。

对应的pytorch代码为:

import torch.nn as nn
import torchclass BasicBlock(nn.Module):expansion = 1def __init__(self, in_channel, out_channel, stride=1, downsample=None):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):super(Bottleneck, self).__init__()self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,kernel_size=1, stride=1, bias=False)  # squeeze channelsself.bn1 = nn.BatchNorm2d(out_channel)# -----------------------------------------self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,kernel_size=3, stride=stride, bias=False, padding=1)self.bn2 = nn.BatchNorm2d(out_channel)# -----------------------------------------self.conv3 = nn.Conv2d(in_channels=out_channel, 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):super(ResNet, self).__init__()self.include_top = include_topself.in_channel = 64self.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))self.in_channel = channel * block.expansionfor _ in range(1, block_num):layers.append(block(self.in_channel, channel))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):return ResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)def resnet101(num_classes=1000, include_top=True):return ResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes, include_top=include_top)

http://chatgpt.dhexx.cn/article/MoFdN1w5.shtml

相关文章

Resnet网络结构图和对应参数表的简单理解

Resnet Resnet即就是残差网络,本文主要是对于resnet给出的网络结构图进行简单解释。 网络结构图 以上就是34层网络的网络结构图。 以上是18层、34层、50层、101层以及152层网络所对应的残差块。 我刚开始在网上看到这两张图片的时候,感觉一点都不懂&a…

pytorch Resnet 网络结构

最近在学习廖老师的pytorch教程,学到Resnet 这部分着实的烧脑,这个模型都捣鼓了好长时间才弄懂,附上我学习过程中最为不解的网络的具体结构连接(网上一直没有找到对应网络结构,对与一个自学的学渣般的我,很…

ResNet网络结构解析--Pytorch

ResNet101–DSSD/SSD (1)ResNet在Pytorch官方代码中有5种不同深度的结构,分别为18、34、50、101、152(各网络深度指的是“需要通过训练更新参数“的层数,如卷积层,全连接层等),和论…

ResNet网络结构详解及代码复现

1. ResNet论文详解 1.1. Introduction 一般网络越深&#xff0c;特征就越丰富&#xff0c;模型效果也就越好。在深度重要的驱动下&#xff0c;出现了2个问题&#xff1a; 梯度消失和梯度爆炸&#xff1a; 梯度消失&#xff1a;误差梯度<1&#xff0c;当网络层数增多时&…

resnet50网络结构_pytorch实践(改造属于自己的resnet网络结构并训练二分类网络)

我的CSDN博客:https://blog.csdn.net/litt1e 我的公众号:工科宅生活 在学习pytorch过程中,突然想拥有属于自己的网络结构,于是便自己选择了一个比较简单的resnet18进行改造,并用其对蚂蚁和蜜蜂进行分类,比较一下没有经过预训练的resnet18好还是自己改造的resnet_diy好。 …

【DL系列】ResNet网络结构详解、完整代码实现

Name&#xff1a; Deep Residual Learning for Image Recognition Author&#xff1a; 何恺明团队 Publiced&#xff1a; 2015.12_CVPR 文章目录 前言1. 残差网络待解决的问题2. ResNet模型亮点 ResNet模型结构1. 残差学习2. Residual模块3. ResNet模型 ResNet-layers模型完整代…

pytorch实现resnet网络结构

ResNet结构和pytorch实现 resnet的网络结构都是经过5个不同数量的残差块最后一个全连接分类完成的。 在resnet50以后&#xff0c;由于层数的增加残差块发生了变化&#xff0c;从原来3x3卷积变为三层卷积&#xff0c;卷积核分别为1x1、3x3、1x1&#xff0c;减少了网络参数。主…

ResNet网络结构搭建

ResNet 下图为包含有18层(17个卷积层和1个全连接层)、34层(33个卷积层和1个全连接层)、50层(49个卷积层和1个全连接层)、101层(100个卷积层和1个全连接层)、152层(151个卷积层和1个全连接层)的resnet结构 下图是论文中给出的两种残差结构。左边的残差结构是针对层数较少网络&a…

ResNet网络结构

注&#xff1a;深度好像就是channel w*h*c 根据b站up霹雳吧啦的讲解做的笔记 视频地址6.1 ResNet网络结构&#xff0c;BN以及迁移学习详解_哔哩哔哩_bilibiliR 6.2 使用pytorch搭建ResNet并基于迁移学习训练_哔哩哔哩_bilibili ResNet网络解决梯度消失、爆炸&#xff0c;以及…

经典网络ResNet介绍

经典网络ResNet(Residual Networks)由Kaiming He等人于2015年提出&#xff0c;论文名为《Deep Residual Learning for Image Recognition》&#xff0c;论文见&#xff1a;https://arxiv.org/pdf/1512.03385.pdf ResNet要解决的是深度神经网络的”退化(degradation)”问题&…

六、ResNet网络详细解析(超详细哦)

1、 RestNet网络 1.1、 RestNet网络结构 ResNet在2015年被提出&#xff0c;在ImageNet比赛classification任务上获得第一名&#xff0c;因为它“简单与实用”并存&#xff0c;之后很多方法都建立在ResNet50或者ResNet101的基础上完成的&#xff0c;检测&#xff0c;分割&…

ResNet结构

文章目录 系列文章目录一、Residual net(残差网络)二、BatchNormalization(BN)三、ResNet结构 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人都开…

深度学习之图像分类(七)--ResNet网络结构

深度学习之图像分类&#xff08;七&#xff09;ResNet 网络结构 目录 深度学习之图像分类&#xff08;七&#xff09;ResNet 网络结构1. 前言2. Residual3. 网络配置4. 代码 本节学习ResNet网络结构&#xff0c;以及迁移学习入门&#xff0c;学习视频源于 Bilibili&#xff0c;…

[NCTF2019]SQLi 1regexp注入

[NCTF2019]SQLi&regexp注入 知识点&#xff1a; 无引号闭合&#xff0c;可以利用转义符 \ %00作为截断字符可以代替注释符#和-- - regexp注入可以配合 ^ 来爆破字符 解题&#xff1a; 打开题目得到&#xff1a; 可以看做插入语句&#xff1a; select * from users where…

buuctf-[NCTF2019]Keyboard

题目是这样子的&#xff1a; 下载完压缩包并解压后打开txt文件&#xff0c;发现是这样一串密文&#xff1a; 其实答案就在问题题目中&#xff0c;keyboard是键盘的意思&#xff0c;那结果显而易见了&#xff0c;o y i w u e u y u w u i i e不难发现&#xff0c;这些字母在键盘…

NCTF Crypto WriteUp

http://ctf.nuptzj.cn/challenges Crypto篇&#xff1a; 第一题、第二题、第七题和CG-CTF一样&#xff0c;不写了… 第三题&#xff1a; 说了全家桶&#xff0c;那就python跑吧… Flag&#xff1a;nctf{base64_base32_and_base16} 150分到手 第四题&#xff1a; 鬼知道进行…

[NCTF2019]Fake XML cookbook

BUUCTF 刷题 [NCTF2019]Fake XML cookbook BUUCTF 刷题前言一、[NCTF2019]Fake XML cookbook总结 前言 通过刷题拓宽自己的知识面 一、[NCTF2019]Fake XML cookbook &#xff08;1&#xff09;打开后如图所示 &#xff08;2&#xff09;尝试了一下万能密码&#xff0c;没啥用…

[NCTF2019]True XML cookbook

打开环境&#xff0c;看到熟悉的页面&#xff0c;和前面的[NCTF2019]Fake XML cookbook页面一样&#xff0c;应该也是XXE漏洞&#xff0c;这里再介绍一下XXE漏洞&#xff1a; XXE(XML External Entity Injection)全称为XML外部实体注入。 XML是什么&#xff1f; XML指可扩展…

[NCTF2019]Sore

[NCTF2019]Sore 附件&#xff1a; ciphertext.txt&#xff1a; nsfAIHFrMuLynuCApeEstxJOzniQuyBVfAChDEznppfAiEIDcyNFBsCjsLvGlDtqztuaHvHbCmuyGNsIMhGlDtbotCoDzDjhyBzHGfHGfoHsuhlssIMvwlixBHHGfDRjoCKrapNIwqNyuxIBACQhtMwCmMCfEBpsrzEuiLGBoMipTkxrznoHfAkqwzvxuzCzDbL…

[NCTF2019]babyRSA1

1.题目代码&#xff1a; # from Crypto.Util.number import * # from flag import flag # # def nextPrime(n): # n 2 if n & 1 else 1 # while not isPrime(n): # n 2 # return n # # p getPrime(1024) # q nextPrime(p) # n p * q # e 0x1000…