首页 > 其他分享 >论文阅读—第二篇《Deep Residual Learning for Image Recognition》

论文阅读—第二篇《Deep Residual Learning for Image Recognition》

时间:2023-03-17 23:47:34浏览次数:77  
标签:nn Image Residual Deep 残差 channels stride self out

Deep Residual Learning for Image Recognition

论文链接

1. 简介

《Deep Residual Learning for Image Recognition》是2015年由何凯明等人提出的一篇论文,该论文提出了一种新的深度神经网络模型——残差网络(ResNet),该模型在当时在多个计算机视觉任务中均取得了最先进的性能表现。在本篇阅读笔记中,我将深入阅读这篇论文,并总结出其主要贡献、方法和实验结果。

2.背景和主要贡献

深度神经网络在计算机视觉领域中取得了重大的进展,但是由于网络深度的增加,出现了梯度消失和梯度爆炸的问题。在此背景下,本文提出了一种新的深度神经网络结构——残差网络(ResNet),该结构可以有效地解决梯度消失和梯度爆炸问题,并可以让网络达到更深的层数,从而提高网络的性能表现。
该论文的主要贡献如下:
提出了残差学习的概念,通过引入残差块来构建更深的神经网络模型,并且证明了残差学习可以有效地解决梯度消失和梯度爆炸的问题。
通过在ImageNet数据集上的实验验证了残差网络的优越性能,达到了当时最先进的结果。

3.方法

3.1 残差块

传统的卷积神经网络通常是通过堆叠多个卷积层和池化层来构建的。而残差网络则是在这些卷积层和池化层之间添加了一些残差块(residual block),如下图所示。
image
如图所示,残差块由两个卷积层和一个跨越连接(shortcut connection)组成。传统的卷积神经网络中,每个卷积层的输入都是上一层的输出,即\(h_l=f(h_{l-1})\),其中\(f(\cdot)\)是该层的特定函数,\(h_{l-1}\)和\(h_{l}\)分别表示上一层和当前层的特征图。而在残差网络中,我们不仅要学习到一个映射\(f(\cdot)\),还要学习到一个残差映射,即\(h_l=f(h_{l-1})+h_{l-1}\)。残差块的作用就是将\(h_{l-1}\)加到\(f(h_{l-1})\)上,从而得到\(h_l\)。这个跨越连接的作用是将输入特征图\(h_{l-1}\)直接添加到输出特征图\(h_l\)中,从而构建一个残差映射。这样可以避免在深度神经网络中出现梯度消失和梯度爆炸的问题,同时可以使得网络更深。

3.2 残差网络结构

在残差网络中,作者提出了两种不同的残差块结构,分别是普通的残差块和瓶颈残差块。其中普通的残差块包含两个 \(3\times3\) 的卷积层,每个卷积层后面都跟着一个 Batch Normalization 和 ReLU 激活函数。瓶颈残差块则由三个卷积层组成,分别是一个 \(1\times1\) 的卷积层、一个 \(3\times3\) 的卷积层和一个 \(1\times1\) 的卷积层,这样可以降低计算复杂度,同时保持相同的网络深度。
在实际应用中,作者采用了一个具有34层的残差网络(ResNet-34)和一个具有152层的残差网络(ResNet-152)。其中ResNet-34采用了普通的残差块,而ResNet-152采用了瓶颈残差块。作者还提出了一个比较特殊的残差网络结构——ResNet-50,该网络结构结合了普通的残差块和瓶颈残差块,共有50层。

3.3 全局平均池化层

在传统的卷积神经网络中,通常会在最后一层使用全连接层进行分类。然而,在深度神经网络中,全连接层的参数数量非常多,容易过拟合。为了避免这个问题,作者提出了使用全局平均池化层代替全连接层,全局平均池化层的作用是将最后一个卷积层的输出特征图转换为一个向量,然后直接将该向量输入到softmax分类器中进行分类。这样可以大大减少网络的参数数量,从而降低过拟合的风险。

4. 实验结果

image

从图中可以看出,ResNet在测试集上的Top-1和Top-5的错误率均低于其他网络。尤其是在网络深度较大的情况下,ResNet相对于其他网络的性能提升非常明显。

5.核心网络架构代码实现(pytorch)

import torch
import torch.nn as nn

# ResNet Basic Block
class BasicBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride=1):
        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.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
                          kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(out_channels)
            )

    def forward(self, x):
        identity = x

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.bn2(out)

        identity = self.shortcut(identity)

        out += identity
        out = self.relu(out)

        return out

# ResNet Bottleneck Block
class Bottleneck(nn.Module):
    def __init__(self, in_channels, out_channels, stride=1):
        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 * 4,
                               kernel_size=1, stride=1, bias=False)
        self.bn3 = nn.BatchNorm2d(out_channels * 4)
        self.relu = nn.ReLU(inplace=True)

        self.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels * 4:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels=in_channels, out_channels=out_channels * 4,
                          kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(out_channels * 4)
            )

    def forward(self, x):
        identity = 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)

        identity = self.shortcut(identity)

        out += identity
        out = self.relu(out)

        return out
		
# ResNet
class ResNet(nn.Module):
    def __init__(self, block, layers, num_classes=1000):
        super(ResNet, self).__init__()

        self.in_channels = 64

        self.conv1 = nn.Conv2d(in_channels=3, out_channels=64,
                               kernel_size=7, stride=2, padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(64)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

        self.layer1 = self.make_layer(block, out_channels=64, num_blocks=layers[0], stride=1)
        self.layer2 = self.make_layer(block, out_channels=128, num_blocks=layers[1], stride=2)
        self.layer3 = self.make_layer(block, out_channels=256, num_blocks=layers[2], stride=2)
        self.layer4 = self.make_layer(block, out_channels=512, num_blocks=layers[3], stride=2)

        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(512 * block.expansion, num_classes)

    def make_layer(self, block, out_channels, num_blocks, stride):
        strides = [stride] + [1] * (num_blocks - 1)
        layers = []
        for stride in strides:
            layers.append(block(self.in_channels, out_channels, stride))
            self.in_channels = out_channels * block.expansion
        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)

        x = self.avgpool(x)
        x = x.reshape(x.shape[0], -1)
        x = self.fc(x)

        return x

6.总结

本文介绍了深度残差网络(ResNet)在图像识别中的应用。ResNet通过引入跨越连接和残差块结构,解决了深度神经网络中的梯度消失和梯度爆炸问题,并且在网络深度较大的情况下仍然能够保持较高的分类性能。此外,作者还提出了全局平均池化层代替全连接层,从而大大减少网络的参数数量,降低过拟合的风险。
总的来说,ResNet的提出对深度神经网络的发展具有重要的意义,不仅在图像识别中取得了非常好的性能,而且在其他领域的应用也取得了很多进展。

标签:nn,Image,Residual,Deep,残差,channels,stride,self,out
From: https://www.cnblogs.com/zhiao/p/17228667.html

相关文章

  • deepfacelab教程之软件版本选择
    AI换脸软件出来很多年了,基于deepfake衍生出来很多,比如FaceSwap,FakeAPP,再到今天要说的DeepFaceLab。目前国内用的较多的还是最后一款,DeepFaceLab,我们以下简称DFL因为是集......
  • High-Resolution Image Synthesis with Latent Diffusion Models
    目录概大概流程代码RombachR.,BlattmannA.,LorenzD.,EsserP.andOmmerB.High-resolutionimagesynthesiswithlatentdiffusionmodels.InIEEEComputerV......
  • 《Detection of Malicious Code Variants Based on Deep Learning》
    Abstract随着互联网的发展,恶意代码攻击呈指数级增长,其中恶意代码变种被列为互联网安全的关键威胁之一。检测恶意代码变体的能力对于防范安全漏洞、数据窃取和其他危险至关......
  • 论文阅读—第一篇《ImageNet Classification with Deep Convolutional Neural Network
    ImageNetClassificationwithDeepConvolutionalNeuralNetworks论文地址1.研究背景:在计算机视觉领域,识别大规模图像集合是一个重要的任务。然而,由于数据量大,多样性......
  • 图神经网络-图游走算法核心代码DeepWalk实现
    本文主要涉及图游走算法DeepWalk的代码实现。1.DeepWalk采样算法对于给定的节点,DeepWalk会等概率的选取下一个相邻节点加入路径,直至达到最大路径长度,或者没有下一个......
  • Conversion of Continuous-Valued Deep Networks to Efficient Event-Driven Networks
    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布!  Frontiersinneuroscience,2017,11:682 Abstract脉冲神经网络(SNN)可能提供一种有效的推理方式,因......
  • fedora上安装netease-music-xx.appimage
    极简描述版网易云音乐外表简洁,没有广告,让人想起了千千静听。自带的音乐播放器Pragha,没有歌词,私人电台。但是在Linux上编译netease-music,依赖很多,怕搞坏系统,所以安装appim......
  • Deep-DRM算法理解
    title:GCN学习笔记categories: -生物信息学date:2023-03.13hidden:truemathjax:trueGCNGCN(GraphConvolutionalNetwork),图卷积网络,是深度学习算法应用最成......
  • LoadImagesAndLabels
    classLoadImagesAndLabels(Dataset):#YOLOv5train_loader/val_loader,loadsimagesandlabelsfortrainingandvalidationcache_version=0.6#datase......
  • 【Deepin】开机自启
    原理和Windows的startup文件夹一样,都是开机后系统会运行文件夹下的文件而在deepin,桌面图标都是.desktop结尾的文件,类比桌面快捷方式把.desktop文件放到用户自启目录~/.c......