目录

  • 1.DCNv1
  • 2.DCNv2

1.DCNv1

可变形卷积顾名思义就是卷积的位置是可变形的,并非在传统的N × N的网格上做卷积,这样的好处就是更准确地提取到我们想要的特征(传统的卷积仅仅只能提取到矩形框的特征)
DCN v1的核心思想在于它认为卷积核不应该是一个简简单单的矩形
在不同的阶段,不同的特征图,甚至不同的像素点上都可能有其最优的卷积核结构。
因此DCN v1提出在方形卷积核上的每个点学习一个偏移(offset),卷积核可以根据不同的数据学习不同的卷积核结构,如图1所示。


图1:可变形卷积核。(a)是标准的3×3卷积。(b),( c),(d)是给普通卷积加上偏移之后形成的可变形的卷积核,其中蓝色的是新的卷积点,箭头是位移方向。


可变形卷积的结构可以分为上下两个部分:

  • 上面那部分是基于输入的特征图生成x,y方向的offset
  • 下面那部分是基于特征图和offset通过可变形卷积获得输出特征图

假设输入的特征图宽高分别为w,h,下面那部分的卷积核尺寸是 k h k_h kh​和 k w k_w kw​,那么上面那部分卷积层的卷积核数量应该是 2 ∗ k h ∗ k w 2*k_h*k_w 2∗kh​∗kw​,其中2代表x,y两个方向的offset。

并且,这里输出特征图的维度和输入特征图的维度一样,那么offset的维度就是[batch, k h k_h kh​, k w k_w kw​,h,w]

假设下面那部分设置了group参数(代码实现中默认为4),那么第一部分的卷积核数量就是 2 ∗ k h ∗ k w ∗ g r o u p 2*k_h*k_w*group 2∗kh​∗kw​∗group,即每一个group共用一套offset。下面的可变形卷积可以看作先基于上面那部分生成的offset做了一个插值操作,然后再执行普通的卷积。


具体实现的流程大概如下:

  • step1:求输入特征图 U U U(维度=[b,h,w,c])每个像素的偏移量:经过一个普通卷积,padding设置为same,对应的输出结果维度是[b,h,w,2c],记作 V V V。

  • 将输入特征图 U U U中的像素索引值与V相加,得到偏移后的position(即在原始图片U中的坐标值),需要将position值限定为图片大小以内。position的大小为(bhw*2c),但position只是一个坐标值,而且还是float类型的,我们需要这些float类型的坐标值获取像素(双线性差值)。

    • 举个例子:我们取一个坐标值,将其转换为四个整数floor(a), ceil(a), floor(b), ceil(b)。
    • 将这四个整数进行整合,得到四对坐标(floor(a),floor(b)), ((floor(a),ceil(b)), ((ceil(a),floor(b)), ((ceil(a),ceil(b))。
    • 这四对坐标每个坐标都对应 U U U中的一个像素值,而我们需要得到(a,b)的像素值,这里采用双线性差值的方式计算(一方面是因为获得的像素更精确,另外一方面是因为可以进行反向传播)。
  • 在得到position的所有像素后,即得到了输出特征图 M M M,将这个新图片M作为输入数据输入到别的层中,如普通卷积。

2.DCNv2

  1. 增加更多的可变形卷积层
  2. 除了让模型学习采样点的偏移,还要学习每个采样点的权重,这是对减轻无关因素干扰的最重要的工作
  3. 使用R-CNN对Faster R-CNN进行知识蒸馏
  4. 目前只能实现3*3大小的卷积

更多的可变形卷积:

  • 在DCN v2将conv3到conv5 block的 3*3卷积全部替换为了可变形卷积,因此可变形卷积层数达到了 12个。这一操作在场景更复杂的COCO数据集有着比较明显的性能提升。

加权采样点偏移:

  • DCNv2在DCNv1的基础上增加了一个权重系数 m m m,对卷积的在输入特征图上的采样点的偏移量计算权重,去除无关的上下文信息,对于某些不想要的采样点权重可以直接学习成0。

使用R-CNN对Faster R-CNN进行知识蒸馏:

  • 在DCN v2中,作者使用了特征模仿(Feature Mimicking)的方式来用R-CNN对Faster R-CNN的优化。特征模仿是一个比较高级的模型迁移策略,它主要用在知识蒸馏中。
  • 它先训练一个准确率比较高但是速度慢的大型的Teacher网络,然后再训练一个速度快但是泛化能力略差的小的Student网络。
  • 在训练Student网络的过程中,模型不仅要优化它本身任务的损失函数,还要以Teacher网络学习到的特征为目标,优化它的中间的特征层。
  • 因为Student网络的参数量是固定的,所以通过这个策略优化之后的Student网络不仅速度很快,而且能够达到了Teacher类似的准确率。
  • DCN v2使用R-CNN来指导加了了可变形卷积的Faster R-CNN训练的目的是使可变形卷积能够自行的学到更好的采样点的偏移和权重,从而减少无关因素对模型的负面影响。

代码:

import torch
from torch import nnfrom yolox.models.network_blocks import get_activationclass DeformConv2d(nn.Module):def __init__(self, inc, outc, kernel_size=3, stride=1, padding=1, bias=None, modulation=False,act="silu"):"""Args:modulation (bool, optional): If True, Modulated Defomable Convolution (Deformable ConvNets v2)."""super(DeformConv2d, self).__init__()self.kernel_size = kernel_sizeself.padding = paddingself.stride = strideself.zero_padding = nn.ZeroPad2d(padding)self.conv = nn.Conv2d(inc, outc, kernel_size=kernel_size, stride=kernel_size, bias=bias)self.p_conv = nn.Conv2d(inc, 2*kernel_size*kernel_size, kernel_size=3, padding=1, stride=stride)nn.init.constant_(self.p_conv.weight, 0)self.p_conv.register_backward_hook(self._set_lr)
#------------------------------------------------------------------self.bn = nn.BatchNorm2d(outc)self.act = get_activation(act, inplace=True)
#------------------------------------------------------------------self.modulation = modulationif modulation:self.m_conv = nn.Conv2d(inc, kernel_size*kernel_size, kernel_size=3, padding=1, stride=stride)nn.init.constant_(self.m_conv.weight, 0)self.m_conv.register_backward_hook(self._set_lr)@staticmethoddef _set_lr(module, grad_input, grad_output):grad_input = (grad_input[i] * 0.1 for i in range(len(grad_input)))grad_output = (grad_output[i] * 0.1 for i in range(len(grad_output)))def forward(self, x):offset = self.p_conv(x)if self.modulation:m = torch.sigmoid(self.m_conv(x))dtype = offset.data.type()ks = self.kernel_sizeN = offset.size(1) // 2if self.padding:x = self.zero_padding(x)# (b, 2N, h, w)p = self._get_p(offset, dtype)# (b, h, w, 2N)p = p.contiguous().permute(0, 2, 3, 1)q_lt = p.detach().floor()q_rb = q_lt + 1q_lt = torch.cat([torch.clamp(q_lt[..., :N], 0, x.size(2)-1), torch.clamp(q_lt[..., N:], 0, x.size(3)-1)], dim=-1).long()q_rb = torch.cat([torch.clamp(q_rb[..., :N], 0, x.size(2)-1), torch.clamp(q_rb[..., N:], 0, x.size(3)-1)], dim=-1).long()q_lb = torch.cat([q_lt[..., :N], q_rb[..., N:]], dim=-1)q_rt = torch.cat([q_rb[..., :N], q_lt[..., N:]], dim=-1)# clip pp = torch.cat([torch.clamp(p[..., :N], 0, x.size(2)-1), torch.clamp(p[..., N:], 0, x.size(3)-1)], dim=-1)# bilinear kernel (b, h, w, N)g_lt = (1 + (q_lt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_lt[..., N:].type_as(p) - p[..., N:]))g_rb = (1 - (q_rb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_rb[..., N:].type_as(p) - p[..., N:]))g_lb = (1 + (q_lb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_lb[..., N:].type_as(p) - p[..., N:]))g_rt = (1 - (q_rt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_rt[..., N:].type_as(p) - p[..., N:]))# (b, c, h, w, N)x_q_lt = self._get_x_q(x, q_lt, N)x_q_rb = self._get_x_q(x, q_rb, N)x_q_lb = self._get_x_q(x, q_lb, N)x_q_rt = self._get_x_q(x, q_rt, N)# (b, c, h, w, N)x_offset = g_lt.unsqueeze(dim=1) * x_q_lt + \g_rb.unsqueeze(dim=1) * x_q_rb + \g_lb.unsqueeze(dim=1) * x_q_lb + \g_rt.unsqueeze(dim=1) * x_q_rt# modulationif self.modulation:m = m.contiguous().permute(0, 2, 3, 1)m = m.unsqueeze(dim=1)m = torch.cat([m for _ in range(x_offset.size(1))], dim=1)x_offset *= mx_offset = self._reshape_x_offset(x_offset, ks)# out = self.conv(x_offset)out = self.act(self.bn(self.conv(x_offset)))return outdef _get_p_n(self, N, dtype):p_n_x, p_n_y = torch.meshgrid(torch.arange(-(self.kernel_size-1)//2, (self.kernel_size-1)//2+1),torch.arange(-(self.kernel_size-1)//2, (self.kernel_size-1)//2+1))# (2N, 1)p_n = torch.cat([torch.flatten(p_n_x), torch.flatten(p_n_y)], 0)p_n = p_n.view(1, 2*N, 1, 1).type(dtype)return p_ndef _get_p_0(self, h, w, N, dtype):p_0_x, p_0_y = torch.meshgrid(torch.arange(1, h*self.stride+1, self.stride),torch.arange(1, w*self.stride+1, self.stride))p_0_x = torch.flatten(p_0_x).view(1, 1, h, w).repeat(1, N, 1, 1)p_0_y = torch.flatten(p_0_y).view(1, 1, h, w).repeat(1, N, 1, 1)p_0 = torch.cat([p_0_x, p_0_y], 1).type(dtype)return p_0def _get_p(self, offset, dtype):N, h, w = offset.size(1)//2, offset.size(2), offset.size(3)# (1, 2N, 1, 1)p_n = self._get_p_n(N, dtype)# (1, 2N, h, w)p_0 = self._get_p_0(h, w, N, dtype)p = p_0 + p_n + offsetreturn pdef _get_x_q(self, x, q, N):b, h, w, _ = q.size()padded_w = x.size(3)c = x.size(1)# (b, c, h*w)x = x.contiguous().view(b, c, -1)# (b, h, w, N)index = q[..., :N]*padded_w + q[..., N:]  # offset_x*w + offset_y# (b, c, h*w*N)index = index.contiguous().unsqueeze(dim=1).expand(-1, c, -1, -1, -1).contiguous().view(b, c, -1)x_offset = x.gather(dim=-1, index=index).contiguous().view(b, c, h, w, N)return x_offset@staticmethoddef _reshape_x_offset(x_offset, ks):b, c, h, w, N = x_offset.size()x_offset = torch.cat([x_offset[..., s:s+ks].contiguous().view(b, c, h, w*ks) for s in range(0, N, ks)], dim=-1)x_offset = x_offset.contiguous().view(b, c, h*ks, w*ks)return x_offset

get_activation代码如下:

def get_activation(name="silu", inplace=True):if name == "silu":module = nn.SiLU(inplace=inplace)elif name == "relu":module = nn.ReLU(inplace=inplace)elif name == "lrelu":module = nn.LeakyReLU(0.1, inplace=inplace)else:raise AttributeError("Unsupported act type: {}".format(name))return module

PS:其实自己还可以补充些自己需要的激活函数。

参考文献1
参考文献2

可变形卷积:DCNv1and DCNv2相关推荐

  1. 可变形卷积学习(RepPoints)

    近来在学习anchor-free网络,看到了可变形卷积(Deformable Convolutional Networks(DCN))的内容,大致总结一下,便于后面回顾. 可变形卷积可从以下三篇论文去 ...

  2. CVPR 2023 | 65.4 AP!刷新COCO目标检测记录!InternImage:基于可变形卷积的大规模视觉基础模型...

    点击下方卡片,关注"CVer"公众号 AI/CV重磅干货,第一时间送达 点击进入->Transformer和目标检测技术交流群 转载自:机器之心 来自浦江实验室.清华等机构的 ...

  3. 可变形卷积网络--Deformable Convolutional Networks

    https://arxiv.org/abs/1703.06211 Microsoft Research Asia Code coming soon 本文可以看做是对 Spatial Transform ...

  4. 深度学习之 DCN(Deformable Convolution)-可变形卷积

    Paper link: http://openaccess.thecvf.com/content_ICCV_2017/papers/Dai_Deformable_Convolutional_Netwo ...

  5. RepPoints(本质是可变形卷积DCN)再理解

    虽然在之前学习过RepPoints这个网络,但当时理解较为浅显,现在再看论文和一些博客解释,感觉又有了新的收获. RepPoints是一种anchor-free网络,说的是使用具有一组代表性的点来表示 ...

  6. CVPR2019| ADCrowdNet: 用于人群理解的可变形卷积网络

    点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 提出了一种用于人群理解的注意力可变形卷积网络ADCrowdNet,它可以解决高拥塞噪声场景的精度下降问题.ADCro ...

  7. 更灵活、有个性的卷积——可变形卷积(Deformable Conv)

    作者简介 CW,广东深圳人,毕业于中山大学(SYSU)数据科学与计算机学院,毕业后就业于腾讯计算机系统有限公司技术工程与事业群(TEG)从事Devops工作,期间在AI LAB实习过,实操过道路交通元 ...

  8. 可变形卷积神经网络 | Deformable Network

    论文标题:Deformable Convolutional Networks 论文链接:https://arxiv.org/abs/1703.06211 所要解决的问题 视觉识别的关键挑战是如何在对象 ...

  9. 可变形卷积系列(三) Deformable Kernels,创意满满的可变形卷积核 | ICLR 2020

    论文提出可变形卷积核(DK)来自适应有效感受域,每次进行卷积操作时都从原卷积中采样出新卷积,是一种新颖的可变形卷积的形式,从实验来看,是之前方法的一种有力的补充.   来源:晓飞的算法工程笔记 公众号 ...

最新文章

  1. linux命令用tar czvf .tar.gz好用的
  2. 用python帮博士师兄解决流态化专业问题
  3. android之SharedPreferences
  4. bash给脚本加进度条_shell脚本实现进度条
  5. 录屏直播时,只有部分屏幕的解决办法
  6. 数学魔鬼表达式——第三天
  7. 【洛谷】P3369 【模板】普通平衡树
  8. 德州农工大学计算机专业如何,德州农工大学美国排名
  9. 《ArcGIS10.2》 Part1 在地图上标注地名或坐标
  10. python numpy 版本问题:error module compiled against API version 0xc but this version of numpy is 0xb
  11. VUE通过自定义指令,只允许输入大写英文以及数字
  12. 用Python进行数据分析之金融和经济数据应用
  13. 深入了解示波器(八):如何选择示波器
  14. 李宏毅2020机器学习深度学习 笔记1(理论上持续更新中)
  15. 联通云服务器安全性能怎么样,云安全解决方案
  16. 苹果手机数据线充不了电_深圳苹果手机数据线多少钱一条
  17. 微软解释“云下载”如何重新安装Windows 10
  18. 学习马克思数学手稿,为无穷小微积分呐喊!
  19. VB顺序文件案例:简易文本编辑器
  20. 郭大侠与Rabi-Ribi

热门文章

  1. oracle 2003,Oracle + Windows 2003 群集手记
  2. ios 隔空投安装ipa_IOS客户端app在线安装ipa包,
  3. Python语言-NL-工作日的力量
  4. 4336: BJOI2015 骑士的旅行
  5. 高速不按规定车道行驶_不按规定车道行驶扣几分罚款多少?
  6. Elasticsearch进阶使用
  7. ajax无刷新聊天室,实现一个无刷新的基于ajax的简易聊天室
  8. Maxcompute 分区
  9. Redis缓存树形结构
  10. POJ1017题解(语音讲解题意以及样例分析)