深度学习:GoogLeNet核心思想详细讲解(原创)

news2024/12/20 19:21:27

深度学习:GoogLeNet核心思想详细讲解

  • 想法来源
    • 时代局限性
    • 稀疏运算特性
      • 稀疏矩阵
      • 稀疏运算
    • 并行计算
    • 结合稀疏与并行
  • Inception block
  • GoogLeNet
    • Average pooling
    • 辅助分类器
  • 训练方法(Training Method)
    • 超参数设置
    • 模型集成
      • 训练阶段
      • 预测阶段
  • 基于GoogLeNet的服装分类(Pytorch)
    • 服装分类数据集
    • 定义模型
    • 测试数据
    • 训练模型

💡 在2014年的ImageNet图像识别挑战赛中,一个名叫GoogLeNet [Szegedy et al., 2015]的网络架构大放异彩。
GoogLeNet吸收了NiN中串联网络的思想,并在此基础上做了改进。 这篇论文的一个重点是解决了什么样大小的卷积核最合适的问题。
毕竟,以前流行的网络使用小到1 * 1,大到5 * 5的卷积核。 本文的一个观点是,有时使用不同大小的卷积核组合是有利的。
在本节中,我们将介绍一个稍微简化的GoogLeNet版本:我们省略了一些为稳定训练而添加的特殊特性,现在有了更好的训练方法,这些特性不是必要的。

想法来源

时代局限性

如果想提高模型的性能,作者认为:当模型的层数足够深,标注好的数据足够多的时候,那么将很高效的训练出一个精度不错的模型。但是这个方案有两个缺点

  1. 数据越多就意味着参数越多,但是就很容易面临着overfitting,当我们标注高质量的时,成本很昂贵,比如我们要标注下面的数据:
    在这里插入图片描述
    这两张图片在我们看来都是二哈,但是它们是两个不同的品种,普通人往往无法标注这些精细的数据,就需要专家标注。
  2. 在深度神经网络中,我们增加一个卷积层,参数量平方倍增长,但是那个年代算力是有限的,跑起来也就十分昂贵。增加的卷积层,会造成很多的权重为0,因为ReLU激活函数卷积神经网络的局部连接(当采用gpu并行计算时),会造成计算资源的浪费。

稀疏运算特性

稀疏矩阵

在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵;与之相反,若非0元素数目占大多数时,则称该矩阵为稠密矩阵。定义非零元素的总数比上矩阵所有元素的总数为矩阵的稠密度。

稀疏运算

在这里插入图片描述

根据上面的缺点,作者认为我们应该把全连接层替换成稀疏连接结构,这样就可以避免计算资源的浪费,加速收敛。
作者还提到了Hebbian principle,主旨是:

  1. 如果突触两侧的两个神经元(即连接)同时被激活,则该突触的强度会选择性地增加。

  2. 如果突触两侧的两个神经元被异步激活,则该突触被选择性地削弱或消除。

并行计算

随着现在计算硬件的飞速发展,我们如果在gpu上用稀疏计算,那么它的效率将为减少100倍,无论我们怎么调试,它的效果都不尽人意,所以作者认为要充分利用gpu并行计算。

结合稀疏与并行

作者想要找到一个鱼与熊掌兼得的方案,在使用稀疏运算的优势的同时,还要充分利用GPU
利用稀疏矩阵分解成密集矩阵计算的原理来加快收敛速度。举个例子下图左侧是个稀疏矩阵(很多元素都为0,不均匀分布在矩阵中),和一个2x2的矩阵进行卷积,需要对稀疏矩阵中的每一个元素进行计算;如果像右图那样把稀疏矩阵分解成2个子密集矩阵,再和2x2矩阵进行卷积,稀疏矩阵中0较多的区域就可以不用计算,计算量就大大降低。在这里插入图片描述
但是这些都是作者的假设,他也不能合理的解释其原因。

Inception block

在这里插入图片描述
Inception的主要思想是找到一个拥有稀疏连接的卷积神经网络局部计算并且近似的并行计算的计算方式。是传统的vgg、alexnet的串联结构不用,第一个版本左图 a,采用了并行的结构,分别采用 1 * 1,3 * 3, 5 * 5,的卷积和池化对previous层同时提取特征,然后把这些卷积核的输出尺寸固定,最后把他们堆叠到一起,这就是Inception块。
它的优点是可以提取到不同尺度的信息,意味着特征更多,分类更准确,缓解了串行卷积层特征丢失的问题(由于感受野限制)
但是左图由于大量的使用5 * 5卷积,计算量也随之水涨船高,作者根据Network in Network这篇论文,具体细节参考之前的文章。通过1 * 1 卷积,先降维,在升维,减少了参数量,增加了模型的表达能力(非线性)。于是就有右图b。

GoogLeNet

请添加图片描述

Average pooling

网络一共22层,为了减少参数作者把alexnet的两层全连接层换成了全局平均池化,数据有多少类别,最后的channel数就是多少,把每个channel的feature换成这个channel所有feature的平均值,再经过soft Max。最终通过实验发现,利用average pooling的精度比全连接层好了6%。

辅助分类器

它的作用主要是在浅层设置分类器来缓解梯度消失,其中作者在之后的论文中提到这种方法效果不理想,就把这个结构删除了,本文就不在过多描述。

训练方法(Training Method)

超参数设置

dropout:0.7
SGDM:momentum=0.9
learning rate:decreasing learning rate by 4% every 8 epoch。

模型集成

训练阶段

作者训练了7个模型,这七个模型有相同的学习率策略,模型结构,初始化权重(由于作者的疏忽)。
不同点: 根据不同的图像采样,随机的图像输入顺序。

预测阶段

  1. 把图像根据短边resize四个尺寸,分别为256、288,320、352。
  2. 每个尺寸在根据左中右,上中下分别裁剪出三个小图。
  3. 把每张小图取四个角和中央,然后resize 224 * 224。
  4. 然后每张图做一个镜像操作。
    根据上述操作,每张图可以变成4 * 3 * 6 * 2 = 144张,然后对结果取均值。
    在这里插入图片描述

基于GoogLeNet的服装分类(Pytorch)

服装分类数据集

我们可以通过框架中的内置函数将Fashion-MNIST数据集下载并读取到内存中。

# 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式,
# 并除以255使得所有像素的数值均在0到1之间
def load_data_fashion_mnist(batch_size, resize=None):  #@save
    """下载Fashion-MNIST数据集,然后将其加载到内存中"""
    trans = [transforms.ToTensor()]
    if resize:
        trans.insert(0, transforms.Resize(resize))
    trans = transforms.Compose(trans)#通过compose组合多个操作
    mnist_train = torchvision.datasets.FashionMNIST(
        root="../data", train=True, transform=trans, download=True)
    mnist_test = torchvision.datasets.FashionMNIST(
        root="../data", train=False, transform=trans, download=True)
    return (data.DataLoader(mnist_train, batch_size, shuffle=True,
                            num_workers=4),
            data.DataLoader(mnist_test, batch_size, shuffle=False,
                            num_workers=4))
                            #num workers 为线程数

定义模型


import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l


class Inception(nn.Module):
    # c1--c4是每条路径的输出通道数
    def __init__(self, in_channels, c1, c2, c3, c4, **kwargs):
        super(Inception, self).__init__(**kwargs)
        # 线路1,单1x1卷积层
        self.p1_1 = nn.Conv2d(in_channels, c1, kernel_size=1)
        # 线路2,1x1卷积层后接3x3卷积层
        self.p2_1 = nn.Conv2d(in_channels, c2[0], kernel_size=1)
        self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)
        # 线路3,1x1卷积层后接5x5卷积层
        self.p3_1 = nn.Conv2d(in_channels, c3[0], kernel_size=1)
        self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)
        # 线路4,3x3最大汇聚层后接1x1卷积层
        self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
        self.p4_2 = nn.Conv2d(in_channels, c4, kernel_size=1)

    def forward(self, x):
        p1 = F.relu(self.p1_1(x))
        p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))
        p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
        p4 = F.relu(self.p4_2(self.p4_1(x)))
        # 在通道维度上连结输出
        return torch.cat((p1, p2, p3, p4), dim=1)
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
                   nn.ReLU(),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1),
                   nn.ReLU(),
                   nn.Conv2d(64, 192, kernel_size=3, padding=1),
                   nn.ReLU(),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b3 = nn.Sequential(Inception(192, 64, (96, 128), (16, 32), 32),
                   Inception(256, 128, (128, 192), (32, 96), 64),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b4 = nn.Sequential(Inception(480, 192, (96, 208), (16, 48), 64),
                   Inception(512, 160, (112, 224), (24, 64), 64),
                   Inception(512, 128, (128, 256), (24, 64), 64),
                   Inception(512, 112, (144, 288), (32, 64), 64),
                   Inception(528, 256, (160, 320), (32, 128), 128),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b5 = nn.Sequential(Inception(832, 256, (160, 320), (32, 128), 128),
                   Inception(832, 384, (192, 384), (48, 128), 128),
                   nn.AdaptiveAvgPool2d((1,1)),
                   nn.Flatten())

net = nn.Sequential(b1, b2, b3, b4, b5, nn.Linear(1024, 10))                                                                            

测试数据

def evaluate_accuracy_gpu(net, data_iter, device=None): #@save
    """使用GPU计算模型在数据集上的精度"""
    if isinstance(net, nn.Module):
        net.eval()  # 设置为评估模式
        if not device:
            device = next(iter(net.parameters())).device
    # 正确预测的数量,总预测的数量
    metric = d2l.Accumulator(2)#累加器
    
    with torch.no_grad():#禁止计算梯度
        for X, y in data_iter:
            if isinstance(X, list):
                # BERT微调所需的(之后将介绍)
                X = [x.to(device) for x in X]
            else:
                X = X.to(device)
            y = y.to(device)
            metric.add(d2l.accuracy(net(X), y), y.numel())
    return metric[0] / metric[1]

训练模型

#@save
def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    """用GPU训练模型(在第六章定义)"""
    def init_weights(m):
        if type(m) == nn.Linear or type(m) == nn.Conv2d:
            nn.init.xavier_uniform_(m.weight)
    net.apply(init_weights)
    print('training on', device)
    net.to(device)
    optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    loss = nn.CrossEntropyLoss()
    animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
                            legend=['train loss', 'train acc', 'test acc'])
    timer, num_batches = d2l.Timer(), len(train_iter)
    for epoch in range(num_epochs):
        # 训练损失之和,训练准确率之和,样本数
        metric = d2l.Accumulator(3)
        net.train()
        for i, (X, y) in enumerate(train_iter):
            timer.start()
            optimizer.zero_grad()
            X, y = X.to(device), y.to(device)
            y_hat = net(X)
            l = loss(y_hat, y)
            l.backward()
            optimizer.step()#更新参数
            with torch.no_grad():
                metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
            timer.stop()
            train_l = metric[0] / metric[2]
            train_acc = metric[1] / metric[2]
            if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
                animator.add(epoch + (i + 1) / num_batches,
                             (train_l, train_acc, None))
        test_acc = evaluate_accuracy_gpu(net, test_iter)
        animator.add(epoch + 1, (None, None, test_acc))
    print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
          f'test acc {test_acc:.3f}')
    print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
          f'on {str(device)}')
train_iter, test_iter = load_data_fashion_mnist(256, resize=224)
train_ch6(net, train_iter, test_iter, 10, 0.01, d2l.try_gpu())

在这里插入图片描述

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

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

相关文章

WordPress 6.1新功能 (特性和截图)

WordPress 6.1 Beta 于几天前发布,预计将于 2022 年 11 月 1 日发布。这将是 2022 年的最后一个主要版本,将带来许多新功能和改进。 我们一直在密切监视开发并在我们的测试站点上尝试新功能。 在本文中,我们将通过功能和屏幕截图让您先睹为快…

基于javaweb的医院管理系统(java+springboot+mybatis+vue+mysql)

基于javaweb的医院管理系统(javaspringbootmybatisvuemysql) 运行环境 Java≥8、MySQL≥5.7、Node.js≥10 开发工具 后端:eclipse/idea/myeclipse/sts等均可配置运行 前端:WebStorm/VSCode/HBuilderX等均可 适用 课程设计,大作业&…

对于一个即将上线的网站,如何测试

web应用:也叫做网站,相对于客户端应用来说,web应用无需单独安装,在浏览器上即可使用其功能。 web应用的主要开发流程如下: 在网站开发的整个流程中,测试验收是上线发布前的最后一个环节,测试是…

Linux环境下安装Jenkins

首先安装Jenkins之前,linux中必须安装好了JDK和Maven,如果还没有安装过,下面准备好安装教程 Linux环境安装JDK: https://www.cnblogs.com/xuliangxing/p/7066913.html Linux环境安装Maven: https://blog.csdn.net/qq_35868412/article/detail…

【数据库04】中级开发需要掌握哪些SQL进阶玩法

前 言 🍉 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端 ☕专栏简介:相当硬核,黑皮书《数据库系统概念》读书笔记,讲解: 1.数据库系统的基本概念(数据…

Unicode云对象对接代码Demo

实现点击按钮,获取云对象返回内容,例下图 新建云对象-co1 index.obj.js代码 // 云对象教程: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj // jsdoc语法提示教程:https://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/129 mo…

深入理解计算机系统:内存越界引用和缓冲区溢出

注:最后有面试挑战,看看自己掌握了吗 文章目录原因造成后果缓冲区溢出执行攻击代码exploit code蠕虫和病毒的区别原因 C对数组引用不进行任何边界检查,而且局部变量和状态信息(寄存器值,返回地址)都放在栈…

2.1 Python 解释器

1. 什么是 Python 解释器 Python 解释器是解释 Python 脚本执行的程序. 开发者在编写 Python 代码保存后, 就会得到一个以.py为扩展名的文本文件, 若要运行此文件, 就需要Python解释器去执行.2. Python 解释器的种类 Python 有好几种版本的解释器:CPython: 官方版本的解释器,…

猿创征文|技术成长之各进制之间的转换

目录 一.非十进制转十进制 方法: 示例 解释 二进制转十进制 八进制转十进制 十六进制转十进制 二.十进制转非十进制 整数部分 方法 示例 十进制整数转二进制 十进制整数转八进制 十进制整数转十六进制 小数部分 方法 十进制小数转二进制 十进制小数转…

反应性叠氮化物N3-PEG-NH2,Azide-PEG-Amine,叠氮-聚二乙醇-胺

一:产品描述 1、名称 英文:N3-PEG-NH2,Azide-PEG-Amine 中文:叠氮-聚二乙醇-胺 2、CAS编号:N/A 3、所属分类:Amine PEG Azide PEG 4、分子量:可定制,叠氮-聚二乙醇-胺10k、叠氮…

Allegro DFM Ravel Rule检查工具介绍

Allegro DFM Ravel Rule检查工具介绍 Allegro任何一个版本都支持DFM Ravel Rule检查,即便是166的版本 打开后的界面如下所示 可以检查项目 测试点,阻焊,走线,丝印,过孔,milling,装配,outline相关的DFM检查 可以让违反规则的设计处以DRC的形式报出来 避免加工问题 首…

Spring+SpringMVC+Mybatis SSM框架详解

一、JDBC编程 1、JDBC 简介 JDBC其实就是 Java 官方提供的一套规范(接口),用于帮助开发人员快速实现不同关系型数据库的连接。 程序运行的时候,数据都是在内存中的。当程序终止的时候,通常都需要将数据保存到磁盘上…

VScode 官网下载太慢解决方法

用惯了HBuilder 和 WebStorm,发现身边很多人也在用 VSCode,就像尝试下。 但是,官网下载太慢了。https://code.visualstudio.com/ 我可是 500M 的宽带啊~!!! 有小道消息说,VSCode 对中国大陆用…

【Linux】软件包管理器 --- yum

目录🌈前言Linux 软件包管理器 yum🚁1、什么是软件包🚂2、yum指令🚃3、关于 rzsz🌈前言 本篇文章进行开发工具的学习!!! Linux 软件包管理器 yum 🚁1、什么是软件包 源…

heapdump 攻击面利用

点击上方蓝字关注我们 一、heapdump案例 1.1 项目中的分析 这个是项目中遇到的一个例子,发现了heapdump泄露,但没有找到可用session,当时就想着内存中应该是有账号密码的,于是就开始找了起来。 用OQL进行搜索,先找…

异地远程群晖NAS教程【cpolar内网穿透】

公网/外网访问群晖NAS,虽然品牌NAS都会有自带DDNS服务,但是公网IPV4很难申请,所以很多用户都会转战内网穿透。网上也有很多教程,比如frp…,但是需要有公网服务器支持来进行搭建,有一定的要求。 cpolar内网穿…

Graphviz安装教程

Graphviz安装教程 官网下载graphviz的安装包 ,网址: https://graphviz.org/download/ 进入下面页面。此处我选择这个版本进行下载, 后面就是安装和配置环境变量问题 安装的时候记住安装路径(最好放到anaconda文件夹下,即**\An…

通讯录的实现(静态版本和动态版本和文件版本)

为什们要实现通讯录? 主要是为了让我们将结构体的知识,了解的更加深刻,将结构体应用一下,我们先将静态的通讯录实现,在进行改良,用动态内存的知识再将通讯录改造一边,将动态内容的知识也运用一…

C++ Reference: Standard C++ Library reference: C Library: cstring: strncat

C官网参考链接&#xff1a;https://cplusplus.com/reference/cstring/strncat/ 函数 <cstring> strncat char * strncat ( char * destination, const char * source, size_t num ); 从字符串中追加字符 将source的第一个num个字符追加到destination&#xff0c;并追加…

重型机床热误差补偿温度敏感测点的识别与优化选择

重型机床热误差补偿温度敏感测点的识别与优化选择 动机与主要贡献 ● 热误差预测的性能主要取决于预测模型的准确性和鲁棒性以及输入的温度变量 ● 在大型数控机床热误差补偿方案中&#xff0c;由于温度敏感点的结构和发热机理复杂&#xff0c;目前仍缺乏有效的温度敏感点识别…