Split to Be Slim: 论文复现

yizhihongxing

摘要:在本论文中揭示了这样一种现象:一层内的许多特征图共享相似但不相同的模式。

本文分享自华为云社区《Split to Be Slim: 论文复现》,作者: 李长安 。

Split to Be Slim: An Overlooked Redundancy in Vanilla Convolution 论文复现

1、问题切入

已经提出了许多有效的解决方案来减少推理加速模型的冗余。然而,常见的方法主要集中在消除不太重要的过滤器或构建有效的操作,同时忽略特征图中的模式冗余。

在本论文中揭示了这样一种现象:一层内的许多特征图共享相似但不相同的模式。但是,很难确定具有相似模式的特征是否是冗余的或包含基本细节。因此,论文作者不是直接去除不确定的冗余特征,而是提出了一种基于分割的卷积操作,即 SPConv,以容忍具有相似模式但需要较少计算的特征。

具体来说,论文将输入特征图分为Representative部分和不Uncertain冗余部分,其中通过相对繁重的计算从代表性部分中提取内在信息,而对不确定冗余部分中的微小隐藏细节进行一些轻量级处理手术。为了重新校准和融合这两组处理过的特征,我们提出了一个无参数特征融合模块。此外,我们的 SPConv 被制定为以即插即用的方式替换 vanilla 卷积。在没有任何花里胡哨的情况下,基准测试结果表明,配备 SPConv 的网络在 GPU 上的准确性和推理时间上始终优于最先进的基线,FLOPs 和参数急剧下降。

2、特征冗余问题

Split to Be Slim: 论文复现

然而,如上图所示,同一层的特征中存在相似模式,也就是说存在特征冗余问题。但同时,并未存在完全相同的两个通道特征,进而导致无法直接剔除冗余通道特征。 因此,可以选择一些有代表性的特征图来补充内在信息,而剩余的冗余只需要补充微小的不同细节。

3、SPConv详解

Split to Be Slim: 论文复现

在现有的滤波器中,比如常规卷积、GhostConv、OctConv、HetConv均在所有输入通道上执行k*k卷积。然而,如上图所示,同一层的特征中存在相似模式,也就是说存在特征冗余问题。但同时,并未存在完全相同的两个通道特征,进而导致无法直接剔除冗余通道特征。

受此现象启发,作者提出将所有输入特征按比例拆分为两部分:

  1. Representative部分执行k*k卷积提取重要信息;
  2. Uncertain部分执行1*1卷积补充隐含细节信息。

因此该过程可以描述为(见SPConv的左侧部分),公式如下图所示:

Split to Be Slim: 论文复现

3.1 Further Reduction for Reprentative

在将所有输入通道分成两个主要部分后,代表部分之间可能存在冗余。换句话说,代表通道可以分为几个部分,每个部分代表一个主要类别的特征,例如颜色和纹理。因此,我们在代表性通道上采用组卷积以进一步减少冗余,如图 2 的中间部分所示。我们可以将组卷积视为具有稀疏块对角卷积核的普通卷积,其中每个块对应于通道,并且分区之间没有连接。这意味着,在组卷积之后,我们进一步减少了代表性部分之间的冗余,同时我们还切断了可能不可避免地有用的跨通道连接。我们通过在所有代表性通道上添加逐点卷积来弥补这种信息丢失。与常用的组卷积后点卷积不同,我们在相同的代表性通道上进行 GWC 和 PWC。然后我们通过直接求和来融合这两个结果特征,因为它们具有相同的通道来源,从而获得了额外的分数(这里我们将组大小设置为 2)。所以方程2的代表部分可以表述为方程3:

Split to Be Slim: 论文复现

3.2 Parameter Free Feature Fusion Module

到目前为止,我们已经将 vanilla 3×3 卷积拆分为两个操作:对于代表部分,我们进行 3×3 组卷积和 1×1 逐点卷积的直接求和融合,以抵消分组信息丢失;对于冗余部分,我们应用 1 × 1 内核来补充一些微小的有用细节。结果,我们得到了两类特征。因为这两个特征来自不同的输入通道,所以需要一种融合方法来控制信息流。与等式 2 的直接求和融合不同,我们为我们的 SP-Conv 设计了一个新颖的特征融合模块,无需导入额外的参数,有助于实现更好的性能。如图 2 右侧所示,

Split to Be Slim: 论文复现

3.3 代码复现

import paddle
import paddle.nn as nn
def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
 """3x3 convolution with padding"""
 return nn.Conv2D(in_planes, out_planes, kernel_size=3, stride=stride,
                     padding=dilation, groups=groups, dilation=dilation)
class SPConv_3x3(nn.Layer):
 def __init__(self, inplanes=32, outplanes=32, stride=1, ratio=0.5):
 super(SPConv_3x3, self).__init__()
 self.inplanes_3x3 = int(inplanes*ratio)
 self.inplanes_1x1 = inplanes - self.inplanes_3x3
 self.outplanes_3x3 = int(outplanes*ratio)
 self.outplanes_1x1 = outplanes - self.outplanes_3x3
 self.outplanes = outplanes
 self.stride = stride
 self.gwc = nn.Conv2D(self.inplanes_3x3, self.outplanes, kernel_size=3, stride=self.stride,
                             padding=1, groups=2)
 self.pwc = nn.Conv2D(self.inplanes_3x3, self.outplanes, kernel_size=1)
 self.conv1x1 = nn.Conv2D(self.inplanes_1x1, self.outplanes,kernel_size=1)
 self.avgpool_s2_1 = nn.AvgPool2D(kernel_size=2,stride=2)
 self.avgpool_s2_3 = nn.AvgPool2D(kernel_size=2, stride=2)
 self.avgpool_add_1 = nn.AdaptiveAvgPool2D(1)
 self.avgpool_add_3 = nn.AdaptiveAvgPool2D(1)
        self.bn1 = nn.BatchNorm2D(self.outplanes)
        self.bn2 = nn.BatchNorm2D(self.outplanes)
 self.ratio = ratio
 self.groups = int(1/self.ratio)
 def forward(self, x):
 # print(x.shape)
        b, c, _, _ = x.shape
        x_3x3 = x[:,:int(c*self.ratio),:,:]
        x_1x1 = x[:,int(c*self.ratio):,:,:]
        out_3x3_gwc = self.gwc(x_3x3)
 if self.stride ==2:
            x_3x3 = self.avgpool_s2_3(x_3x3)
        out_3x3_pwc = self.pwc(x_3x3)
        out_3x3 = out_3x3_gwc + out_3x3_pwc
        out_3x3 = self.bn1(out_3x3)
        out_3x3_ratio = self.avgpool_add_3(out_3x3).squeeze(axis=3).squeeze(axis=2)
 # use avgpool first to reduce information lost
 if self.stride == 2:
            x_1x1 = self.avgpool_s2_1(x_1x1)
        out_1x1 = self.conv1x1(x_1x1)
        out_1x1 = self.bn2(out_1x1)
        out_1x1_ratio = self.avgpool_add_1(out_1x1).squeeze(axis=3).squeeze(axis=2)
        out_31_ratio = paddle.stack((out_3x3_ratio, out_1x1_ratio), 2)
        out_31_ratio = nn.Softmax(axis=2)(out_31_ratio)
        out = out_1x1 * (out_31_ratio[:,:,1].reshape([b, self.outplanes, 1, 1]).expand_as(out_1x1))\
 + out_3x3 * (out_31_ratio[:,:,0].reshape([b, self.outplanes, 1, 1]).expand_as(out_3x3))
 return out
# paddle.summary(SPConv_3x3(), (1,32,224,224))
spconv = SPConv_3x3()
tmp = paddle.randn([1, 32, 224, 224])
conv_out1 = spconv(tmp)
print(conv_out1.shape) 
W0724 22:30:03.841145 13041 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 10.1
W0724 22:30:03.845882 13041 gpu_resources.cc:91] device: 0, cuDNN Version: 7.6.
[1, 32, 224, 224]
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/nn/layer/norm.py:654: UserWarning: When training, we now always track global mean and variance.
 "When training, we now always track global mean and variance.")

4、消融实验

为验证所提方法的有效性,设置SPConv中的卷积核k=3,g=2,同时整个网络设置统一的全局超参数(不同阶段设置不同的会更优,但会过于精细)。

在小尺度数据集Cifar10、resnet18网络进行对比分析,为公平对比,所有实验均在含1个NVIDIA Tesla V100GPU的服务器上从头开始训练,且采用默认的数据增广与训练策略,不包含其他额外Tricks。

import paddle
from paddle.metric import Accuracy
from paddle.vision.transforms import Compose, Normalize, Resize, Transpose, ToTensor
from sp_resnet import resnet18_sp
callback = paddle.callbacks.VisualDL(log_dir='visualdl_log_res_sp')
normalize = Normalize(mean=[0.5, 0.5, 0.5],
                    std=[0.5, 0.5, 0.5],
 data_format='HWC')
transform = Compose([ToTensor(), Normalize(), Resize(size=(224,224))])
cifar10_train = paddle.vision.datasets.Cifar10(mode='train',
                                               transform=transform)
cifar10_test = paddle.vision.datasets.Cifar10(mode='test',
                                              transform=transform)
# 构建训练集数据加载器
train_loader = paddle.io.DataLoader(cifar10_train, batch_size=128, shuffle=True, drop_last=True)
# 构建测试集数据加载器
test_loader = paddle.io.DataLoader(cifar10_test, batch_size=128, shuffle=True, drop_last=True)
res_sp = paddle.Model(resnet18_sp(num_classes=10))
optim = paddle.optimizer.Adam(learning_rate=3e-4, parameters=res_sp.parameters())
res_sp.prepare(
 optim,
 paddle.nn.CrossEntropyLoss(),
 Accuracy()
 )
res_sp.fit(train_data=train_loader,
 eval_data=test_loader,
        epochs=10,
        callbacks=callback,
        verbose=1
 )
import paddle
from paddle.metric import Accuracy
from paddle.vision.transforms import Compose, Normalize, Resize, Transpose, ToTensor
from paddle.vision.models import resnet18
callback = paddle.callbacks.VisualDL(log_dir='visualdl_log_res_18')
normalize = Normalize(mean=[0.5, 0.5, 0.5],
                    std=[0.5, 0.5, 0.5],
 data_format='HWC')
transform = Compose([ToTensor(), Normalize(), Resize(size=(224,224))])
cifar10_train = paddle.vision.datasets.Cifar10(mode='train',
                                               transform=transform)
cifar10_test = paddle.vision.datasets.Cifar10(mode='test',
                                              transform=transform)
# 构建训练集数据加载器
train_loader = paddle.io.DataLoader(cifar10_train, batch_size=128, shuffle=True, drop_last=True)
# 构建测试集数据加载器
test_loader = paddle.io.DataLoader(cifar10_test, batch_size=128, shuffle=True, drop_last=True)
res_18 = paddle.Model(resnet18(num_classes=10))
optim = paddle.optimizer.Adam(learning_rate=3e-4, parameters=res_18.parameters())
res_18.prepare(
 optim,
 paddle.nn.CrossEntropyLoss(),
 Accuracy()
 )
res_18.fit(train_data=train_loader,
 eval_data=test_loader,
        epochs=10,
        callbacks=callback,
        verbose=1
 )

5、实验结果分析

最后,我们再来看一下消融实验结果,见下图。可以看到:

  • 添加了SPConV模块的ResNet18效果反而不如原始的ResNet18

在原作中,作者给出了ResNet20、VGG16在数据集Cifar10上的对比结果,原因也可能在于本实验中模型迭代次数不够,但是相比来看,特征图在进行了去冗余操作之后(类似于剪枝),精度下降似乎是正确的。

Split to Be Slim: 论文复现

6、总结

在该文中,作者重新对常规卷积中的信息冗余问题进行了重思考,为缓解该问题,作者提出了一种新颖的SPConv,它将输入特征拆分为两组不同特征并进行不同的处理,最后采用简化版SK进行融合。最后作者通过充分的实验分析说明了所提方法的有效性,在具有更高精度的时候具有更快的推理速度、更少的FLOPs与参数量。

所提SPConv是一种“即插即用”型单元,它可以轻易与其他网络架构相结合,同时与当前主流模型压缩方法互补,如能精心组合设计,有可能得到更轻量型的模型。

7、参考资料

即插即用!北邮&南开大学开源SPConv:精度更高、速度更快的卷积

Split to Be Slim: An Overlooked Redundancy in Vanilla Convolution

 

点击关注,第一时间了解华为云新鲜技术~

原文链接:https://www.cnblogs.com/huaweiyun/p/17349605.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Split to Be Slim: 论文复现 - Python技术站

(0)
上一篇 2023年4月25日
下一篇 2023年4月25日

相关文章

  • SSD-Tensorflow 512×512 训练配置

    搞了几天终于把这个给搞得差不多了,遇到的错误这里也记录一下: 一、配置【配置什么的300和512其实差不多,这里只举一个例子来分析一下】  之前的文件修改什么的和300×300的一样:https://www.cnblogs.com/GrPhoenix/p/10018072.html 从自己训练的ssd_300_vgg模型开始训练ssd_512_vgg的模型 …

    tensorflow 2023年4月6日
    00
  • Keras split train test set when using ImageDataGenerator

    Keras split train test set when using ImageDataGenerator I have a single directory which contains sub-folders (according to labels) of images. I want to split this data into train …

    Keras 2023年4月7日
    00
  • 【转载】Caffe + Ubuntu 14.04 + CUDA 6.5 新手安装配置指南

      洋洋洒洒一大篇,就没截图了,这几天一直在折腾这个东西,实在没办法,不想用Linux但是,为了Caffe,只能如此了,安装这些东西,遇到很多问题,每个问题都要折磨很久,大概第一次就是这样的。想想,之后应用,应该还会遇到很多问题吧,不过没办法了,骑虎难下!!这里有个建议是,如果将来要做大数据集,最好事先给Linux留多点空间,比如Imagenet,估计500…

    Caffe 2023年4月8日
    00
  • 机器学习中的算法(2)-支持向量机(SVM)基础 – LeftNotEasy – 博客园

      版权声明:     本文由LeftNotEasy发布于http://leftnoteasy.cnblogs.com, 本文可以被全部的转载或者部分使用,但请注明出处,如果有问题,请联系wheeleast@gmail.com   前言:     又有很长的一段时间没有更新博客了,距离上次更新已经有两个月的时间了。其中一个很大的原因是,不知道写什么好-_-,…

    机器学习 2023年4月13日
    00
  • 【机器学习】:特征筛选方法

    一.基于统计值的筛选方法 1.过滤法:选择特征的时候,不管模型如何,首先统计计算该特征和和label的一个相关性,自相关性,发散性等等统计指标。 优点:特征选择开销小,有效避免过拟合 缺点:没有考虑后续的学习器来选择特征,减弱了学习器的学习能力(因为某些特征可能和label算出来相关性不大,但是可能和其他特征交叉后,会和label具有很强的关联性) 2.单变…

    机器学习 2023年4月12日
    00
  • 【全文翻译】YOLOv4:目标检测的最佳速度和准确性

      论文连接:https://arxiv.org/abs/2004.10934   翻译的很多都是直译的,不准的地方请欢迎大佬指正 摘要     有许多功能可以提高卷积神经网络(CNN)的准确性。需要在大型数据集上对这些特征的组合进行实际测试,并对结果进行理论证明。一些功能仅在某些模型上运行,并且仅在某些问题上运行,或者仅在小规模数据集上运行; 而某些功能(…

    2023年4月8日
    00
  • Tensorflow函数——tf.variable_scope()

    https://blog.csdn.net/yuan0061/article/details/80576703 2018年06月05日 09:38:25 yuan0061 阅读数:2567   tf.variable_scope(name_or_scope,default_name=None,values=None,initializer=None,regu…

    tensorflow 2023年4月6日
    00
  • 生成对抗网络(GAN)之 Basic Theory 学习笔记

    生成对抗网络(GAN)之 Basic Theory 学习笔记   前言:最近学习了李宏毅生成对抗网络篇(2018年)的视频(视频地址:李宏毅对抗生成网络(GAN)国语教程(2018)),因为截止今天(3.23),2020版还未讲到生成对抗网络,因此选择18年。本次学习笔记主要为Basic Theory部分,主要讲解GAN的数学原理。  GAN又称生成对抗网络…

    2023年4月5日
    00
合作推广
合作推广
分享本页
返回顶部