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

这篇具有很好参考价值的文章主要介绍了卷积神经网络学习—Resnet50(论文精读+pytorch代码复现)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

如果说在CNN领域一定要学习一个卷积神经网络,那一定非Resnet莫属了。
接下来我将按照:Resnet论文解读、Pytorch实现ResNet50模型两部分,进行讲解,博主也是初学者,不足之处欢迎大家批评指正。

预备知识:卷积网络的深度越深,提取的特征越高级,性能越好,但传统的卷积神经网络随着层数深度的增加,会面临网络退化、梯度消失、梯度爆炸等问题,使得高层网络的性能反而不如浅层网络。

卷积细节: 将一个*(W,H,C)的3维矩阵*,输入卷积层,卷积步长stride,边界填充数量paddingKxK卷积核Cout个:

输出一个(W-K+2padding)/stride +1,(H-K+2padding)/stride +1,Cout)的3维矩阵。

网络退化: 深层网络训练模型可收敛,但在测试集和训练集的误差均大于浅层网络。
(与过拟合不同:过拟合是训练集误差低,测试集误差高)resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能
梯度消失: 假设每层梯度是一个小于1的数,由链式法则,反向传播时,梯度时不断相乘的,每向前传播一层,梯度就乘以一个小于1的数,传到最后一层,梯度已经接近0了,这就是梯度消失,换句话说就是,小于1的数连成很快会趋近于0。
梯度爆炸: 反之,如果每层梯度是一个大于1的数,大于1的数连成很快会趋近于无穷。

为解决上述问题
Resnet创新亮点
1.解决梯度消失\爆炸问题:引入BN层(Batch Normalization),弃用Dropout
2.解决网络退化问题:引入残差(Residual)


`提示:以下是本篇文章正文

一、Resnet论文精读

引入残差

残差的基本思想:真实测量值=预测值+残差
resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能
**

残差块

**:
resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能
其中,输入X,分为两路,X为恒等映射,F(X)为残差映射,两者求和进入激活函数,再输出Relu(F(X)+X)。
resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能

残差F(X)的作用:是修正恒等映射X的误差,使网络拟合的更好。
如果X足够好,则残差的参数均为0,使输出的F(X)=0;
如果X不够好,F(X)在X的基础上优化。

其中,F(X)与X相加时,shape必须相同,若F(X)的数据维数变化(如stride>1降维),则X也需要进行相应的变化(如对X做1x1的卷积)。

求F(X)残差的卷积均使用3x3conv,下采样大小降维一半。

由于恒等映射X的存在,反向传播时,梯度可以从深层直接给到浅层,避免了梯度消失与爆炸。

改进的残差块:resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能

**

ResNet50模型基本构成

**
ResNet50有两个基本的块,分别名为Conv BlockIdentity Block
Conv Block:针对X和F(X)的维度(通道数和size)是不一样的,所以不能连续串联,它的作用是改变网络的维度;
resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能

Identity Block:针对X和F(X)的维度(通道数和size)相同,可以串联,用于加深网络的。
resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能
**

BN层

:**
Batch normalization:目的是预处理使我们的一批(Batch)的feature map满足均值为0,方差为1的分布规律,这样能够加速网络的收敛。(在网络中间调整每层输入的feature map)。

一个batch size为2(两张图片,每张图片有3个通道,其中颜色红,绿,蓝分别代表r,g,b通道。)的Batch Normalization的原理,首先会统计每个通道数目所有点的像素值,求得均值和方差,然后在每个通道上分别用该点的像素值减均值除方差得到该点的像素值,此过程就是BN。最后将其接入到激活函数中。
(其中,Xi是指一批数据的同一个通道的所有特征图的数据,如下图X1就是指两张彩图的R通道的所有数据)

resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能

resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能
上述公式中,xi经过减均值,除方差之后,得到的数据的均值为0,方差为1,而后面的γ和β参数的作用又是什么呢?有时均值为0,方差为1并不是最好的效果,所以可以用通过γ调整数据的方差,通过β调整数据的均值。
resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能

介绍完BN层的原理,下面我们来看看具体的实例吧:
feature map1、feature map2分别是由image1、image2经过一系列卷积池化后得到的特征矩阵。其中每个网格的值代表该点的像素值,分别统计feature map1 和feature map2每个通道的像素值,得到一个矩阵,在使用BN的计算公式计算经过BN以后,得到每个通道每个像素点的像素值。计算公式也如下。
resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能
[注]:
(1)训练时要将traning参数设置为True,在验证时将trainning参数设置为False。在pytorch中可通过创建 模型的model.train()和model.eval()方法控制。
(2)batch size尽可能设置大点,设置小后表现可能很糟糕,设置的越大求的均值和方差越接近整个训练集的均值和方差。
(3)一般将bn层放在卷积层(Conv)和激活层(例如Relu)之间,且卷积层不要使用偏置bias,因为使用偏置和不使用偏置的yi是相等的,所以使用偏置只会徒增网络的参数,导致训练起来更加的费劲。
resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能

标准化(standardization):将数据通过去均值实现中心化的处理,根据凸优化理论与数据概率分布相关知识,数据中心化符合数据分布规律,更容易取得训练之后的泛化效果, 数据标准化是数据预处理的常见方法之一,缩放和每个点都有关系,通过方差(variance)体现出来。与归一化对比,标准化中所有数据点都有贡献(通过均值和标准差造成影响)。加速模型收敛:标准化后,最优解的寻优过程明显会变得平缓,更容易正确的收敛到最优解。
归一化(Normalization):归一化的目标是找到某种映射关系,将原数据映射到(a,b)区间上,如0~1之间,缩放仅仅跟最大、最小值的差别有关。提升模型精度:归一化后,不同维度之间的特征在数值上有一定比较性,可以大大提高分类器的准确性。

**

Resnet50总体结构

:**
resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能
Resnet网络就是残差块的堆叠,解决了网络退化问题,实现网络层数的加深,使之拥有足够好的特征提取能力。

补充:
Resnet解决网络退化的原理
1.深度梯度回传顺畅:恒等映射这一路的梯度是1,可以把浅层的信号传到深层,也可以把深层的梯度注回浅层,防止梯度消失。
2.传统线性结构网络难以拟合“恒等映射”:什么都不做时很重要;skip connection可以让模型自行选择要不要更新;弥补了高度线性造成的不可逆的信息损失。
3.图像相邻像素梯度的局部相关性:解决了传统多层卷积造成的,回传的相邻像素梯度的局部相关性越来越低的问题。

二、Resnet50代码复现

resnet50论文,深度学习,cnn,学习,pytorch,神经网络,人工智能

完整代码

代码如下(示例):文章来源地址https://www.toymoban.com/news/detail-805704.html

import torch.nn as nn
import torch


# Resnet 18/34使用此残差块
class BasicBlock(nn.Module):  # 卷积2层,F(X)和X的维度相等
    # expansion是F(X)相对X维度拓展的倍数
    expansion = 1  # 残差映射F(X)的维度有没有发生变化,1表示没有变化,downsample=None

    # in_channel输入特征矩阵的深度(图像通道数,如输入层有RGB三个分量,使得输入特征矩阵的深度是3),out_channel输出特征矩阵的深度(卷积核个数),stride卷积步长,downsample是用来将残差数据和卷积数据的shape变的相同,可以直接进行相加操作。
    def __init__(self, in_channel, out_channel, stride=1, downsample=None, **kwargs):
        super(BasicBlock, self).__init__()

        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channel)  # BN层在conv和relu层之间

        self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channel)

        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample

    def forward(self, x):
        identity = x
        if self.downsample is not 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=F(X)+X
        out += identity
        out = self.relu(out)

        return out


# Resnet 50/101/152使用此残差块
class Bottleneck(nn.Module):  # 卷积3层,F(X)和X的维度不等
    """
    注意:原论文中,在虚线残差结构的主分支上,第一个1x1卷积层的步距是2,第二个3x3卷积层步距是1。
    但在pytorch官方实现过程中是第一个1x1卷积层的步距是1,第二个3x3卷积层步距是2,
    这么做的好处是能够在top1上提升大概0.5%的准确率。
    """
    # expansion是F(X)相对X维度拓展的倍数
    expansion = 4

    def __init__(self, in_channel, out_channel, stride=1, downsample=None, groups=1, width_per_group=64):
        super(Bottleneck, self).__init__()

        width = int(out_channel * (width_per_group / 64.)) * groups
        # 此处width=out_channel

        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=width,kernel_size=1, stride=1, bias=False)  # squeeze channels
        self.bn1 = nn.BatchNorm2d(width)
        # -----------------------------------------
        self.conv2 = nn.Conv2d(in_channels=width, out_channels=width, groups=groups,kernel_size=3, stride=stride, bias=False, padding=1)
        self.bn2 = nn.BatchNorm2d(width)
        # -----------------------------------------
        self.conv3 = nn.Conv2d(in_channels=width, out_channels=out_channel * self.expansion,kernel_size=1, stride=1, bias=False)  # unsqueeze channels
        self.bn3 = nn.BatchNorm2d(out_channel * self.expansion)

        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample

    def forward(self, x):
        identity = x
        # downsample是用来将残差数据和卷积数据的shape变的相同,可以直接进行相加操作。
        if self.downsample is not 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=F(X)+X
        out += identity
        out = self.relu(out)

        return out


class ResNet(nn.Module):

    def __init__(self,
                 block,  # 使用的残差块类型
                 blocks_num,  # 每个卷积层,使用残差块的个数
                 num_classes=1000,  # 训练集标签的分类个数
                 include_top=True,  # 是否在残差结构后接上pooling、fc、softmax
                 groups=1,
                 width_per_group=64):

        super(ResNet, self).__init__()
        self.include_top = include_top
        self.in_channel = 64  # 第一层卷积输出特征矩阵的深度,也是后面层输入特征矩阵的深度

        self.groups = groups
        self.width_per_group = width_per_group

        # 输入层有RGB三个分量,使得输入特征矩阵的深度是3
        self.conv1 = nn.Conv2d(3, self.in_channel, kernel_size=7, stride=2,padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(self.in_channel)

        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

        # _make_layer(残差块类型,残差块中第一个卷积层的卷积核个数,残差块个数,残差块中卷积步长)函数:生成多个连续的残差块的残差结构
        self.layer1 = self._make_layer(block, 64, blocks_num[0])
        self.layer2 = self._make_layer(block, 128, blocks_num[1], stride=2)
        self.layer3 = self._make_layer(block, 256, blocks_num[2], stride=2)
        self.layer4 = self._make_layer(block, 512, blocks_num[3], stride=2)

        if self.include_top:  # 默认为True,接上pooling、fc、softmax
            self.avgpool = nn.AdaptiveAvgPool2d((1, 1))  # 自适应平均池化下采样,无论输入矩阵的shape为多少,output size均为的高宽均为1x1
            # 使矩阵展平为向量,如(W,H,C)->(1,1,W*H*C),深度为W*H*C
            self.fc = nn.Linear(512 * block.expansion, num_classes)  # 全连接层,512 * block.expansion为输入深度,num_classes为分类类别个数

        for m in self.modules():  # 初始化
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')

    # _make_layer()函数:生成多个连续的残差块,(残差块类型,残差块中第一个卷积层的卷积核个数,残差块个数,残差块中卷积步长)
    def _make_layer(self, block, channel, block_num, stride=1):
        downsample = None

        # 寻找:卷积步长不为1或深度扩张有变化,导致F(X)与X的shape不同的残差块,就要对X定义下采样函数,使之shape相同
        if stride != 1 or self.in_channel != channel * block.expansion:
            downsample = nn.Sequential(
                nn.Conv2d(self.in_channel, channel * block.expansion, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(channel * block.expansion))

        # layers用于顺序储存各连续残差块
        # 每个残差结构,第一个残差块均为需要对X下采样的残差块,后面的残差块不需要对X下采样
        layers = []
        # 添加第一个残差块,第一个残差块均为需要对X下采样的残差块
        layers.append(block(self.in_channel,
                            channel,
                            downsample=downsample,
                            stride=stride,
                            groups=self.groups,
                            width_per_group=self.width_per_group))

        self.in_channel = channel * block.expansion
        # 后面的残差块不需要对X下采样
        for _ in range(1, block_num):
            layers.append(block(self.in_channel,
                                channel,
                                groups=self.groups,
                                width_per_group=self.width_per_group))
        # 以非关键字参数形式,将layers列表,传入Sequential(),使其中残差块串联为一个残差结构
        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)

        if self.include_top:  # 一般为True
            x = self.avgpool(x)
            x = torch.flatten(x, 1)
            x = self.fc(x)

        return x

# 至此resnet的基本框架就写好了
# ——————————————————————————————————————————————————————————————————————————————————
# 下面定义不同层的resnet


def resnet50(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnet50-19c8e357.pth
    return ResNet(Bottleneck, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)


def resnet34(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnet34-333f7ec4.pth
    return ResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)


def resnet101(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnet101-5d3b4d8f.pth
    return ResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes, include_top=include_top)


def resnext50_32x4d(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth
    groups = 32
    width_per_group = 4
    return ResNet(Bottleneck, [3, 4, 6, 3],
                  num_classes=num_classes,
                  include_top=include_top,
                  groups=groups,
                  width_per_group=width_per_group)


def resnext101_32x8d(num_classes=1000, include_top=True):
    # https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth
    groups = 32
    width_per_group = 8
    return ResNet(Bottleneck, [3, 4, 23, 3],
                  num_classes=num_classes,
                  include_top=include_top,
                  groups=groups,
                  width_per_group=width_per_group)

到了这里,关于卷积神经网络学习—Resnet50(论文精读+pytorch代码复现)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深度学习实战——卷积神经网络/CNN实践(LeNet、Resnet)

          忆如完整项目/代码详见github: https://github.com/yiru1225 (转载标明出处 勿白嫖 star for projects thanks) 本系列博客重点在深度学习相关实践(有问题欢迎在评论区讨论指出,或直接私信联系我)。 第一章  深度学习实战——不同方式的模型部署(CNN、Yolo)_如何部署cnn_

    2023年04月11日
    浏览(48)
  • 【AI】《动手学-深度学习-PyTorch版》笔记(十九):卷积神经网络模型(GoogLeNet、ResNet、DenseNet)

    发布时间:2014年 GoogLeNet的贡献是如何选择合适大小的卷积核,并将不同大小的卷积核组合使用。 之前介绍的网络结构都是串行的,GoogLeNet使用并行的网络块,称为“Inception块” “Inception块”前后进化了四次,论文链接: [1]https://arxiv.org/pdf/1409.4842.pdf [2]https://arxiv.org/pdf/150

    2024年02月12日
    浏览(68)
  • 现代卷积神经网络(ResNet)

    专栏:神经网络复现目录 本章介绍的是现代神经网络的结构和复现,包括深度卷积神经网络(AlexNet),VGG,NiN,GoogleNet,残差网络(ResNet),稠密连接网络(DenseNet)。 文章部分文字和代码来自《动手学深度学习》 残差网络(Residual Network,简称 ResNet)是由微软研究院于

    2024年02月07日
    浏览(43)
  • 62、python - 全手写搭建 resnet50 神经网络

    如果将上篇文章中涉及到的算法都自己手写完一遍后,我们开始尝试利用自己手写的算法,搭建一个完整的 resnet50 神经网络。 网络结构就参考这个链接中的网络结构,是在之前下载模型的章节中,下载的模型。 为了搭建一个完整的神经网络,定义一个 Resnet 的类,这个类就

    2024年01月24日
    浏览(40)
  • 经典神经网络论文超详细解读(六)——DenseNet学习笔记(翻译+精读+代码复现)

    上一篇我们介绍了ResNet:经典神经网络论文超详细解读(五)——ResNet(残差网络)学习笔记(翻译+精读+代码复现) ResNet通过短路连接,可以训练出更深的CNN模型,从而实现更高的准确度。今天我们要介绍的是 DenseNet(《Densely connected convolutional networks》) 模型,它的基本

    2024年02月03日
    浏览(62)
  • 经典神经网络论文超详细解读(八)——ResNeXt学习笔记(翻译+精读+代码复现)

    今天我们一起来学习何恺明大神的又一经典之作:  ResNeXt(《Aggregated Residual Transformations for Deep Neural Networks》) 。这个网络可以被解释为 VGG、ResNet 和 Inception 的结合体,它通过重复多个block(如在 VGG 中)块组成,每个block块聚合了多种转换(如 Inception),同时考虑到跨层

    2024年02月03日
    浏览(55)
  • Python基于深度学习机器学习卷积神经网络实现垃圾分类垃圾识别系统(GoogLeNet,Resnet,DenseNet,MobileNet,EfficientNet,Shufflent)

    文章目录 1 前言+ 2 卷积神经网络(CNN)详解+ 2.1 CNN架构概述+ 2.1.1 卷积层+ 2.1.2 池化层+ 2.1.3 全连接层 2.2 CNN训练过程+ 2.3 CNN在垃圾图片分类中的应用 3 代码详解+ 3.1 导入必要的库+ 3.2 加载数据集+ 3.3 可视化随机样本+ 3.4 数据预处理与生成器+ 3.5 构建、编译和训练CNN模型+ 3.5.

    2024年02月04日
    浏览(53)
  • FPGA上利用Vitis AI部署resnet50 TensorFlow神经网络模型

    参考Xilinx官方教程快速入门 • Vitis AI 用户指南 (UG1414) 克隆 Vitis AI 存储库以获取示例、参考代码和脚本(连接github失败可能需要科学上网)。 安装Docker如何在 Ubuntu 20.04 上安装和使用 Docker 安装完docker后,下载最新Vitis AI Docker, 将官方的指令 docker pull xilinx/vitis-ai-pytorch/tensorfl

    2024年02月04日
    浏览(46)
  • 深度学习论文解读分享之diffGrad:一种卷积神经网络优化方法

    diffGrad: An Optimization Method for Convolutional Neural Networks Shiv Ram Dubey , Member, IEEE, Soumendu Chakraborty , Swalpa Kumar Roy , Student Member, IEEE, Snehasis Mukherjee, Member, IEEE, Satish Kumar Singh, Senior Member, IEEE, and Bidyut Baran Chaudhuri, Life Fellow, IEEE Adaptive moment estimation (Adam), difference of gradient, gradient descent,

    2024年01月17日
    浏览(53)
  • 人工智能(Pytorch)搭建模型6-使用Pytorch搭建卷积神经网络ResNet模型

    大家好,我是微学AI,今天给大家介绍一下人工智能(Pytorch)搭建模型6-使用Pytorch搭建卷积神经网络ResNet模型,在本文中,我们将学习如何使用PyTorch搭建卷积神经网络ResNet模型,并在生成的假数据上进行训练和测试。本文将涵盖这些内容:ResNet模型简介、ResNet模型结构、生成假

    2024年02月06日
    浏览(78)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包