什么是Resnet50模型?

article/2025/9/17 7:42:21

1 深度残差网络

 随着CNN的不断发展,为了获取深层次的特征,卷积的层数也越来越多。一开始的 LeNet 网络只有 5 层,接着 AlexNet 为 8 层,后来 VggNet 网络包含了 19 层,GoogleNet 已经有了 22 层。但仅仅通过增加网络层数的方法,来增强网络的学习能力的方法并不总是可行的,因为网络层数到达一定的深度之后,再增加网络层数,那么网络就会出现随机梯度消失的问题,也会导致网络的准确率下降。以下实验结果也表明确实出现了该现象,论文中称为网络退化现象,注意这和网络过拟合是两种情况。
在这里插入图片描述

1.1 什么是梯度爆炸、梯度消失?

在这里插入图片描述
上图是一个四层的全连接的网络,包括输入层、隐层(中间除了输入层跟输出层的总和)、输出层,假设每层网络激活后的输出为fi(x),其i表示第i层,x指的是第i层的输入,也就是第i-1层的输出,f是作为激活函数,那么就在这里插入图片描述,反向传播算法是基于梯度下降,以目标负梯度方向对参数进行调整,参数的更新为在这里插入图片描述,如果要更新第二层隐藏层的权值信息,根据链式求导法则:在这里插入图片描述其实类似于在这里插入图片描述就是对激活函数进行求导,如果所求导结果大于1,那么随着层数的增加,求出的梯度的更新将以指数形式相应增加,发生前文所提到的梯度爆炸;如果小于1,求出的梯度的更新将以指数形式相应减少,就会发生梯度消失。

1.2 如何解决这个问题?

 为了解决这一问题,传统的方法是采用数据初始化和正则化的方法,这解决了梯度消失的问题,但是网络准确率的问题并没有改善。而残差网络的出现可以解决梯度问题,而网络层数的增加也使其表达的特征也更好,相应的检测或分类的性能更强,再加上残差中使用了 1×1 的卷积,这样可以减少参数量,也能在一定程度上减少计算量。

 ResNet 网络的关键就在于其结构中的残差单元,如下图所示,在残差网络单元中包含了跨层连接,图中的曲线可以将输入直接跨层传递,进行了同等映射,之后与经过卷积操作的结果相加。假设输入图像为 x,输出为H(x),中间经过卷积之后的输出为F(x)的非线性函数,那最终的输出为H(x) = F(x) + x,这样的输出仍然可以进行非线性变换,残差指的是“差”,也就是F(x),而网络也就转化为求残差函数F(x) = H(x) - x,这样残差函数要比 F(x) = H (x) 更加容易优化。

在这里插入图片描述
 Resnet可以理解为三个人之间传话的游戏,第一个人传给第二个人,第二个人传给第三个人,那么第三个人收到的信息可能会由于第二个人理解错误,接收的信息受到影响,增加了传错的概率,所以Resnet的作用可以直跳过第二个人,直接把话给到第三个人。这个就是对于Resnet的简单理解。

1.3 什么是残差?

 ResNet提出了两种mapping:一种是identity mapping,指的就是图中”弯弯的曲线”,另一种residual mapping,指的就是除了”弯弯的曲线“那部分,所以最后的输出是 H(x) = F(x) + x,identity mapping顾名思义,就是指本身,也就是公式中的x,而residual mapping指的是“差”,也就是F(x) = H(x)−x,所以残差指的就是F(x)部分,这里有解释了一遍F(x) = H(x)−x。

2 Resnet50 网络

 Resnet50网络中包含了49 个卷积层,外加一个全连接层(FC)。如下图所示,Resnet50网络结构可以分成七个部分,第一部分不包含残差块,主要对输入进行卷积、正则化、激活函数、最大池化的计算。第二、三、四、五部分结构都包含了残差块,图中的绿色图块不会改变残差块的尺寸,只用于改变残差块的维度。在Resnet50网络结构中,残差块都有三层卷 积,那网络总共就是有1+3 × (3+4+6+3) = 49个卷积层,加上最后的全连接层总共是50层,这也是Resnet50名称的由来。网络的输入为224×224×3,经过前五部分的卷积计算,输出为7×7×2048,池化层会将其转化成一个特征向量,最后分类器会对这个特征向量进行计算并输出类别概率。

下面这张图片是Resnet文章所展示的结构图,文章会对其进行剖析,让人好理解。
在这里插入图片描述
Resnet50的另外一种理解。
在这里插入图片描述

2.1 ResNet50整体结构

上图可划分为左、中、右3个部分,三者内容分别:Resnet50整体结构;Resnet50各个stage具体结构;Bottleneck具体结构。
在这里插入图片描述
整体结构部分分为5个stage,其中stage 0 的结构是比较简单,可以视其为对INPUT图像的预处理,后4个Stage都由Bottleneck组成,结构较为相似。Stage 1包含3个Bottleneck,剩下的3个stage分别包括4、6、3个Bottleneck。

stage 0 阶段

  • (3,224,224) 指输入INPUT的通道数(channel)、高(height)和宽(width),即(C,H,W)。现假设输入的高度和宽度相等,所以用(C,W,W)表示。
    该stage中第1层包括3个先后操作:
    1.CONV
    CONV是卷积(Convolution)的缩写,7×7指卷积核大小,64指卷积核的数量(即该卷积层输出的通道数),/2指卷积核的步长为2。
    2.BN
    BN是Batch Normalization的缩写,即常说的BN层。
    3.RELU
    RELU指ReLU激活函数。

  • 该stage中第2层为MAXPOOL,即最大池化层,其卷积核大小为3×3、步长为2。

  • (64,56,56)是该stage输出的通道数(channel)、高(height)和宽(width),其中64等于该stage第1层卷积层中卷积核的数量,56等于224/2/2(步长为2会使输入尺寸减半)。

总体来讲,在Stage 0中,形状为(3,224,224)的输入先后经过卷积层、BN层、ReLU激活函数、MaxPooling层得到了形状为(64,56,56)的输出。

stage 1 阶段

与stage 0类似,stage1输入的形状为(64,56,56),输出的形状为(64,56,56)

Bottleneck具体结构

现在要介绍2种Bottleneck的结构。“BTNK”指的是BottleNeck的缩写。

2种Bottleneck分别对应了2种情况:输入与输出通道数相同(BTNK2)、输入与输出通道数不同(BTNK1),这一点可以结合ResNet原文。

BTNK2

BTNK2有2个可变的参数C和W,即输入的形状(C,W,W)中的c和W。

令形状为(C,W,W)的输入为x,令BTNK2左侧的3个卷积块(以及相关BN和RELU)为函数F(x),两者相加(F(x)+x)后再经过1个ReLU激活函数,就得到了BTNK2的输出,该输出的形状仍为(C,W,W),即上文所说的BTNK2对应输入x与输出F(x)通道数相同的情况。

BTNK1

BTNK1有4个可变的参数C、W、C1和S。

与BTNK2相比,BTNK1多了1个右侧的卷积层,令其为函数G(x)。BTNK1对应了输入x与输出F(x)通道数不同的情况,也正是这个添加的卷积层将x变为G(x),起到匹配输入与输出维度差异的作用(G(x)和F(x)通道数相同),进而可以进行求和F(x)+G(x)。

总结

ResNet后4个stage中都有BTNK1和BTNK2。

  • 4个stage中BTNK2参数规律相同,4个stage中BTNK2的参数全都是1个模式和规律,只是输入的形状(C,W,W)不同。
  • stage 1中BTNK1参数的规律与后3个stage不同,然而,4个stage中BTNK1的参数的模式并非全都一样。具体来讲,后3个stage中BTNK1的参数模式一致,stage 1中BTNK1的模式与后3个stage的不一样,这表现在以下2个方面:
    1.参数S:BTNK1左右两个1×1卷积层是否下采样:
     stage 1中的BTNK1:步长S为1,没有进行下采样,输入尺寸和输出尺寸相等。
     后3个stage的BTNK1:步长S为2,进行了下采样,输入尺寸是输出尺寸的2倍。
    2.参数C和C1:BTNK1左侧第一个1×1卷积层是否减少通道数
     stage 1中的BTNK1:输入通道数C和左侧1×1卷积层通道数C1相等(C=C1=64),即左侧1×1卷积层没有减少通道数。
     后3个stage的BTNK1:输入通道数C和左侧1×1卷积层通道数C1不相等(C=2*C1),左侧1×1卷积层有减少通道数。

代码实现

class Bottleneck(nn.Module):expansion = 4  # 卷积核是前一个卷积核的四倍def __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.BatchNormalization(out_channel)# -----------------------------------------self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel, kernel_size=3, bias=False,stride=stride, padding=1)self.bn2 = nn.BatchNormalization(out_channel)# -----------------------------------------self.conv3 = nn.Conv2d(out_channels=out_channel * self.expansion, kernel_size=1, stride=1,bias=False)self.bn3 = nn.BatchNormalization(out_channel * self.expansion)# -----------------------------------------self.relu = nn.ReLU(inplace=True)self.downsample = downsampledef forward(self, x):identity = xif self.downsample is not None:  # 为None的话对应实线的残差结构,如果不为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 = self.add([out, identity])out = self.relu(out)return out

引入Resnet50网络之后的效果

在这里插入图片描述

参考:

  1. https://zhuanlan.zhihu.com/p/353235794
  2. 哔哩哔哩—霹雳吧啦
  3. https://arxiv.org/abs/1512.03385

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

相关文章

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网络结构详解

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

卷积神经网络学习—Resnet50(论文精读+pytorch代码复现)

前言一、Resnet论文精读引入残差残差块ResNet50模型基本构成BN层Resnet50总体结构 二、Resnet50代码复现完整代码 前言 如果说在CNN领域一定要学习一个卷积神经网络,那一定非Resnet莫属了。 接下来我将按照:Resnet论文解读、Pytorch实现ResNet50模型两部…

Java类加载器介绍

1.类加载器介绍 类加载器负责将class文件加载到内存中,并为之生成对应的java.lang.Class对象。对于任意一个类,都需要加载它的类加载器和这个类本身来确定该类在JVM中唯一性,也就是说,同一个class文件用两个不同的类加载器加载并…

类加载与类加载器概述

目录 一、类加载 类的加载: 类的连接: 类的初始化: 类初始化步骤: 类的初始化时机: 二、类加载器 类加载器的作用 JVM的类加载机制 Java运行时具有以下内置类加载器: 一、类加载 当程序要使用某…

十一、类加载器的作用

狂神说Java:https://www.bilibili.com/video/BV1p4411P7V3 1、类加载的作用 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象,作为方法区中类数据…

2.类加载器

回顾 上一节我们学习了JVM类加载机制,我们学习到大概的过程:通过类加载器将编译好的class文件加载到JVM进程中,通过字节码执行引擎去执行代码。这只是一个整体的过程,具体的细节我们从本节开始分析。 通过本节我们将掌握以下知识&…

Java类加载器

一.类的生命周期 1. 加载(Loading):找 Class 文件 1. 通过一个类的全限定名来获取定义此类的二进制字节流。 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。 3.在内存中生成一个代表这个类的java.lang.Class对象&#xf…

Java类加载器的使用

Java类加载器 classloader顾名思义,即是类加载。虚拟机把描述类的数据从class字节码文件加载到内存,并对数据进行检验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。 先认识一下类加载…

JVM 类加载器

什么是类加载器 类加载器负责在运行时将Java类动态加载到Java虚拟机,他们也是JRE(Java运行时环境)的一部分。因此,借助类加载器,JVM无需了解底层文件或文件系统即可运行Java程序。此外,这些Java类不会一次…

类加载器深入理解

虚拟机设计团队把类加载阶段中“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的模块称为“类加载器”。 类加载器在类层次划分、OSGI、热部署、代码加密等领域…

java获取类加载器

获取类加载器的方法: //扩展类加载器MainClassLoader classLoader MainTest.class.getClassLoader();//表示当前线程的类加载器——应用程序类加载器ClassLoader contextClassLoader Thread.currentThread().getContextClassLoader();//—启动类加载器ClassLoader systemClas…

类加载器的种类

类加载器的种类有四种,如下图所示: 1.启动类加载器(引导类加载器,Bootstrap ClassLoader) 这个类加载使用C/C语言实现的,嵌套在JVM内部它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar、res…

Java类加载器详解

1 特点 双亲委派: 如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载…

【类加载器】java类加载器

类装载器ClassLoader(一个抽象类) 描述一下JVM加载class文件的原理机制 类装载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件,在java中类装载器把一个类装入JVM,经过以下步骤: 1、装载&#xff…

什么是类加载器?

类加载器 什么是类加载器,作用是什么? 类加载器就是加载字节码文件(.class)的类 Java语言是一种具有动态性的解释语言,类(CLASS) 只有被加载到 JVM 中后才能运行。当运行指定程序时,JVM会将编译生成的.class文件按照需求和一定的规…

类加载器

类加载过程 加载->连接->初始化。连接过程又可分为三步:验证->准备->解析。 类加载器分类 JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader: 启动类加载器&…