• [论文理解] Convolution with even-sized kernels and symmetric padding


    Convolution with even-sized kernels and symmetric padding

    Intro

    本文探究了偶数kernel size的卷积对网络的影响,结果表明偶数卷积在结果上并不如奇数卷积。文章从实验与原理上得出结论,偶数卷积之所以结果更差,是因为偶数卷积会使得feature map偏移,即“the shift problem”,这将导致学习到的feature不具备更强的表征能力。本文提出信息侵蚀假设,认为奇数卷积中心对称,而偶数卷积在实现时没有对称点,这将导致在实现时卷积利用的信息不能是各个方向的,只能是左上或其他方向(取决于具体实现),因此整体将会导致feature map往一个方向偏移。为了解决这个问题,文章提出symmetric padding方法来弥补各个方向带来的损失,结果提示很明显。

    The shift problem

    奇数kernel size的卷积实现起来很容易,在对应位置计算当前位置和其八个邻域方向位置的feature值与权重求和即对应输出位置一个值,而偶数kernel size的卷积要如何实现呢?在tensorflow里,偶数kernel size的卷积如2×2卷积是利用当前点和其左上、上方、左方一共四个点与对应权值相乘求和得到的,正因如此,在实现过程,输出feature map的感受野其实是有缺陷的,他只能对应与其左上方的区域,多层卷积之后暴露出来的问题就是feature map的偏移。

    如上图所示,第一行是没使用本文方法padding的conv2x2的结果,第二行是本文方法的结果。

    输出的feature map和输入feature map的关系可以表述为:

    [F^o(p) = sum_{i=1}^{c_i}sum_{delta in mathcal{R}}omega_i(delta) cdot F^i(p+delta) ]

    其中p表示位置坐标,(F^i)(F^o)分别表示输入feature和输出feature,(delta)表示卷积核内的位置,(omega_i)表示卷积核的权重。

    对于奇数kernel size卷积,其中(mathcal{R})可以写成:

    [mathcal{R} = {(-kappa,-kappa),(-kappa,-kappa+1),cdots,(kappa,kappa)},kappa = lceil frac{k-1}{2} ceil ]

    以kernel的中心为原点,各个方向的偏移值就是上面的表示。对于奇数卷积,显然上式是中心对称的,而对于偶数kernel size卷积,对应的(mathcal{R})定义为:

    [mathcal{R} = {(1-kappa,1-kappa),(1-kappa,2-kappa) ,cdots,(kappa,kappa) } ]

    上式并没有利用各个方向的信息,并且卷积核并不是中心对称的。

    The information erosion hypothesis

    对于输入位置p,经过n次偶数卷积之后对应的位置为:

    [F_n[p - (frac{n}{2},frac{n}{2})] gets F_0(p) ]

    因而网络越深,shift现象越严重。

    为了说明偶数卷积对信息的侵蚀作用,文章定义feature的L1范数为该feature map信息量的度量。

    [Q_n = frac{1}{hw} sum_{pin h imes w} |F_n(p)|,Q_n < Q_{n-1} ]

    基于这个定义,文章实验了不同kernel size的信息量,得到如图所示结果:

    可以看到C3和C5整体信息量锐减的比C2和C4慢的多。

    Symmetric padding

    为了解决shift带来的影响,本文提出了一种padding方式,具体的操作如图所示:

    即先将feature map分成四个group,每个group在不同方向上按如图所示的方式进行padding,最后不用padding直接conv2x2即可。

    这样做的好处就是使得网络的某些channel能利用到特定方向的信息,从宏观上看网络利用到了各个方向的信息,一定程度上缓解了shift带来的问题。

    Codding

    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    
    class SpConv2d(nn.Module):
        def __init__(self,in_channels,out_channels,kernel_size,stride,padding,*args,**kwargs):
            super(SpConv2d,self).__init__()
            self.conv = nn.Conv2d(in_channels,out_channels,kernel_size,stride,padding)
        def forward(self,x):
            n,c,h,w = x.size()
            assert c % 4 == 0
            x1 = x[:,:c//4,:,:]
            x2 = x[:,c//4:c//2,:,:]
            x3 = x[:,c//2:c//4*3,:,:]
            x4 = x[:,c//4*3:c,:,:]
            x1 = nn.functional.pad(x1,(1,0,1,0),mode = "constant",value = 0) # left top
            x2 = nn.functional.pad(x2,(0,1,1,0),mode = "constant",value = 0) # right top
            x3 = nn.functional.pad(x3,(1,0,0,1),mode = "constant",value = 0) # left bottom
            x4 = nn.functional.pad(x4,(0,1,0,1),mode = "constant",value = 0) # right bottom
            x = torch.cat([x1,x2,x3,x4],dim = 1)
            return self.conv(x)
    
    class Net(nn.Module):
        def __init__(self):
            super(Net,self).__init__()
            self.conv = SpConv2d(4,16,2,1,0)
        def forward(self,x):
            return self.conv(x)
    if __name__ == "__main__":
        x = torch.randn(2,4,14,14)
        net = Net()
        print(net(x))
    
  • 相关阅读:
    第七周编程总结
    第六周编程总结
    第五周编程总结
    2019 第四周作业编程总结
    第三周编程总结
    寒假作业 pta编程总结3
    跟着官网学Angular-创建响应式表单-源代码
    RxJS---转载
    NPM
    Sass
  • 原文地址:https://www.cnblogs.com/aoru45/p/12253838.html
Copyright © 2020-2023  润新知