Inception(盗梦空间)及代码实现


前言

这段时间观看b站up主 刘二大人 的关于深度学习的讲解,让我获益匪浅。让我了解到什么是盗梦空间(Inception),如何将结构嵌入到模型中,下面是视频地址:

https://www.bilibili.com/video/BV1Y7411d7Ys?p=11&share_source=copy_web

感兴趣的朋友,也可将Inception(盗梦空间)结构放入之前mnist数据识别的代码中进行尝试,因为维度改变,全连接层参数相应的也要进行改变。链接如下:
https://blog.csdn.net/qq_42962681/article/details/116270125?spm=1001.2014.3001.5501


以下是本篇文章正文内容,可供参考,如有不足,恳请大家指正,共同学习。

一、Inception(盗梦空间)是什么?

当你构建卷积层时,你要决定卷积核的大小,如何判别哪种卷积核效果更好?是1x1合适,还是3x3合适,还是5x5合适?要不要添加pooling层?
由于这些参数都是超参数,需要进行手动设置,在实验中逐个尝试的话无疑是一件费时费力的工程,这时通过Inception(盗梦空间)模块可很好的解决相应问题。

使用多个不同的卷积核,同时对输入图片进行处理(保证输出后的图像尺寸不变,只更改其维度),最后对处理的数据进行拼接。

二、使用步骤

1.空间结构

结构如图所示(示例):
图中5x5卷积和3x3卷积,都对图像进行了相应的填充,因此输入图像尺度和输出图像尺度不变。
在这里插入图片描述

2.结构模型

代码如下(示例):
代码中的数据集我使用的是常用的MNIST数据集,单个图像样本大小为(1, 28,28)。

盗梦空间代码示意图

import torch
import torch.nn as nn
from torch.utils.data import DataLoader  # 我们要加载数据集的
from torchvision import transforms  # 数据的原始处理
from torchvision import datasets  # pytorch十分贴心的为我们直接准备了这个数据集
import torch.nn.functional as F  # 激活函数
import torch.optim as optim

#盗梦空间Inception
#图像输入网络中同时经过4种不同的卷积进行处理,这里保证分别处理后的,w,h都相同,以便后方拼接
#[b, c, w, h],这里b=64直接套用了上文提到的mnist数据集中batch_size的大小,可自由设置。
class InceptionA(torch.nn.Module):
    def __init__(self,in_channels):
        super(InceptionA,self).__init__()
        #[64,1,28,28]-[64,16,28,28] 通过卷积核为一的卷积,图像尺寸不变
        self.branch1x1 = nn.Conv2d(in_channels,16,kernel_size=1)

        self.branch5x5_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
        # [64,16,28,28]-[64,24,28,28] 通过卷积核为5的卷积,因为w,h分别填充了2,所以图像尺寸不变
        self.branch5x5_2 = nn.Conv2d(16,24, kernel_size=5,padding=2)

        self.branch3x3_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
        # [64,16,28,28]-[64,24,28,28] 通过卷积核为3的卷积,因为填充了1,所以图像尺寸不变
        self.branch3x3_2 = nn.Conv2d(16, 24, kernel_size=3, padding=1)
        # [64,24,28,28]-[64,24,28,28] 通过卷积核为3的卷积,因为填充了1,所以图像尺寸不变
        self.branch3x3_3 = nn.Conv2d(24, 24, kernel_size=3, padding=1)

        #[64,1,28,28]-[64,24,28,28]
        self.branch_pool = nn.Conv2d(in_channels, 24, kernel_size=1)

    def forward(self,x):
        branch1x1 = self.branch1x1(x)

        branch5x5 = self.branch5x5_1(x)
        branch5x5 = self.branch5x5_2(branch5x5)

        branch3x3 = self.branch3x3_1(x)
        branch3x3 = self.branch3x3_2(branch3x3)
        branch3x3 = self.branch3x3_3(branch3x3)

        #平均池化尺寸不变
        branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)
        branch_pool = self.branch_pool(branch_pool)

        outputs = [branch1x1, branch5x5, branch3x3, branch_pool]
        #[b,c,h,w] dim=1是维度方向拼接 ,这里返回的维度是上述几个维度相加(16+24+24+24=88)
        return torch.cat(outputs, dim=1)

模块示意图
在这里插入图片描述
通过盗梦空间的图片,只更改其的通道数量,而不更改图像的尺寸大小,因此在维度方向进行拼接,上图拼接后的通道数量为24+16+24+24=88,对应了下面第二层卷积层的输入维度。

将盗梦空间结构嵌入到我们的网络中


# 接下来我们看一下模型是怎么做的
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 定义了我们第一个要用到的卷积层,因为图片输入通道为1,第一个参数就是
        # 输出的通道为10,kernel_size是卷积核的大小,这里定义的是5x5的
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
        # 看懂了上面的定义,下面这个你肯定也能看懂
        self.conv2 = torch.nn.Conv2d(88, 20, kernel_size=5)

        #调用盗梦空间
        self.incep1 = InceptionA(in_channels=10)
        self.incep2 = InceptionA(in_channels=20)

        # 再定义一个池化层
        self.mp = torch.nn.MaxPool2d(2)
        # 最后是我们做分类用的线性层
        self.fc = torch.nn.Linear(1408, 10)

    # 下面就是计算的过程
    def forward(self, x):
        # Flatten data from (n, 1, 28, 28)
        batch_size = x.size(0)  # 这里面的0是x大小第1个参数,自动获取batch大小
        #(64, 1, 28, 28)经过10组kernel=5的卷积 ((64, 10, 24, 24)),通过最大池化(64, 10, 12, 12)
        x = F.relu(self.mp(self.conv1(x)))
        # 输入到盗梦空间(64, 10, 12, 12),尺寸不变,维度相加(64, 88, 12, 12)
        x = self.incep1(x)
        # (64, 88, 12, 12)经过20组kernel=5的卷积 ((64, 20, 8, 8)),通过最大池化(64, 20, 4, 4)
        x = F.relu((self.mp(self.conv2(x))))
        #输入到盗梦空间(64, 20, 4, 4),尺寸不变,维度相加(64, 88, 4, 4) ioriw
        x = self.incep2(x)
        # 为了给我们最后一个全连接的线性层用
        # 我们要把一个二维的图片(实际上这里已经是处理过的)64X88x4x4张量变成一维的
        x = x.view(batch_size, -1)  # flatten
        #64X88x4x4改变为64x1408
        # 经过线性层,确定他是0~9每一个数的概率
        #64x1408改变为64x10 因为手写数据集10个分类
        x = self.fc(x)
        return x

总结

学无止境,越走下去,发现自己不懂的越多,深感渺小,还需继续努力。

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值