动态卷积之CondConv和DynamicConv

Motivation

现在的诸多task中,普遍需要capacity较大的模型,而随着模型参数的不断增加,计算成本也越来越高。对于一些对latency有较高要求的task,显然是一种挑战。在传统的CNN网络中,一旦训练完成,所有的kernal参数就固定了。对于任意的输入,所有的kernal都对他们同等对待。所以为了提高模型的capacity,大多数方法堆叠卷积层或者增加卷积层的channel数(即增加深度和广度),这种做法虽然一定程度上可以提升模型performance,但显然会造成 computationally expensive。

所以为了压缩模型,在增加模型capacity的同时不会增加太多参数和计算量,动态卷积的概念应运而生。动态卷积的出发点就是,当训练结束后,kernal不再是一个定值,而是一个由input决定的变量。因此kernal相当于一个以input为自变量的function;换句话说就是对于不同的input,都会通过计算得到各自不同的卷积核参数。这种做法相当于变相的增加了模型的capacity,与此同时模型参数和计算量是非常小的。

CondConv

论文名称:CondConv: Conditionally Parameterized Convolutions for Efficient Inference

链接:https://arxiv.org/abs/1904.04971

与其叫条件卷积,私认为动态卷积更加贴切。在CondConv中,通过下述公式得到kernal的参数:
在这里插入图片描述
这里 x x x表示上一个layer的输出, n n n表示这一层Condconv Layer有 n n n个expert(expert就是该层的卷积核W), σ \sigma σ表示激活函数, α i = r i ( x ) \alpha_{i}=r_{i}(x) αi=ri(x)表示一个样本依赖的加权参数。

所以一个CondConv层的卷积核参数的由来,就是通过上述的线性组合公式。整个流程可以概括为:依赖于输入 x x x,在卷积操作之前,通过routing函数 r i ( x ) r_{i}(x) ri(x)计算出每一个expert前面的系数 α i \alpha_{i} αi,再通过线性组合,得到CondConv层最终的kernal,最后与输入 x x x做卷积,并进行activation。在这里,routing weight的计算公式如下:
在这里插入图片描述
对于输入 x x x,首先做GlobalAveragePooling,随后右乘一个矩阵R(该矩阵的目的是将维度映射到n个expert上面,以实现后续的线性组合),最后通过sigmoid将每一个维度上的权值规约到[0,1]区间。因此,根据输入 x x x的不同,就会得到不同的routing weight向量,进而CondConv层的kernal也各有差异。

CondConv的流程如下图(a)所示:
在这里插入图片描述
上图(a)中所示的CondConv与图(b)都是将routing weight与expert做线性组合,但还是存在一些区别:CondConv只需要做一次卷积,而图(b)的方式要做n次(expert的数目)卷积。我们知道,直观上expert数目越多,模型的performace越好。因此图(a)的计算量会比图(b)少很多,计算开销大大减少,体现了CondConv这种设计的优越性。

实验部分感兴趣的话可以看论文,我在这里只放一组很有意思的实验结果:
在这里插入图片描述
通过上图发现,绝大部分的routing weight都在0或1附近,也就是说expert是sparse activated。这里谈一下我的看法,这些expert很可能编码了不同实例的特征,每一个expert对应了一个characteristic,只有拥有这个特征的input输入进来时,才会对该expert进行激活,随后作为filter,能够更好的进行特征提取。因为最近实例分割的论文有几篇用到动态卷积,思想和这个比较类似。

总而言之,CondConv提出了这类动态卷积的思想,challenge了「所有输入要共享卷积核参数」的观点。由于每个layer只需要做一次卷积,CondConv非常高效。同时突出了一个非常重要的研究问题,即如何更好的表示和利用样本的相关性来提升模型的performace。

DynamicConv

论文名称:Dynamic Convolution: Attention over Convolution Kernels

链接:https://arxiv.org/pdf/1912.03458.pdf
在这里插入图片描述

文章从动态感知器出发,类比到动态卷积上面。首先,动态感知器可由下述公式概括:
在这里插入图片描述
其中 π k \pi_{k} πk表示第k个线性函数 W ~ k T x + b ~ k \widetilde{W}_{k}^{T}x+\widetilde{b}_{k} W kTx+b k的attetion权重,这个权重在输入 x x x不同的情况下是不同的。因此在给定input的情况下,动态感知器代表了该input的最佳线性函数组合。又因为该模型是非线性的,所以动态感知器拥有更强大的representation能力。

而得到attention weight这一过程计算开销是非常小的,远小于weight与输入之间的矩阵乘法,如下式:
在这里插入图片描述
因此,动态感知器在提升模型capacity进而提升模型表示能力的同时,并没有额外增加计算开销。

接下来推广到动态卷积DynamicConv,其实和动态感知器的思想是非常相似的,如下图:
在这里插入图片描述
给某个Layer设置 K K K个尺度和通道数相同的kernal,通过各自的attention权重 π k \pi_{k} πk进行融合,从而得到该层的卷积核参数。计算 π k ( x ) \pi_{k}(x) πk(x)的过程如图中虚线方框所示,首先做GlobalAvgPooling,得到全局Spatial特征,再通过两个FC层映射到 K K K的维度,最后做softmax归一化。这样得到的 K K K个attention权重就可以分配给该层的 K K K个kernal。这里与SENet不同的是,SENet是在channel层面的attention,而DynamicConv是以整个kernal为一个被attention的对象。
在这里插入图片描述
再关注一下计算复杂度:假设feature map的大小为 H ∗ W H*W HW,kernal的size为 D k ∗ D k D_{k}*D_{k} DkDk C i n C_{in} Cin C o u t C_{out} Cout表示输入通道数和输出通道数。所以在计算attention权重时额外增加的计算量为 H W C i n + C i n 2 / 4 + C i n K / 4 HWC_{in}+C_{in}^{2}/4+C_{in}K/4 HWCin+Cin2/4+CinK/4(除以4是因为第一层FC将维度从 C i n C_{in} Cin缩小到四分之一),在kernal融合时额外增加的计算量为 K C i n C o u t D k 2 + K C o u t KC_{in}C_{out}D_{k}^{2}+KC_{out} KCinCoutDk2+KCout。这两部分额外开销都远小于静态卷积计算的 H W C i n C o u t D k 2 HWC_{in}C_{out}D_{k}^{2} HWCinCoutDk2,因此只要当 K < < H W K<<HW K<<HW,这部分额外开销是非常efficient的,根据上表可以直观看出。
在这里插入图片描述
训练过程中要关注两个问题:(1)通过softmax把所有的attention weight限定在[0,1]内,并且sum为1。这样做就把kernal融合的空间压缩为一个三角形空间,相比于CondConv的两个pyramid空间,更适合进行优化;(2)由于attention权重大多数是sparse的(与CondConv的实验异曲同工),所以大多数的kernal得不到训练,为解决这个问题,作者提出了下述公式进行平滑:
在这里插入图片描述
这里 z k z_{k} zk表示第二层FC的输出。举个栗子方便理解:假设该层有K=2个kernal, z z z输出的结果为(0.01, 0.99),那么在反向传播时第二个kernal可以得到更好地学习,而第一个kernal的参数学习会被抑制。所以采用上述公式,假如超参数 τ = 30 \tau=30 τ=30,那么此时 π 1 \pi_{1} π1的值就比之前不做平滑的大很多。因为 z 1 z_{1} z1即使缩小了30被,经指数函数仍然是趋近于1;而 z 2 z_{2} z2一旦缩小30倍,attention就从 e 0.99 e^{0.99} e0.99下降成了 e 0.03 e^{0.03} e0.03,这个削弱幅度是巨大的。因此平滑操作有利于所有的kernel进行参数的迭代更新。

实验太多就不贴了,感兴趣的可以阅读原文细品~

总结

两篇文章都是动态卷积相关的,在不增加计算开销的同时,增大模型的capacity进而提升模型performace。动态卷积的思想就是根据不同的input,动态生成不同的卷积核系数,然后自适应地做kernel的融合,从而能够更好地进行特征提取和表示,打破了kernal对所有输入样例一视同仁的传统。总体上换汤不换药,都可以在经典的网络中plug-in,大致都属于kernal层面的attention,只有实现细节上稍有不同(总感觉无非就是求attention系数计算的不同,CondConv用Sigmoid做约束,而DynamicConv采用了softmax做归一,导致融合的space不一样)。目前我只看到了Google的CondConv代码是开源的,说一句谷歌大法好。

最近还有几篇动态卷积相关的文章:

DyNet: Dynamic Convolution for Accelerating Convolutional Neural Networks

Revisiting Dynamic Convolution via Matrix Decomposition (ICLR21)

后一篇好像很牛批的样子,抽空看下。

  • 12
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 动态卷积是指在卷积操作过程中,通过改变卷积核的大小和形状,实现对输入数据的不同区域进行不同滤波操作的一种方法。PyTorch是一个开源的深度学习框架,支持动态卷积操作。 在PyTorch中,动态卷积可以通过使用torch.nn.functional中的函数来实现。torch.nn.functional中的conv1d、conv2d和conv3d等函数都可以进行动态卷积操作。 在使用动态卷积之前,需要将卷积核定义为一个可学习的变量,并设置卷积核的形状。PyTorch中的torch.nn.Parameter可以用于定义可学习的变量。在每次进行卷积操作时,可以根据需要改变卷积核的形状。这样,在每次进行卷积操作时,卷积核的形状都可以是不同的。 动态卷积的一个应用场景是图像语义分割。在图像语义分割中,需要对图像的不同区域进行不同的特征提取,以便更好地进行像素级分类。通过使用动态卷积,可以根据图像中不同区域的内容和特征,调整卷积核的大小和形状,提取不同区域的特征,从而更好地进行语义分割任务。 总之,动态卷积是指在卷积操作中,根据需要改变卷积核的大小和形状,实现对输入数据不同区域的不同滤波操作的一种方法。PyTorch作为一个深度学习框架,支持动态卷积操作,并通过设置卷积核为可学习的变量,可以方便地进行动态卷积操作。 ### 回答2: 动态卷积是指卷积神经网络中的一种卷积操作,它的卷积核大小可以根据输入数据的形状进行动态调整。在PyTorch中,通过使用nn.Conv2d()函数来实现动态卷积。 nn.Conv2d()函数的参数包括输入通道数、输出通道数、卷积核大小和步长等。对于动态卷积,其中的卷积核大小可以通过传入一个变量来灵活地调整。 一般情况下,我们可以将输入数据的尺寸通过调用torch.Tensor.size()来获取,并根据这个尺寸来确定卷积核的大小。 示例如下: ```python import torch import torch.nn as nn # 定义输入数据及其尺寸 input_data = torch.randn(1, 3, 32, 32) input_size = input_data.size() # 定义卷积核大小,通过调用torch.Tensor.size()来动态设置 kernel_size = (input_size[2] // 2, input_size[3] // 2) # 定义动态卷积conv = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=kernel_size, stride=1) # 执行动态卷积 output = conv(input_data) # 输出动态卷积后的特征图尺寸 print(output.size()) ``` 在上述示例中,首先定义了一个输入数据及其尺寸input_data和input_size,然后根据input_size动态地计算卷积核大小kernel_size。接着,通过nn.Conv2d()函数定义了一个动态卷积conv,参数包括输入通道数、输出通道数和卷积核大小等。最后,通过执行conv(input_data)来进行动态卷积操作,得到输出特征图output,并通过output.size()来获取特征图的尺寸。 总之,动态卷积是PyTorch中的一个功能强大的卷积操作,可以根据输入数据的形状来自动调整卷积核的大小,从而更好地适应不同的数据。 ### 回答3: 动态卷积是指在卷积操作中,卷积核的大小和步长可以动态地变化。在传统的卷积操作中,卷积核的大小和步长是固定的,无法根据不同的输入数据进行调整。而动态卷积则通过可学习的方式,根据输入数据的特征动态调整卷积核的大小和步长。 PyTorch是一个基于Python的深度学习框架,提供了动态卷积的实现。在PyTorch中,动态卷积通过nn.Module类中的Conv2d函数实现。Conv2d函数中的参数包括输入通道数、输出通道数、卷积核大小和步长等。 具体而言,动态卷积可以通过传入一个可变的卷积核大小和步长的值来实现。这些可变的值可以是从训练数据中自动学习得到的,也可以是根据不同的输入数据进行调整的。这样的设计可以让动态卷积更加灵活,适应不同的输入数据和任务需求。 动态卷积在深度学习中有着广泛的应用。例如,在自然语言处理中,可以利用动态卷积来处理变长的句子序列;在计算机视觉中,可以利用动态卷积来处理不同尺寸的图像。动态卷积的灵活性和高效性使得它成为深度学习中的重要组件之一。 总之,动态卷积是指可以动态调整卷积核大小和步长的卷积操作。PyTorch提供了动态卷积的实现方式,通过传入可变的参数来实现灵活的卷积操作。动态卷积在深度学习中有着广泛的应用,能够适应不同的输入数据和任务需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值