深度残差网络(Deep residual network, ResNet)

2023-11-15

一、前言

深度残差网络(Deep residual network, ResNet)的提出是CNN图像史上的一件里程碑事件,让我们先看一下ResNet在ILSVRC和COCO 2015上的战绩:
图1 ResNet在ILSVRC和COCO 2015上的战绩

ResNet取得了5项第一,并又一次刷新了CNN模型在ImageNet上的历史,
ImageNet分类Top-5误差:
图2 ImageNet分类Top-5误差
那么ResNet为什么会有如此优异的表现呢?其实ResNet是解决了深度CNN模型难训练的问题,从图2中可以看到14年的VGG才19层,而15年的ResNet多达152层,这在网络深度完全不是一个量级上,所以如果是第一眼看这个图的话,肯定会觉得ResNet是靠深度取胜。事实当然是这样,但是ResNet还有架构上的技巧,这才使得网络的深度发挥出作用,这个技巧就是残差学习(Residual learning)。

二、深度网络的退化问题

从经验来看,网络的深度对模型的性能至关重要,当增加网络层数后,网络可以进行更加复杂的特征模式的提取,所以当模型更深时理论上可以取得更好的结果,
在深度学习中,网络层数增多一般会伴着下面几个问题

  1. 计算资源的消耗
  2. 模型容易过拟合
  3. 梯度消失/梯度爆炸问题的产生
  • 问题1可以通过GPU集群来解决,对于一个企业资源并不是很大的问题;
  • 问题2的过拟合通过采集海量数据,并配合Dropout正则化等方法也可以有效避免;
  • 问题3通过Batch Normalization也可以避免。
    貌似我们只要无脑的增加网络的层数,我们就能从此获益,但实验数据给了我们当头一棒。实验发现深度网络出现了退化问题(Degradation problem):网络深度增加时,网络准确度出现饱和,甚至出现下降。这个现象可以在下图中直观看出来:
    在这里插入图片描述56层的网络比20层网络效果还要差。这不会是过拟合问题,因为56层网络的训练误差同样高。我们知道深层网络存在着梯度消失或者爆炸的问题,这使得深度学习模型很难训练。但是现在已经存在一些技术手段如BatchNorm来缓解这个问题。因此,出现深度网络的退化问题是非常令人诧异的。

当网络退化时,浅层网络能够达到比深层网络更好的训练效果,这时如果我们把低层的特征传到高层,那么效果应该至少不比浅层的网络效果差,或者说如果一个VGG-100网络在第98层使用的是和VGG-16第14层一模一样的特征,那么VGG-100的效果应该会和VGG-16的效果相同。但是实验结果表明,VGG-100网络的训练和测试误差比VGG-16网络的更大。这说明A网络在学习恒等映射的时候出了问题,也就是传统的网络("plain" networks)很难去学习恒等映射。也就是说,我们不得不承认肯定是目前的训练方法有问题,才使得深层网络很难去找到一个好的参数。
所以,我们可以在VGG-100的98层和14层之间添加一条直接映射(Identity Mapping)来达到此效果。

从信息论的角度讲,由于DPI(数据处理不等式)的存在,在前向传输的过程中,随着层数的加深,Feature Map包含的图像信息会逐层减少,而ResNet的直接映射的加入,保证了 l+1层的网络一定比 l 层包含更多的图像信息。

基于这种使用直接映射来连接网络不同层直接的思想,残差网络应运而生。

三、残差学习

3.1 残差网络原理

对于一个堆积层结构(几层堆积而成)当输入为x时其学习到的特征记为H (x),现在我们希望其可以学习到残差F(x)= H(x) - x,这样其实原始的学习特征是H(x)= F(x) + x。之所以这样是因为残差学习相比原始特征直接学习更容易。当残差为0时,此时堆积层仅仅做了恒等映射,至少网络性能不会下降,实际上残差不会为0,这也会使得堆积层在输入特征基础上学习到新的特征,从而拥有更好的性能。残差学习的结构如下图所示。这有点类似与电路中的“短路”,所以是一种短路连接(shortcut connection)。

  • 改变前目标: 训练F(x) 逼近 H(x)
  • 改变后目标:训练 F(x)逼近H(x) - x
    在这里插入图片描述

上图中,左边的original block需要调整其内部参数,使得输入的x经过卷积操作后最终输出的F(x)等于x,即实现了恒等映射F(x)=x,等号左边是block的输出,右边是block的输入。但是这种结构的卷积网络很难调整其参数完美地实现F(x)=x。再看右边的Res block。因为shortcut的引入,整个block的输出变成了F(x)+x,block的输入还是x。此时网络需要调整其内部参数使得F(x)+x=x,也就是直接令其内部的所有参数为0,使得F(x)=0,F(x)+x=x就变成了0+x = x,等号左边是block的输出,右边是block的输入。输出等于输入,即完美地完成了恒等映射。

3.2 ResNet结构为什么可以解决深度网络退化问题?

因为ResNet更加容易拟合恒等映射,原因如下:

ResNet的结构使得网络具有与学习恒等映射的能力,同时也具有学习其他映射的能力。因此ResNet的结构要优于传统的卷积网络(plain networks)结构。

3.3 残差单元

由于ResNet要求 F(x)与 x 的维度大小要一致才能够相加,因此在 F(x) 与 x 维度不相同时就需要对 x 的维度做调整。
ResNet使用两种残差单元,如下图所示。左图对应的是浅层网络,而右图对应的是深层网络。对于短路连接,当输入和输出维度一致时,可以直接将输入加到输出上。但是当维度不一致时(对应的是维度增加一倍),这就不能直接相加。有两种策略:
(A方式)采用zero-padding增加维度,此时一般要先做一个downsamp,可以采用strde=2的pooling,这样不会增加参数;
(B方式)采用新的映射(projection shortcut),一般采用1x1的卷积,这样会增加参数,也会增加计算量。
在这里插入图片描述
A方式采用0填充.,完全不存在任何的残差学习能力。
B方式的模型复杂度偏高

因此论文中采用折中的C方式

C方式在F(x)的维度与 x的维度相同时,直接用 F(x) 加上 x,在维度不同时,才采用1x1的卷积层对 x 的维度进行调整。

def identity_block(input_tensor, kernel_size, filters, stage, block):
    """The identity block is the block that has no conv layer at shortcut. A方式

    # Arguments
        input_tensor: input tensor
        kernel_size: defualt 3, the kernel size of middle conv layer at main path
        filters: list of integers, the filters of 3 conv layer at main path
        stage: integer, current stage label, used for generating layer names
        block: 'a','b'..., current block label, used for generating layer names

    # Returns
        Output tensor for the block.
    """
    filters1, filters2, filters3 = filters
    if K.image_data_format() == 'channels_last':
        bn_axis = 3
    else:
        bn_axis = 1
    conv_name_base = 'res' + str(stage) + block + '_branch'
    bn_name_base = 'bn' + str(stage) + block + '_branch'

    x = Conv2D(filters1, (1, 1), name=conv_name_base + '2a')(input_tensor)
    x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x)
    x = Activation('relu')(x)

    x = Conv2D(filters2, kernel_size,
               padding='same', name=conv_name_base + '2b')(x)
    x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
    x = Activation('relu')(x)

    x = Conv2D(filters3, (1, 1), name=conv_name_base + '2c')(x)
    x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x)
    
  	x = layers.add([x, input_tensor])
    x = Activation('relu')(x)
    return x

def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)):
    """conv_block is the block that has a conv layer at shortcut
    B方式
    # Arguments
        input_tensor: input tensor
        kernel_size: defualt 3, the kernel size of middle conv layer at main path
        filters: list of integers, the filterss of 3 conv layer at main path
        stage: integer, current stage label, used for generating layer names
        block: 'a','b'..., current block label, used for generating layer names

    # Returns
        Output tensor for the block.

    Note that from stage 3, the first conv layer at main path is with strides=(2,2)
    And the shortcut should have strides=(2,2) as well
    """
    filters1, filters2, filters3 = filters
    if K.image_data_format() == 'channels_last':
        bn_axis = 3
    else:
        bn_axis = 1
    conv_name_base = 'res' + str(stage) + block + '_branch'
    bn_name_base = 'bn' + str(stage) + block + '_branch'

    x = Conv2D(filters1, (1, 1), strides=strides,
               name=conv_name_base + '2a')(input_tensor)
    x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x)
    x = Activation('relu')(x)

    x = Conv2D(filters2, kernel_size, padding='same',
               name=conv_name_base + '2b')(x)
    x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
    x = Activation('relu')(x)

    x = Conv2D(filters3, (1, 1), name=conv_name_base + '2c')(x)
    x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x)

    shortcut = Conv2D(filters3, (1, 1), strides=strides,
                      name=conv_name_base + '1')(input_tensor)
    shortcut = BatchNormalization(axis=bn_axis, name=bn_name_base + '1')(shortcut)

    x = layers.add([x, shortcut])
    x = Activation('relu')(x)
    return x

3.4 ResNet的网络结构

ResNet网络是参考了VGG19网络,在其基础上进行了修改,并通过短路机制加入了残差单元,如下图所示。变化主要体现在ResNet直接使用stride=2的卷积做下采样,并且用global average pool层替换了全连接层。ResNet的一个重要设计原则是:当feature map大小降低一半时,feature map的数量增加一倍,这保持了网络层的复杂度。从下图中可以看到,ResNet相比普通网络每两层间增加了短路机制,这就形成了残差学习,其中虚线表示feature map数量发生了改变。下图展示的34-layer的ResNet,还可以构建更深的网络如表1所示。从表中可以看到,对于18-layer和34-layer的ResNet,其进行的两层间的残差学习,当网络更深时,其进行的是三层间的残差学习,三层卷积核分别是1x1,3x3和1x1,一个值得注意的是隐含层的feature map数量是比较小的,并且是输出feature map数量的1/4。
在这里插入图片描述不同深度的ResNet

四、实验结果

在这里插入图片描述在这里插入图片描述

作者搭建了不同深度的ResNet模型进行了实验,结果如上图所示。ResNet在ImageNet上的错误率与网络的深度是线性关系,网络越深,错误率越低。说明在一定ResNet的网路结构解决之前所说的网络退化的问题。

在这里插入图片描述
这是作者在CIFAR-10上的实验结果,这里使用的shortcut是A方式,可以看出来在相同深度下ResNet的参数量远远小于其他网络,这也使得我们在训练和预测模型的时候计算比较快。作者还尝试训练了1202层的ResNet,但是最终结果并没有110层的效果好,作者分析可能是因为过拟合的原因。作者还将ResNet用于Faster-RCNN中,获得了2015年COCO的detection的冠军。

ResNet-50 完整代码

https://download.csdn.net/download/qq_34213260/12457533

参考资料:

https://zhuanlan.zhihu.com/p/31852747
https://zhuanlan.zhihu.com/p/32085715
https://zhuanlan.zhihu.com/p/42706477

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深度残差网络(Deep residual network, ResNet) 的相关文章

  • Linux安全扫描工具ClamAV安装及使用

    导语 Clam AntiVirus ClamAV 是免费而且开放源代码的防毒软件 软件与病毒码的更新皆由社群免费发布 ClamAV在命令行下运行 它不将杀毒作为主要功能 默认只能查出系统内的病毒 但是无法清除 需要用户自行对病毒文件进行处理
  • Csharp:WebClient and WebRequest use http download file

    Csharp WebClient and WebRequest use http download file 20140318 塗聚文收錄 string filePath 20140302 pdf string fileName http
  • Unity - 射线检测

    Unity 射线检测 本文简要分析了Unity中各类 射线检测 的基本原理及用法 及不同检测手段的性能对比 内容包括 Ray 射线 RaycastHit 光线投射碰撞信息 Raycast 光线投射 BoxCast SphereCast Ca
  • 学习黑马JVM的笔记

    JVM详解 一 JVM介绍 1 什么是JVM 2 有什么好处 3 学习路线 二 内存结构 1 程序计数器 Program Counter Registe 1 定义 2 作用 3 特点 4 演示 2 虚拟机栈 Java Virtual Mac
  • 通过socket获取对方ip地址

    struct sockaddr in sa int len sizeof sa if getpeername sockfd struct sockaddr sa len printf 对方IP s inet ntoa sa sin addr

随机推荐

  • GDI/GDI+/D2D/D3D

    GDI GDI D2D D3D 标签 GDID3D 2015 07 27 11 28 503人阅读 评论 0 收藏 举报 分类 Windows系统 7 原文链接 2D Drawing APIs in Windows 在 Windows 7
  • 微服务之服务网关(GateWay)

    服务网关 概述 什么是网关 为什么需要网关 GateWay实现网关 spring cloud 2 0 概念 Route 路由 工作流程 搭建 动态路由 Predicate 断言 注意 Filter 过滤 自定义过滤器 todo gatewa
  • 亲测有效!电脑系统自己停止或休眠了怎么办?如何禁止系统休眠断网?

    亲测有效 电脑系统自己停止或休眠了怎么办 如何禁止系统休眠断网 新安装的操作系统 在开启一段时间无人操作的情况下 经常发现电脑休眠了 或者网络断开了 这种情况如何解决 上干货 电脑休眠 睡眠问题 1 打开控制面板 找到 电源选项 2 更改电
  • 前端神器avalonJS入门(一)

    http www 360doc com content 14 1031 20 21412 421521791 shtml avalonJS是司徒正美开发和维护的前端mvvm框架 可以轻松实现数据的隔离和双向绑定 相比angularJS等前端
  • vscode使用ftp-sync快速上传项目代码到服务器(宝塔ftp为例)

    使用vscode开发工具小伙伴们可以在vscode搜一下ftp sync这个插件 然后点击下载安装 2 使用快捷键 Ctrl Shift P命令 输入ftp sync Init 然后选中执行 3 执行上述命令快速生成 vscode ftp
  • 面向对象编程三大特征

    面向对象三大特征 封装 继承 多态的概述以及其优点 static static表示静态 是Java中的一个修饰符 可以修饰成员方法 成员变量 可以直接通过类名调用 静态变量 特点 被该类所有对象共享不属于对象 属于类 静态变量随着类的加载而
  • Scanner中nextInt()和nextLine()详解(秒懂)

    直接上代码 输出结果 结果分析 nextInt 和nextLine 顺序互换代码如下 输出结果 结果分析 解决方法 可以将nextLine 用next 替换 两者nextLine 执行之前再加一个空nextLine 让这个空的清楚掉回车符再
  • 【Xilinx Vivado时序分析/约束系列5】FPGA开发时序分析/约束-IO时序分析

    在之前介绍的是FPGA内部的时序分析 包括以下几种情况 寄存器与寄存器之间 输入PAD 输入时钟 与寄存器之间 寄存器与输出 PAD 输出时钟 之间 输入PAD 输入时钟 与输出PAD 输出时钟 现在就开始分析FPGA与外部的其他器件的连接
  • python numpy格式化打印

    1 问题描述 在使用numpy的时候 我们经常在debug的时候将numpy数组打印下来 但是有的时候数组里面都是小数 数组又比较大 打印下来的时候非常不适合观察 这里主要讲一下如何让numpy打印的结果更加简洁 2 问题解决 这里需要使用
  • matlab参数方程画曲线

    求x2 3x 1 0 x 5 0 1 5 y1 x x 3x 1 y2 zeros size x plot x y1 x y2 f x xx 3x 1 x1 fzero f 0 5 x2 fzero f 2 5 x 0 2 1 8 2 5
  • vue获取url中的参数值,this.$route.query

    如果有的参数可传可不传 可以使用 传参 例如 http 192 168 1 12 8080 detail id 123 获取的时候 let id this route query id 一 在vue组件单页面中获取页面参数 watch ro
  • devops(后端)

    1 前言 该devpos架构为gitlab jenkins harbor k8s 项目是java项目 流程为从gitlab拉取项目代码到jenkins jenkins通过maven将项目代码打成jar包 通过dockerfile构建jdk环
  • WINDBG 驱动调试命令

    windbg 符号加载 首先添加符号 打开 windbg 工具栏 file gt Symbol File Path 写入路径如下所示 SRV E tools win7 sp1 x86 然后勾选左下角的Reload 确定 执行下面执行强制加载
  • 新纪录学习创作1(@RequestMapping、HttpServletRequest)

    1 RequestMapping 用来处理请求地址映射的注解 可用于类或方法上 用于类上 表示类中的所有响应请求的方法都是以该地址作为父路径 用于方法上 表示在类的父路径下追加方法上注解中的地址将会访问到该方法 此处需注意 RequestM
  • 全国大学生算法设计与编程挑战赛 (秋季赛)——正式赛

    最大化 max Description 有一张NN个点的无向图 要求给每个点分配一个标号 使得任意一条边两端的点的标号差 绝对值 不能超过给出的常数 DD 要求在此基础上最大化标号的最大值减最小值 如果答案为 infin 则输出 1 Inp
  • DS二叉排序树之创建和插入

    题目描述 给出一个数据序列 建立二叉排序树 并实现插入功能 对二叉排序树进行中序遍历 可以得到有序的数据序列 输入 第一行输入t 表示有t个数据序列 第二行输入n 表示首个序列包含n个数据 第三行输入n个数据 都是自然数且互不相同 数据之间
  • 在Unity中 改变地形(Terrain),并加上水面、树、草地、材质(地板上色)

    在Unity中 如何使用地形 Terrain 并加上水面 树 草地 材质 地板上色 目录 在Unity中 如何使用地形 Terrain 并加上水面 树 草地 材质 地板上色 一 水面素材包 导入 二 地形 Terrain 地貌设置 地形上升
  • 对音频进行vad及降噪处理

    感觉有必要写一篇博客了 这几天在小组比赛中负责对语音进行处理 处理有两个 一个是用vad对音频进行端点确定 即把静音部分去掉 第二个是对音频进行降噪处理 之前在网上找了许多资料 才找到谷歌之前开发过一个叫webrtc的轮子 里面集成了许多有
  • LaTeX总结8(矩阵排版)

    1 首先矩阵排版要引入一个新的宏包 usepackage amsmath 2 首先就是格式的问题了 begin matrix 只是普通的矩阵 0 1 1 2 end matrix begin pmatrix 加括号的矩阵 0 1 1 2 e
  • 深度残差网络(Deep residual network, ResNet)

    文章目录 一 前言 二 深度网络的退化问题 三 残差学习 3 1 残差网络原理 3 2 ResNet结构为什么可以解决深度网络退化问题 3 3 残差单元 3 4 ResNet的网络结构 四 实验结果 ResNet 50 完整代码 参考资料