【深度学习】总目录

深度残差网络(ResNet)由微软研究院的何恺明、张祥雨、任少卿、孙剑提出。研究动机是为了解决深度网络的退化问题,不同于过去的网络是通过学习去拟合一个分布,ResNet通过学习去拟合相对于上一层输出的残差。实验表明,ResNet能够通过增加深度来提升性能,而且易于优化,参数量更少,在许多常用数据集上有非常优秀的表现。ResNet 在2015 年的ILSVRC中取得了冠军。

论文链接:ResNet Deep Residual Learning for Image Recognition

1 Motivation

深度卷积网络整合了特征层和分类层进行端到端的训练,堆叠的层数越多,提取的特征越丰富。许多非凡的视觉识别任务都得益于非常深(16-30层)的网络。堆叠的层数越多网络学习的效果越好吗?并不是,如下图所示,56层的网络再训练集和测试集上的表现都不如20层的网络。

  • 梯度消失/爆炸会影响梯度的收敛。但是,权重的初始化,以及中间的归一化层已经很大程度上解决了梯度问题,使得网络能够收敛。这种退化不是梯度消失/爆炸导致的。
  • 过拟合是训练误差很小,而测试误差很大,这种退化也不是过拟合导致的。

对于退化问题,既然浅层网络的性能优于深度网络,那么不妨做这样的一个假设:有一个浅层网络和一个对应的深层网络,深层网络就是在浅层网络后面多加了几层。深层网络的效果是不应该比浅层的差的,当前面的层是已经学好的浅层网络,而添加的层都是恒等映射。但是,事实证明找不到这样一个看上去比较优的解。即实际上较深模型后面添加的不是恒等映射,而是一些非线性层。因此,退化问题也表明了:通过多个非线性层来近似恒等映射可能是困难的。

2 Architectural Details

Residual Learning

论文引入深度残差学习框架来解决网络退化问题。让新堆叠的层直接拟合残差取代拟合底层映射,用H(x)表示所需的底层映射,利用堆叠的非线性层拟合F(x)=H(x)-x,原始映射将被重铸为F(x)+x。当输入已经足够好,残差块输出为0。这种恒等映射可以被看作是神经网络的shortcut,它不会增加参数和计算复杂度,用常规的库就可以简单地实现。

残差结构比正常的结构多了右侧的曲线,这个曲线也叫作shortcut connection,通过跳接在激活函数前,将上一层(或几层)的输出与本层输出相加,将求和的结果输入到激活函数作为本层的输出。

Identity vs. Projection Shortcuts.

短接有三种方法(A)升维时补零填充,所有的短接都不会增加参数(B)升维时利用1×1的卷积投影,维度相同时使用Identity (C) 所有短接都用投影

从上图可以看出,C的效果最好,我们将其归因于额外的参数。A/B/C的微小不同表明了,投影并不是解决网络退化问题的关键,因此为了减少计算复杂度和模型的尺寸,我们不用C,用B。

Deeper Bottleneck Architectures.

对于更深的网络,我们引入bottleneck的设计。下图左边为34-layer网络的一个block,右边为bottleneck block。当输入为m×m×256,像左边一样做两个3×3的卷积,计算复杂度为64-d时的16倍,计算量为m×m×256×3×3×256×2。而先利用1×1的卷积降维再做一个3×3的卷积,再升维,计算量为m×m×256×1×1×64+m×m×64×3×3×64+m×m×64×1×1×256,和之前的64-d的计算量差不多。因为bottleneck的设计,50-layer的网络,虽然通道数增加了4倍,但是计算量差不多。

3 ResNet网络架构

左边为Plain Networks,遵循两个设计原则:(1)每个block内filter个数不变(不同颜色表示不同的block) (2)feature map大小减半时,filter个数加倍。VGG中用池化下采样,我们用步长为2的卷积执行下采样,同时用全局平均池化代替全连接(更少的参数量和计算量,防止过拟合),最后接softmax。

右边为残差网络,在Plain Networks的基础上增加shortcut。当输入和输出维度一样时,可以直接相加。当维度增加(残差分支出现下采样)时,(A)对多出来的通道补零填充(B)利用1×1的卷积升维。不管采取哪种方案,第一个卷积用的都是步长为2的卷积。

从上图可以看出:

  • 粗的线条时验证集上的,细的线条是训练集误差。一开始训练集的误差要比验证集上大,因为做了一些数据增强,噪声比较大。
  • 有残差的网络收敛要快一些。
  • 没有残差的网络,18-layer的误差比34-layer少,而有残差的网络,34-layer的误差小于18-layer。

事实证明:(1)深度残差网络易于优化,而对应的plain网络随着网络的加深错误率增加。(2)深度残差网络随着深度增加准确率也会增加。

为什么ResNet训的动,训的快?

假设原始网络输出为g(x),在此基础上再加一些层,输出变为f(g(x)),对它进行求导df(g(x))/dx=df(g(x))/dg(x)·dg(x))/dx。新加的层数越多,矩阵的乘法就越多,因为梯度比较小,乘来乘去就变为0了,也就是梯度消失。但是如果加了ResNet,此时输出为f(g(x))+g(x),对它进行求导df(g(x))/dx+dg(x))/dx,df(g(x))/dx很小没有关系,来自浅层网络的dg(x))/dx相对来说会大一些。

4 代码

Block实现

class BasicBlock(nn.Module):
scale = 1 def __init__(self, in_channels, out_channels, stride=1, downsample=False):
super(BasicBlock, self).__init__()
self.conv1 = nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
# -------------------------------------------------------------------------------
self.conv2 = nn.Conv2d(in_channels=out_channels, out_channels=out_channels,
kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)
# -------------------------------------------------------------------------------
self.conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
kernel_size=1, stride=2, bias=False)
self.bn = nn.BatchNorm2d(out_channels)
self.downsample = downsample def forward(self, x):
identity = x
if self.downsample:
identity = self.conv(x)
x = self.relu(self.bn1(self.conv1(x)))
x = self.bn2(self.conv2(x))
x = x + identity
return self.relu(x)

18层和34层的ResNet用的普通的block:

  • 当输入层数和输出层数不一样时,要对右边的shortcut进行1×1卷积的升维(下采样),在conv3_x,conv4_x,con5_x的第一个block都需要进行升维
  • 升维后不需要relu,但需要bn层
  • 在每个block内通道数不会改变,所以scale为1
  • 卷积后都有bn层,所以bias=False

Bottleneck实现

class Bottleneck(nn.Module):
scale = 4 def __init__(self, in_channels, out_channels, stride=1, downsample=False):
super(Bottleneck, self).__init__() self.conv1 = nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
kernel_size=1, stride=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
# ------------------------------------------------------------------------
self.conv2 = nn.Conv2d(in_channels=out_channels, out_channels=out_channels,
kernel_size=3, stride=stride, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)
# ------------------------------------------------------------------------
self.conv3 = nn.Conv2d(in_channels=out_channels, out_channels=out_channels * self.scale,
kernel_size=3, stride=1, padding=1, bias=False)
self.bn3 = nn.BatchNorm2d(out_channels * self.scale)
# -------------------------------------------------------------------------
self.conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels * self.scale,
kernel_size=1, stride=stride, bias=False)
self.bn = nn.BatchNorm2d(out_channels * self.scale)
self.downsample = downsample
# -------------------------------------------------------------------------
self.relu = nn.ReLU(inplace=True) def forward(self, x):
identity = x
if self.downsample:
identity = self.conv(x)
x = self.relu(self.bn1(self.conv1(x)))
x = self.relu(self.bn2(self.conv2(x)))
x = self.bn3(self.conv3(x))
x = x + identity
return x
  • 每个block的第一个卷积核的个数和最后卷积核的个数都相差四倍,scale=4
  • 在conv3_x,conv4_x,con5_x的第一个block都需要下采样,因此在block中的第二个卷积中stride=2
  • 在虚线残差结构的主分支上,第一个1x1卷积层的步距是2,第二个3x3卷积层步距是1。但在pytorch官方实现过程中是第一个1x1卷积层的步距是1,第二个3x3卷积层步距是2,这么做的好处是能够在top1上提升大概0.5%的准确率。

Block重复叠加

    def make_layers(self, block, block_number, channels, stride):
layers = []
downsample = False
if self.inchannels != channels * block.scale:
downsample = True
layers.append(block(self.inchannels, channels, stride, downsample))
for i in range(1, block_number):
layers.append(block(channels * block.scale, channels, 1, False))
self.inchannels = channels * block.scale
return nn.Sequential(*layers)

block:在ResNet18中用BasicBlock,在ResNet18中用Bottleneck

block_number:block重复的次数

channels:每个block中第一个卷积核的个数,channels*scale就是该block的输出通道数

stride:在conv2_x的stride为1,其余都为2

5 迁移学习

1. 下载预训练模型

import torchvision.models.resnet,点击resnet进入,链接如下

model_urls = {
'resnet18': 'https://download.pytorch.org/models/resnet18-f37072fd.pth',
'resnet34': 'https://download.pytorch.org/models/resnet34-b627a593.pth',
'resnet50': 'https://download.pytorch.org/models/resnet50-0676ba61.pth',
'resnet101': 'https://download.pytorch.org/models/resnet101-63fe2227.pth',
'resnet152': 'https://download.pytorch.org/models/resnet152-394f9c45.pth',
'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth',
'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth',
}

2.读取预训练模型,将全连接层的输出改为想要的类别数

    model = resnet34()
model.load_state_dict(torch.load("resnet34-b627a593.pth"),strict=False)
inchannel = model.fc.in_features
model.fc = nn.Linear(inchannel,2)

【论文笔记】ResNet深度残差网络的更多相关文章

  1. Resnet——深度残差网络(一)

    我们都知道随着神经网络深度的加深,训练过程中会很容易产生误差的积累,从而出现梯度爆炸和梯度消散的问题,这是由于随着网络层数的增多,在网络中反向传播的梯度会随着连乘变得不稳定(特别大或特别小),出现最多 ...

  2. Resnet——深度残差网络(二)

    基于上一篇resnet网络结构进行实战. 再来贴一下resnet的基本结构方便与代码进行对比 resnet的自定义类如下: import tensorflow as tf from tensorflo ...

  3. 深度残差网络——ResNet学习笔记

    深度残差网络—ResNet总结 写于:2019.03.15—大连理工大学 论文名称:Deep Residual Learning for Image Recognition 作者:微软亚洲研究院的何凯 ...

  4. Dual Path Networks(DPN)——一种结合了ResNet和DenseNet优势的新型卷积网络结构。深度残差网络通过残差旁支通路再利用特征,但残差通道不善于探索新特征。密集连接网络通过密集连接通路探索新特征,但有高冗余度。

    如何评价Dual Path Networks(DPN)? 论文链接:https://arxiv.org/pdf/1707.01629v1.pdf在ImagNet-1k数据集上,浅DPN超过了最好的Re ...

  5. 深度残差网络(DRN)ResNet网络原理

    一说起“深度学习”,自然就联想到它非常显著的特点“深.深.深”(重要的事说三遍),通过很深层次的网络实现准确率非常高的图像识别.语音识别等能力.因此,我们自然很容易就想到:深的网络一般会比浅的网络效果 ...

  6. CNN卷积神经网络_深度残差网络 ResNet——解决神经网络过深反而引起误差增加的根本问题,Highway NetWork 则允许保留一定比例的原始输入 x。(这种思想在inception模型也有,例如卷积是concat并行,而不是串行)这样前面一层的信息,有一定比例可以不经过矩阵乘法和非线性变换,直接传输到下一层,仿佛一条信息高速公路,因此得名Highway Network

    from:https://blog.csdn.net/diamonjoy_zone/article/details/70904212 环境:Win8.1 TensorFlow1.0.1 软件:Anac ...

  7. 关于深度残差网络(Deep residual network, ResNet)

    题外话: From <白话深度学习与TensorFlow> 深度残差网络: 深度残差网络的设计就是为了克服这种由于网络深度加深而产生的学习效率变低,准确率无法有效提升的问题(也称为网络退化 ...

  8. 使用dlib中的深度残差网络(ResNet)实现实时人脸识别

    opencv中提供的基于haar特征级联进行人脸检测的方法效果非常不好,本文使用dlib中提供的人脸检测方法(使用HOG特征或卷积神经网方法),并使用提供的深度残差网络(ResNet)实现实时人脸识别 ...

  9. 深度残差网络(ResNet)

    引言 对于传统的深度学习网络应用来说,网络越深,所能学到的东西越多.当然收敛速度也就越慢,训练时间越长,然而深度到了一定程度之后就会发现越往深学习率越低的情况,甚至在一些场景下,网络层数越深反而降低了 ...

  10. [DeeplearningAI笔记]卷积神经网络2.3-2.4深度残差网络

    4.2深度卷积网络 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 [残差网络]--He K, Zhang X, Ren S, et al. Deep Residual Learni ...

随机推荐

  1. VulnHub-ical打靶记录

    这绝对是最简单的一个题目了. 目标发现 netdiscover -r 192.168.0.10/24 根据靶场和本地系统的网段进行扫描. 信息收集 nmap -sV -Pn -sT -sC -A 19 ...

  2. IaC:实现持续交付和 DevOps 自动化的关键

    基础架构即代码(IaC)和 CI/CD 流水线最初似乎并不匹配.因为它们代表了两种不同的流程.IaC 主要关注基础设施的配置和开发,而 CI/CD 则围绕软件开发.测试和部署. 然而,将 IaC 集成 ...

  3. KubeOperator技术方案

    KubeOperator技术方案 总体介绍︎ KubeOperator 是一个开源的轻量级 Kubernetes 发行版,专注于帮助企业规划.部署和运营生产级别的 Kubernetes 集群. Kub ...

  4. vue的history模式与哈希模式原理

    hash模式 <!-- * @Author: dezhao.zhao@hand-china.com * @Date: 2021-10-26 17:52:25 * @Description: -- ...

  5. 【笔记】Oracle列转行unpivot&行转列 PIVOT

    unpivot 说明:将表中多个列缩减为一个聚合列(多列转多行) 语法:unpivot(新列名 for 聚合列名 in (对应的列名1-列名n )) 写到了一个力扣的题,发现这个unpivot函数还没 ...

  6. 力扣26(java&python)-删除有序数组中的重复项(简单)

    题目: 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度.元素的 相对顺序 应该保持 一致 . 由于在某些语言中不能改变数组的长 ...

  7. 力扣539(java)-最小时间差(中等)

    题目: 给定一个 24 小时制(小时:分钟 "HH:MM")的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示. 示例 1: 输入:timePoints = [" ...

  8. HarmonyOS NEXT应用开发案例——行程地址交换动画

    介绍 本示例介绍使用显式动画 animateTo 实现左右地址交换动画.该场景多用于机票.火车票购买等出行类订票软件中. 效果预览图 使用说明 加载完成后显示地址交换动画页面,点击中间的图标,左右两边 ...

  9. WPF 已知问题 RadioButton 指定 GroupName 后关闭窗口可能导致无法选中

    本文记录一个 WPF 已知问题,当 WPF 的 RadioButton 指定 GroupName 且将 IsChecked 状态绑定到 ViewModel 上,将包含以上控件的代码的窗口显示两个,接着 ...

  10. selenium项目中遇到的问题总结

    问题:在pycharm中运行用例能成功,在命令行运行提示找不到com包解决办法:添加一个PYTHONPATH的环境变量,值为工程目录的路径 当要查找的文本前后有换行时,用如下方法解决//td[cont ...