精华内容
下载资源
问答
  • ACNet:通过非对称卷积块增强强大的CNN的内核骨架ACNet ICCV 2019论文:ACNet:通过非对称卷积块增强强大的CNN的内核骨架 其他实现:PaddlePaddle重新实现以构建ACNet和转换权重已被PaddlePaddle官方仓库接受。 @ ...
  • 非对称卷积

    2021-08-27 09:13:24
    非对称卷积的代码实现 假设有一个5x5大小的特征图,使用3x3的卷积,不进行padding(即valid),步长默认为1。 计算量: 先进行3x1卷积核的滑动,横向滑动3次,纵向滑动5次,每一次计算量为3,计算量为(3x5)x3=45。...

    非对称卷积的代码实现

    假设有一个5x5大小的特征图,使用3x3的卷积,不进行padding(即valid),步长默认为1。
    计算量:
    先进行3x1卷积核的滑动,横向滑动3次,纵向滑动5次,每一次计算量为3,计算量为(3x5)x3=45。得到的新的特征图为 [3,5] 。再进行1x3卷积,横向滑动3次,纵向滑动3次,每一次计算量为3,计算量为(3x3)x3=27。则总的计算量为45+27=72
    使用3x3的卷积核对5x5的图进行卷积得到的计算量为:横竖三次滑动,每次计算量为9,则9x9=81>72

    代码
    输入

    import torch
    a = torch.randn(1,32,5,5)  # 创建一个1x32x5x5的输入,BNWH格式
    conv3x1 = torch.nn.Conv2d(32,32,(3,1))    # 3x1卷积
    conv1x3 = torch.nn.Conv2d(32,32,(1,3))    # 1x3卷积
    
    out = conv3x1(a)
    print(out.shape)  # 进行了3x1后的output的形状
    out = conv1x3(out)
    print(out.shape)
    
    

    输出:

    torch.Size([1, 32, 3, 5])
    torch.Size([1, 32, 3, 3])
    
    Process finished with exit code 0
    
    展开全文
  • 针对这些问题,提出了一种新的深度学习方法,使用无监督的非对称卷积自编码器,对数据进行特征学习。另外,提出了一种新的基于非对称卷积自编码器和多类支持向量机相结合的方法。在 KDD99 数据集上进行了实验,实验...
  • 通过非对称卷积块增强CNN的核骨架摘要1.研究背景2. 相关工作2.1 非对称卷积2.2 CNN架构中的中性结构3. 方法3.1 公式3.2 利用卷积的可加性 下面要介绍的论文发于ICCV2019,题为「ACNet:Strengthening the Kernel ...

    在这里插入图片描述

    论文:https://arxiv.org/pdf/1908.03930v1.pdf

    代码:https://github.com/ShawnDing1994/ACN

    下面要介绍的论文发于ICCV2019,题为「ACNet:Strengthening the Kernel Skeletons for Powerful CNN via Asymmetric ConvolutionBlocks」
    在这里插入图片描述

    摘要

    由于在给定的应用环境中,设计合适的卷积神经网络(CNN)结构,需要大量人工的工作或大量的GPU资源消耗,研究界正在寻找网络结构无关的CNN结构,这种结构可以很容易地插入到多个成熟的体系结构中,以提高我们实际应用程序的性能。我们提出了非对称卷积块(ACB)作为CNN的构造块,它使用一维非对称卷积核来增强方形卷积核,我们用ACBs代替标准的方形卷积核来构造一个非对称卷积网络ACNet,该网络可以训练到更高的精度。训练后,我们等价地将ACNet转换为相同的原始架构,因此将不需要额外的计算。实验证明,ACNet可以在CIFARImageNet上显著提高各种经典模型的性能。

    1.研究背景

    卷积神经网络在视觉理解方面取得了巨大的成功,这使得其可以应用在安全系统、移动电话、汽车等各种应用中。由于前端设备通常受限于计算资源,就要求网络在保证精度的条件下要尽可能轻量。另一方面,随着CNN架构设计的相关研究增多,模型的性能得到了显著改善,但当现有的模型不能满足我们的特定需求时,要定制一种新的架构需要花费极高的成本。最近,研究者们正在寻求与架构无关的新型CNN结构,例如SE块和准六边形内核,它们可以直接和各种网络结构结合使用,以提高它们的性能。最近对CNN结构的研究主要集中在以下两个方面:

    1)层之间是如何相互连接的,例如简单的堆叠在一起、恒等映射、密集连接等;

    2)如何组合不同层的输出以提高学习表示的质量;

    本文提出了非对称卷积块(ACB),它是用三个并行的 d × d , 1 × d , d × 1 d\times d,1\times d,d\times 1 d×d,1×d,d×1核来代替原始的 d × d d\times d d×d 核,如图Figure1所示:

    在这里插入图片描述
    给定一个网络,我们通过将每个方形卷积核替换为ACB模块,并训练网络到收敛。之后我们将每个ACB中非对称核的权值加到方形核的对应位置,将ACNet转换为和原始网络等效的结构。ACNet可以提高基准模型的性能,在CIFAR和ImageNet上优势明显。更好的是,ACNet引入了0参数,因此无需仔细调参就能将其与不同的CNN结构结合起来,并且易于在主流CNN框架上实现,以及不需要额外的推理时间开销。

    2. 相关工作

    2.1 非对称卷积

    非对称卷积通常用于逼近现有的正方形卷积以进行模型压缩和加速,先前的一些工作表明,可以将标准的 d × d d \times d d×d 卷积分解为 1 × d 1 \times d 1×d d × 1 d \times 1 d×1 卷积,以减少参数量。其背后的理论相当简单:如果二维卷积核的秩为1,则运算可等价地转换为一系列一维卷积。然而,由于深度网络中下学习到的核具有分布特征值,其内在秩比实际中的高,因此直接将变换应用于核会导致显著的信息损失。Denton等人基于SVD分解找到一个低秩逼近,然后对上层进行精细化以恢复性能。Jaderberg等人通过最小化重构误差,成功学习了水平核和垂直核。Jin等人应用结构约束使二维卷积可分离,在获得相当精度的条件下时间加速了2倍。另一方面,非对称卷积也被广泛的用来做网络结构设计,例如Inception-v3中,7*7卷积被1*7卷积和7*1卷积代替。语义分割ENet网络也采用这种方法来设计高效的语义分割网络,虽然精度略有下降,但降低了33%的参数量。

    2.2 CNN架构中的中性结构

    我们不打算修改CNN架构,而是使用一些与架构无关的结构来增强现有的模型。因此,我们的方法对任何网络都是有效的。例如,SE块可以附加到卷积层后,使用学习到的权重重新缩放特征图通道数,从而在合理的附加参数量和计算代价下显著提高精度。作为另一个示例,可以将辅助分类器插入模型中以帮助监督学习过程,这确实可以提高性能,但是需要额外的人为调整超参数。相比之下,ACNet在训练中不会引入任何超参数,并且在推理过程中不需要额外的参数和计算。因此,在实际应用中,开发人员可以使用ACNet来增强各种模型,而无需进行详细的参数调整,并且最终用户可以享受性能提升而又不会减慢推理速度。

    3. 方法

    3.1 公式

    对于一个尺寸为 H × W H \times W H×W 通道数为D的卷积核,以通道数为C的特征图作为输入,我们使用 F ∈ R H × W × C F \in R^{H\times W\times C} FRH×W×C 表示卷积核, M ∈ R U × V × C M \in R^{U\times V\times C} MRU×V×C 表示输入,这是一个尺寸为UxV通道数为C的特征图, O ∈ R R × T × D O\in R^{R\times T\times D} ORR×T×D代表输出特征图。对于这个层的第j个卷积核,相应的输出特征映射通道是:

    在这里插入图片描述
    其中*是二维卷积算子。 M : , : , k M_{:,:,k} M:,:,k是M的第k个通道的尺寸为UxV的特征图, F : , : , k ( i ) F_{:,:,k}^{(i)} F:,:,k(i) 代表 F ( j ) F^{(j)} F(j) 的第k个通道的尺寸为HxW的特征图。在现代CNN体系结构中,批量归一化(BN)被广泛使用,以减少过度拟合,加快训练过程。通常情况下,批量归一化层之后通常会接一个线性变化,以增强表示能力。和公式1相比,输入变成:

    在这里插入图片描述
    其中, μ j \mu_j μj σ j \sigma_j σj是批标准化的通道平均值和标准差, γ j \gamma_j γj β j \beta_j βj是缩放系数和偏移量。

    3.2 利用卷积的可加性

    我们试图以不对称卷积可以等效地融合到标准方形核层中的方式来使用,这样就不会引入额外的推理时间计算负担。我们注意到卷积的一个有用性质:如果几个大小兼容的二维核在相同的输入上以相同的步幅操作以产生相同分辨率的输出,并且它们的输出被求和,我们可以将这些核在相应的位置相加,从而得到一个产生相同输出的等效核。也就是说,二维卷积的可加性可以成立,即使核大小不同。

    在这里插入图片描述
    其中 I I I 是一个矩阵, K ( 1 ) K^{(1)} K(1) K ( 2 ) K^{(2)} K(2) 是具有兼容尺寸的两个2D核,
    在这里插入图片描述
    是在对应位置的求和操作。注意 I I I 可能会被裁剪或者执行Padding操作。这里,“兼容”意味着我们可以把较小的内核“修补”到较大的内核上。在形式下,p层和q的下面这种转换是可行的:

    在这里插入图片描述
    例如,3x1和1x3是和3x3兼容的。通过研究滑动窗口形式的卷积计算,可以很容易地验证这一点,如图Figure2所示:

    在这里插入图片描述
    对于一个特定的卷积核 F ( j ) F^{(j)} F(j),一个指定的点y,则输出 O : , : , j O_{:,:,j} O:,:,j 可以使用下式计算:

    在这里插入图片描述
    其中,X是输入M上相应的滑动窗口。显然,当我们将两个滤波器产生的输出通道相加时,如果一个通道上的每个y,其在另一个通道上的对应点共享相同的滑动窗口,则其相加性质(等式3)成立。

    3.3 ACB不增加任何推理时间开销

    在本文中,我们关注3x3卷积,这在现代CNN体系结构中大量使用。在给定的体系结构下,我们通过简单地将每个3x3卷积层替换为ACB来构建ACNet,该ACB模块包含三个并行层,内核大小分别为3x31x3,和3x1。和标准CNN的常规做法类似,在三层中的每一层之后都进行批量归一化,这被成为分子,并将三个分支的输出综合作为ACB的输出。请注意,我们可以使用与原始模型相同的配置来训练ACNet,而无需调整任何额外的超参数。如4.1和4.2节中所示,我们可以训练ACNet达到更高的精度。训练完成后,我们尝试将每个ACB转换为产生相同输出的标准卷积层这样,与经过常规训练的对等方相比,我们可以获得不需要任何额外计算的功能更强大的网络。该转换通过两个步骤完成,即BN融合和分支融合。

    BN融合 卷积的同质性使得后续的BN和线性变换可以等价的融合到具有附加偏置的卷积层中。从公式2可以看出,对于每个分支,如果我们构造一个新的内核 γ j σ j F ( j ) {{\gamma_j}\over{\sigma_j}}F^{(j)} σjγjF(j)

    然后加上偏置 − μ j γ j σ j + β j -{{\mu_j\gamma_j}\over{\sigma_j}}+\beta_j σjμjγj+βj ,我们可以产生相同的输出。

    分支融合 我们通过在平方核的相应位置加入非对称核,将三个BN融合分支合并成标准卷积层。在实际应用中,这种转换是通过建立一个原始结构的网络并使用融合的权值进行初始化来实现的,这样我们就可以在与原始结构相同的计算预算下产生与ACNet相同的输出。更正式地,对于第j个卷积核, F ′ ( j ) F^{'(j)} F(j) 表示融合后的卷积核, b j b_j bj 代表偏置, F ˉ ( j ) \bar F^{(j)} Fˉ(j) F ^ ( j ) \hat F^{(j)} F^(j) 分别代表1x3和3x1卷积核的输出,融合后的结果可以表示为:

    在这里插入图片描述
    然后我们可以很容易地验证对于任意滤波器j,
    在这里插入图片描述
    其中, O : , : , j , O ˉ : , : , j , O ^ : , : , j O_{:,:,j},\bar O_{:,:,j},\hat O_{:,:,j} O:,:,j,Oˉ:,:,j,O^:,:,j 代表原始 3 × 3 , 1 × 3 , 3 × 1 3\times 3,1\times 3,3\times 1 3×3,1×3,3×1 三个分支的输出。Figure3展示了这个过程。

    在这里插入图片描述
    值得注意的是,尽管可以将ACB等价地转换为标准层,但是等效值仅在推理时才成立,因为训练动态是不同的,从而导致不同的性能。训练过程的不等价性是由于内核权重的随机初始化,以及由它们参与的不同计算流得出的梯度。

    4. 实验

    我们进行了大量的实验来验证ACNet在一系列数据集和架构上提高CNN性能的有效性。具体地说,我们选择一个现成的体系结构作为基线,构建一个ACNet的对等物,从头开始培训它,将它转换为与基线相同的结构,并测试它以收集准确性。对于可比性,所有的模型都经过训练直到完全收敛,并且每一对基线和ACNet使用相同的配置,例如,学习速率计划和批大小。

    4.1节和4.2节,论文在CIFAR10和CIFAR100数据集,ImageNet数据集进行对比测试,结果如Table1,Table2,Table3所示。

    4.3 节还展示了消融研究,也就是对AlexNet和ResNet在ImageNet图像上进行测试,采用控制变量法控制ACB的三个关键影响因素,同时对比了将图片旋转的测试效果,最终使用了ACB模块全部技巧的网络模型获得了几乎所有测试情况的新SOTA结果,证明了ACB模块能够增加对数据旋转的适应能力。

    4.4 节用以说明ACB增强了方形卷积核的骨架信息。论文在训练过程中通过随机丢弃网络中3*3卷积核的骨架权重和边角权重,所谓骨架权重和边角权重的定义如Figure 4所示,骨架权重就是和中间位置直接相连的4个位置加上自身,剩下的就是边角部分了。

    4.1 在CIFAR上的性能改进

    为了对我们的方法在各种CNN架构上进行初步的评价,我们在CIFAR-10和CIFAR-100上对几个有代表性的基准模型Cifar-quick、VGG16、ResNet-56、WRN-16-8和DenseNet-40进行了实验。

    对于Cifar-quick、VGG-16、ResNet-56和DenseNet-40,我们按照惯例使用0.1、0.01、0.001和0.0001的阶梯学习率训练模型。对于WRN-16-8,我们遵循原始论文[35]中报告的训练配置。我们使用了所采用的数据增强技术,即填充到40 40,随机裁剪和左右翻转。

    从表1和表2中可以看出,所有模型的性能都有明显的提升,这表明ACBs的好处可以与各种架构相结合。
    在这里插入图片描述

    4.2 在ImageNet上的性能改进

    然后,通过在ImageNet上的一系列实验,我们继续在真实世界的应用程序上验证我们的方法的有效性,这些实验包括来自1000个类的128万张用于训练的图像和50K用于验证的图像。我们分别用AlexNet、ResNet-18和DenseNet-121作为plain-style、residual和dense - connected架构的代表。每个模型以256个批处理规模进行150个epoch的训练,这比通常采用的基准(如90 epoch)要长,因此精度的提高不能简单归结为基础模型的不完全收敛。对于数据的增强,我们采用标准的管道,包括包围框扭曲,左右翻转和颜色移动,作为一个常见的实践。特别是我们使用的AlexNet的普通版本来自Tensorflow GitHub,它由五个堆叠的卷积层和三个完全连接的层组成,没有本地响应归一化(LRN),也没有跨gpu连接。值得注意的是,由于AlexNet的前两层分别使用了11 × 11和5 × 5核,因此可以扩展ACBs使其具有更大的非对称核。但是对于这两层我们仍然只使用1× 3和3 × 1的卷积,因为这样大规模的卷积在现代CNN中越来越不受欢迎,使得大型的ACBs不那么有用。

    如表3所示,单作物Top-1精度AlexNet、ResNet-18和DenseNet-121提升1.52%,分别为0.78%和1.18%。在实践中,针对相同的精度目标,我们可以使用ACNet来增强一个更高效的模型,以更少的推理时间、能量消耗和存储空间来实现目标。另一方面,在计算预算或模型大小相同的限制下,我们可以使用ACNet以明显的优势提高精度,从而从终端用户的角度来看,所获得的性能可以被视为免费的利益。
    在这里插入图片描述

    4.3 消融研究

    虽然我们有经验证明ACNet的有效性,但我们仍然希望找到一些解释。在本节中,我们试图通过一系列消融研究来研究ACNet。具体来说,我们关注以下三个设计决策:1)水平核,2)垂直核,3)每个分支中的批处理规范化。为了具有可比性,我们使用相同的训练配置,在ImageNet上用不同的消融来训练几个AlexNet和ResNet-18模型。值得注意的是,如果去掉分支中的批归一化,我们将对整个ACB的输出进行批归一化,即批归一化层的位置由预求和变为后求和。

    在这里插入图片描述
    从表4可以看出,去掉这三种设计中的任何一种都会降低模型的质量。然而,尽管水平和垂直的卷积都可以提高性能,由于在实践中水平方向和垂直方向的处理不平等,可能会存在一些差异,例如:我们通常执行随机的左右翻转,而不是上下翻转图像来增强训练数据。因此,如果在模型中输入一幅倒置的图像,原始的3 × 3层应该产生无意义的结果,这是自然的,但是水平核将在轴对称位置产生与原始图像相同的输出(图4),部分ACB仍能提取出正确的特征。考虑到这一点,我们假设ACBs可以增强模型对旋转畸变的鲁棒性,使模型能够更好地泛化未见数据。

    在这里插入图片描述
    然后,我们用整个验证集的旋转扭曲图像测试之前训练的模型,包括逆时针90◦旋转,180◦旋转,和上下翻转。当然,每个模型的精度都显著降低,但水平核模型在180度旋转和上下翻转图像上提供了明显更高的精度。例如,ResNet-18在水平方向上的精度略低于在垂直方向上的精度,但在180度方向上的精度要高0.75%。与基础模型相比,其在原/ 180度翻转图像上的精度分别提高了0.34% / 1.27%。可以预见,模型发挥类似的性能在180度旋转和上下翻转输入,因为180度旋转+左右翻转等价于上下翻转,由于数据增强方法,模型对左右翻转具有鲁棒性。

    总之,我们已经证明,acb,特别是内部的水平核,可以增强模型的鲁棒性,以可观的边际旋转畸变。虽然这可能不是ACNet有效的主要原因,但我们认为它有希望激发对转动不变性问题的进一步研究。

    4.4 ACB增强方形核的骨架

    直观地看,当向平方内核添加水平和垂直内核时,可以将其视为显式增强骨架部分的方法,我们试图通过研究骨骼和角落重量之间的差异来解释ACNet的有效性。

    受CNN剪枝的启发,我们首先在不同的空间位置删除一些权值,然后在CIFAR-10上使用ResNet56观察性能下降。具体地,我们在核中随机设置一些单独的权值为零,并对模型进行检验。如图5a所示,标注为转角的曲线,我们从每个角的四个角中随机选择权重
    为获得给定的每个卷积层的全局稀疏度比,将它们设为0。注意,4/9 = 44.4%,44%的稀疏比意味着去掉四个角的大部分权值。对于骨架,我们只从每个核的骨架中随机选择权值。对于全局,内核中的每个权重都有平等的被选择的机会。实验采用不同的随机种子重复5次,并绘制了mean±std曲线。

    在这里插入图片描述
    然后,画出不同丢弃比例下的测试集准确率图,如Figure5所示:

    在这里插入图片描述
    通过对比图Figure5(a)和Figure5(b)发现,丢弃骨架部分的权重会降低准确率,而丢弃边角部分的权重却能获得更好的精度。然后,我们通过研究卷积核的数值来研究上叙述现象发生的原因。我们使用幅度(即绝对值)作为衡量参数重要性的指标,许多先前的CNN加速工作都采用了该指标。具体来说,我们将一个卷积层中所有融合的2D卷积核都加起来,通过最大值进行逐层归一化,最后获得所有层的归一化核的平均值。更正式地,我们让 F ( i , j ) F^{(i,j)} F(i,j) 表示第i个3x3卷积层的第j个核,L代表3x3卷积层的个数,maxabs代表逐像素的求最大值和取绝对值操作,所以平均核矩阵可以计算为:

    在这里插入图片描述
    其中,
    在这里插入图片描述
    我们在Figure 4(a)和Figure 4(b)上给出了经过正常训练的ResNet56和融合了ACNet的A值。某个网格的数值和颜色表示该参数在所有位置上平均重要性。从Figure5(a)看出正常训练的ResNet56参数分布是不平衡的,即中心点的A值最大,而四个角点的A值最小。Figure5(b)显示ACNet加剧了这种不平衡,因为四个角点的A值减小到了0.4以下,并且骨架中心点的A值为1.0,这意味着该位置在每个3*3层中始终占据主导地位。值得注意的是,方向,水平,垂直核的相应位置上的权重可能会在符号上相反,因此它们将它们相加可能会产生更大或者更小的幅度。但我们观察到一个一致的现象,即模型学会了在每一层增强骨骼部位的权重。我们继续研究如果将非对称核加到其他位置而不是中心骨架时模型的行为。具体来说,我们使用和以前相同的训练配置来训练Resnet56的ACNet对应网络,但是将水平卷积核向下平移一个像素,垂直卷积核向右平移一个像素。因此,在分支融合时,我们得到Figure 4©的结果。我们观察到, 这样的ACB网络还可以增强边界,但是强度不如常规ACB对骨骼的增强。该模型的准确度为94.67%,比常规的ACNet低0.42%(Table1)。此外我们对模型融合进行了类似的消融实验,可以看到丢弃边角部分的参数仍然获得了最高的精度,丢弃增强的右下角边界不会比丢弃左上角2*2方形的权重得到更好的结果。

    总结一下

    1)3*3卷积核的骨架部分比边角部分更加重要;
    2)ACB可以增强卷积核的骨架部分,从而提高性能;
    3)和常规的ACB相比,将水平和垂直核添加到边界会降低模型的性能;
    4)这样做也可以增加边界的重要性,但是不能削弱其它部分的重要性。

    因此,我们将ACNet的有效性部分归因于它进一步增强卷积核骨架的能力。

    5. 结论

    为了提高各种CNN架构的性能,我们提出了非对称卷积块(ACB),该算法将三个分别具有正方形,水平和垂直核的卷积分支的输出求和。我们通过使用ACB替换成熟体系结构中的方形核卷积层来构建非对称卷积网络(ACNet),并在训练后将其转换为原始网络结构。在CIFAR和ImageNet数据集上,通过在经典网络上使用ACNet评估我们的性能,取得了SOTA结果。我们已经表明,ACNet可以以可观察的幅度增强模型对旋转失真的鲁棒性,并显著增强方形卷积核的骨骼部分。并且ACNet也易于使用主流框架实现,方便研究者follow这项工作。

    ACBlock

    import torch.nn as nn
    import torch.nn.init as init
    from custom_layers.crop_layer import CropLayer
    
    
    class ACBlock(nn.Module):
    
        def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1,
                     padding_mode='zeros', deploy=False,
                     use_affine=True, reduce_gamma=False, use_last_bn=False, gamma_init=None):
            super(ACBlock, self).__init__()
            self.deploy = deploy
            if deploy:
                self.fused_conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
                                            kernel_size=(kernel_size, kernel_size), stride=stride,
                                            padding=padding, dilation=dilation, groups=groups, bias=True,
                                            padding_mode=padding_mode)
            else:
                self.square_conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
                                             kernel_size=(kernel_size, kernel_size), stride=stride,
                                             padding=padding, dilation=dilation, groups=groups, bias=False,
                                             padding_mode=padding_mode)
                self.square_bn = nn.BatchNorm2d(num_features=out_channels, affine=use_affine)
    
                center_offset_from_origin_border = padding - kernel_size // 2
                ver_pad_or_crop = (padding, center_offset_from_origin_border)
                hor_pad_or_crop = (center_offset_from_origin_border, padding)
                if center_offset_from_origin_border >= 0:
                    self.ver_conv_crop_layer = nn.Identity()
                    ver_conv_padding = ver_pad_or_crop
                    self.hor_conv_crop_layer = nn.Identity()
                    hor_conv_padding = hor_pad_or_crop
                else:
                    self.ver_conv_crop_layer = CropLayer(crop_set=ver_pad_or_crop)
                    ver_conv_padding = (0, 0)
                    self.hor_conv_crop_layer = CropLayer(crop_set=hor_pad_or_crop)
                    hor_conv_padding = (0, 0)
                self.ver_conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=(kernel_size, 1),
                                          stride=stride,
                                          padding=ver_conv_padding, dilation=dilation, groups=groups, bias=False,
                                          padding_mode=padding_mode)
    
                self.hor_conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=(1, kernel_size),
                                          stride=stride,
                                          padding=hor_conv_padding, dilation=dilation, groups=groups, bias=False,
                                          padding_mode=padding_mode)
                self.ver_bn = nn.BatchNorm2d(num_features=out_channels, affine=use_affine)
                self.hor_bn = nn.BatchNorm2d(num_features=out_channels, affine=use_affine)
    
                if reduce_gamma:
                    assert not use_last_bn
                    self.init_gamma(1.0 / 3)
    
                if use_last_bn:
                    assert not reduce_gamma
                    self.last_bn = nn.BatchNorm2d(num_features=out_channels, affine=True)
    
                if gamma_init is not None:
                    assert not reduce_gamma
                    self.init_gamma(gamma_init)
    
        def init_gamma(self, gamma_value):
            init.constant_(self.square_bn.weight, gamma_value)
            init.constant_(self.ver_bn.weight, gamma_value)
            init.constant_(self.hor_bn.weight, gamma_value)
    
        def single_init(self):
            init.constant_(self.square_bn.weight, 1.0)
            init.constant_(self.ver_bn.weight, 0.0)
            init.constant_(self.hor_bn.weight, 0.0)
    
        def forward(self, input):
            if self.deploy:
                return self.fused_conv(input)
            else:
                square_outputs = self.square_conv(input)
                square_outputs = self.square_bn(square_outputs)
                vertical_outputs = self.ver_conv_crop_layer(input)
                vertical_outputs = self.ver_conv(vertical_outputs)
                vertical_outputs = self.ver_bn(vertical_outputs)
                horizontal_outputs = self.hor_conv_crop_layer(input)
                horizontal_outputs = self.hor_conv(horizontal_outputs)
                horizontal_outputs = self.hor_bn(horizontal_outputs)
                result = square_outputs + vertical_outputs + horizontal_outputs
                if hasattr(self, 'last_bn'):
                    return self.last_bn(result)
                return result
    
                
    class CropLayer(nn.Module):
    
        #   E.g., (-1, 0) means this layer should crop the first and last rows of the feature map. And (0, -1) crops the first and last columns
        def __init__(self, crop_set):
            super(CropLayer, self).__init__()
            self.rows_to_crop = - crop_set[0]
            self.cols_to_crop = - crop_set[1]
            assert self.rows_to_crop >= 0
            assert self.cols_to_crop >= 0
    
        def forward(self, input):
            if self.rows_to_crop == 0 and self.cols_to_crop == 0:
                return input
            elif self.rows_to_crop > 0 and self.cols_to_crop == 0:
                return input[:, :, self.rows_to_crop:-self.rows_to_crop, :]
            elif self.rows_to_crop == 0 and self.cols_to_crop > 0:
                return input[:, :, :, self.cols_to_crop:-self.cols_to_crop]
            else:
                return input[:, :, self.rows_to_crop:-self.rows_to_crop, self.cols_to_crop:-self.cols_to_crop]
    

    Demo

    在这里插入图片描述

    这个Demo非常简单,在一张256*256的灰度图像上,分别做卷积核为(3,3)的运算,以及先进行卷积核为(1,3)的运算、然后进行卷积核为(3,1)的运算,比较二者的差异。

    • 项目结构
      在这里插入图片描述
    • 主要代码
    import cv2
    import torch.nn as nn
    from torch.utils.data import DataLoader
    from torchvision import datasets, transforms
    
    
    def image_show(title, image):
        cv2.imshow(title, image)
        cv2.waitKey(0)
    
    
    transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Resize(256),
        transforms.Grayscale()
    ])
    
    images_dataset = datasets.ImageFolder(root='./data/', transform=transform)
    images_loader = DataLoader(dataset=images_dataset, batch_size=1, shuffle=False, num_workers=0)
    
    print(len(images_dataset))  # 3
    print(images_dataset.class_to_idx)  # {'images': 0}
    
    
    class Model3x3(nn.Module):
        def __init__(self):
            super(Model3x3, self).__init__()
            self.conv3x3 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(3, 3))
    
        def forward(self, x):
            x = self.conv3x3(x)
            return x
    
    
    class Model3x1and1x3(nn.Module):
        def __init__(self):
            super(Model3x1and1x3, self).__init__()
            self.conv3x1 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(1, 3))
            self.conv1x3 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(3, 1))
    
        def forward(self, x):
            x = self.conv3x1(x)
            x = self.conv1x3(x)
            return x
    
    
    model3x3 = Model3x3()
    model3x1and1x3 = Model3x1and1x3()
    
    for data in images_loader:
        images, labels = data
        print(images.shape)  # torch.Size([1, 1, 256, 256])
    
        outputs3x3 = model3x3(images)
        print(outputs3x3.shape)  # torch.Size([1, 1, 254, 254])
        outputs3x3 = outputs3x3.detach().numpy()
        print(outputs3x3.shape)  # (1, 1, 254, 254)
        output3x3 = outputs3x3[0]
        print(output3x3.shape)  # (1, 254, 254)
        image_show('output3x3.jpg', output3x3[0])
    
        outputs3x1and1x3 = model3x1and1x3(images)
        print(outputs3x1and1x3.shape)  # torch.Size([1, 1, 254, 254])
        outputs3x1and1x3 = outputs3x1and1x3.detach().numpy()
        print(outputs3x1and1x3.shape)  # (1, 1, 254, 254)
        output3x1and1x3 = outputs3x3[0]
        print(output3x1and1x3.shape)  # (1, 254, 254)
        image_show('output3x1and1x3.jpg', output3x1and1x3[0])
    
        diff = outputs3x3[0] - outputs3x1and1x3[0]
        print(diff)
    
    
    • 实验结果
      在这里插入图片描述
      在这里插入图片描述
    展开全文
  • 在实际应用中,我们可能会遇到使用非对称卷积的情况,如谷歌的inceptionv3v4中就有使用1x7,7x1的卷积,这和我们平时使用的3x3卷积不同,是不对称的。 计算量 相比直接进行卷积,非对称卷积能够减少计算量。原来是 n...

    前言

    在实际应用中,我们可能会遇到使用非对称卷积的情况,如谷歌的inceptionv3v4中就有使用1x7,7x1的卷积,这和我们平时使用的3x3卷积不同,是不对称的。

    计算量

    相比直接进行卷积,非对称卷积能够减少计算量。原来是 n×n 次乘法,改了以后,变成了 2×n 次乘法了,n越大,运算量减少的越多。
    假设有一个5x5大小的特征图,使用3x3的卷积,不进行padding(即valid),步长默认为1。
    计算量
    先进行3x1卷积核的滑动,横向滑动3次,纵向滑动5次,每一次计算量为3,计算量为(3x5)x3=45。得到的新的特征图为 [3,5] 。再进行1x3卷积,横向滑动3次,纵向滑动3次,每一次计算量为3,计算量为(3x3)x3=27。则总的计算量为45+27=72
    使用3x3的卷积核对5x5的图进行卷积得到的计算量为:横竖三次滑动,每次计算量为9,则9x9=81>72

    代码

    import torch
    a = torch.randn(1,32,5,5)  # 创建一个1x32x5x5的输入,BNWH格式
    conv3x1 = torch.nn.Conv2d(32,32,(3,1))    # 3x1卷积
    conv1x3 = torch.nn.Conv2d(32,32,(1,3))    # 1x3卷积
    
    out = conv3x1(a)
    print(out.shape)  # 进行了3x1后的output的形状
    out = conv1x3(out)
    print(out.shape)
    

    得到:

    torch.Size([1, 32, 3, 5])
    torch.Size([1, 32, 3, 3])
    
    展开全文
  • 本文将ACNet中的非对称卷积思想与LESRCNN进行组合,取得了更好的性能。由于作者尚未开源,故笔者进行了简单的复现,复现还是挺容易的,哈哈。 Abstract 本文提出了一种对称CNN网络ACNet,它由.

    编辑:Happy
    首发:AIWalker

    标题&作者团队

    Paper:https://arxiv.org/abs/2103.13634

    Code:https://github.com/hellloxiaotian/ACNet

    本文是哈工大左旺孟老师团队在图像超分方面的最新工作,已被IEEE TSMC收录。本文将ACNet中的非对称卷积思想与LESRCNN进行组合,取得了更好的性能。由于作者尚未开源,故笔者进行了简单的复现,复现还是挺容易的,哈哈。

    Abstract

    本文提出了一种非对称CNN网络ACNet,它由非对称模块(AB)、记忆力增强模块(MEB)、高频特征增强模块(HFFEB)构成。其中非对称模块采用两个一维卷积从水平和垂直方向对方框卷积进行增强,提升局部显著特征的影响性因子;MEB则通过残差链接方式对AB提取的低频特征进行融合,将低频特征变换到高频特征;HFFEB则融合低频与高频特征得到更鲁棒性的超分特征。实验结果表明:本文所提ACNet可以有效解决SISR、盲SISR以及噪声不可知盲SISR等问题。

    本文主要贡献包含以下几点:

    • 提出一种多级特征融合机制,通过对低频特征和高频特征融合,它可以很好的解决长期依赖问题,避免了上采样机制导致性能退化问题。
    • 提出一种非对称架构增强局部关键点的影响性以得到了鲁邦的低频特征;
    • 提出一种灵活的上采样机制,它可以使得所提方案解决SISR等问题。

    Method

    framework

    上图给出了本文所提非对称卷积网络ACNet结构示意图,它由三个模块构成:深度为17的AB模块、深度为1的MEB以及深度为5的HFFEB。

    • AB部分与2019年丁霄汉博士提出的ACNet中的ACB模块基本一致:训练时三个分支:一个分支为 1 × 3 1\times 3 1×3卷积,一个分支为 3 × 1 3\times 1 3×1,一个分支为 3 × 3 3\times 3 3×3卷积;推理时三个分支可以合并为单一卷积。

    • MEB则是对所有AB提取的特征通过残差学习方式进行融合,并将所提取的低频特征转换为高频特征。注:该模块同时还进行了特征上采样。其中sub-conv部分的结构示意图如下所示。这里与EDSR中的上采样基本一样,略过咯。 sub-conv

    • HFFEB则对源自LR的低频特征以及上述融合高频特征进行融合处理得到更精确的超分特征。这个地方是本文所提方法与之前常见网络不同之处:在更高分辨率采用更多卷积进行增强以提升重建性能。

    • 损失函数方面,本文选择了MSE损失.

    本文所设计的网络实在过于简单,好像并没有什么需要深入介绍,看图就够了,或者看文末的参考实现亦可。

    Experiments

    在训练方面,作者采用两步法:(1) DIV2K的训练集+验证集同时参与训练;(2) DIV2K的训练集上进行微调。

    直接上结果,下面两个图给出了Set5、Set14、B100、U100等数据的性能对比。

    Set5&Set14

    image-20210404163912956

    从上面四个表可以看到:在三个尺度上,本文所提ACNet均取得了还不错的性能。

    图片2

    上表给出了不同噪声强度下的图像超分性能对比。在计算复杂度、推理耗时、性能以及视觉效果方面,所提方法ACNet取得了比较好的均衡。

    题外语

    lesrcnn

    这篇论文整体看上去非常简洁,思想也比较简单。在网络结构方面,它与LESRCNN的结构上基本是一致的;而LESRNN与EDSR也是非常的相似。区别有这么三点:

    • 重建部分:EDSR在上采样最终的分辨率后直接采用一个卷积进行重建;而LESRCNN在上采样到最终分辨率后采用了5层卷积进行处理。LESRCNN的这种处理方法无疑会造成比较大的计算量。
    • 残差模块部分:EDSR中的残差模块采用Conv-ReLU-Conv方式;而LESRCNN则采用ReLU-Conv-ReLU-Conv方式。
    • 低频特征与高频特征融合部分:EDSR中用于融合的特征并未经ReLU处理,先add再上采样;而LESRCNN则用ReLU进行了处理,然而分别用sub-conv上采样后再融合。

    再回过来头看LESRCNN与ACNet,则基本属于将2019年提出的ACNet在LESCNN中的直接应用;事实上,ACNet与IMDN的组合的可行性在2020年的超分竞赛中已得到了印证。所以,这篇文章的创新之处着实不多。

    另外,需要吐槽的一点:这里对比的都是一些比较早期的方法,像最近两年的IMDN、RFANet、RFDN、PAN等优秀的轻量型模型均未进行对比。

    不过这篇论文有一点值得称赞:复现难度非常低。笔者粗看了下结构花了很少时间就完成了code的实现,并仅仅基于DIV2K训练数据训练了66W步。在BI退化方面,笔者训练的模型性能要比作者文中列出来的指标高0.04-0.1dB不等。ACNet的参考实现code如下所示。

    class MeanShift(nn.Conv2d):
        def __init__(self,
                     rgb_range=1.0,
                     rgb_mean=(0.4488, 0.4371, 0.4040),
                     rgb_std=(1.0, 1.0, 1.0),
                     sign=-1):
            super(MeanShift, self).__init__(3, 3, kernel_size=1)
            std = torch.Tensor(rgb_std)
            self.weight.data = torch.eye(3).view(3, 3, 1, 1) / std.view(3, 1, 1, 1)
            self.bias.data = sign * rgb_range * torch.Tensor(rgb_mean) / std
            self.requires_grad = False
    
            
    class Upsampler(nn.Sequential):
        def __init__(self,
                     scale,
                     channels,
                     bn=False,
                     act=False,
                     bias=True):
            m = []
            if (scale & (scale - 1)) == 0:
                for _ in range(int(math.log(scale, 2))):
                    m.append(nn.Conv2d(channels, 4 * channels, 3, 1, 1, bias=bias))
                    m.append(nn.PixelShuffle(2))
                    if bn:
                        m.append(nn.BatchNorm2d(channels))
                    if act:
                        m.append(nn.ReLU(inplace=True))
            elif scale == 3:
                m.append(nn.Conv2d(channels, 9 * channels, 3, 1, 1, bias=bias))
                m.append(nn.PixelShuffle(3))
                if bn:
                    m.append(nn.BatchNorm2d(channels))
    
                if act:
                    m.append(nn.ReLU(inplace=True))
            else:
                raise NotImplementedError
            super().__init__(*m)
            
            
    class ACBlock(nn.Module):
        def __init__(self, in_channels, out_channels):
            super(ACBlock, self).__init__()
            self.conv1x3 = nn.Conv2d(in_channels, out_channels, (1, 3), 1, (0, 1))
            self.conv3x1 = nn.Conv2d(in_channels, out_channels, (3, 1), 1, (1, 0))
            self.conv3x3 = nn.Conv2d(in_channels, out_channels, (3, 3), 1, (1, 1))
    
        def forward(self, x):
            conv3x1 = self.conv3x1(x)
            conv1x3 = self.conv1x3(x)
            conv3x3 = self.conv3x3(x)
            return conv3x1 + conv1x3 + conv3x3
          
          
    class ACNet(nn.Module):
        def __init__(self,
                     scale=2,
                     in_channels=3,
                     out_channels=3,
                     num_features=64,
                     num_blocks=17,
                     rgb_range=1.0):
            super(ACNet, self).__init__()
            self.scale = scale
            self.num_blocks = num_blocks
            self.num_features = num_features
    
            # pre and post process
            self.sub_mean = MeanShift(rgb_range=rgb_range, sign=-1)
            self.add_mena = MeanShift(rgb_range=rgb_range, sign=1)
    
            # AB module
            self.blk1 = ACBlock(in_channels, num_features)
            for idx in range(1, num_blocks):
                self.__setattr__(f"blk{idx+1}", nn.Sequential(nn.ReLU(inplace=True), ACBlock(num_features, num_features)))
    
            # MEB
            self.lff = nn.Sequential(
                nn.ReLU(inplace=False),
                Upsampler(scale, num_features),
                nn.Conv2d(num_features, num_features, 3, 1, 1),
                nn.ReLU(inplace=True),
                nn.Conv2d(num_features, num_features, 3, 1, 1)
            )
            self.hff = nn.Sequential(
                nn.ReLU(inplace=False),
                Upsampler(scale, num_features),
                nn.Conv2d(num_features, num_features, 3, 1, 1),
                nn.ReLU(inplace=True),
                nn.Conv2d(num_features, num_features, 3, 1, 1)
            )
    
            # HFFEB
            self.fusion = nn.Sequential(
                nn.ReLU(inplace=False),
                nn.Conv2d(num_features, num_features, 3, 1, 1),
                nn.ReLU(inplace=True),
                nn.Conv2d(num_features, num_features, 3, 1, 1),
                nn.ReLU(inplace=True),
                nn.Conv2d(num_features, out_channels, 3, 1, 1),
            )
    
        def forward(self, x):
            inputs = self.sub_mean(x)
            blk1 = self.blk1(inputs)
    
            high = blk1
            tmp = blk1
            for idx in range(1, self.num_blocks):
                tmp = self.__getattr__(f"blk{idx+1}")(tmp)
                high = high + tmp
    
            lff = self.lff(blk1)
            hff = self.hff(high)
    
            fusion = self.fusion(lff + hff)
            output = self.add_mena(fusion)
            return output   
    

    推荐阅读

    1. 你的感知损失可能用错了,沈春华团队提出随机权值广义感知损失
    2. CVPR2021|超分性能不变,计算量降低50%,董超等人提出用于low-level加速的ClassSR
    3. SANet|融合空域与通道注意力,南京大学提出置换注意力机制
    4. GhostSR|针对图像超分的特征冗余,华为诺亚&北大联合提出GhostSR
    5. 图像超分中的那些知识蒸馏
    6. ICLR2021 | 显著提升小模型性能,亚利桑那州立大学&微软联合提出SEED
    7. RepVGG|让你的ConVNet一卷到底,plain网络首次超过80%top1精度
    8. Transformer再下一城!low-level多个任务榜首被占领
    9. 通道注意力新突破!从频域角度出发,浙大提出FcaNet
    10. 无需额外数据、Tricks、架构调整,CMU开源首个将ResNet50精度提升至80%+新方法
    11. 46FPS+1080Px2超分+手机NPU,arm提出一种基于重参数化思想的超高效图像超分方案
    12. 动态卷积超进化!通道融合替换注意力,减少75%参数量且性能显著提升 ICLR 2021
    13. CVPR2021|“无痛涨点”的ACNet再进化,清华大学&旷视科技提出Inception类型的DBB
    展开全文
  • 非对称卷积—Asymmetric Convolutions

    千次阅读 2018-04-13 00:00:00
    2、非对称卷积能够降低运算量,这个很好理解吧,原来是 n×n 次乘法,改了以后,变成了 2×n 次乘法了,n越大,运算量减少的越多,原文如下: the computational cost saving increases dramatically as n grows. 3...
  • 点击下方卡片,关注“CVer”公众号AI/CV重磅干货,第一时间送达由哈尔滨工业大学、鹏城实验室、国立清华大学及香港中文大学的学者提出了一种用于盲噪声的盲超分辨的非对称卷积神经网络,该论文...
  • 之前在深度学习面试题16:小卷积核级联卷积VS大卷积核卷积中介绍过小卷积核的三个优势: ①整合了三个线性激活层,代替单一线性激活层,增加了判别能力。 ②减少了网络参数。 ③减少了计算量 在《Rethinking...
  • AB利用两个一维非对称卷积强化水平和垂直方向上的平方卷积核,以提高局部显著特征的影响因子 MEB通过残差学习(RL)技术融合AB中所有的分层低频特征,将得到的低频特征转化为高频特征。解决了长期依赖性问题,避免了...
  • 矩形卷积和非对称卷积核,卷积后的特征图尺寸计算其实原理是一样的。 矩形卷积 如果输入图像是正方形,尺寸为WxW,卷积核尺寸为FxF,步幅为S,Padding使用P,经过该卷积层后输出的特征图尺寸为NxN: 如果输入...
  •   2)非对称卷积能够降低运算量,这个很好理解吧,原来是 n×n 次乘法,改了以后,变成了 2×n 次乘法了,n越大,运算量减少的越多。   3)虽然可以降低运算量,但这种方法不是哪儿都适用的,非对称卷积在图片...
  • 哈工大、台湾国立清华大学与香港中文大学的研究人员联合提出用于盲图像超分辨的非对称卷积网络,该文收录于IEEE Transactions on Systems, Man, and Cyber...
  • 行业分类-物理装置-基于非对称卷积的具有粒度级多尺度特性的车辆检测方法.zip
  • 非对称卷积增强CNN特征拟合

    千次阅读 2020-02-02 17:56:37
    来源:非对称卷积增强CNN特征拟合 原创作者来自清华大学和国家信息技术研究中心~论文链接:https://arxiv.org/pdf/1905.10089.pdf代码链接:https://github.com/anheidelonghu/ACNet提出原因1、在指定的应用环境中...
  • 行业分类-物理装置-基于YOLOV3和非对称卷积的小尺寸交通标志识别方法.zip
  • 基于圆柱体坐标系和非对称卷积的点云分割算法 Cylindrical and Asymmetrical 3D Convolution Network for LiDAR Segmentation——祝新革 文章目录基于圆柱体坐标系和非对称卷积的点云分割算法前言一、点云分割的...
  • PyTorch卷积模块

    2021-01-07 01:22:21
    构造一个简单的多层卷积神经网络 import numpy as np import torch from torch.autograd import Variable from torch import nn, optim import matplotlib.pyplot as plt class SimpleCNN(nn.Module): def __init__...
  • 深度学习总结:常见卷积神经网络2Inception v1Inception v2BN层Inception v3非对称卷积分解Inception v4总结  上一篇博客主要回顾了VGG和Resnet,这一篇主要回顾一下GoogLeNet系列。 Inception v1 Inception v1...
  • 基于非对称分解卷积的网络安全检测.pdf
  • 针对目标追踪过程中由于目标快速运动及尺度变化导致追踪失败的问题, 提出了一种基于全卷积对称网络的目标尺度自适应追踪算法。首先利用MatConvNet框架构建全卷积对称网络, 使用训练好的网络得到实验图像与模板的多维...
  • 深度学习是机器学习领域中一个新的研究方向...卷积神经网络是一类包含卷积计算且具有深度结构的前馈神经网络,是深度学习代表算法之一。ppt是概括了传统的经典神经网络和卷积神经网络,希望对有ppt讲解需求的人有帮助。
  • 基于非对称全局卷积神经网络的遥感图像识别方法.pdf
  • 基于非对称混洗卷积神经网络的苹果叶部病害分割.pdf
  • 3D卷积pytorch

    2020-11-10 15:29:20
    基于Pytorch的3D卷积 2D卷积和3D卷积的区别及pytorch实现
  • 每一个nXn的卷积核都可以被分解为nX1和1Xn的两层卷积核,在本文中,作者使用了n=5的非对称卷积,在参数量上,5X5的非对称卷积仅仅比3X3的常规卷积多了一个参数,但是它们的感受野扩大了一倍,并且在网络中增加了函数...
  • keras实现分组卷积

    2021-01-15 09:52:44
    分组卷积在pytorch中比较容易实现,只需要在卷积的时候设置group参数即可 比如设置分组数为2 conv_group = nn.Conv2d(C_in,C_out,kernel_size=3,stride=3,padding=1,groups = 2) 但是,tensorflow中目前还没有分组...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,254
精华内容 6,901
关键字:

非对称卷积