【图像分类】【深度学习】【Pytorch版本】GoogLeNet(InceptionV1)模型算法详解

【图像分类】【深度学习】【Pytorch版本】GoogLeNet(InceptionV1)模型算法详解

文章目录

  • 【图像分类】【深度学习】【Pytorch版本】GoogLeNet(InceptionV1)模型算法详解
  • 前言
  • GoogLeNet讲解
    • Inception结构
    • InceptionV1结构
    • 1x1卷积的作用
  • GoogLeNet模型结构
  • GoogLeNet Pytorch代码
  • 完整代码
  • 总结


前言

GoogLeNet是由谷歌的Szegedy, Christian等人在《Going Deeper With Convolutions【CVPR-2015】》【论文地址】一文中提出的模型,主要特点是提高了网络内部计算资源的利用率,允许增加网络的深度和宽度,同时保持计算预算不变。


GoogLeNet讲解

此前传统的方式简单粗暴的增加隐藏层(网络深度)和各层神经元数目(网络宽度)以达到提高网络性能的目的, 但这类方法存在致命的问题:更大的参数空间需要更多的计算资源并且更容易导致过拟合;网络越深则梯度越容易消失导致优化更加困难。
卷积神经网络的性能提高都是依赖于提高网络的深度和宽度,如何在增加网络深度和宽度的同时减少参数?解决思路便是全连接变成稀疏连接,GoogLeNet从网络结构上入手,改变了网络结构,提出了inception的卷积网络结构:

  1. 空间(spatial)上的稀疏连接:卷积神经网络本身对输入图像的局部进行卷积,而不是对整个图像进行卷积,参数共享降低了总参数的数目并减少了计算量。
  2. 在特征维度(feature channel)上的稀疏:多个尺寸上进行卷积再聚合,把相关性强的特征聚集到一起(也是种稀疏连接),并使用1x1卷积进行降维,减少通道数,限制网络的大小,降低了计算复杂度。

Inception结构

原始的(基本)Inception模块,其通过多个尺寸上进行卷积再聚合,来提取更密集的特征。

对输入做了4个分支,分别用不同尺寸的filter进行卷积或池化,最后再在特征维度上拼接到一起,以便下一阶段能够同时从不同的尺度上提取特征。这种全新的结构设计能带来以下好处:

  1. 采用大小不同的卷积核,在多个尺度上同时进行卷积,意味着感受野的大小不同,得到的的特征尺度不同,特征更为丰富也意味着最后分类判断时更加准确。
  2. inception在特征维度上进行分解 (稀疏矩阵分解原理),在多个尺度上预先把相关性强的特征单独汇聚,(Hebbian原则) 强化具有相似类型特征的filter之间的关联(filter bank),如分别聚集1x1的的特征、3x3的特征和5x5的特征,用更少的filter来提取相关的特征,再将多个尺度的filter bank特征进行组合。

InceptionV1结构

原始的Inception 结构存在一个不可忽视的问题:卷积运算运算量过大,如果特征图的通道数过大(即当上一层的输出通道数较大时)会导致当前Inception模块的运算消费巨大,特别是当前Inception模块中的pooling层输出的通道数和输入保持一致,且由于多组卷积核并联运算,因此这是随着层数的堆叠而爆炸式增长的!
针对这一问题对原始结构做了改进,加上1x1卷积层作为reduction层做降维和特征映射、空间信息整合和引入非线性,以达到网络的压缩从而减少计算量。

1x1卷积的作用

1x1卷积在卷积神经网络中起着重要的作用:

  1. 降维和特征映射:1x1卷积可以用于降低通道数(即特征的维度),通过减少输入特征图的通道数来降低计算和存储成本,这对于减少模型的参数量、加快计算速度以及控制过拟合都非常有用。同时,1x1卷积也可以用于增加通道数,以增加特征的表达能力;
  2. 空间信息整合:尽管1x1卷积的感受野很小,但它可以在通道维度上对输入特征进行组合和整合,从而引入跨通道的交互和增加模型的非线性能力(1x1卷积中的非线性激活函数),这有助于模型学习不同通道之间的相关性和特征之间的互动,更好地拟合复杂的数据分布和提取更丰富的特征表示;
  3. 网络的压缩和加速:1x1卷积可以减少通道数,压缩卷积神经网络,减小模型的计算量和存储需求,从而实现更快的推理速度和更高的效率。

    参数量:
    使用128个3x3的卷积核对512通道特征图进行卷积:512×3×3×128=589824
    使用24个1x1卷积核先对512通道特征图降维,再用128个3x3的卷积核进行卷积:512×1×1×24+24×3×3×128=12504

1x1卷积成为设计高效、灵活和强大的网络架构的重要工具。


GoogLeNet模型结构

下图是原论文给出的关于VGGnet模型结构的详细示意图:

GoogLeNet在图像分类中分为两部分:backbone部分: *主要由InceptionV1模块、卷积层和池化层(汇聚层)组成,分类器部分: 由主分类器和俩个辅助分类器组成。


GoogLeNet Pytorch代码

卷积层组: 卷积层+激活函数

# 卷积组:Conv2d+ReLU
class BasicConv2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0):
        super(BasicConv2d, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding)
        self.relu = nn.ReLU(inplace=True)
    def forward(self, x):
        x = self.conv(x)
        x = self.relu(x)
        return x

InceptionV1模块: 卷积层组+池化层

# InceptionV1:BasicConv2d+MaxPool2d
class InceptionV1(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch5x5red, ch5x5, pool_proj):
        super(Inception, self).__init__()
        # 1×1卷积
        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
        # 1×1卷积+3×3卷积
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3red, kernel_size=1),
            BasicConv2d(ch3x3red, ch3x3, kernel_size=3, padding=1)   # 保证输出大小等于输入大小
        )
        # 1×1卷积+5×5卷积
        self.branch3 = nn.Sequential(
            BasicConv2d(in_channels, ch5x5red, kernel_size=1),
            BasicConv2d(ch5x5red, ch5x5, kernel_size=5, padding=2)   # 保证输出大小等于输入大小
        )
        # 3×3池化+1×1卷积
        self.branch4 = nn.Sequential(
            nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
            BasicConv2d(in_channels, pool_proj, kernel_size=1)
        )
    def forward(self, x):
        branch1 = self.branch1(x)
        branch2 = self.branch2(x)
        branch3 = self.branch3(x)
        branch4 = self.branch4(x)
        # 拼接
        outputs = [branch1, branch2, branch3, branch4]
        return torch.cat(outputs, 1)

辅助分类器: 池化层+卷积层组+全连接层+dropout

# 辅助分类器:AvgPool2d+BasicConv2d+Linear+dropout
class InceptionAux(nn.Module):
    def __init__(self, in_channels, num_classes):
        super(InceptionAux, self).__init__()
        # 池化层
        self.averagePool = nn.AvgPool2d(kernel_size=5, stride=3)
        # 1×1卷积
        self.conv = BasicConv2d(in_channels, 128, kernel_size=1)  # output[batch, 128, 4, 4]
        # 全连接层
        self.fc1 = nn.Linear(2048, 1024)
        self.fc2 = nn.Linear(1024, num_classes)

    def forward(self, x):
        # aux1: N x 512 x 14 x 14
        # aux2: N x 528 x 14 x 14
        x = self.averagePool(x)
        # aux1: N x 512 x 4 x 4
        # aux2: N x 528 x 4 x 4
        x = self.conv(x)
        # N x 128 x 4 x 4
        x = torch.flatten(x, 1)
        x = F.dropout(x, 0.5, training=self.training)
        # N x 2048
        x = F.relu(self.fc1(x), inplace=True)
        x = F.dropout(x, 0.5, training=self.training)
        # N x 1024
        x = self.fc2(x)
        # N x num_classes
        return x

完整代码

import torch.nn as nn
import torch
import torch.nn.functional as F
from torchsummary import summary

class GoogLeNet(nn.Module):
    def __init__(self, num_classes=1000, aux_logits=True, init_weights=False):
        super(GoogLeNet, self).__init__()
        self.aux_logits = aux_logits

        self.conv1 = BasicConv2d(3, 64, kernel_size=7, stride=2, padding=3)
        self.maxpool1 = nn.MaxPool2d(3, stride=2, ceil_mode=True)

        self.conv2 = BasicConv2d(64, 64, kernel_size=1)
        self.conv3 = BasicConv2d(64, 192, kernel_size=3, padding=1)
        self.maxpool2 = nn.MaxPool2d(3, stride=2, ceil_mode=True)

        self.inception3a = InceptionV1(192, 64, 96, 128, 16, 32, 32)
        self.inception3b = InceptionV1(256, 128, 128, 192, 32, 96, 64)
        self.maxpool3 = nn.MaxPool2d(3, stride=2, ceil_mode=True)

        self.inception4a = InceptionV1(480, 192, 96, 208, 16, 48, 64)
        self.inception4b = InceptionV1(512, 160, 112, 224, 24, 64, 64)
        self.inception4c = InceptionV1(512, 128, 128, 256, 24, 64, 64)
        self.inception4d = InceptionV1(512, 112, 144, 288, 32, 64, 64)
        self.inception4e = InceptionV1(528, 256, 160, 320, 32, 128, 128)
        self.maxpool4 = nn.MaxPool2d(3, stride=2, ceil_mode=True)

        self.inception5a = InceptionV1(832, 256, 160, 320, 32, 128, 128)
        self.inception5b = InceptionV1(832, 384, 192, 384, 48, 128, 128)

        if self.aux_logits:
            self.aux1 = InceptionAux(512, num_classes)
            self.aux2 = InceptionAux(528, num_classes)

        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.dropout = nn.Dropout(0.4)
        self.fc = nn.Linear(1024, num_classes)
        if init_weights:
            self._initialize_weights()
    def forward(self, x):
        # N x 3 x 224 x 224
        x = self.conv1(x)
        # N x 64 x 112 x 112
        x = self.maxpool1(x)
        # N x 64 x 56 x 56
        x = self.conv2(x)
        # N x 64 x 56 x 56
        x = self.conv3(x)
        # N x 192 x 56 x 56
        x = self.maxpool2(x)

        # N x 192 x 28 x 28
        x = self.inception3a(x)
        # N x 256 x 28 x 28
        x = self.inception3b(x)
        # N x 480 x 28 x 28
        x = self.maxpool3(x)
        # N x 480 x 14 x 14
        x = self.inception4a(x)
        # N x 512 x 14 x 14
        if self.training and self.aux_logits:    # eval model lose this layer
            aux1 = self.aux1(x)

        x = self.inception4b(x)
        # N x 512 x 14 x 14
        x = self.inception4c(x)
        # N x 512 x 14 x 14
        x = self.inception4d(x)
        # N x 528 x 14 x 14
        if self.training and self.aux_logits:    # eval model lose this layer
            aux2 = self.aux2(x)

        x = self.inception4e(x)
        # N x 832 x 14 x 14
        x = self.maxpool4(x)
        # N x 832 x 7 x 7
        x = self.inception5a(x)
        # N x 832 x 7 x 7
        x = self.inception5b(x)
        # N x 1024 x 7 x 7

        x = self.avgpool(x)
        # N x 1024 x 1 x 1
        x = torch.flatten(x, 1)
        # N x 1024
        x = self.dropout(x)
        x = self.fc(x)
        # N x 1000(num_classes)
        if self.training and self.aux_logits:   # 训练阶段使用
            return x, aux2, aux1
        return x
    # 对模型的权重进行初始化操作
    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)

# InceptionV1:BasicConv2d+MaxPool2d
class InceptionV1(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch5x5red, ch5x5, pool_proj):
        super(InceptionV1, self).__init__()
        # 1×1卷积
        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
        # 1×1卷积+3×3卷积
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3red, kernel_size=1),
            BasicConv2d(ch3x3red, ch3x3, kernel_size=3, padding=1)   # 保证输出大小等于输入大小
        )
        # 1×1卷积+5×5卷积
        self.branch3 = nn.Sequential(
            BasicConv2d(in_channels, ch5x5red, kernel_size=1),
            # 在官方的实现中,其实是3x3的kernel并不是5x5,这里我也懒得改了,具体可以参考下面的issue
            # Please see https://github.com/pytorch/vision/issues/906 for details.
            BasicConv2d(ch5x5red, ch5x5, kernel_size=5, padding=2)   # 保证输出大小等于输入大小
        )
        # 3×3池化+1×1卷积
        self.branch4 = nn.Sequential(
            nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
            BasicConv2d(in_channels, pool_proj, kernel_size=1)
        )
    def forward(self, x):
        branch1 = self.branch1(x)
        branch2 = self.branch2(x)
        branch3 = self.branch3(x)
        branch4 = self.branch4(x)
        # 拼接
        outputs = [branch1, branch2, branch3, branch4]
        return torch.cat(outputs, 1)

# 辅助分类器:AvgPool2d+BasicConv2d+Linear+dropout
class InceptionAux(nn.Module):
    def __init__(self, in_channels, num_classes):
        super(InceptionAux, self).__init__()
        # 池化层
        self.averagePool = nn.AvgPool2d(kernel_size=5, stride=3)
        # 1×1卷积
        self.conv = BasicConv2d(in_channels, 128, kernel_size=1)  # output[batch, 128, 4, 4]
        # 全连接层
        self.fc1 = nn.Linear(2048, 1024)
        self.fc2 = nn.Linear(1024, num_classes)
    def forward(self, x):
        # aux1: N x 512 x 14 x 14
        # aux2: N x 528 x 14 x 14
        x = self.averagePool(x)
        # aux1: N x 512 x 4 x 4
        # aux2: N x 528 x 4 x 4
        x = self.conv(x)
        # N x 128 x 4 x 4
        x = torch.flatten(x, 1)
        x = F.dropout(x, 0.5, training=self.training)
        # N x 2048
        x = F.relu(self.fc1(x), inplace=True)
        x = F.dropout(x, 0.5, training=self.training)
        # N x 1024
        x = self.fc2(x)
        # N x num_classes
        return x

# 卷积组: Conv2d+ReLU
class BasicConv2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0):
        super(BasicConv2d, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding)
        self.relu = nn.ReLU(inplace=True)
    def forward(self, x):
        x = self.conv(x)
        x = self.relu(x)
        return x

if __name__ == '__main__':
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    model = GoogLeNet().to(device)
    summary(model, input_size=(3, 224, 224))

summary可以打印网络结构和参数,方便查看搭建好的网络结构。


总结

尽可能简单、详细的介绍了深度可分卷积的原理和卷积过程,讲解了GoogLeNet(InceptionV1)模型的结构和pytorch代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/121534.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Maven-构建生命周期与插件

一、概念和基础 Maven针对项目的构建和发布定义了一系列明确的步骤,根据作用不同这些步骤分属于不同的生命周期。Maven针对每个步骤都有对应的默认插件,Maven在构建过程中是通过调用这些插件完成整个过程的。开发者只需要通过简单的命令就可以驱动maven…

Microsoft SDKs 有文件重定义导致编译失败的处理

一个32位的mfc项目,之前采用vs2019编译,现在换了电脑(系统是win10),采用vs2022编译时,提示如下错误: 1>------ 已启动生成: 项目: aAnsys, 配置: Debug Win32 ------ 1>cl : 命令行 warning D9035: “Gm”选项…

Luckysheet 实现excel多人在线协同编辑

前言 前些天看到Luckysheet支持协同编辑Excel,正符合我们协同项目的一部分,故而想进一步完善协同文章,但是遇到了一下困难,特此做声明哈,若侵权,请联系我删除文章! 若侵犯版权、个人隐私&#x…

图及谱聚类商圈聚类中的应用

背景 在O2O业务场景中,有商圈的概念,商圈是业务运营的单元,有对应的商户BD负责人以及配送运力负责任。这些商圈通常是一定地理围栏构成的区域,区域内包括商户和用户,商圈和商圈之间就通常以道路、河流等围栏进行分隔。…

酷开科技持续推动智能投影行业创新发展

近年来,投影仪逐渐成为年轻人追捧的家居时尚单品。据国际数据公司(IDC)报告显示,2022年中国投影机市场总出货量505万台,超80%为家用投影仪。相比于电视,投影仪外观小巧、屏幕大小可调节,无论是卧…

PostgreSql中解析JSON字段和解析TEXT中的JSON字段

初始化操作 创建表 CREATE TABLE orders ( "ID" int8 NOT NULL,"info_j" json NOT NULL,"info_t" text NOT NULL );初始化表 INSERT INTO orders("ID", "info_j","info_t") VALUES (1, {"name":&qu…

setViaGenMode

1.命令描述 setViaGenMode用于设置vias的全局变量,包括使用addRing / addStripe命令连接rings 、stripes,editPowerVia、sroute、addSplitPowerVia以及手拉线使用的editAddRoute/editCommitRoute。 2.-optimize_cross_via true false 未完待续

人大金仓三大兼容:SQL Server迁移无忧

SQL Server在数据库领域一直占据着重要地位。作为一款成熟稳定的关系型数据库管理系统,SQL Server在国内有着广泛的用户群体,医疗、海关、政务等行业的核心业务系统多采用SQL Server数据库。随着政策与市场的双重驱动,信息技术应用创新产业的…

Spring RabbitMQ那些事(1-交换机配置消息发送订阅实操)

这里写目录标题 一、序言二、配置文件application.yml三、RabbitMQ交换机和队列配置1、定义4个队列2、定义Fanout交换机和队列绑定关系2、定义Direct交换机和队列绑定关系3、定义Topic交换机和队列绑定关系4、定义Header交换机和队列绑定关系 四、RabbitMQ消费者配置五、Rabbit…

C语言面试

数据类型(基本内置类型) char //字符数据类型 short //短整型 int //整型 long //长整型 long long //更长的整型 float //单精度浮点数 double //双精度浮点数 类型的基本归类 整形家族: …

英伟达发布RAPIDS cuDF框架 pandas在GPU上运行速度快了150倍

11月9日 消息:Nvidia 发布了一款名为 RAPIDS cuDF 的新版本,据称可以将 pandas 运行在 GPU 上,并且性能提升了150倍。pandas 是一款流行的基于 Python 的数据框架库,用于数据处理和分析。它的开源版本由 Wes McKinney 开发和发布&…

RT-Thread提供的网络世界入口 -net组件

作为一款在RTOS领域对网络支持很丰富的RT-Thread,对设备联网功能的支持的工具就是net组件。 位于/rt-thread/components/net路劲下,作为一款基础组件,env与Studio的工程配置项界面的配置项都依赖该目录下的Kconfig。 我们对网络功能的选择&am…

关于卷积神经网络的步幅(stride)

认识步幅(stride) 卷积核从输入数组的最左上方开始,按从左往右、从上往下的顺序,依次在输入数组上滑动,我们将每次滑动的行数和列数称为步幅。 计算步幅 假设输入的形状n∗n,卷积核的形状为f∗f&#xff0…

css排版—— 一篇优雅的文章(中英文) vs 聊天框的特别排版

文章 <div class"contentBox"><p>这是一篇范文——仅供测试使用</p><p>With the coming of national day, I have a one week holiday. I reallyexpect to it, because it want to have a short trip during these days. Iwill travel to Ji…

机器学习模板代码(期末考试复习)自用存档

机器学习复习代码 利用sklearn实现knn import numpy as np import pandas as pd from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import GridSearchCVdef model_selection(x_train, y_train):## 第一个是网格搜索## p是选择查找方式:1是欧…

Vue3 + Vite + Ts + Router搭建项目

1、新建文件夹 从新建的文件夹cmd进入终端 2、安装vite—依据vite创建vue3项目 2.1、运行 npm init vitelatest2.2.1、输入项目名称 2.2.2、选择vue 2.2.3、选择TypeScript语言 3、安装依赖项 3.1、进入刚才创建的文件夹 cd vite-project 3.2、查看镜像 #查看当前源 npm con…

【uniapp+vue3/vue2】ksp-cropper高性能图片裁剪工具,详解

效果图&#xff1a; 1、ksp-cropper是hbuilder插件市场中的一款插件&#xff0c;兼容vue2和vue3 ksp-cropper插件安装地址&#xff0c;直接点击跳转 2、插件用法相对简单 &#xff08;1&#xff09;只要url有值就会显示插件&#xff0c;为空就会隐藏插件 &#xff08;2&#…

自动化测试框架 —— pytest框架入门篇

今天就给大家说一说pytest框架。 今天这篇文章呢&#xff0c;会从以下几个方面来介绍&#xff1a; 1、首先介绍一下pytest框架 2、带大家安装Pytest框架 3、使用pytest框架时需要注意的点 4、pytest的运行方式 5、pytest框架中常用的插件 01、pytest框架介绍 pytest 是 pytho…

国产猫罐头可以长期作为主食吗?我家的优质TOP的猫罐头分享

我最近一直在调查国产猫罐头可以长期作为主食吗&#xff1f;看看我的购物订单&#xff0c;我已经尝试了几十款了。今天&#xff0c;我想和大家分享一些关于国产猫罐头的经验和见解。 近年来&#xff0c;国产宠粮市场取得了突破性的进展&#xff0c;各个猫粮商在配方、营养数据…

win10添加回环网卡步骤

打开命令行输入hdwwiz 添加新硬件向导 结果