【Pytorch】复杂神经网络(GoogleNet,Inception)

一、怎么提升神经网络的性能
要想提升网络的性能,要么增加网络的深度(网络层次的数量),要么提高网络的宽度(神经元的数量)。但是一旦增加网络的深度和宽度就会遇到一些问题。
(1)增加神经元和网络的深度会增加相关的超参数数量,会增加对训练数据集的要求。
(2)计算复杂度很大
(3)梯度弥散问题
所以我们最好的办法就是增加网络深度和宽度的同时,减少超参数的数量。最简单的办法就是将全连接变为稀疏连接。但这种办法因为机器硬件的限制,不能减少计算的时间。

所以我们需要通过聚类的方式,将稀疏矩阵变为较为密集的矩阵提高性能。
因此GoogleNet提出的Inception网络结构就是一种稀疏性高计算性能的网络结构。

二、Inception V1
最初的Inception结构:
在这里插入图片描述
思路就是“稀疏”+”稠密保证既增加了神经元的数量,又减少了运算的时间。
其中1X1的卷积核的作用是减少输入数据的维度。即降低了输入数据的通道数(宽度和高度不变),压缩之后再通过3X3或者5X5的卷积核调整通道数复原。
如输入数据为(1922828)通过1X1的卷积核可以得到(162828)在通过5X5卷积核可以得到(322828)通过计算,可以在这种情况下的运算速度大概是十分之一。

下图是完整的结构:
在这里插入图片描述
在这里插入图片描述

三、Inception V2
3x3的卷积核的参数为9,5x5的卷积核参数为25,所以理论上使用3x3的卷积核更好,那么我们能不能找一种特殊的卷积方式,在不改变表达方式的情况下,分解卷积核呢?
答案是可以的,经过很多论文和实验证明。可以拆分卷积核。
如下图,一个nxn的卷积核可以拆成1xn的卷积核后接nx1的卷积核。
在这里插入图片描述
四、Inception V3
Inception V3一个最重要的改进是分解。将7x7分解成两个一维的卷积(1x7,7x1),3x3也是一样(1x3,3x1),这样的好处,既可以加速计算,又可以将1个卷积拆成2个卷积,使得网络深度进一步增加,增加了网络的非线性(每增加一层都要进行ReLU)。

五、Inception V4
Inception V4研究了Inception模块与残差连接的结合。

六、简单Inception网络的实现

(1)导入包

import torch
from torch import nn
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
import matplotlib.pyplot as plt

(2)准备数据

batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307, ), (0.3081, ))
])

train_dataset = datasets.MNIST(root='dataset/mnist',
                               train=True,
                               download=True,
                               transform=transform)
train_loader = DataLoader(dataset=train_dataset,
                          batch_size=batch_size,
                          shuffle=True)

test_dataset = datasets.MNIST(root='dataset/mnist',
                              train=False,
                              download=True,
                              transform=transform)
test_loader = DataLoader(dataset=test_dataset,
                         batch_size=batch_size,
                         shuffle=False)

(3)构建模型
我们要对如下的模型进行建模。
在这里插入图片描述
首先,如模型图,我们需要一个平均池化层,4个卷积1x1卷积层,1个5x5卷积层,两个3x3卷积层。这将模型分为四条路线。
所以在__init__方法中,我们将建立:
branch1x1:输入通道待定,输出通道为16,卷积核大小为1。
branch5x5:输入通道待定,输出通道为16,卷积核大小为1。输入通道为16,输出通道为24,卷积核为5,为了保证数据最后能拼接,故步长为2
branch3x3:同理根据图来建立。
branch_pool:一个池化层。
前馈中,将输入分别输入4个层,再将结果通过torch.cat方法拼接在一起,dim=1表示通过通道进行拼接。

class InceptionA(nn.Module):
    def __init__(self, in_channels):
        super(InceptionA, self).__init__()
        self.branch1X1 = nn.Conv2d(in_channels, 16, kernel_size=1)

        self.branch5X5_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
        self.branch5X5_2 = nn.Conv2d(16, 24, kernel_size=5, padding=2)

        self.branch3X3_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
        self.branch3X3_2 = nn.Conv2d(16, 24, kernel_size=3, padding=1)
        self.branch3X3_3 = nn.Conv2d(24, 24, kernel_size=3, padding=1)

        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]
        return torch.cat(outputs, dim=1)

这样一个inception层就构建完毕了,再结合其他层,我们就能建立一个复杂一点的神经网络。下面对整个神经网络进行建模。
(1)因为MINIST数据是(batch,1,28,28) 的大小,所以现进行一个卷积->池化->激活层,输出为(batch,10,12,12)。
(2)再将数据输入一个inception层(输入通道参数为10),输出结果为(batch,88,8,8)。
(3)再进行一个卷积->池化->激活层,出入为(batch,20,4,4)。
(4)再进行一个inception层(输入通道参数为20),输出结果为(batch,88,4,4)。
(5)将数据进行展开成(batch,1,1408)通过最后一个线性层。

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(88, 20, kernel_size=5)

        self.incep1 = InceptionA(in_channels=10)
        self.incep2 = InceptionA(in_channels=20)

        self.mp = nn.MaxPool2d(2)
        self.fc = nn.Linear(1408, 10)

    def forward(self, x):
        in_size = x.size(0)
        x = F.relu(self.mp(self.conv1(x)))
        x = self.incep1(x)
        x = F.relu(self.mp(self.conv2(x)))
        x = self.incep2(x)
        x = x.view(in_size, -1)
        x = self.fc(x)
        return x

其他训练和测试代码与简单神经网络没有差别。
在这里插入图片描述
在这里插入图片描述
最后可以看到正确率最高达到98.98%比简单神经网络的正确率要高。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值