MixNet解析以及pytorch源码

Posted AI浩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MixNet解析以及pytorch源码相关的知识,希望对你有一定的参考价值。

文章目录

摘要

MixConv 的主要思想是在单个深度卷积操作中混合多个不同大小的内核,以便它可以轻松地从输入图像中捕获不同类型的模式。 大核来捕获高分辨率的特征(我理解是全局的特征),又需要小核来捕获低分辨率的特征(我理解是图片的纹理特征),以提高模型的准确性和效率。网络结构如图:

这种特征拼接和Inceptions 有很多相似的地方,但是卷积采用分组卷积的方式,所以参数的计算量比较小。想要理解MixNet,首先要理解大小卷积核的优缺点,然后,理解分组卷积。

大卷积核与小卷积核

究竟是大卷积核好,还是小的卷积核好,这个大家一直在争论。CNN的鼻祖LeNet和惊艳到大家的AlexNet都使用了大卷积核。后来,到VGG开始使用3×3的卷积核,再发展到YOLOV4、5里面使用了大量的1×1的卷积核。

卷积核越大,receptive field(感受野)越大,看到的图片信息越多,因此获得的特征越好。但是大的卷积核会导致计算量的暴增,不利于模型深度的增加,计算性能也会降低。

于是在VGG、Inception网络中,利用2个3×3卷积核的组合来代替1个5×5卷积核,感受野不变,计算量还得到降低。多个 3x3 的卷积层比一个大尺寸 filter卷积层有更多的非线性(更多层的非线性函数),使得判决函数更加具有判决性。

正因为这些因素,导致了人们越来越喜欢小卷积核。

最近,人们又开始重新审视大卷积核,比如MixNet使用了3×3、5×5、7×7和9×9等,还有更猛的RepLKNet,直接使用31×31大小的卷积核。但是都不再是普通的卷积了,比如MixNet使用的是分组卷积,这样大大降低模型的计算量。

分组卷积

分组卷积则是对输入feature map进行分组,然后每组分别卷积。如下图:

分组卷积则是对输入feature map进行分组,然后每组分别卷积。

假设输入feature map的尺寸仍为 C 0 × H × W C_0\\times H \\times W C0×H×W,输出feature map的数量为 C 1 C_1 C1个,如果设定要分成G个groups,则每组的输入feature map数量为 C 0 G \\fracC_0G GC0,每组的输出feature map数量为 C 1 G \\fracC1G GC1,每个卷积核的尺寸为 C 0 G × K × K \\fracC_0G\\times K \\times K GC0×K×K,卷积核的总数仍为 C 1 C_1 C1个,每组的卷积核数量为 C 1 G \\fracC1G GC1,卷积核只与其同组的输入map进行卷积,卷积核的总参数量为 N × C 0 G × K × K N\\times \\fracC_0G\\times K \\times K N×GC0×K×K总参数量减少为原来的 1 G \\frac1G G1

计算量公式:
[ ( 2 × K 2 × C 0 / g + 1 ) × H × W × C o / g ] × g \\left[\\left(2 \\times K^2 \\times C_0 / g +1\\right) \\times H \\times W \\times C_o / g\\right] \\times g [(2×K2×C0/g+1)×H×W×Co/g]×g
分组卷积的参数量为:
K ∗ K ∗ C 0 g ∗ C 1 g ∗ g K * K * \\fracC_0g * \\fracC_1g * g KKgC0gC1g
举例:

输入的尺寸是227×227×3,卷积核大小是11×11,输出是6,输出维度是55×55,group为3

我们带入公式可以计算出

参数量:

1 1 2 × 3 3 × 6 3 × 3 11^2 \\times \\frac33 \\times \\frac63 \\times 3 112×33×36×3=726

运算量:

[ ( 2 × 1 1 2 × 3 / 3 + 1 ) × 55 × 55 × 6 / 3 ] × 3 \\left[\\left(2 \\times 11^2 \\times3 / 3 +1\\right) \\times 55 \\times 55 \\times 6 / 3\\right] \\times 3 [(2×112×3/3+1)×55×55×6/3]×3=2205225

MinNet核心代码

mixnet_s参数列表:

	mixnet_s = [(16,  16,  [3],              [1],    [1],    1, 1, 'ReLU',  0.0),
                (16,  24,  [3],              [1, 1], [1, 1], 2, 6, 'ReLU',  0.0),
                (24,  24,  [3],              [1, 1], [1, 1], 1, 3, 'ReLU',  0.0),
                (24,  40,  [3, 5, 7],        [1],    [1],    2, 6, 'Swish', 0.5),
                (40,  40,  [3, 5],           [1, 1], [1, 1], 1, 6, 'Swish', 0.5),
                (40,  40,  [3, 5],           [1, 1], [1, 1], 1, 6, 'Swish', 0.5),
                (40,  40,  [3, 5],           [1, 1], [1, 1], 1, 6, 'Swish', 0.5),
                (40,  80,  [3, 5, 7],        [1],    [1, 1], 2, 6, 'Swish', 0.25),
                (80,  80,  [3, 5],           [1],    [1, 1], 1, 6, 'Swish', 0.25),
                (80,  80,  [3, 5],           [1],    [1, 1], 1, 6, 'Swish', 0.25),
                (80,  120, [3, 5, 7],        [1, 1], [1, 1], 1, 6, 'Swish', 0.5),
                (120, 120, [3, 5, 7, 9],     [1, 1], [1, 1], 1, 3, 'Swish', 0.5),
                (120, 120, [3, 5, 7, 9],     [1, 1], [1, 1], 1, 3, 'Swish', 0.5),
                (120, 200, [3, 5, 7, 9, 11], [1],    [1],    2, 6, 'Swish', 0.5),
                (200, 200, [3, 5, 7, 9],     [1],    [1, 1], 1, 6, 'Swish', 0.5),
                (200, 200, [3, 5, 7, 9],     [1],    [1, 1], 1, 6, 'Swish', 0.5)]

列的含义

第一列:in_channels,输入的通道。

第二列:out_channels,输出的通道。

第三列:卷积核的大小。

第四列:信道扩张,应用在MixNetBlock的扩展阶段。

第五列:信道映射,应用在MixNetBlock的末尾,映射输出通道。

第六列:stride,特征图缩放的倍数。

第七列:信道扩张的倍数。

第八列:激活函数

第九列:SE注意力机制放大的倍率。0代表没有SE。

行代表每个MixNetBlock的配置,MixNetBlock的代码如下:

class MixNetBlock(nn.Module):
    def __init__(
            self,
            in_channels,
            out_channels,
            kernel_size=[3],
            expand_ksize=[1],
            project_ksize=[1],
            stride=1,
            expand_ratio=1,
            non_linear='ReLU',
            se_ratio=0.0
    ):
        super(MixNetBlock, self).__init__()
        expand = (expand_ratio != 1)
        expand_channels = in_channels * expand_ratio
        se = (se_ratio != 0.0)
        self.residual_connection = (stride == 1 and in_channels == out_channels)
        conv = []
        if expand:
            # 扩展阶段
            pw_expansion = nn.Sequential(
                GroupedConv2d(in_channels, expand_channels, expand_ksize),
                nn.BatchNorm2d(expand_channels),
                NON_LINEARITY[non_linear]
            )
            conv.append(pw_expansion)
        # depthwise convolution phase
        dw = nn.Sequential(
            MDConv(expand_channels, kernel_size, stride),
            nn.BatchNorm2d(expand_channels),
            NON_LINEARITY[non_linear]
        )
        conv.append(dw)
        if se:
            # squeeze and excite
            squeeze

以上是关于MixNet解析以及pytorch源码的主要内容,如果未能解决你的问题,请参考以下文章

pytorch源码解析-动态接口宏

MixNet实战:使用MixNet实现图像分类

HashMap源码解析

HashMap源码解析

[源码解析] PyTorch 分布式之弹性训练---Rendezvous 引擎

[源码解析] PyTorch 分布式 ----- DistributedDataParallel 之进程组