GoogLeNet详解

news2024/12/26 12:07:04

入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。

✨完整代码在我的github上,有需要的朋友可以康康✨

https://github.com/tt-s-t/Deep-Learning.git

目录

一、GoogLeNet网络的背景

二、GooLeNet网络结构

1、Inception模块

2、辅助分类器

3、GooLeNet网络

 三、GooLeNet的亮点

 1、引入Inception结构

 2、使用1x1的卷积核进行降维映射处理

3、添加两个辅助分类器帮助训练

4、使用全局平均池化

5、1*n和n*1卷积核并联代替n*n卷积核

 四、GooLeNet代码实现


一、GoogLeNet网络的背景

想要更好的预测效果,就要从网络深度和网络宽度两个角度出发增加网络的复杂度。

但这个思路有两个较为明显的问题:

首先,更复杂的网络意味着更多的参数,也很容易过拟合;

其次,更复杂的网络会消耗更多的计算资源,而且卷积核个数设计不合理,导致了卷积核中参数没有被完全利用(多数权重都趋近0)时,会造成大量计算资源的浪费。

因此GoogLeNet在专注于加深网络结构的同时,引入了新的基本结构——Inception模块,以增加网络的宽度。GoogLeNet一共22层,没有全连接层,在2014年的ImageNet图像识别挑战赛中获得了冠军。


二、GooLeNet网络结构

1、Inception模块

 Inception模块的基本组成结构有四个:1x1卷积,3x3卷积,5x5卷积,3x3最大池化。

最后再对四个成分运算结果进行通道上组合。

这就是Naive Inception(上图a)的核心思想:利用不同大小的卷积核实现不同尺度的感知,最后进行融合,可以得到图像更好的表征(即探索特征图上不同邻域内的“相关性”)。

Note:每个分支得到的特征矩阵高和宽必须相同。

但Naive Inception有两个缺点:

(1)所有卷积层直接和前一层输入的数据对接,所以卷积层中的计算量会很大(一变四);

(2)在这个单元中使用的最大池化层保留了输入数据的特征图的深度,所以在最后进行合并后总输出的特征图的深度一定会增加,这样增加了该单元之后的网络结构的计算量。

所以多加使用了1x1 卷积核主要目的是进行压缩降维,减少参数量(即上图b),从而让网络更深、更宽,更好的提取特征,这种思想也称为Pointwise Conv(逐点卷积),简称PW。

压缩降维:通过卷积层的输出通道数来调整这很好理解;

减少参数量:假设输入通道数为Cin,原本是直接要使用输出通道数为Cout的N*N卷积层来进行卷积,那么所需参数量为Cin*Cout*N*N;如果加上输出通道数为k的1*1卷积核的话,所需参数量为:Cin*k+N*N*Cout*k,只要k足够小就能使参数量大幅度下降了。

2、辅助分类器

因为神经网络的中间层也具有很强的识别能力,因此GooLeNet在一些中间层中添加了含有多层的分类器。

GoogLeNet中共增加了两个辅助的softmax分支。

网络结构如下图所示(其中的红圈圈就是辅助的分类器)

作用:

(1)为了避免梯度消失,用于向前传导梯度(反向传播时如果有一层求导为0,链式求导结果则为0)—— 最主要的原因;

(2)将中间某一层输出用作分类,起到模型融合作用(最终的分类结果以及这两个辅助分类器的结果(辅助分类按一个较小的权重加到最终分类结果中)一同决判出最终训练得到的分类结果)。但实际测试时,这两个辅助softmax分支会被去掉(因为辅助的主要原因是为了向前传导梯度,因此训练完后就没有价值了,理应扔掉)。

(3)正则化作用:

      在后续的研究中,Google团队研究人员发现辅助分类器在训练早期并没有改善收敛:在两个模型达到高精度之前,两种网络的训练进度看起来几乎相同;接近训练结束,有辅助分支的网络才开始超越没有任何分支的网络的准确性,达到了更高的稳定水平,因此辅助分类器更多的还是起到了一个正则化的作用(防止过拟合)。

3、GooLeNet网络

这是最初GooLeNet论文中展示的网络参数

 以下展示的是torchvision.models.GoogLeNet()的网络结构:

 其中Inception发生变化,将5*5卷积核部分也替换成了3*3卷积。

以下展示Inception3a:


 三、GooLeNet的亮点

 1、引入Inception结构

引入的Inception融合了不同尺度的特征信息,能得到更好的特征表征。

更意味着提高准确率,不一定需要堆叠更深的层或者增加神经元个数等,可以转向研究更稀疏但是更精密的结构同样可以达到很好的效果。

 2、使用1x1的卷积核进行降维映射处理

 降低了维度也减少了参数量(NiN是用于代替全连接层)。

3、添加两个辅助分类器帮助训练

避免梯度消失,用于向前传导梯度,也有一定的正则化效果,防止过拟合。

4、使用全局平均池化

用全局平均池化代替全连接层大大减少了参数量(与NiN一致)

5、1*n和n*1卷积核并联代替n*n卷积核

在InceptionV3中,在不改变感受野同时减少参数的情况下,采用1*n和n*1的卷积核并联来代替InceptionV1-V2中n*n的卷积核(发掘特征图的高的特征,以及特征图的宽的特征)。

这种方法在大维度的特征图上表现不好,在特征图12-20维度上表现好,若这种叠加的不对称分解卷积走高维路线,则更易训练(深层网络适合)。

降低了计算量和减少了参数量。


 四、GooLeNet代码实现

完整代码可以在我的github上看https://github.com/tt-s-t/Deep-Learning.git

在里面的GooLeNet文件夹中,分有调用torchvision.module.goolenet()实现的和自行搭建实现的

这里展示模型搭建代码

import torch
import torch.nn as nn
import torch.nn.functional as F

#conv+ReLU
class BasicConv2d(nn.Module):
    def __init__(self, in_channels, out_channels, **kwargs):
        super(BasicConv2d, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, **kwargs)
        self.relu = nn.ReLU()
 
    def forward(self, x):
        x = self.conv(x)
        x = self.relu(x)
        return x

#前部
class Front(nn.Module):
    def __init__(self):
        super(Front, self).__init__()

        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)

    def forward(self,input):
        #输入:(N,3,224,224)
        x = self.conv1(input)#(N,64,112,112)
        x = self.maxpool1(x)#(N,64,56,56)
        x = self.conv2(x)#(N,64,56,56)
        x = self.conv3(x)#(N,192,56,56)
        x = self.maxpool2(x)#(N,192,28,28)
        return x

class Inception(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3_1_1, ch3x3_1, ch3x3_2_1, ch3x3_2, pool_ch):
        super(Inception, self).__init__()

        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)

        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3_1_1, kernel_size=1),
            BasicConv2d(ch3x3_1_1, ch3x3_1, kernel_size=3, padding=1)
        )

        self.branch3 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3_2_1, kernel_size=1),
            BasicConv2d(ch3x3_2_1, ch3x3_2, kernel_size=3, padding=1)
        )
        self.branch4 = nn.Sequential(
            nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
            BasicConv2d(in_channels, pool_ch, kernel_size=1)
        )

    def forward(self, x):
        #输入(N,Cin,Hin,Win)
        branch1 = self.branch1(x)#(N,C1,Hin,Win)
        branch2 = self.branch2(x)#(N,C2,Hin,Win)
        branch3 = self.branch3(x)#(N,C3,Hin,Win)
        branch4 = self.branch4(x)#(N,C4,Hin,Win)
        outputs = [branch1, branch2, branch3, branch4]
        return torch.cat(outputs, 1)#(N,C1+C2+C3+C4,Hin,Win)

#辅助分类器
class InceptionAux(nn.Module):
    def __init__(self, in_channels, num_classes):
        super(InceptionAux, self).__init__()
        self.averagePool = nn.AvgPool2d(kernel_size=5, stride=3)
        self.conv = BasicConv2d(in_channels, 128, kernel_size=1)

        self.fc1 = nn.Linear(2048, 1024)
        self.fc2 = nn.Linear(1024, num_classes)

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

# GooLeNet网络主体
class GoogLeNet(nn.Module):
    def __init__(self, num_classes=1000, aux_logits=True):
        super(GoogLeNet, self).__init__()
        self.aux_logits = aux_logits

        self.front = Front()

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

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

        self.inception5a = Inception(832, 256, 160, 320, 32, 128, 128)
        self.inception5b = Inception(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)

    def forward(self, x):
        #输入:(N,3,224,224)
        x = self.front(x)#(N,192,28,28)
        x = self.inception3a(x)#(N,256,28,28)
        x = self.inception3b(x)#(N,480,28,28)
        x = self.maxpool3(x)#(N,480,14,14)
        x = self.inception4a(x)#(N,512,14,14)
        if self.training and self.aux_logits:
            aux1 = self.aux1(x)

        x = self.inception4b(x)#(N,512,14,14)
        x = self.inception4c(x)#(N,512,14,14)
        x = self.inception4d(x)#(N,528,14,14)
        if self.training and self.aux_logits:
            aux2 = self.aux2(x)

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

        x = self.avgpool(x)#(N,1024,1,1)
        x = torch.flatten(x, 1)#(N,1024)
        x = self.dropout(x)
        x = self.fc(x)#(N,num_classes)
        if self.training and self.aux_logits:
            return x, aux2, aux1
        return x

欢迎大家在评论区批评指正,谢谢~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++入门——auto、范围for、nullptr

下一篇就要类和对象了,剩了点零碎的知识点就浅浅水一篇把 一. auto关键字 在早期C/C中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但遗憾的 是一直没有人去使用它,这是由于变量本身就具备生命周期…

算法及时间、空间复杂度

算法 算法是对问题求解过程的一种描述,是为解决一个或一类问题给出的一个确定的、有限长的操作序列。严格说来,一个算法必须满足以下5个重要特性: (1)有穷性:对于任意一组合法的输入值,在执行有…

【数据结构与算法——C语言版】5. 排序算法(2)——冒泡排序

前言 上篇文章【数据结构与算法——C语言版】4. 排序算法(1)——选择排序我们介绍了排序算法中的选择排序,其时间复杂度是O(n2),本篇文章我们将介绍另一种同样时间复杂度是O(n2)的排序算法——冒牌排序,这两种算法思路…

ChatGPT背后的开源AI框架Ray,现在值10亿美元

Ray 被 OpenAI、亚马逊等科技公司用来开发大模型,是最近异军突起的框架。 最近一段时间,文本生成的人工智能在互联网上掀起了一阵风暴:ChatGPT 因为可以对人们能想到的几乎任何问题提供非常详细、近乎逼真的回答而受到追捧。大模型应用的出现…

Mapper代理开发案例及MyBatis核心

本片文章需要参考我的前一篇文章:MyBatis入门案例引入总结,使用mapper代理开发的好处就是可以解决开发中硬编码的问题和简化后期的SQL执行。使用这种方式可以不用写接口的实现类,免除了复杂的方法,使得代码更加清晰易懂按照以前的…

vue的过渡动画(有vue的动画库和ui库的介绍)

一、概念 Vue 在插入、更新或者移除 DOM 时&#xff0c;提供多种不同方式的应用过渡效果。 二、默认过渡 <template><div><button click"isShow!isShow">显示/隐藏</button><transition appear><h1 v-show"isShow" cl…

过滤器和拦截器的使用及管理

参考&#xff1a;(70条消息) Spring过滤器和拦截器的区别_yjc0403的博客-CSDN博客https://www.cnblogs.com/colin220/p/9606412.htm概述过滤器&#xff1a;是在javaweb中&#xff0c;你传入的request、response提前过滤掉一些信息&#xff0c;或者提前设置一些参数&#xff0c;…

Anaconda安装之后Spyder打不开解决办法--目前有用 jupyter notebook 无法正常运行2023.1.7

纯纯小白&#xff0c;探索一天&#xff0c;终于成功&#xff0c;需要我的经历没有白费&#xff0c;让大家少走弯路。 问题描述 从官网下载Anaconda之后&#xff0c;安装&#xff0c;一切正常。打开Anaconda navigator在弹出窗口选择了更新&#xff08;我怀疑这就根源&#xf…

Js逆向教程24-作用域和自执行函数

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; Js逆向教程24-作用域和自执行函数 一、变量作用域 1.1局部变量 function jb() {var a"我是局部变量"return a; }1.2全局变…

【Java寒假打卡】Java基础-异常

【Java寒假打卡】Java基础-异常异常概述throws声明异常throw抛出异常try-catch 抛出异常throwable的成员方法异常概述 Exception:称之为异常类&#xff0c;他表示程序本身可以处理的问题 RuntimeException及其子类&#xff1a;运行时异常。&#xff08;空指针异常&#xff0c;…

JUC总结系列篇 (二) : 对线程的理解和使用总结

文章内容&#xff1a; 一.为什么需要多线程 二.线程的创建 三.线程的方法sleep(),run(),wait(),yeid(),join(),interrupt()等方法归纳总结 四.线程的状态及其转换 五.线程的交替执行案例 六.多个线程依次执行案例 七.多线程并发带来的线程安全问题 一.为什么需要多线程&#x…

Linux项目自动化构建工具-make/Makefile

一、前言 会不会写makefile&#xff0c;从一个侧面说明了一个人是否具备完成大型工程的能力。一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefile定义了一系列的规则来指定&#xff0c;哪些文件需要先编译&#xff0c;哪些文件…

前端入门笔记 04 —— Web(html CSS)布局

响应式布局 屏幕尺寸变化&#xff0c;需要响应式网页设计RWD web页面适应不同屏幕宽度因素 液态站点&#xff0c;拉伸充满浏览器窗口 小屏幕挤成一团&#xff0c;大屏幕空白间隙过大固定宽度 像素为单位固定尺寸 小屏幕滚动&#xff0c;大屏幕空白 实现 设置meta标签媒体查…

数据结构入门5-1(数和二叉树)

目录 注 树和二叉树的定义 树的定义 树的基本术语 二叉树的定义 树和二叉树的抽象数据类型定义 二叉树的性质和存储结构 二叉树的性质 二叉树的存储结构 1. 顺序存储结构 2. 链式存储结构 遍历二叉树和线索二叉树 遍历二叉树&#xff08;traversing binary tree&a…

加密与安全

目录 一、编码算法 1.1、ASCII 1.1.1、ASCII简介 1.1.2、ASCII产生原因 1.1.3、表达方式 1.1.4、标准表 1.1.5、大小规则 1.2、Unicode 1.2.1简介 1.2.2编码和实现 1.3、汉字编码 1.3.1、GB2312-80 标准 1.3.2、GBK 编码标准 1.3.3、GB18030编码标准 1.4、URL编…

【Node】中Express框架连接Mysql实现用户注册接口

Node.js中Express框架连接Mysql实现用户注册接口 处理用户注册接口简单分为三步&#xff1a; 1、注册校验 2、完善逻辑 3、拆分模块 拆分模块能够使部分功能能够复用&#xff0c;封装好各个模块使得模块间只能通过有限的接口互相访问&#xff0c;从而降低耦合&#xff0c;拆分模…

LeetCode[1046]最后一块石头的重量

难度&#xff1a;简单 题目&#xff1a; 有一堆石头&#xff0c;每块石头的重量都是正整数。每一回合&#xff0c;从中选出两块最重的 石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 x < y。那么粉碎的可能结果如下&#xff1a;如果 x …

『年度总结』时光如梭 | 再见 2022 | 你好 2023

⭐创作时间2022年12月31日⭐ ✨结果一直到现在才发&#xff0c;说真的写年度总结还是第一次写比较不熟练&#xff0c;去年有这个活动也有佬叫我参加&#xff0c;不过没参加。今年想着有时间来写下的&#xff0c;结果写到现在才发&#xff0c;这东西说真的挺难写的&#…

机器视觉(九):图像配准

目录&#xff1a; 机器视觉&#xff08;一&#xff09;&#xff1a;概述 机器视觉&#xff08;二&#xff09;&#xff1a;机器视觉硬件技术 机器视觉&#xff08;三&#xff09;&#xff1a;摄像机标定技术 机器视觉&#xff08;四&#xff09;&#xff1a;空域图像增强 …

python简单爬虫

爬虫真是一件有意思的事儿啊&#xff0c;之前写过爬虫&#xff0c;用的是urllib2、BeautifulSoup实现简单爬虫&#xff0c;scrapy也有实现过。最近想更好的学习爬虫&#xff0c;那么就尽可能的做记录吧。这篇博客就我今天的一个学习过程写写吧。 一 正则表达式 正则表达式是一…