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

news2024/9/23 11:22:58

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

文章目录

  • 【图像分类】【深度学习】【Pytorch版本】GoogLeNet(InceptionV4)模型算法详解
  • 前言
  • GoogLeNet(InceptionV4)讲解
    • Stem结构
    • Inception-A结构
    • Inception- B结构
    • Inception-C结构
    • redution-A结构
    • redution-B结构
    • GoogLeNet(InceptionV4)模型结构
  • GoogLeNet(InceptionV4) Pytorch代码
  • 完整代码
  • 总结


前言

GoogLeNet(InceptionV4)是由谷歌的Szegedy, Christian等人在《Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning【AAAI-2017】》【论文地址】一文中提出的改进模型,InceptionV4保留了此前的Inception模块的核心思想基础上进行了改进和优化,InceptionV4的所有模块都采用了统一的设计原则,即采用Inception模块作为基本单元,通过堆叠纯Inception基本单元来实现复杂的网络结构。

因为InceptionV4、Inception-Resnet-v1和Inception-Resnet-v2同出自一篇论文,大部分读者对InceptionV4存在误解,认为它是Inception模块与残差学习的结合,其实InceptionV4没有使用残差学习的思想,它基本延续了Inception v2/v3的结构,只有Inception-Resnet-v1和Inception-Resnet-v2才是Inception模块与残差学习的结合产物。


GoogLeNet(InceptionV4)讲解

InceptionV4的三种基础Inception结构与InceptionV3【参考】中使用的结构基本一样,但InceptionV4引入了一些新的模块形状及其间的连接设计,在网络的早期阶段引入了“Stem”模块,用于快速降低特征图的分辨率,从而减少后续Inception模块的计算量。

Stem结构

stem结构实际上是替代了此前的Inception系列网络中Inception结构组之前的网络层,Stem中借鉴了InceptionV3中使用的并行结构、不对称卷积核结构,并使用1*1的卷积核用来降维和增加非线性,可以在保证信息损失足够小的情况下,使得计算量降低。

所有卷积中没有标记为V表示填充方式为"SAME Padding",输入和输出维度一致;标记为V表示填充方式为"VALID Padding",输出维度视具体情况而定。

Inception-A结构

对应InceptionV3中的结构Ⅰ。

Inception- B结构

对应InceptionV3中的结构Ⅱ,只是1×3卷积和3×1卷积变成了1×7卷积和7×1卷积。

Inception-C结构

对应InceptionV3中的结构Ⅲ,只是3×3卷积变成了1×3卷积和3×1卷积的串联结构。

redution-A结构

对应InceptionV3中的特殊结构。

k和l表示卷积个数,不同网络结构的redution-A结构k和l是不同的,Inception-ResNet会在其他博文中介绍。

redution-B结构

采用并行、不对称卷积和1*1的卷积来降低计算量。

GoogLeNet(InceptionV4)模型结构

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

GoogLeNet(InceptionV4)在图像分类中分为两部分:backbone部分: 主要由InceptionV4模块、Stem模块和池化层(汇聚层)组成,分类器部分:由全连接层组成。
InceptionV4三种Inception模块的个数分别为4、7、3个,而InceptionV3中则为3、5、2个,因此InceptionV4的层次更深、结构更复杂,feature map更多。为了降低计算量,在Inception-A和Inception-B后面分别添加了Reduction-A和Reduction-B的结构,用来降低计算量。


GoogLeNet(InceptionV4) Pytorch代码

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

# 卷积组: Conv2d+BN+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.bn = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU(inplace=True)
    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x

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

# Stem:BasicConv2d+MaxPool2d
class Stem(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(Stem, self).__init__()
        # conv3*3(32 stride2 valid)
        self.conv1 = BasicConv2d(in_channels, 32, kernel_size=3, stride=2)
        # conv3*3(32 valid)
        self.conv2 = BasicConv2d(32, 32, kernel_size=3)
        # conv3*3(64)
        self.conv3 = BasicConv2d(32, 64, kernel_size=3, padding=1)
        # maxpool3*3(stride2 valid) & conv3*3(96 stride2 valid)
        self.maxpool4 = nn.MaxPool2d(kernel_size=3, stride=2)
        self.conv4 = BasicConv2d(64, 96, kernel_size=3, stride=2)

        # conv1*1(64)+conv3*3(96 valid)
        self.conv5_1_1 = BasicConv2d(160, 64, kernel_size=1)
        self.conv5_1_2 = BasicConv2d(64, 96, kernel_size=3)
        # conv1*1(64)+conv7*1(64)+conv1*7(64)+conv3*3(96 valid)
        self.conv5_2_1 = BasicConv2d(160, 64, kernel_size=1)
        self.conv5_2_2 = BasicConv2d(64, 64, kernel_size=(7, 1), padding=(3, 0))
        self.conv5_2_3 = BasicConv2d(64, 64, kernel_size=(1, 7), padding=(0, 3))
        self.conv5_2_4 = BasicConv2d(64, 96, kernel_size=3)

        # conv3*3(192 valid) & maxpool3*3(stride2 valid)
        self.conv6 = BasicConv2d(192, 192, kernel_size=3, stride=2)
        self.maxpool6 = nn.MaxPool2d(kernel_size=3, stride=2)

    def forward(self, x):
        x1_1 = self.maxpool4(self.conv3(self.conv2(self.conv1(x))))
        x1_2 = self.conv4(self.conv3(self.conv2(self.conv1(x))))
        x1 = torch.cat([x1_1, x1_2], 1)

        x2_1 = self.conv5_1_2(self.conv5_1_1(x1))
        x2_2 = self.conv5_2_4(self.conv5_2_3(self.conv5_2_2(self.conv5_2_1(y1))))
        x2 = torch.cat([x2_1, x2_2], 1)

        x3_1 = self.conv6(x2)
        x3_2 = self.maxpool6(x2)
        x3 = torch.cat([x3_1, x3_2], 1)
        return x3

Inception-A模块: 卷积层组+池化层

# InceptionV4A:BasicConv2d+MaxPool2d
class InceptionV4A(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch3x3redX2, ch3x3X2, pool_proj):
        super(InceptionV4A, self).__init__()
        # conv1*1(96)
        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
        # conv1*1(64)+conv3*3(96)
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3red, kernel_size=1),
            BasicConv2d(ch3x3red, ch3x3, kernel_size=3, padding=1)   # 保证输出大小等于输入大小
        )
        # conv1*1(64)+conv3*3(96)+conv3*3(96)
        self.branch3 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3redX2, kernel_size=1),
            BasicConv2d(ch3x3redX2, ch3x3X2, kernel_size=3, padding=1),
            BasicConv2d(ch3x3X2, ch3x3X2, kernel_size=3, padding=1)         # 保证输出大小等于输入大小
        )
        # avgpool + conv1*1(96)
        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)

Inception-B模块: 卷积层组+池化层

# InceptionV4B:BasicConv2d+MaxPool2d
class InceptionV4B(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3_1, ch3x3_2, ch3x3redX2, ch3x3X2_1, ch3x3X2_2, pool_proj):
        super(InceptionV4B, self).__init__()
        # conv1*1(384)
        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
        # conv1*1(192)+conv1*7(224)+conv1*7(256)
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3red, kernel_size=1),
            BasicConv2d(ch3x3red, ch3x3_1, kernel_size=[1, 7], padding=[0, 3]),
            BasicConv2d(ch3x3_1, ch3x3_2, kernel_size=[7, 1], padding=[3, 0])   # 保证输出大小等于输入大小
        )
        # conv1*1(192)+conv1*7(192)+conv7*1(224)+conv1*7(224)+conv7*1(256)
        self.branch3 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3redX2, kernel_size=1),
            BasicConv2d(ch3x3redX2, ch3x3redX2, kernel_size=[1, 7], padding=[0, 3]),
            BasicConv2d(ch3x3redX2, ch3x3X2_1, kernel_size=[7, 1], padding=[3, 0]),
            BasicConv2d(ch3x3X2_1, ch3x3X2_1, kernel_size=[1, 7], padding=[0, 3]),
            BasicConv2d(ch3x3X2_1, ch3x3X2_2, kernel_size=[7, 1], padding=[3, 0])  # 保证输出大小等于输入大小
        )
        # avgpool+conv1*1(128)
        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)

Inception-C模块: 卷积层组+池化层

# InceptionV4C:BasicConv2d+MaxPool2d
class InceptionV4C(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch3x3redX2, ch3x3X2_1, ch3x3X2_2, ch3x3X2_3,pool_proj):
        super(InceptionV4C, self).__init__()
        # conv1*1(256)
        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
        # conv1*1(384)+conv1*3(256) & conv3*1(256)
        self.branch2_0 = BasicConv2d(in_channels, ch3x3red, kernel_size=1)
        self.branch2_1 = BasicConv2d(ch3x3red, ch3x3, kernel_size=[1, 3], padding=[0, 1])
        self.branch2_2 = BasicConv2d(ch3x3red, ch3x3, kernel_size=[3, 1], padding=[1, 0])

        # conv1*1(384)+conv1*3(448)+conv3*1(512)+conv3*1(256) & conv7*1(256)
        self.branch3_0 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3redX2, kernel_size=1),
            BasicConv2d(ch3x3redX2, ch3x3X2_1, kernel_size=[1, 3], padding=[0, 1]),
            BasicConv2d(ch3x3X2_1, ch3x3X2_2, kernel_size=[3, 1], padding=[1, 0]),
        )
        self.branch3_1 = BasicConv2d(ch3x3X2_2, ch3x3X2_3, kernel_size=[1, 3], padding=[0, 1])
        self.branch3_2 = BasicConv2d(ch3x3X2_2, ch3x3X2_3, kernel_size=[3, 1], padding=[1, 0])

        # avgpool+conv1*1(256)
        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_0 = self.branch2_0(x)
        branch2 = torch.cat([self.branch2_1(branch2_0), self.branch2_2(branch2_0)], dim=1)
        branch3_0 = self.branch3_0(x)
        branch3 = torch.cat([self.branch3_1(branch3_0), self.branch3_2(branch3_0)], dim=1)
        branch4 = self.branch4(x)
        # 拼接
        outputs = [branch1, branch2, branch3, branch4]
        return torch.cat(outputs, 1)

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

# redutionA:BasicConv2d+MaxPool2d
class redutionA(nn.Module):
    def __init__(self, in_channels, k, l, m, n):
        super(redutionA, self).__init__()
        # conv3*3(n stride2 valid)
        self.branch1 = nn.Sequential(
            BasicConv2d(in_channels, n, kernel_size=3, stride=2),
        )
        # conv1*1(k)+conv3*3(l)+conv3*3(m stride2 valid)
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, k, kernel_size=1),
            BasicConv2d(k, l, kernel_size=3, padding=1),
            BasicConv2d(l, m, kernel_size=3, stride=2)
        )
        # maxpool3*3(stride2 valid)
        self.branch3 = nn.Sequential(nn.MaxPool2d(kernel_size=3, stride=2))

    def forward(self, x):
        branch1 = self.branch1(x)
        branch2 = self.branch2(x)
        branch3 = self.branch3(x)
        # 拼接
        outputs = [branch1,branch2, branch3]
        return torch.cat(outputs, 1)

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

# redutionB:BasicConv2d+MaxPool2d
class redutionB(nn.Module):
    def __init__(self, in_channels, ch3x3red, ch3x3, ch3x3redX2, ch3x3X2):
        super(redutionB, self).__init__()
        # conv1*1(192)+conv3*3(192 stride2 valid)
        self.branch1 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3red, kernel_size=1),
            BasicConv2d(ch3x3red, ch3x3, kernel_size=3, stride=2)
        )
        # conv1*1(256)+conv1*7(256)+conv7*1(320)+conv3*3(320 stride2 valid)
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3redX2, kernel_size=1),
            BasicConv2d(ch3x3redX2, ch3x3redX2, kernel_size=(1, 7), padding=(0, 3)),# 保证输出大小等于输入大小
            BasicConv2d(ch3x3redX2, ch3x3X2, kernel_size=(7, 1), padding=(3, 0)),
            BasicConv2d(ch3x3X2, ch3x3X2, kernel_size=3, stride=2)
        )
        #  maxpool3*3(stride2 valid)
        self.branch3 = nn.Sequential(nn.MaxPool2d(kernel_size=3, stride=2))

    def forward(self, x):
        branch1 = self.branch1(x)
        branch2 = self.branch2(x)
        branch3 = self.branch3(x)
        # 拼接
        outputs = [branch1,branch2, branch3]
        return torch.cat(outputs, 1)

完整代码

GoogLeNet(InceptionV4)的输入图像尺寸是299×299

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

class GoogLeNetV4(nn.Module):
    def __init__(self, num_classes=1000, init_weights=False):
        super(GoogLeNetV4, self).__init__()
        # stem模块
        self.stem = Stem(3, 384)
        # InceptionA模块
        self.inceptionA = InceptionV4A(384, 96, 64, 96, 64, 96, 96)
        # RedutionA模块
        self.RedutionA = redutionA(384, 192, 224, 256, 384)
        # InceptionB模块
        self.InceptionB = InceptionV4B(1024, 384, 192, 224, 256, 192, 224,256,128)
        # RedutionB模块
        self.RedutionB = redutionB(1024,     192, 192, 256, 320)
        # InceptionC模块
        self.InceptionC = InceptionV4C(1536, 256, 384, 256, 384, 448, 512, 256,256)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.dropout = nn.Dropout(0.8)
        self.fc = nn.Linear(1536, num_classes)
        if init_weights:
            self._initialize_weights()

    def forward(self, x):
        # Stem Module
        # N x 3 x 299 x 299
        x = self.stem(x)
        # InceptionA Module * 4
        # N x 384 x 26 x 26
        x = self.inceptionA(self.inceptionA(self.inceptionA(self.inceptionA(x))))
        # ReductionA Module
        # N x 384 x 26 x 26
        x = self.RedutionA(x)
        # InceptionB Module * 7
        # N x 1024 x 12 x 12
        x = self.InceptionB(self.InceptionB(self.InceptionB(self.InceptionB(self.InceptionB(self.InceptionB(self.InceptionB(x)))))))
        # ReductionB Module
        # N x 1024 x 12 x 12
        x = self.RedutionB(x)
        # InceptionC Module * 3
        # N x 1536 x 5 x 5
        x = self.InceptionC(self.InceptionC(self.InceptionC(x)))
        # Average Pooling
        # N x 1536 x 5 x 5
        x = self.avgpool(x)
        # N x 1536 x 1 x 1
        x = x.view(x.size(0), -1)
        # Dropout
        # N x 1536
        x = self.dropout(x)
        # Linear(Softmax)
        # N x 1536
        x = self.fc(x)
        # N x 1000
        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)

# InceptionV4A:BasicConv2d+MaxPool2d
class InceptionV4A(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch3x3redX2, ch3x3X2, pool_proj):
        super(InceptionV4A, self).__init__()
        # conv1*1(96)
        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
        # conv1*1(64)+conv3*3(96)
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3red, kernel_size=1),
            BasicConv2d(ch3x3red, ch3x3, kernel_size=3, padding=1)   # 保证输出大小等于输入大小
        )
        # conv1*1(64)+conv3*3(96)+conv3*3(96)
        self.branch3 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3redX2, kernel_size=1),
            BasicConv2d(ch3x3redX2, ch3x3X2, kernel_size=3, padding=1),
            BasicConv2d(ch3x3X2, ch3x3X2, kernel_size=3, padding=1)         # 保证输出大小等于输入大小
        )
        # avgpool+conv1*1(96)
        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)

# InceptionV4B:BasicConv2d+MaxPool2d
class InceptionV4B(nn.Module):
    def __init__(self, in_channels, ch1x1, ch_red, ch_1, ch_2, ch_redX2, ch_X2_1, ch_X2_2, pool_proj):
        super(InceptionV4B, self).__init__()
        # conv1*1(384)
        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
        # conv1*1(192)+conv1*7(224)+conv1*7(256)
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch_red, kernel_size=1),
            BasicConv2d(ch_red, ch_1, kernel_size=[1, 7], padding=[0, 3]),
            BasicConv2d(ch_1, ch_2, kernel_size=[7, 1], padding=[3, 0])   # 保证输出大小等于输入大小
        )
        # conv1*1(192)+conv1*7(192)+conv7*1(224)+conv1*7(224)+conv7*1(256)
        self.branch3 = nn.Sequential(
            BasicConv2d(in_channels, ch_redX2, kernel_size=1),
            BasicConv2d(ch_redX2, ch_redX2, kernel_size=[1, 7], padding=[0, 3]),
            BasicConv2d(ch_redX2, ch_X2_1, kernel_size=[7, 1], padding=[3, 0]),
            BasicConv2d(ch_X2_1, ch_X2_1, kernel_size=[1, 7], padding=[0, 3]),
            BasicConv2d(ch_X2_1, ch_X2_2, kernel_size=[7, 1], padding=[3, 0])  # 保证输出大小等于输入大小
        )
        # avgpool+conv1*1(128)
        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)

# InceptionV4C:BasicConv2d+MaxPool2d
class InceptionV4C(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch3x3redX2, ch3x3X2_1, ch3x3X2_2, ch3x3X2_3,pool_proj):
        super(InceptionV4C, self).__init__()
        # conv1*1(256)
        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
        # conv1*1(384)+conv1*3(256) & conv3*1(256)
        self.branch2_0 = BasicConv2d(in_channels, ch3x3red, kernel_size=1)
        self.branch2_1 = BasicConv2d(ch3x3red, ch3x3, kernel_size=[1, 3], padding=[0, 1])
        self.branch2_2 = BasicConv2d(ch3x3red, ch3x3, kernel_size=[3, 1], padding=[1, 0])

        # conv1*1(384)+conv1*3(448)+conv3*1(512)+conv3*1(256) & conv7*1(256)
        self.branch3_0 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3redX2, kernel_size=1),
            BasicConv2d(ch3x3redX2, ch3x3X2_1, kernel_size=[1, 3], padding=[0, 1]),
            BasicConv2d(ch3x3X2_1, ch3x3X2_2, kernel_size=[3, 1], padding=[1, 0]),
        )
        self.branch3_1 = BasicConv2d(ch3x3X2_2, ch3x3X2_3, kernel_size=[1, 3], padding=[0, 1])
        self.branch3_2 = BasicConv2d(ch3x3X2_2, ch3x3X2_3, kernel_size=[3, 1], padding=[1, 0])

        # avgpool+conv1*1(256)
        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_0 = self.branch2_0(x)
        branch2 = torch.cat([self.branch2_1(branch2_0), self.branch2_2(branch2_0)], dim=1)
        branch3_0 = self.branch3_0(x)
        branch3 = torch.cat([self.branch3_1(branch3_0), self.branch3_2(branch3_0)], dim=1)
        branch4 = self.branch4(x)
        # 拼接
        outputs = [branch1, branch2, branch3, branch4]
        return torch.cat(outputs, 1)

# redutionA:BasicConv2d+MaxPool2d
class redutionA(nn.Module):
    def __init__(self, in_channels, k, l, m, n):
        super(redutionA, self).__init__()
        # conv3*3(n stride2 valid)
        self.branch1 = nn.Sequential(
            BasicConv2d(in_channels, n, kernel_size=3, stride=2),
        )
        # conv1*1(k)+conv3*3(l)+conv3*3(m stride2 valid)
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, k, kernel_size=1),
            BasicConv2d(k, l, kernel_size=3, padding=1),
            BasicConv2d(l, m, kernel_size=3, stride=2)
        )
        # maxpool3*3(stride2 valid)
        self.branch3 = nn.Sequential(nn.MaxPool2d(kernel_size=3, stride=2))

    def forward(self, x):
        branch1 = self.branch1(x)
        branch2 = self.branch2(x)
        branch3 = self.branch3(x)
        # 拼接
        outputs = [branch1,branch2, branch3]
        return torch.cat(outputs, 1)

# redutionB:BasicConv2d+MaxPool2d
class redutionB(nn.Module):
    def __init__(self, in_channels, ch3x3red, ch3x3, ch_redX2, ch_X2):
        super(redutionB, self).__init__()
        # conv1*1(192)+conv3*3(192 stride2 valid)
        self.branch1 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3red, kernel_size=1),
            BasicConv2d(ch3x3red, ch3x3, kernel_size=3, stride=2)
        )
        # conv1*1(256)+conv1*7(256)+conv7*1(320)+conv3*3(320 stride2 valid)
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch_redX2, kernel_size=1),
            BasicConv2d(ch_redX2, ch_redX2, kernel_size=(1, 7), padding=(0, 3)),# 保证输出大小等于输入大小
            BasicConv2d(ch_redX2, ch_X2, kernel_size=(7, 1), padding=(3, 0)),
            BasicConv2d(ch_X2, ch_X2, kernel_size=3, stride=2)
        )
        #  maxpool3*3(stride2 valid)
        self.branch3 = nn.Sequential(nn.MaxPool2d(kernel_size=3, stride=2))

    def forward(self, x):
        branch1 = self.branch1(x)
        branch2 = self.branch2(x)
        branch3 = self.branch3(x)
        # 拼接
        outputs = [branch1,branch2, branch3]
        return torch.cat(outputs, 1)

# Stem:BasicConv2d+MaxPool2d
class Stem(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(Stem, self).__init__()
        # conv3*3(32 stride2 valid)
        self.conv1 = BasicConv2d(in_channels, 32, kernel_size=3, stride=2)
        # conv3*3(32 valid)
        self.conv2 = BasicConv2d(32, 32, kernel_size=3)
        # conv3*3(64)
        self.conv3 = BasicConv2d(32, 64, kernel_size=3, padding=1)
        # maxpool3*3(stride2 valid) & conv3*3(96 stride2 valid)
        self.maxpool4 = nn.MaxPool2d(kernel_size=3, stride=2)
        self.conv4 = BasicConv2d(64, 96, kernel_size=3, stride=2)

        # conv1*1(64)+conv3*3(96 valid)
        self.conv5_1_1 = BasicConv2d(160, 64, kernel_size=1)
        self.conv5_1_2 = BasicConv2d(64, 96, kernel_size=3)
        # conv1*1(64)+conv7*1(64)+conv1*7(64)+conv3*3(96 valid)
        self.conv5_2_1 = BasicConv2d(160, 64, kernel_size=1)
        self.conv5_2_2 = BasicConv2d(64, 64, kernel_size=(7, 1), padding=(3, 0))
        self.conv5_2_3 = BasicConv2d(64, 64, kernel_size=(1, 7), padding=(0, 3))
        self.conv5_2_4 = BasicConv2d(64, 96, kernel_size=3)

        # conv3*3(192 valid) & maxpool3*3(stride2 valid)
        self.conv6 = BasicConv2d(192, 192, kernel_size=3, stride=2)
        self.maxpool6 = nn.MaxPool2d(kernel_size=3, stride=2)

    def forward(self, x):
        x1_1 = self.maxpool4(self.conv3(self.conv2(self.conv1(x))))
        x1_2 = self.conv4(self.conv3(self.conv2(self.conv1(x))))
        x1 = torch.cat([x1_1, x1_2], 1)

        x2_1 = self.conv5_1_2(self.conv5_1_1(x1))
        x2_2 = self.conv5_2_4(self.conv5_2_3(self.conv5_2_2(self.conv5_2_1(x1))))
        x2 = torch.cat([x2_1, x2_2], 1)

        x3_1 = self.conv6(x2)
        x3_2 = self.maxpool6(x2)
        x3 = torch.cat([x3_1, x3_2], 1)
        return x3

# 卷积组: Conv2d+BN+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.bn = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU(inplace=True)
    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x

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

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


总结

尽可能简单、详细的介绍了InceptionV4的改进方案,讲解了GoogLeNet(InceptionV4)模型的结构和pytorch代码。

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

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

相关文章

4-1三个整数的最大数

#include<stdio.h> int main(){int a,b,c,t,max;printf("请输入三个数&#xff1a;");scanf("%d,%d,%d",&a,&b,&c);t(a>b)?a:b;max(t>c)?t:c;printf("输出三个数中最大是数字是&#xff1a;%d",max);return 0;}

单链表相关面试题--3.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点

/* 解题思路&#xff1a; 通过快慢指针找到中间节点&#xff0c;快指针每次走两步&#xff0c;慢指针每次走一步&#xff0c;当快指针走到结尾的时候&#xff0c;慢指针正好走到中间位置 */ typedef struct ListNode Node; struct ListNode* middleNode(struct ListNode* head)…

全面解读数据资产入表风口,与企业有什么关系和影响

亿信华辰『数据资产入表实务系列直播』第一期成功举办。我们邀请到了亿信华辰高级顾问专家、湖北省软件企业协会数据要素发展工作委员会专家委员刘晗为大家带来数据入表知识体系分享&#xff0c;全程干货&#xff0c;深度解读&#xff0c;以下是演讲上半部分直播内容。 一、数据…

Netty源码学习4——服务端是处理新连接的netty的reactor模式

零丶引入 在前面的源码学习中&#xff0c;梳理了服务端的启动&#xff0c;以及NioEventLoop事件循环的工作流程&#xff0c;并了解了Netty处理网络io重要的Channel &#xff0c;ChannelHandler&#xff0c;ChannelPipeline。 这一篇将学习服务端是如何构建新的连接。 一丶网络包…

​使用SPDK lib搭建自己的NVMe-oF Target应用​

一. 背景 NVMe是一种抽象的传输协议层&#xff0c;旨在提供可靠的NVMe命令和数据传输。NVMe over Fabric (NVMe-oF) 实现了NVMe标准在PCIe总线上的扩展&#xff0c;可以支持数据中心的网络存储&#xff0c;它支持多种传输方式包括FC&#xff0c;RDMA和TCP。NVMe-oF服务(应用) 是…

【已解决】移动号码在移动网上营业厅更换为8元保号套餐

有很多人的副卡基本是为了接收银行卡短信&#xff0c;平时基本不打电话和用流量&#xff0c;每个月固定消费在18-30左右&#xff0c;很浪费。今天发现在网上营业厅就可以修改8元保号套餐&#xff0c;分享给大家。 保号套餐 有以下两种&#xff1a; 解决办法&#xff1a; 1、…

redis非关系型数据库

redis非关系型数据库&#xff0c;缓存型数据库 关系型数据库和非关系型数据库的区别 关系型数据库 关系型数据库是一个结构化的数据库。 记录方式&#xff1a;行和列 行的作用&#xff1a;记录对象的属性 列的作用&#xff1a;声明对象 表与表之间是有关联的&#xff1a…

LR学习笔记——初识lightroom

文章目录 介绍图库界面修改照片界面 介绍 Lightroom是Adobe公司开发的一款用于图片后期处理制作的软件&#xff0c;被称为Adobe Photoshop Lightroom。其增强的校正工具、强大的组织功能以及灵活的打印选项可以帮助加快图片后期处理速度&#xff0c;将更多的时间投入拍摄。 相…

Web自动化测试工具的关键功能

当涉及到 Web 应用程序开发和维护&#xff0c;自动化测试工具发挥着至关重要的作用。这些工具不仅仅简化了测试过程&#xff0c;还有助于保障软件质量、提高生产力和减少人力资源的投入。以下是Web自动化测试工具提供的关键功能&#xff1a; 1. 自动化脚本录制和回放功能 Web 自…

口袋参谋:如何通过布局“问大家”,快速提高宝贝转化!

问大家对于中小卖家来说&#xff0c;是非常适合的&#xff0c;因为我们完全可以靠对问大家的布局&#xff0c;提高宝贝的转化率。 问大家的作用 问大家主要是方便买家在购买前&#xff0c;了解商品的一些问题&#xff0c;而作为该不该购买的参考。对于卖家来说&#xff0c;是…

GaussDB新特性Ustore存储引擎介绍

1、 Ustore和Astore存储引擎介绍 Ustore存储引擎&#xff0c;又名In-place Update存储引擎&#xff08;原地更新&#xff09;&#xff0c;是openGauss 内核新增的一种存储模式。此前的版本使用的行存储引擎是Append Update&#xff08;追加更新&#xff09;模式。相比于Append…

亚马逊第二个大语言模型 Olympus 即将上线

据外媒爆料&#xff0c;亚马逊正在训练他的第二个大语言模型——Olympus&#xff0c;很有可能在今年12月份上线。亚马逊计划将Olympus接入在线零售商店、Echo等设备上的Alexa语音助手&#xff0c;并为AWS平台提供新的功能。据说这个大语言模型规模达到2万亿&#xff08;2000B&a…

C#入门(13):特性Attribute

C# 特性&#xff08;Attributes&#xff09;是用于在运行时为程序元素&#xff08;如类、方法、属性等&#xff09;添加声明性信息的一种方式。这些信息可以在程序运行时通过反射&#xff08;Reflection&#xff09;访问。特性可以用来控制程序行为、添加元数据或者影响程序的运…

为何公司强调流程员工总是觉得反感?

在企业管理中&#xff0c;流程设计对于提高效率和降低风险至关重要。然而&#xff0c;很多企业在流程设计时常犯一些常见的错误&#xff0c;导致基层员工对流程感到烦扰&#xff0c;甚至产生抵触情绪。本文将通过分析一个企业的报销流程问题&#xff0c;探讨如何优化流程以提高…

mysqlbinlog使用记录

首先要确认mysql启用了binlog功能。一般默认启用。 mysql> select log_bin; ----------- | log_bin | ----------- | 1 | ----------- 然后确认binlog目录 mysql> select log_bin_basename; ---------------------------- | log_bin_basename | -----…

【【VDMA彩条显示实验之四 含C语言代码】】

VDMA彩条显示实验之四 含C语言代码 VTC 手册简介 所有的视频都需要有时序 有时序的地方就需要有 时序控制器 VTC的 主要作用是 产生 视频时序 相对于上一节 在这里 我们会理解的更多 观察 这个 HB 信号 其实这个和上一节的图片差不多 在 行同步信号 前面就是前沿 在 行同步…

【数据结构初阶】单链表SLlist

描述 不同于顺序表&#xff0c;顺序表的数据是存储在一个连续的空间里的 而链表它是链接起来的结构体地址。 所以我们不用像顺序表一样先创建一块空间出来&#xff0c;而是创建一个能存数据节点和节点与下一个节点之间的连接&#xff1b; 所以&#xff1a;“一个能存数据节点…

基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖(六)

新增菜品 1.1 需求分析与设计1.1.1 产品原型1.1.2 接口设计1.1.3 表设计 2.2 代码开发2.2.1 文件上传实现2.2.2 新增菜品实现 2.3 功能测试 1.1 需求分析与设计 1.1.1 产品原型 后台系统中可以管理菜品信息&#xff0c;通过 新增功能来添加一个新的菜品&#xff0c;在添加菜品…

BUUCTF [BJDCTF2020]just_a_rar 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 来源&#xff1a;https://github.com/BjdsecCA/BJDCTF2020 密文&#xff1a; 下载附件&#xff0c;解压得到一个.rar压缩包。 解题思路&#xff1a; 1、根据压缩包的名字提示我们使用4位纯数字进行破解。使用ARCH…