文章目录
可变形卷积DCNv1 & DCNv2
✨✨✨论文及代码详解——可变形卷积(DCNv1)
✨✨✨论文及代码详解——可变形卷积(DCNv2)
DCNv3 是InternImage中提出的,DCNv3在DCNv2版本上进行了改进。
✨✨✨论文详解——《InternImage: Exploring Large-Scale Vision Foundation Models with Deformable Convolutions》
InterImage官方代码: https://github.com/OpenGVLab/InternImage
概述
如下图,首先下载InterImage官方代码,然后在segmentation、detection、classification文件夹下均可以找到ops_dcnv3文件夹,该文件夹下的内容就是实现DCNv3算子的核心代码。

modules
如下图所示,modules文件夹中的dcnv3.py文件主要定义了DCNv3模块。
其中DCNv3_pytorch是DCNv3的pytorch实现版本,DCNv3是DCNv3的C++实现版本。

functions
如下图所示,function文件夹中的dcnv3_func.py文件定义了DCNv3的一些核心操作。
其中黄色部分的DCNv3Function类被c++版本的DCNv3调用。
其中红色部分的dcnv3_core_pytorch方法被pytorch版本的DCNv3_pytorch调用。

src
src下的代码是用C++来实现DCNv3中核心操作,其下的cpu和cuda分别表示cpu和cuda编程两种实现版本。c++实现的版本需要去编译,否则如上图所示,黄色箭头指向的import DCNv3有红色波浪线,无法正常导入。
如果想import DCNv3成功,有两种解决办法:
(1)需要编译:DCNv3具体编译方法是直接运行make.sh文件(但是这种方法很容易编译失败,对于pytorch,cuda的版本以及c++编译器的配置都有要求)
(2)不需要编译:去官网上下载轮子https://github.com/OpenGVLab/InternImage/releases/tag/whl_files (更推荐这种方法,但是也需要注意cuda和pytorch的版本)

本文重点介绍DCNv3的pytorch实现部分。
dcnv3.py
to_channels_first
- 功能:将通道维度放在前面,输入
(b,h,w,c),输出(b,c,h,w)
# 将通道维度放在前面:(b,h,w,c)->(b,c,h,w)
class to_channels_first(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x): # (b,h,w,c)
return x.permute(0, 3, 1, 2) #(b,c,h,w)
to_channels_last
- 功能:将通道维度放在后面,输入
(b,c,h,w),输出(b,h,w,c)
# 将通道维度放在后面 (b,c,h,w)->(b,h,w,c)
class to_channels_last(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x): # (b,c,h,w)
return x.permute(0, 2, 3, 1) # (b,h,w,c)
build_norm_layer
- 功能:构建归一化层,可以选择
Batch Norm或者Layer Norm
def build_norm_layer(dim,
norm_layer,
in_format='channels_last',
out_format='channels_last',
eps=1e-6):
layers = []
if norm_layer == 'BN':
if in_format == 'channels_last':
layers.append(to_channels_first())
layers.append(nn.BatchNorm2d(dim))
if out_format == 'channels_last':
layers.append(to_channels_last())
elif norm_layer == 'LN':
if in_format == 'channels_first':
layers.append(to_channels_last()) # (b,c,h,w)->(b,h,w,c)
layers.append(nn.LayerNorm(dim, eps=eps))
if out_format == 'channels_first':
layers.append(to_channels_first())
else:
raise NotImplementedError(
f'build_norm_layer does not support {
norm_layer}')
return nn.Sequential(*layers)
build_act_layer
- 功能:构建激活函数层,可选择
RELU / SiLU / GELU激活函数
def build_act_layer(act_layer):
if act_layer == 'ReLU':
return nn.ReLU(inplace=True)
elif act_layer == 'SiLU':
return nn.SiLU(inplace=True)
elif act_layer == 'GELU':
return nn.GELU()
raise NotImplementedError(f'build_act_layer does not support {
act_layer}')
_is_power_of_2
- 功能:检查n是否是2的某次方,且n不为0
如果n & (n - 1)为0,则说明n是2的某次方。
def _is_power_of_2(n):
if (not isinstance(n, int)) or (n < 0): # 如果n不为整数或者n小于0
raise ValueError(
"invalid input for _is_power_of_2: {} (type: {})".format(n, type(n)))
return (n & (n - 1) == 0) and n != 0
CenterFeatureScaleModule
- 功能:生成缩放系数。
F.linear的输出取决于传入的实参weight和bias,然后再通过sigmod函数归一化。
class CenterFeatureScaleModule(nn.Module):
def forward(self,
query,
center_feature_scale_proj_weight, # (group,channels)
center_feature_scale_proj_bias):
center_feature_scale = F.linear(query,
weight=center_feature_scale_proj_weight,
bias=center_feature_scale_proj_bias).sigmoid() # 全连接层+sigmod
# F.linear的输出取决于传入的实参weight和bias
# 输入:(*,channels) -> 输出:(*,group)
return center_feature_scale
DCNv3_pytorch
class DCNv3_pytorch 是分组可变形卷积DCNv3的pytorch的实现版。
'''分组可变形卷积 pytorch实现版'''
class DCNv3_pytorch(nn.Module):
def __init__(
self,
channels=64, # 通道数
kernel_size=3, # 卷积核大小
dw_kernel_size=None, # 深度可分离卷积核大小
stride=1, # 步长
pad=1, # 填充
dilation=1, #空洞率
group=4,# 分组数
offset_scale=1.0,
act_layer='GELU', # 激活函数
norm_layer='LN', # 归一化层
center_feature_scale=False):
super().__init__()
if channels % group != 0: # 分组卷积必须保证通道数可以被组数整除
raise ValueError(
f'channels must be divisible by group, but got {
channels} and {
group}')
_d_per_group = channels // group # 每个组数拥有的通道数
dw_kernel_size = dw_kernel_size if dw_kernel_size is not None else kernel_size # 设置深度可分离卷积核的大小
# 最好把_d_per_group设置为2的某次方,方便cuda的具体实现
if not _is_power_of_2(_d_per_group):
warnings.warn(
"You'd better set channels in DCNv3 to make the dimension of each attention head a power of 2 "
"which is more efficient in our CUDA implementation.")
self.offset_scale = offset_scale
self.channels = channels
self.kernel_size = kernel_size
self.dw_kernel_size = dw_kernel_size
self.stride = stride
self.dilation = dilation
self.pad = pad
self.group = group
self.group_channels =

本文围绕可变形卷积DCNv3展开,介绍其在DCNv2基础上的改进。重点讲解DCNv3的pytorch实现部分,包括dcnv3.py中各函数功能,如通道维度调整、归一化层构建等,还阐述了DCNv3在实现中的三个改进点,同时提及dcnv3_func.py中相关函数。
最低0.47元/天 解锁文章
165





