一些常见的CNN模型

本文对常见的卷积神经网络(CNN)模型进行了总结,包括VGG、GoogLeNet、ResNet、RIR、InceptionResNet、PreActResNet、ResNeXt、WideResNet、Xception、DenseNet、SENet、SqueezeNet、MobileNet和ShuffleNet。这些模型在深度学习领域有着重要影响,各有特点和应用场景。VGG以其深层数量和小卷积核成为特征提取的首选,GoogLeNet通过Inception结构解决了模型复杂度问题,ResNet通过残差学习解决了梯度消失问题,而DenseNet则通过密集连接提升了特征传播效率。
摘要由CSDN通过智能技术生成

最近闲着无聊在家敲了一些基本的CNN模型,这里对网上资料做一个简要的整理总结,供自己学习使用。

一、VGG

​ VGG模型是2014年ILSVRC竞赛的第二名,第一名是GoogLeNet。但是VGG模型在多个迁移学习任务中的表现要优于googLeNet。而且,从图像中提取CNN特征,VGG模型是首选算法。它的缺点在于,参数量有140M之多,需要更大的存储空间。但是这个模型很有研究价值。

VGG有多种网络结构,如VGG-11,VGG-13,VGG-16,VGG-19等。以吴恩达老师视频中讲到的VGG-16为例,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XWvLlckU-1582552397623)(E:\Code\some models\blog\images\VGG-16.png)]

VGG网络的特点:(1)采用了小卷积核。作者将卷积核全部替换为3x3。(2)作者采用了小池化核。相比AlexNet的3x3的池化核,VGG全部为2x2的池化核。(3)层数更深,特征图更宽。基于前两点外,由于卷积核专注于扩大通道数、池化专注于缩小宽和高,使得模型架构上更深更宽的同时,计算量的增加放缓。

​ VGG的提出,使人们得到了这样一个结论:卷积神经网络的深度增加和小卷积核的使用对网络的最终分类识别效果有很大的作用。

二、GoogLeNet

文章中提出优化模型有两种途径:提高深度或是宽度。但是这两种方法都存在局限性:1.参数太多,容易过拟合,若训练数据集有限;2.网络越大计算复杂度越大,难以应用;3.网络越深,梯度越往后穿越容易消失,难以优化模型。

GoogLeNet正是围绕着这两个思路提出的,其通过构建密集的块结构——Inception(如下图)来近似最优的稀疏结构,从而达到提高性能而又不大量增加计算量的目的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OAl0uEfb-1582552397623)(E:\Code\some models\blog\images\Inception.png)]

GoogLeNet增加了多种核1x1,3x3,5x5,还有直接max pooling的,但是如果简单的将这些应用到feature map上的话,concat起来的feature map厚度将会很大,所以在googlenet中为了避免这一现象提出的inception具有如下结构,在3x3前,5x5前,max pooling后分别加上了1x1的卷积核起到了降低feature map厚度的作用。5*5的卷积核会带来巨大的计算量,所以采用1 * 1的卷积核进行降维。(以下是一个Inception的代码)

class Inception(nn.Module):
    def __init__(self,in_channels, n1x1, n3x3_reduce, n3x3, n5x5_reduce, n5x5,         npool):
        super().__init__()
        self.brance1 = nn.Sequential(
            nn.Conv2d(in_channels,n1x1,kernel_size=1),
            nn.BatchNorm2d(n1x1),
            nn.ReLU(inplace=True)
        )
        
        self.brance2 = nn.Sequential(
            nn.Conv2d(in_channels,n3x3_reduce,kernel_size=1),
            nn.BatchNorm2d(n3x3_reduce),
            nn.ReLU(inplace=True),
            nn.Conv2d(n3x3_reduce,n3x3,kernel_size=3,padding=1),
            nn.BatchNorm2d(n3x3),
            nn.ReLU(inplace=True)
        )
        
        self.brance3 = nn.Sequential(
            nn.Conv2d(in_channels,n5x5_reduce,kernel_size=1),
            nn.BatchNorm2d(n5x5_reduce),
            nn.ReLU(inplace=True),
            nn.Conv2d(n5x5_reduce,n5x5,kernel_size=5,padding=2),
            nn.BatchNorm2d(n5x5),
            nn.ReLU(inplace=True)
        )
        
        self.brance4 = nn.Sequential(
            nn.MaxPool2d(3,stride=1,padding=1),
            nn.Conv2d(in_channels,npool,kernel_size=1),
            nn.BatchNorm2d(npool),
            nn.ReLU(inplace=True)
        )
        
    def forward(self,x):
        out = [self.brance1(x),self.brance2(x),self.brance3(x),self.brance4(x)]
        out = torch.cat(out,1)
        return out

为了解决深度问题,GoogLeNet巧妙的在不同深度处增加了两个loss来保证梯度回传消失的现象。总的网络结构如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3hEEqS23-1582552397624)(E:\Code\some models\blog\images\GoogLeNet.png)]

三、ResNet

ResNet的提出背景是网络越深效果越好,因为CNN越深越能提取到更丰富更抽象的特征,这些特征有更高更鲁棒的语义信息,网络越深对输入图像的变化越不敏感。但是单纯的深模型会遇到问题:模型深,易造成梯度消失,继续训练时,很难再更新参数,很难学到特征。

基于这种背景,何凯明团队于2015年提出了ResNet(Residual Networks 残差网络)。残差网络(如下)通过在一个浅层网络基础上叠加y=x层,可以让网络随深度增加而不退化。将浅层的输入值直接连接到端部位置,这样避免了层层映射过程中,由于权重小于1而导致的梯度消失。它一方面使得模型可以更深,这样网络表达的能力更好了,另一方面也使得训练速度加快。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XpZgAUSL-1582597894786)(E:\Code\some models\blog\images\ResNet.webp.jpg)]

假设某段神经网络的输入是x,期望输出是H(x),如果直接把x传递到输出端,那么我们要学习的目标是F(x)=H(x)-x。此时目标相当于发生变更,称之为残差。(以下是一个残差模块的代码)

class BottleNeck(nn.Module):
    expansion = 4
    def __init__(self,in_channels,out_channels,stride=1):
        super().__init__()
        self.residual_function = nn.Sequential(
            nn.Conv2d(in_channels,out_channels,stride=1,bias=False),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels,out_channels,stride=stride,padding=1,bias=False),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels,out_channels*BottleNeck.expansion,\
                      kernel_size=1,bias=False),
            nn.BatchNorm2d(out_channels*expansion)
        )
        self.shortcut = nn.Sequential()
        if stride!=1 or in_channels!=out_channels*BottleNeck.expansion:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels,out_channels*BottleNeck.expansion,\
                          kernel_size=1,bias=False),
                nn.BatchNorm2d(out_channels*BottleNeck.expan
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值