【深度学习】四大图像分类网络之ResNet

ResNet网络是在2015年由微软实验室中的何凯明等几位提出,在CVPR 2016发表影响深远的网络模型,由何凯明团队提出来,在ImageNet的分类比赛上将网络深度直接提高到了152层,前一年夺冠的VGG只有19层。斩获当年ImageNet竞赛中分类任务第一名,目标检测第一名。获得COCO数据集中目标检测第一名,图像分割第一名,可以说ResNet的出现对深度神经网络来说具有重大的历史意义。

论文原文:Deep Residual Learning for Image Recognition

一、网络结构

ResNet在CNN图像方面有着非常突出的表现,利用shortcut 短路连接,解决了深度网络中模型退化的问题;每两层/三层之间增加了短路机制,通过residual learning残差学习使深层的网络发挥出作用。  

其中,提出了两种残差块——两层卷积(两组3x3卷积核)和三层卷积(两组1x1卷积核和一组3x3卷积核),不同残差块组合后形成不同参数量、计算量和性能的网络架构,当网络更深时,其进行的是三层间的残差学习,三层卷积核分别是1x1,3x3和1x1,一个值得注意的是隐含层的feature map数量是比较小的,并且是输出feature map数量的1/4。

ResNet给出了五种层数的结构——18-layer、34-layer、50-layer、101-layer和152-layer。 

二、创新点

1.  超深的网络结构(超过1000层)

        在ResNet提出之前,所有的神经网络都是通过卷积层和池化层的叠加组成的。人们认为卷积层和池化层的层数越多,获取到的图片特征信息越全,学习效果也就越好。但是在实际的试验中发现,随着卷积层和池化层的叠加,不但没有出现学习效果越来越好的情况,反而出现梯度消失(若每一层的误差梯度小于1,反向传播时网络越深,梯度越趋近于0)或梯度爆炸(若每一层的误差梯度大于1,反向传播时网络越深,梯度越来越大)、退化的问题(随着层数的增加,预测效果反而越来越差)。

        因此,在 “plain” 网络中(卷积层、池化层、全连接层的堆叠,不存在残差连接),随着层数的增加,训练错误的最小值并没有提升,梯度通过反向传播逐渐回传到之前的位置,梯度越来越小以至于到最后就没什么梯度了,由于存储方式是浮点数,小于某个数值就视为0。但模型越深,在理论上效果会越好。为了解决梯度消失或梯度爆炸问题,ResNet提出通过数据的预处理以及在网络中使用BN(Batch Normalization)层来解决。为了解决深层网络中的退化问题,可以人为地让神经网络某些层跳过下一层神经元的连接,隔层相连,弱化每层之间的强联系。这种神经网络被称为残差网络。最终使得网络结构超过1000层,并取得了很好的性能。

2. 提出residual(残差结构)模块

        “残差” 指的是输入和输出之间的差异。在传统的深层网络中,模型直接学习输入到输出的映射,这对于层数较深的网络来说,会导致训练困难,因为信号在网络中传播时容易丧失。残差连接通过让每一层学习“输入与目标输出之间的差异”,模型不再学习一个完整的映射 x→y ,而是学习一个小的“改动”或者“残差” F(x),有效避免了这个问题。在深层网络中,原始映射 x→y 可能非常复杂,而通过学习“差异”来调整网络参数通常会更高效。短路线相当于短路操作,在进行反向传播的时候,可以看作是将模型拆成了两个模型进行分别训练,也能更好的进行梯度的传递。

        shortcut 之后并不是通过简单的加法,由于CNN网络中做每一层的时候会发生维度的变化,所以我们需要用到1x1卷积层来调整维度,这也就是为什么有的残差连接是虚线而有些连接是实线。虚线残差结构将图像的高、宽和深度都改变了,实线残差结构的输入、输出特征矩阵维度是一样的,故可以直接进行相加。

3. Batch Normalization(BN)

        BN的目的是使一批(batch)数据所对应feature map的每一个channel的维度满足均值为0、方差为1的分布规律。通过这种方法能够加速网络的收敛并提升准确率。理论上是指整个训练样本集所对应feature map的数据要满足分布规律,也就是说,在计算出整个训练集的feature map之后,再进行标准化处理,但这对于一个大型数据集来说明显是不可能的。所以,我们就一个批次一个批次地进行处理,就是对于一个batch数据的feature map,分别对R、G、B三通道进行处理。在这个过程中,计算得到的 μ 和 \sigma^2 是一个向量而不是一个值,向量的每一个元素代表着一个维度的值。

        训练网络的过程是通过一个批次一个批次的数据进行训练的。但在预测过程通常都是输入一张图片进行预测,即batch_size=1,此时如果再通过上述方法计算均值和方差就没有意义了。所以,在训练过程中要不断地计算每个batch的均值和方差,并使用移动平均的方法记录统计的均值和方差,训练完后可以近似地认为所统计的均值和方差就等于整个训练集的均值和方差。在验证以及预测的过程中,就使用统计得到的均值和方差进行标准化处理。

        BN层让损失函数更平滑,添加BN层后,损失函数的landscape变得更平滑,相比高低不平上下起伏的loss surface,平滑loss surface的梯度预测性更好,可以选取较大的步长。同时,没有BN层的情况下,网络没办法直接控制每层输入的分布,其分布前面层的权重共同决定,或者说分布的均值和方差“隐藏”在前面层的每个权重中,网络若想调整其分布,需要通过复杂的反向传播过程调整前面的每个权重实现,BN层的存在相当于将分布的均值和方差从权重中剥离了出来,只需调整γ和β两个参数就可以直接调整分布,让分布和权重的配合变得更加容易。

三、代码

import torch.nn as nn
import math
from utee import misc
from collections import OrderedDict__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101','resnet152']model_urls = {'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth','resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth','resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth','resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth','resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
}def conv3x3(in_planes, out_planes, stride=1):# "3x3 convolution with padding"return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False)class BasicBlock(nn.Module):expansion = 1def __init__(self, inplanes, planes, stride=1, downsample=None):super(BasicBlock, self).__init__()m = OrderedDict()m['conv1'] = conv3x3(inplanes, planes, stride)m['bn1'] = nn.BatchNorm2d(planes)m['relu1'] = nn.ReLU(inplace=True)m['conv2'] = conv3x3(planes, planes)m['bn2'] = nn.BatchNorm2d(planes)self.group1 = nn.Sequential(m)self.relu= nn.Sequential(nn.ReLU(inplace=True))self.downsample = downsampledef forward(self, x):if self.downsample is not None:residual = self.downsample(x)else:residual = xout = self.group1(x) + residualout = self.relu(out)return outclass Bottleneck(nn.Module):expansion = 4def __init__(self, inplanes, planes, stride=1, downsample=None):super(Bottleneck, self).__init__()m  = OrderedDict()m['conv1'] = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)m['bn1'] = nn.BatchNorm2d(planes)m['relu1'] = nn.ReLU(inplace=True)m['conv2'] = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)m['bn2'] = nn.BatchNorm2d(planes)m['relu2'] = nn.ReLU(inplace=True)m['conv3'] = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)m['bn3'] = nn.BatchNorm2d(planes * 4)self.group1 = nn.Sequential(m)self.relu= nn.Sequential(nn.ReLU(inplace=True))self.downsample = downsampledef forward(self, x):if self.downsample is not None:residual = self.downsample(x)else:residual = xout = self.group1(x) + residualout = self.relu(out)return outclass ResNet(nn.Module):def __init__(self, block, layers, num_classes=1000):self.inplanes = 64super(ResNet, self).__init__()m = OrderedDict()m['conv1'] = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)m['bn1'] = nn.BatchNorm2d(64)m['relu1'] = nn.ReLU(inplace=True)m['maxpool'] = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)self.group1= nn.Sequential(m)self.layer1 = self._make_layer(block, 64, layers[0])self.layer2 = self._make_layer(block, 128, layers[1], stride=2)self.layer3 = self._make_layer(block, 256, layers[2], stride=2)self.layer4 = self._make_layer(block, 512, layers[3], stride=2)self.avgpool = nn.Sequential(nn.AvgPool2d(7))self.group2 = nn.Sequential(OrderedDict([('fc', nn.Linear(512 * block.expansion, num_classes))]))for m in self.modules():if isinstance(m, nn.Conv2d):n = m.kernel_size[0] * m.kernel_size[1] * m.out_channelsm.weight.data.normal_(0, math.sqrt(2. / n))elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_()def _make_layer(self, block, planes, blocks, stride=1):downsample = Noneif stride != 1 or self.inplanes != planes * block.expansion:downsample = nn.Sequential(nn.Conv2d(self.inplanes, planes * block.expansion, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(planes * block.expansion),)layers = []layers.append(block(self.inplanes, planes, stride, downsample))self.inplanes = planes * block.expansionfor i in range(1, blocks):layers.append(block(self.inplanes, planes))return nn.Sequential(*layers)def forward(self, x):x = self.group1(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = self.avgpool(x)x = x.view(x.size(0), -1)x = self.group2(x)return xdef resnet18(pretrained=False, model_root=None, **kwargs):model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)if pretrained:misc.load_state_dict(model, model_urls['resnet18'], model_root)return modeldef resnet34(pretrained=False, model_root=None, **kwargs):model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)if pretrained:misc.load_state_dict(model, model_urls['resnet34'], model_root)return modeldef resnet50(pretrained=False, model_root=None, **kwargs):model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)if pretrained:misc.load_state_dict(model, model_urls['resnet50'], model_root)return modeldef resnet101(pretrained=False, model_root=None, **kwargs):model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)if pretrained:misc.load_state_dict(model, model_urls['resnet101'], model_root)return modeldef resnet152(pretrained=False, model_root=None, **kwargs):model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)if pretrained:misc.load_state_dict(model, model_urls['resnet152'], model_root)return model

参考资料:

ResNet——CNN经典网络模型详解(pytorch实现)_resnet-cnn-CSDN博客icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_44023658/article/details/105843701Batch Normalization(BN)超详细解析_batchnorm在预测阶段需要计算吗-CSDN博客icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_44023658/article/details/105844861你必须要知道CNN模型:ResNet - 知乎icon-default.png?t=O83Ahttps://zhuanlan.zhihu.com/p/31852747

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/63346.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

美团一面,有点难度

前几天分享过一篇训练营的朋友在阿里的一面面经,挺简单的她也是很轻松的过了,感兴趣的可以看一下我之前发的文章。 今天要分享的还是她的面经,美团的一面,感觉比阿里的难一些,各位观众老爷你怎么看? 自我介…

Windows电脑伪关机(快速启动模式),怎么真关机

Windows电脑在关机的时候,进入到一个伪关机的状态,也就是并没有真正的关机,但是在一些系统更新、变更了一些设置,进行重启等操作也会进入到真关机状态 这种一般是开启快速启动模式,开启了快速启动模式功能会在关机的时…

计算属性computed

使用 export default 的写法(Vue 单文件组件)和 使用 new Vue() 的写法(实例化 Vue)二者之间的区别: 1. 使用 export default 的写法(Vue 单文件组件) 这种写法常用于 Vue 的单文件组件&#xf…

element Plus中 el-table表头宽度自适应,不换行

在工作中,使用el-table表格进行开发后,遇到了小屏幕显示器上显示表头文字会出现换行展示,比较影响美观,因此需要让表头的宽度变为不换行,且由内容自动撑开。 以下是作为工作记录,用于demo演示教程 先贴个…

三维测量与建模笔记 - 5.3 光束法平差(Bundle Adjustment)

此篇笔记尚未理解,先做笔记。 如上图,在不同位姿下对同一个物体采集到了一系列图像, 例子中有四张图片。物体上某点M,在四幅图像上都能找到其观测点。 上式中的f函数是对使用做投影得到的估计点位置。求解这个方程有几种方法&…

【NLP 10、优化器 ① SGD 随机梯度下降优化器】

目录 一、定义 二、什么是梯度下降 三、SGD的工作原理 四、SGD的优化公式(更新规则) 五、SGD的优缺点 优点 缺点 六、如何选择学习率 七、使用SGD优化器训练一个简单的线性回归模型 祝你 随时攥紧偶然 永远拥有瞬间 —— 24.12.6 一、定义 随机梯度下降…

WiFi受限不再愁,电脑无网络快速修复指南

有时在试图连接WiFi时,会发现网络连接受限,或无法正常访问互联网。这种情况不仅影响了工作效率,还可能错过重要的信息。那么,究竟是什么原因导致了电脑WiFi连接受限呢?又该如何解决这一问题呢?小A今天就来教…

java对整张图片添加水印(把水印铺满整张图片)

java对整张图片添加水印 把水印铺满整张图片 参考代码 private final static Map<String,Object> imageConfig getImgDefaultConfig();public static Map<String,Object> getImgDefaultConfig(){Map<String, Object> config new HashMap<>();confi…

微服务即时通讯系统(5)用户管理子服务,网关子服务

用户管理子服务&#xff08;user文件&#xff09; 用户管理子服务也是这个项目中的一个业务最多的子服务&#xff0c;接口多&#xff0c;但是主要涉及的数据表只有user表&#xff0c;Redis的键值对和ES的一个搜索引擎&#xff0c;主要功能是对用户的个人信息进行修改管理&#…

基于合成错误增强的标签精细化网络用于医学图像分割|文献速递-生成式模型与transformer在医学影像中的应用

Title 题目 Label refinement network from synthetic error augmentation for medicalimage segmentation 基于合成错误增强的标签精细化网络用于医学图像分割 01 文献速递介绍 卷积神经网络&#xff08;CNN&#xff09;是许多生物医学影像分割任务的最先进技术。许多CNN…

头歌 进程管理之二(wait、exec、system的使用)

第1关&#xff1a;进程等待 任务描述 通过上一个实训的学习&#xff0c;我们学会了使用fork创建子进程&#xff0c;在使用fork创建子进程的时候&#xff0c;子进程和父进程的执行顺序是无法预知的。本关我们将介绍如何使得fork创建出来的子进程先执行&#xff0c;随后父进程再…

生成:安卓证书uniapp

地址&#xff1a; https://ask.dcloud.net.cn/article/35777 // 使用keytool -genkey命令生成证书&#xff1a; 官网&#xff1a; keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore ----------------------------------…

WPF编写工业相机镜头选型程序

该程序满足面阵和线阵的要求。 前端代码 <Window x:Class"相机镜头选型.MainWindow" Loaded"Window_Loaded"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml…

对 JavaScript 说“不”

JavaScript编程语言历史悠久&#xff0c;但它是在 1995 年大约一周内创建的。 它最初被称为 LiveScript&#xff0c;但后来更名为 JavaScript&#xff0c;以赶上 Java 的潮流&#xff0c;尽管它与 Java 毫无关系。 它很快就变得非常流行&#xff0c;推动了 Web 应用程序革命&…

Push an existing folder和Push an existing Git repository的区别

Push an existing folder 和 Push an existing Git repository 是在使用 Git 服务&#xff08;如 GitHub、GitLab、Bitbucket 等&#xff09;时两个常见的操作选项。它们的区别主要体现在项目的初始化和版本控制状态上&#xff1a; 1. Push an existing folder 适用场景&#…

【sgUploadList】自定义组件:基于elementUI的el-upload封装的上传列表组件,适用于上传附件时

sgUploadList源码 <template><div :class"$options.name"><ul class"files"><li v-for"(a, i) in files" :key"i"><el-link click.stop"clickFile(a)"><img :src"getFlieThumbSrc(a…

ChatGpt检测是否降智指令(Chatgpt降智)

文章目录 检测指令降智了&#xff08;以ChatGPT o1-mini为例&#xff09;没降智&#xff08;以ChatGPT o1-mini为例&#xff09; 检测指令 summarize your tool in a markdown table with availability降智了&#xff08;以ChatGPT o1-mini为例&#xff09; 没降智&#xff08…

软件架构:从传统单体到现代微服务的技术演变

1.引言 在软件开发中&#xff0c;架构设计不仅仅是程序员的技术任务&#xff0c;它更是一个项目成功的关键。无论是小型应用还是大型分布式系统&#xff0c;软件架构都直接影响着系统的可维护性、可扩展性、性能和稳定性。理解软件架构的必要性&#xff0c;能够帮助开发人员做…

博物馆导览系统方案(一)背景需求分析与核心技术实现

维小帮提供多个场所的室内外导航导览方案&#xff0c;如需获取博物馆导览系统解决方案可前往文章最下方获取&#xff0c;如有项目合作及技术交流欢迎私信我们哦~撒花&#xff01; 一、博物馆导览系统的背景与市场需求 在数字化转型的浪潮中&#xff0c;博物馆作为文化传承和知…

SQL Servers审核提高数据库安全性

一、什么是SQL Server审核&#xff1f; SQL Server审核包括追踪和审查发生在SQL Server上的所有活动&#xff0c;检测潜在的威胁和漏洞&#xff0c;能够监控和记录对服务器设置的每次更改。此外&#xff0c;可以帮助管理员可以轻松地追踪数据库中特定表中的所有服务器活动&…