从代码解释GoogleNet Inception-v4


注:本文为笔者查阅资料自行注释,仅供参考😁


Inception-v4可以说是图像分类中很好的素材了,我们可以直接通过 pretrainedmodels 模块来调用Google 开源的很多预构建模型,也可以直接看代码,前者更利于实践应用,而后者则更加利于我们理解这个模型。

源码:pretrained-models.pytorch/pretrainedmodels/models/inceptionv4.py at master · Cadene/pretrained-models.pytorch (github.com)icon-default.png?t=N6B9https://github.com/Cadene/pretrained-models.pytorch/blob/master/pretrainedmodels/models/inceptionv4.py


----Inception-v4框架 

首先我们知道,Inception-v4主体是由 5 个模块组成的:

  Inception-A    Inception-B    Inception-C  Reduction-A    Reduction-B

源码中是这么写的:

    def __init__(self, num_classes=1001):
        super(InceptionV4, self).__init__()
        # Special attributs
        self.input_space = None
        self.input_size = (299, 299, 3)
        self.mean = None
        self.std = None
        # Modules
        self.features = nn.Sequential(
            BasicConv2d(3, 32, kernel_size=3, stride=2),
            BasicConv2d(32, 32, kernel_size=3, stride=1),
            BasicConv2d(32, 64, kernel_size=3, stride=1, padding=1),
            Mixed_3a(),
            Mixed_4a(),
            Mixed_5a(),
            Inception_A(),
            Inception_A(),
            Inception_A(),
            Inception_A(),
            Reduction_A(),  # Mixed_6a
            Inception_B(),
            Inception_B(),
            Inception_B(),
            Inception_B(),
            Inception_B(),
            Inception_B(),
            Inception_B(),
            Reduction_B(),  # Mixed_7a
            Inception_C(),
            Inception_C(),
            Inception_C()
        )
        self.last_linear = nn.Linear(1536, num_classes)

 -------好复杂。。


----卷积池构建 

首先我们看最基础的卷积层——这是后面的每个模块中都要用到的

每个参数的含义如下(有点多,后面就少了)🤢🤢

class BasicConv2d(nn.Module):
    # 定义卷积层的各种参数:  输入通道     输出通道      卷积核大小    步长    填充取值为0表示不填充
    def __init__(self, in_planes, out_planes, kernel_size, stride, padding=0):
        # 调用父类 nn.Module中的初始化方法给BasicConv2d类初始化
        # 注:使用super函数可以让子类调用父类中的函数,如果调用的是init函数,则子类可以继承父类的属性和方法
        super(BasicConv2d, self).__init__()
        self.conv = nn.Conv2d(in_planes, out_planes,
                              kernel_size=kernel_size, stride=stride,
                              padding=padding, bias=False)  # biase偏置为False
        # 归一化层   Batch Normalization 提高模型训练速度,提高模型的鲁棒性
        # eps:防止分母为0的小常数,在对一个通道进行归一化的时候,为了防止分母为0,会在计算前先给分母
        # 加上eps这个小常数,通过这种方式来避免出现分母为0的情况。
        # momentum是用来计算滑动平均值的参数,用来减少内部协变量偏移
        # affine表示是否进行仿射运算
        # 注:仿射运算指的是在全连接层中权重矩阵和偏置向量结合的操作
        #      output = input * weight + biase
        self.bn = nn.BatchNorm2d(out_planes,
                                 eps=0.001,  # value found in tensorflow
                                 momentum=0.1,  # default pytorch value
                                 affine=True)
        # 初始化relu激活函数
        self.relu = nn.ReLU(inplace=True)

    # 前向传播函数forward
    def forward(self, x):
        # 输入的张量x首先经过卷积层卷积
        x = self.conv(x)
        # 经过卷积之后的张量 送到归一化层进行归一化
        x = self.bn(x)
        # 经过归一化之后的结果送到激活层
        x = self.relu(x)
        # 将经过卷积-归一化-激活之后的张量返回
        return x

----Mix-3a,Mix-4a,Mix-5a

class Mixed_3a(nn.Module):
    def __init__(self):
        # 调用父类nn.Module中的方法给Mixed_3a初始化
        super(Mixed_3a, self).__init__()
        # 最大池化层,使用 3 * 3 的池化窗口,步长为2
        self.maxpool = nn.MaxPool2d(3, stride=2)
        # 卷积层,输入通道64 输出通道 96 卷积核尺寸为 3 步长为 2
        self.conv = BasicConv2d(64, 96, kernel_size=3, stride=2)

    # 前向传播,这里仍然是一个最大池化层加上一个卷积层
    def forward(self, x):
        x0 = self.maxpool(x)
        x1 = self.conv(x)
        # 拼接,将最大池化层得到的结果和卷积层得到的结果进行拼接
        out = torch.cat((x0, x1), 1)
        return out

class Mixed_4a(nn.Module):

    def __init__(self):
        # 一样使用父类nn.Module来初始化
        super(Mixed_4a, self).__init__()
        # 定义了分支一,包含两个卷积层
        self.branch0 = nn.Sequential(
            BasicConv2d(160, 64, kernel_size=1, stride=1),  # 第一层,先通过1 * 1的卷积核将160个通道减少到64个,又称作降维
            BasicConv2d(64, 96, kernel_size=3, stride=1)  # 第二层,3 * 3 的卷积核进行卷积操作
        )
        # 下面这些都是一样的,值得一提的是BasicConv2d函数是上面自定义的,并不是API接口
        self.branch1 = nn.Sequential(
            BasicConv2d(160, 64, kernel_size=1, stride=1),
            #padding = (0,3) 表示高度维上不填充,宽度维度上填充3列0
            BasicConv2d(64, 64, kernel_size=(1, 7), stride=1, padding=(0, 3)),
            #padding = (3,0),表示在高度维上填充3行0,而宽度维上不进行填充
            BasicConv2d(64, 64, kernel_size=(7, 1), stride=1, padding=(3, 0)),
            BasicConv2d(64, 96, kernel_size=(3, 3), stride=1)
        )

    def forward(self, x):
        x0 = self.branch0(x)
        x1 = self.branch1(x)
        out = torch.cat((x0, x1), 1)
        return out

class Mixed_5a(nn.Module):

    def __init__(self):
        super(Mixed_5a, self).__init__()
        self.conv = BasicConv2d(192, 192, kernel_size=3, stride=2)
        self.maxpool = nn.MaxPool2d(3, stride=2)

    def forward(self, x):
        x0 = self.conv(x)
        x1 = self.maxpool(x)
        out = torch.cat((x0, x1), 1)
        return out

 ----OK,你现在已经理解了所有Inception-v4里的调用了😍


 

----Inception-A  Inception-B   Inception-C

 

# inception_A模块,只解释部分细节,很多和上面都是一样的
class Inception_A(nn.Module):

    def __init__(self):
        super(Inception_A, self).__init__()
        self.branch0 = BasicConv2d(384, 96, kernel_size=1, stride=1)

        self.branch1 = nn.Sequential(
            BasicConv2d(384, 64, kernel_size=1, stride=1),
            BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1)
        )
        #padding = 1 表示在四周都填上一圈0
        self.branch2 = nn.Sequential(
            BasicConv2d(384, 64, kernel_size=1, stride=1),
            BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1),
            BasicConv2d(96, 96, kernel_size=3, stride=1, padding=1)
        )

        self.branch3 = nn.Sequential(
            nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False),  # 平均池化层,计算 3 * 3 范围的通道品均值,count_include_pad
            # = False 表示计算到边缘的时候不包含空缺部分
            BasicConv2d(384, 96, kernel_size=1, stride=1)
        )

    def forward(self, x):
        x0 = self.branch0(x)
        x1 = self.branch1(x)
        x2 = self.branch2(x)
        x3 = self.branch3(x)
        out = torch.cat((x0, x1, x2, x3), 1)
        return out

class Inception_B(nn.Module):

    def __init__(self):
        super(Inception_B, self).__init__()
        self.branch0 = BasicConv2d(1024, 384, kernel_size=1, stride=1)

        self.branch1 = nn.Sequential(
            BasicConv2d(1024, 192, kernel_size=1, stride=1),
            BasicConv2d(192, 224, kernel_size=(1, 7), stride=1, padding=(0, 3)),
            BasicConv2d(224, 256, kernel_size=(7, 1), stride=1, padding=(3, 0))
        )

        self.branch2 = nn.Sequential(
            BasicConv2d(1024, 192, kernel_size=1, stride=1),
            BasicConv2d(192, 192, kernel_size=(7, 1), stride=1, padding=(3, 0)),
            BasicConv2d(192, 224, kernel_size=(1, 7), stride=1, padding=(0, 3)),
            BasicConv2d(224, 224, kernel_size=(7, 1), stride=1, padding=(3, 0)),
            BasicConv2d(224, 256, kernel_size=(1, 7), stride=1, padding=(0, 3))
        )

        self.branch3 = nn.Sequential(
            nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False),
            BasicConv2d(1024, 128, kernel_size=1, stride=1)
        )

    def forward(self, x):
        x0 = self.branch0(x)
        x1 = self.branch1(x)
        x2 = self.branch2(x)
        x3 = self.branch3(x)
        out = torch.cat((x0, x1, x2, x3), 1)
        return out

class Inception_C(nn.Module):

    def __init__(self):
        super(Inception_C, self).__init__()

        self.branch0 = BasicConv2d(1536, 256, kernel_size=1, stride=1)

        self.branch1_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1)
        self.branch1_1a = BasicConv2d(384, 256, kernel_size=(1, 3), stride=1, padding=(0, 1))
        self.branch1_1b = BasicConv2d(384, 256, kernel_size=(3, 1), stride=1, padding=(1, 0))

        self.branch2_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1)
        self.branch2_1 = BasicConv2d(384, 448, kernel_size=(3, 1), stride=1, padding=(1, 0))
        self.branch2_2 = BasicConv2d(448, 512, kernel_size=(1, 3), stride=1, padding=(0, 1))
        self.branch2_3a = BasicConv2d(512, 256, kernel_size=(1, 3), stride=1, padding=(0, 1))
        self.branch2_3b = BasicConv2d(512, 256, kernel_size=(3, 1), stride=1, padding=(1, 0))

        self.branch3 = nn.Sequential(
            nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False),
            BasicConv2d(1536, 256, kernel_size=1, stride=1)
        )

    def forward(self, x):
        x0 = self.branch0(x)

        x1_0 = self.branch1_0(x)
        x1_1a = self.branch1_1a(x1_0)
        x1_1b = self.branch1_1b(x1_0)
        x1 = torch.cat((x1_1a, x1_1b), 1)

        x2_0 = self.branch2_0(x)
        x2_1 = self.branch2_1(x2_0)
        x2_2 = self.branch2_2(x2_1)
        x2_3a = self.branch2_3a(x2_2)
        x2_3b = self.branch2_3b(x2_2)
        x2 = torch.cat((x2_3a, x2_3b), 1)

        x3 = self.branch3(x)

        out = torch.cat((x0, x1, x2, x3), 1)
        return out

----Reduction-A    Reduction-B

class Reduction_A(nn.Module):

    def __init__(self):
        super(Reduction_A, self).__init__()
        self.branch0 = BasicConv2d(384, 384, kernel_size=3, stride=2)

        self.branch1 = nn.Sequential(
            BasicConv2d(384, 192, kernel_size=1, stride=1),
            BasicConv2d(192, 224, kernel_size=3, stride=1, padding=1),
            BasicConv2d(224, 256, kernel_size=3, stride=2)
        )

        self.branch2 = nn.MaxPool2d(3, stride=2)

    def forward(self, x):
        x0 = self.branch0(x)
        x1 = self.branch1(x)
        x2 = self.branch2(x)
        out = torch.cat((x0, x1, x2), 1)
        return out

class Reduction_B(nn.Module):

    def __init__(self):
        super(Reduction_B, self).__init__()

        self.branch0 = nn.Sequential(
            BasicConv2d(1024, 192, kernel_size=1, stride=1),
            BasicConv2d(192, 192, kernel_size=3, stride=2)
        )

        self.branch1 = nn.Sequential(
            BasicConv2d(1024, 256, kernel_size=1, stride=1),
            BasicConv2d(256, 256, kernel_size=(1, 7), stride=1, padding=(0, 3)),
            BasicConv2d(256, 320, kernel_size=(7, 1), stride=1, padding=(3, 0)),
            BasicConv2d(320, 320, kernel_size=3, stride=2)
        )

        self.branch2 = nn.MaxPool2d(3, stride=2)

    def forward(self, x):
        x0 = self.branch0(x)
        x1 = self.branch1(x)
        x2 = self.branch2(x)
        out = torch.cat((x0, x1, x2), 1)
        return out

 ok,你现在已经理解Inception-V4了!

注:在github上开源的代码里面是要下载预处理权重的

👇就是下面这段:url网址里面就是预处理的权重。

# inception-v4模型预处理段
pretrained_settings = {
    'inceptionv4': {
        'imagenet': {
            # 存储预处理权重的下载链接可以提前下载然后用的时候指定文件地址
            'url': 'https://data.lip6.fr/cadene/pretrainedmodels/inceptionv4-8e4777a0.pth',
            'input_space': 'RGB',
            # 输入图像的尺寸为299*299*3
            'input_size': [3, 299, 299],
            # 输入图像的像素值范围,通常表示像素点的颜色通道值为0`255,这里输入的像素值范围
            # 表示经过归一化之后每个像素点的RGB通道值以浮点数0~1的形式存储
            'input_range': [0, 1],
            # 输入图像的均值
            'mean': [0.5, 0.5, 0.5],
            # 输入图像的标准差
            'std': [0.5, 0.5, 0.5],
            # 输出图像的类别
            'num_classes': 1000
        },
        # 这个代码段代表会将背景也同时分类,使用包含背景的预处理权重
        'imagenet+background': {
            'url': 'http://data.lip6.fr/cadene/pretrainedmodels/inceptionv4-8e4777a0.pth',
            'input_space': 'RGB',
            'input_size': [3, 299, 299],
            'input_range': [0, 1],
            'mean': [0.5, 0.5, 0.5],
            'std': [0.5, 0.5, 0.5],
            'num_classes': 1001
        }
    }
}

 每个模块结合B站上Inception-V4的讲解图示看可以更快理解!

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Inception-v4是一种深度学习模型,由Google团队开发。如果想要在官网下载Inception-v4,可以采取以下步骤: 首先,访问Google Brain官方网站,找到他们的Github页面。在这个页面上,可以找到Inception-v4的代码和详细说明文档。需要注意的是,Inception-v4是一个开源的项目,所以可以直接在GitHub页面上下载它。 其次,如果想要在本地计算机上运行Inception-v4,需要确保具备适当的硬件和软件环境。例如,需要安装CUDA、cuDNN等深度学习框架和库。此外,在运行Inception-v4之前,最好先阅读文档,了解如何配置和运行模型。 最后,在下载和使用Inception-v4的过程中,需要遵循相关的法律和规定。尤其是在涉及敏感数据或人类隐私的情况下,需要格外谨慎。在使用Inception-v4时,需要注意保护个人隐私和数据安全。 ### 回答2: 为了下载inception-v4模型,可以通过官方网站进行获取。首先,使用浏览器打开谷歌(Google)的官方网站(https://www.tensorflow.org/),该网站提供了TensorFlow深度学习框架的文档和资源。 在页面的顶部菜单栏中,可以找到一个名为“Get Started(入门)”的标签。鼠标悬停在该标签上后,会显示一个下拉菜单,其中包含了各种资源和工具。点击下拉菜单中的“Models”选项。 在Models页面中,会列出所有可用的模型和数据集。浏览页面,找到inception模型的部分。点击inception栏目下的链接进入inception模型的详情页。 在inception模型的详情页中,可以找到相关的说明和下载链接。查看下载链接,点击相应的下载按钮以下载inception-v4模型的压缩文件。下载完成后,可以解压缩文件,并按照官方提供的说明进行模型的使用和应用。 总体而言,只需要按照上述步骤在TensorFlow官网中找到inception-v4的模型页面,并通过官方下载链接下载相关文件即可。注意要遵循官方说明进行正确的下载和使用,以获得最佳的结果。 ### 回答3: Inception-v4是一个深度学习模型在计算机视觉任务上具有出色性能的架构。但是,没有从官方网站下载Inception-v4。 Inception-v4最初是由Google Brain团队开发的,并在2016年的一篇论文中被提出。该模型是Inception-v3的改进版本,采用了一些新的技术和架构设计来提高准确性和计算效率。 然而,Inception-v4并没有官方的单独下载网站。相反,我们可以在一些开源机器学习库中找到实现了Inception-v4模型的代码。 例如,TensorFlow和PyTorch等流行的深度学习框架都有相关的代码和实现。可以通过官方的GitHub页面或官方文档来获取这些代码。从这些代码中, 我们可以找到Inception-v4的实现,并下载源代码或通过命令行工具进行安装。 另外,一些机器学习社区也可能有Inception-v4的开源实现代码可供下载。这些社区网站(如GitHub、GitLab等)通常会有用户贡献的模型实现代码。我们可以在这些网站上搜索"Inception-v4"关键字,找到最适合自己需求的实现代码进行下载和使用。 总结而言,要下载Inception-v4,我们应该查看TensorFlow、PyTorch等深度学习框架的官方库,或者搜索并浏览开源机器学习社区的代码仓库。这些途径会提供有关该模型的实现代码和相关信息。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值