[文献阅读] 可变形卷积DCN - Deformable Convolutional Networks

**文献信息:**Deformable Convolutional Networks arxiv.org/abs/1703.06211
发表于ICCV 2017,提出了可变形卷积DCN(Deformable ConvNets)

摘要

卷积神经网络(CNN)由于其构建模块固定的几何结构天然地局限于建模几何变换。

为了提高CNN的转换建模能力,作者提出了可变形卷积可变形RoI池化。两者都基于这样的想法:增加模块中的空间采样位置以及额外的偏移量,并且从目标任务中学习偏移量。并且新的模块可以很方便的替换普通的CNN模块,并且可以通过标准反向传播便易地进行端对端训练。

实验证明了在深度CNN中学习密集空间变换对于复杂的视觉任务(如目标检测和语义分割)是有效的。

Abstract

This week’s report examines Deformable Convolutional Networks (DCN). DCN introduce deformable convolutions and deformable RoI pooling, which add adaptive offsets to the standard grid sampling positions in convolutional and pooling layers. These offsets are learned from the data, allowing the network to capture complex spatial variations. The report explains how deformable convolutions and pooling layers are integrated into CNN and trained end-to-end via standard backpropagation. Experiments on tasks like object detection and semantic segmentation demonstrate significant improvements in performance, highlighting the effectiveness of DCN in handling geometric deformations in visual data.

可变形卷积

CNN本质上局限于建模大量,未知的数据转换。该限制源于CNN模块的固定几何结构:卷积单元在固定位置对输入特征图进行采样;池化层以一个固定的比例降低空间分辨率;一个RoI(感兴趣区域)池化层把RoI分成固定的空间组块等等。

而缺乏处理几何变换的内部机制。这会导致明显的问题。举一个例子,同一CNN层中所有激活单元的感受野大小是相同的。对于在空间位置上编码语义的高级CNN层来说,这是不可取的。由于不同的位置可能对应不同尺度或形变的目标,所以对于具有精细定位的视觉识别来说,例如使用全卷积网络的语义分割,尺度或感受野大小的自适应确定是理想的情况。

在这里插入图片描述

可变形卷积将2D偏移添加到标准卷积中的常规网格采样位置上。它可以使采样网格自由形变。

(a)标准卷积的定期采样网格(绿点)。(b)变形的采样位置(深蓝色点)和可变形卷积中增大的偏移量(浅蓝色箭头)。©(d)是(b)的特例,表明可变形卷积推广了尺度、长宽比和旋转的各种变换。

可变形卷积层

定义标准的卷积过程,对输入的2Dfeature map y上的每一个位置 P 0 P_0 P0,进行以下卷积操作
y ( P 0 ) = ∑ P n ∈ R w ( P n ) ⋅ x ( P 0 + P n ) y(P_0)=\sum_{P_n\in R}w(P_n)\cdot x(P_0+P_n) y(P0)=PnRw(Pn)x(P0+Pn)
其中,P_n是卷积核的每一个位置,w是卷积核.

网格R定义了感受野的大小和扩张,如:定义了一个扩张大小为1的3×3卷积核
R = { ( − 1 , − 1 ) , ( − 1 , 0 ) , . . . , ( 0 , 1 ) , ( 1 , 1 ) } R = \{(−1, −1),(−1, 0), . . . ,(0, 1),(1, 1)\} R={(1,1),(1,0),...,(0,1),(1,1)}
在标准卷积操作中,对每一个位置 P 0 P_0 P0,对其与它在R中的所有偏移位置(上下左右及对角线)的特征点与卷积核对应的位置进行加权求和,得到新特征图上对应的P_0点。例如 R [ 0 ] = ( − 1 , − 1 ) R[0]=(-1,-1) R[0]=(1,1),就是对应 P 0 P_0 P0点的左上角的点。

输出特征映射y上的每个位置 p 0 p_0 p0,我们有
y ( P 0 ) = ∑ P n ∈ R w ( P n ) ⋅ x ( P 0 + P n + Δ P n ) y(P_0)=\sum_{P_n\in R}w(P_n)\cdot x(P_0+P_n+\Delta P_n) y(P0)=PnRw(Pn)x(P0+Pn+ΔPn)
其中, { Δ P n ∣ n = 1 , . . . , N } \{\Delta P_n|n=1,...,N \} {ΔPnn=1,...,N}, N = ∣ R ∣ N = |R| N=R,对应着图中的offsets的每一个位置。

在可形变卷积的操作中,在原来R的偏移量的基础上又加入了一个二维偏移 Δ P n \Delta P_n ΔPn(x、y轴上的偏移),这个 Δ P n \Delta P_n ΔPn的值对应图1中offsets对应位置的值。

由于offsets要通过学习得到,所以是一个浮点值,因此对应的不是特征图上一个真实的位置,如果直接使用取整函数的话无法反向传播,因此该位置的值是通过计算周围4个真实值的双线性插值得到的。
x ( p ) = ∑ q G ( q , p ) ⋅ x ( q ) x(p)=\sum_{q}G(q,p) \cdot x(q) x(p)=qG(q,p)x(q)
其中, g ( a , b ) = m a x ( 0 , 1 − ∣ a − b ∣ ) g(a,b)=max(0,1-|a-b|) g(a,b)=max(0,1ab)

对每一个 P 0 P_0 P0 P n P_n Pn有N个值,对应着卷积核的大小, Δ P n \Delta P_n ΔPn同样也有N个值,对应上图中offset field特征图的N个通道,对于输出的特征图(对应下图中的output feature map)上的每个点,可以单独决定他在原图上采样的3x3的特征点的空间位置。

在这里插入图片描述

可变形池化

对一个输入特征图x和一个 w × h w \times h w×h的RoI,RoI pooling将RoI分割成一个 k × k k \times k k×k的区域(bin),并输出一个 k × k k \times k k×k的特征图y。对于第(i,j)的区域:

1)标准RoI 池化的操作过程:
y ( i , j ) = ∑ p ∈ b i n ( i , j ) x ( P 0 + P ) / n i j y(i,j)=\sum_{p \in bin(i,j)} x(P_0+P)/n_{ij} y(i,j)=pbin(i,j)x(P0+P)/nij

2)可形变 RoI 池化的操作过程:
y ( i , j ) = ∑ p ∈ b i n ( i , j ) x ( P 0 + P + Δ P i j ) / n i j y(i,j)=\sum_{p \in bin(i,j)} x(P_0+P+\Delta P_{ij})/n_{ij} y(i,j)=pbin(i,j)x(P0+P+ΔPij)/nij
这个操作过程跟可形变卷积的基本一样。

讲下 Δ P i j \Delta P_{ij} ΔPij的计算。

对输入特征图x先做一次标准的RoI池化,然后通过一个全连接层,输出一个标准的 k × k k \times k k×k 的offsets Δ P i j ^ \Delta \hat{P_{ij}} ΔPij^,然后根据公式:
Δ P i j = γ ⋅ Δ P i j ^ ⋅ ( w , h ) \Delta P_{ij}=\gamma \cdot \Delta \hat{P_{ij}} \cdot (w,h) ΔPij=γΔPij^(w,h)计算出 Δ P i j \Delta P_{ij} ΔPij。其中, γ \gamma γ是一个超参数设置为0.1。

在这里插入图片描述

感受野的变化

当可变形卷积叠加时,复合变形的影响是深远的。标准卷积中的感受野和采样位置在顶部特征映射上是固定的(左)。它们在可变形卷积中(右)根据目标的尺寸和形状进行自适应调整。

在这里插入图片描述

标准卷积(a)中的固定感受野和可变形卷积(b)中的自适应感受野的图示,使用两层。顶部:顶部特征映射上的两个激活单元,在两个不同尺度和形状的目标上。激活来自3×3滤波器。中间:前一个特征映射上3×3滤波器的采样位置。另外两个激活单元突出显示。底部:前一个特征映射上两个3×3滤波器级别的采样位置。突出显示两组位置,对应于上面突出显示的单元。

在这里插入图片描述

每个图像三元组在三级3×3可变形滤波器中显示了三个激活单元(绿色点)分别在背景(左)、小目标(中)和大目标(右)上的采样位置(每张图像中的93=72993=729个红色点)。

结果

四个模型的backbone层都是使用的ResNet-101,且在相同层将标准卷积替换为可形变卷积。@V和@C分别对应VOC 2012和PASCAl VOC数据集。其余三个网络对应的是目标检测任务,使用VOC2007数据集,并使用mAP作为检验标准,@0.5和@0.7分别对应使用0.5和0.7的IoU。
从图中我们可以看出加入可形变卷积后,每个模型的准确率都得到了提升。DeepLab在加入3层可形变卷积后准确率最高,其余网络在加入6层可形变卷积后准确率最高。

在这里插入图片描述

实验

https://github.com/4uiiurz1/pytorch-deform-conv-v2

可变形卷积的pytorch模块,modulation=True可以设置为DCNv2版本。

偏移量预测卷积层self.p_conv,用于生成偏移量。

对调整后的输入特征图进行卷积操作,普通卷积层self.conv

使用可变形卷积模块可以很方便的替换原有的CNN模块,直接使用。

import torch
from torch import nnclass DeformConv2d(nn.Module):def __init__(self, inc, outc, kernel_size=3, padding=1, stride=1, bias=None, modulation=False):"""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.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)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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/73489.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

德语A1学习

Hast du morgen Zeit? Wann spielen wir? Vocabulary etwas/jemanden brauchen braucht, brauchte, hat gebraucht to need something/somebody Das geht. That works./Thats OK. den ganzen Tag the entire day dieser, diese, dieses this erst just; only G…

路局的上道检修过程中,利用AI视觉技术对轨道两旁设备设施进行检修

在铁路局的上道检修过程中,利用AI视觉技术对轨道两旁设备设施(如信号设备、电缆、接触网、通信设备等)以及铁路上方的电线(如接触网、电力线)进行异常检测,可以显著提高检修效率、降低人工成本并增强安全性。以下是具体的应用方案和技术路径: 1. 应用场景 1.1 轨道两旁…

函数指针/逗号表达式/不用if语句完成的字母输出题

1.函数指针用的不是那么频繁的一个操作&#xff1a; 下面是代码演示&#xff1a; 在这个int (*jump)(int);中 jump是这个指针变量名称&#xff0c;第一个int是指针类型&#xff0c;第二个int是指的这个指针所指的函数参数是int类型的。 #include <stdio.h>// 定义一个…

uniapp报毒

uniapp打包的apk&#xff0c;装机量多了就开始报毒&#xff0c;尝试了多种解决办法都无解&#xff01;&#xff01; 去某宝&#xff0c;解决一次50-100不等&#xff0c;并且没有售后&#xff0c;掉了重新做包&#xff0c;很是无解&#xff0c;包月价格更是离谱。 为此自行测试…

IIS EXPRESS 虚拟目录经验谈!

最近在给客户开发一个事件提醒软件&#xff0c;用的是c# 版本是vs2022&#xff0c;在运行调试程序时&#xff0c;电脑会自动启动IIS Express,电脑右小角出现两个虚拟目录&#xff0c;对应两个端口&#xff0c;图示如下&#xff1a; 只能点击选择http://localhost:52726&#xf…

小程序配置

注册小程序账号和安装开发工具 参考文档&#xff1a;注册小程序账号和安装开发工具https://blog.csdn.net/aystl_gss/article/details/127878658 HBuilder新建项目 填写项目名称&#xff0c;选择UNI-APP&#xff0c;修改路径&#xff0c;点击创建 manifest.json 配置 需要分别…

左叶子之和 找左下角的值 路径总和

1.计算给定二叉树的所有左叶子之和。 #include <bits/stdc.h> using namespace std; struct TreeNode{ int val; TreeNode* left; TreeNode* right; TreeNode(int x) { valx; leftNULL; rightNULL; } }; int findsum(T…

Matlab实现RIME-CNN-LSTM-Multihead-Attention多变量多步时序预测

SCI一区级 | Matlab实现RIME-CNN-LSTM-Multihead-Attention多变量多步时序预测 目录 SCI一区级 | Matlab实现RIME-CNN-LSTM-Multihead-Attention多变量多步时序预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现RIME-CNN-LSTM-Multihead-Attention霜冰算法…

996引擎-自定义属性-方法2:setitemcustomabil

996引擎-自定义属性-方法2:setitemcustomabil 先看下效果测试NPC补全测试代码辅助表公式setitemcustomabil 总结参考资料先看下效果 测试NPC 为了方便测试,先准备个NPC require("Envir/QuestDiary/ex/init.lua"); require("Envir/QuestDiary/utils/init.lu…

苹果电脑杀毒软件CleanMyMac

杀毒软件在苹果家族中是一个小众软件&#xff0c;百度搜索苹果电脑杀毒软件&#xff0c;可能各种杀软良莠不齐&#xff0c;因为在这个市场非常小&#xff0c;绝大多数都是冲着“清理”去的&#xff0c;而不是杀毒。最近测试了一款Mac电脑杀毒软件&#xff0c;杀毒效果也是一般般…

pandas表格内容比较

前阵子来了一个211大学实习生&#xff08;小男生&#xff09;&#xff0c;要比较2个版本字段的变化&#xff0c;辅助完成系统升级字段替换&#xff0c;要求找出哪些字段是新增的&#xff0c;哪些字段是删除的&#xff0c;哪些字段是属性信息修改的&#xff0c;要求半天时间搞定…

【SpringBoot】最佳实践——JWT结合Redis实现双Token无感刷新

JWT概览 JWT概念 JWT是全称是JSON WEB TOKEN&#xff0c;是一个开放标准&#xff0c;用于将各方数据信息作为JSON格式进行对象传递&#xff0c;可以对数据进行可选的数字加密&#xff0c;可使用RSA或ECDSA进行公钥/私钥签名。JWT最常见的使用场景就是缓存当前用户登录信息&am…

面试系列|蚂蚁金服技术面【1】

哈喽&#xff0c;大家好&#xff01;今天分享一下蚂蚁金服的 Java 后端开发岗位真实社招面经&#xff0c;复盘面试过程中踩过的坑&#xff0c;整理面试过程中提到的知识点&#xff0c;希望能给正在准备面试的你一些参考和启发&#xff0c;希望对你有帮助&#xff0c;愿你能够获…

eBPF 实时捕获键盘输入

eBPF 实时捕获键盘输入 本文将带你一步步实现一个基于eBPF kprobe的键盘记录功能&#xff0c;通过Go语言配合libbpfgo&#xff0c;你将学会如何无损地监控系统键盘输入&#xff0c;并从中获取实时数据&#xff0c;进一步提高系统安全和监控能力。 1. 说明 本文属于专栏 Go语言…

APB-清华联合腾讯等机构推出的分布式长上下文推理框架

APB (Accelerating Distributed Long-Context Inference by Passing Compressed Context Blocks acrossGPUs)是清华大学等机构联合提出的分布式长上下文推理框架。通过稀疏注意力机制和序列并行推理方式&#xff0c;有效解决了大模型处理长文本时的效率瓶颈。APB采用更小的Anch…

数据库分库分表介绍

分库分表是解决数据库性能瓶颈的常用技术手段&#xff0c;主要用于应对数据量过大、读写压力过高的问题。通过将数据分散到多个数据库或表中&#xff0c;可以提高系统的扩展性和性能。 1. 分库分表的核心概念 &#xff08;1&#xff09;分库 定义&#xff1a;将数据分散到多个…

#mapreduce打包#maven:could not resolve dependencies for project

打包报错&#xff1a; #报错信息&#xff1a; [ERROR] Failed to execute goal on project mapreduce_teacher1: Could not resolve dependencies for project org.example:mapreduce_teacher1:jar:1.0-SNAPSHOT: Failed to collect dependencies at org.apache.hive:hive-exe…

Rabit

之前发过rabit了&#xff0c;所以这里不再赘述&#xff0c;讲讲原理 在线Rabbit加密 | Rabbit解密- 在线工具 (sojson.com) rabbit加密原理 Rabbit加密算法是一种流密码算法&#xff0c;由Daniel J. Bernstein设计&#xff0c;并被广泛用于多种加密和安全通信应用中。它的设…

【A2DP】深入解读A2DP中通用访问配置文件(GAP)的互操作性要求

目录 一、模式支持要求 1.1 发现模式 1.2 连接模式 1.3 绑定模式 1.4 模式间依赖关系总结 1.5 注意事项 1.6 协议设计深层逻辑 二、安全机制&#xff08;Security Aspects&#xff09; 三、空闲模式操作&#xff08;Idle Mode Procedures&#xff09; 3.1 支持要求 …

模型蒸馏系列——开源项目

推荐项目&#xff1a;MiniMind&#xff08;低成本全流程训练框架&#xff09; GitHub&#xff1a;https://github.com/jingyaogong/minimind 核心特性&#xff1a;完整实现从数据清洗到模型部署的全流程&#xff0c;支持单卡低成本训练&#xff0c;代码全透明&#xff0c;适合…