【YOLOv8改进】 ODConv(Omni-Dimensional Dynamic Convolution):全维度动态卷积
摘要
在现代卷积神经网络(CNN)中,每个卷积层中学习单个静态卷积核是常见的训练范式。然而,最近在动态卷积的研究中表明,通过学习 n 个卷积核的线性组合,并且这些卷积核的权重取决于它们的输入相关注意力,可以显著提高轻量级 CNN 的准确性,同时保持高效的推理。但是,我们观察到,现有的工作通过一个维度(关于卷积核数量)赋予卷积核动态属性,但另外三个维度(关于每个卷积核的空间大小、输入通道数和输出通道数)被忽略了。受此启发,我们提出了全方位动态卷积(ODConv),这是一种更通用且优雅的动态卷积设计,以推进这一研究方向。ODConv 利用一种新颖的多维注意力机制和并行策略,在任何卷积层的卷积核空间的所有四个维度上学习卷积核的互补注意力。作为常规卷积的替代品,ODConv 可以插入许多 CNN 架构中。在 ImageNet 和 MS-COCO 数据集上的广泛实验表明,ODConv 为各种主流的 CNN 骨干网络带来了稳固的准确性提升,包括轻量级和大型网络,例如,在 ImageNet 数据集上为 MobileNetV2|ResNet 系列带来了 3.77%∼5.71%|1.86%∼3.72% 的绝对 top-1 改进。有趣的是,由于其改进的特征学习能力,即使只有一个卷积核的 ODConv 也可以与现有的多核动态卷积对应物相竞争或胜过它们,大大减少了额外的参数。此外,ODConv 也优于其他注意力模块,用于调节输出特征或卷积权重。
YOLO目标检测创新改进与实战案例专栏
专栏目录: YOLO有效改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例
专栏链接: YOLO基础解析+创新改进+实战案例
创新点
ODConv是一种更通用但更优雅的动态卷积设计,它利用一种新颖的多维注意力机制和并行策略来学习卷积核的补充注意力,这些注意力涉及卷积核空间在任何卷积层的所有四个维度(即每个卷积核的空间大小、输入通道数、输出通道数和卷积核数量)。作为常规卷积的直接替代品,ODConv可以嵌入到多种CNN架构中。在ImageNet基准上进行了基础实验,在MS-COCO基准上进行了下游实验。
(a) DyConv(CondConv使用GAP+FC+Sigmoid)与(b) ODConv的示意性比较。与CondConv和DyConv不同,后者为卷积核 $W_{i}$计算单一的注意力标量 $α_{wi}$,ODConv利用一种新颖的多维注意力机制,以并行方式计算 ( W_i ) 在卷积核空间的所有四个维度上的四种类型的注意力 $α_{si}$, $α_{ci}$, $α_{fi}$和 $α_{wi}$。
ODConv中逐步将四种类型的注意力乘以卷积核的示意图。(a) 沿空间维度的位置逐个乘法操作,(b) 沿输入通道维度的通道逐个乘法操作,(c) 沿输出通道维度的滤波器逐个乘法操作,以及 (d) 沿卷积核空间的核维度的核逐个乘法操作。
文章链接
论文地址:论文地址
代码地址:代码地址
yolov8 代码引入
# ODConv2d类继承自nn.Module
class ODConv2d(nn.Module):
def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1,
reduction=0.0625, kernel_num=4):
super(ODConv2d, self).__init__()
self.in_planes = in_planes # 输入通道数
self.out_planes = out_planes # 输出通道数
self.kernel_size = kernel_size # 卷积核尺寸
self.stride = stride # 步长
self.padding = padding # 填充
self.dilation = dilation # 膨胀
self.groups = groups # 分组卷积的组数
self.kernel_num = kernel_num # 核数目,用于核注意力机制
# 初始化注意力模块
self.attention = Attention(in_planes, out_planes, kernel_size, groups=groups,
reduction=reduction, kernel_num=kernel_num)
# 初始化权重参数
self.weight = nn.Parameter(torch.randn(kernel_num, out_planes, in_planes//groups, kernel_size, kernel_size),
requires_grad=True)
self._initialize_weights()
# 根据卷积核尺寸和核数目选择不同的前向传播实现
if self.kernel_size == 1 and self.kernel_num == 1:
self._forward_impl = self._forward_impl_pw1x
else:
self._forward_impl = self._forward_impl_common
def _initialize_weights(self):
# 初始化权重
for i in range(self.kernel_num):
nn.init.kaiming_normal_(self.weight[i], mode='fan_out', nonlinearity='relu')
def update_temperature(self, temperature):
# 更新注意力机制的温度参数,用于调整注意力的强度
self.attention.update_temperature(temperature)
def _forward_impl_common(self, x):
# 通用的前向传播实现,适用于多种注意力机制
channel_attention, filter_attention, spatial_attention, kernel_attention = self.attention(x)
batch_size, in_planes, height, width = x.size()
x = x * channel_attention # 应用通道注意力
x = x.reshape(1, -1, height, width)
# 合并多个注意力权重
aggregate_weight = spatial_attention * kernel_attention * self.weight.unsqueeze(dim=0)
aggregate_weight = torch.sum(aggregate_weight, dim=1).view(
[-1, self.in_planes // self.groups, self.kernel_size, self.kernel_size])
# 执行卷积操作
output = F.conv2d(x, weight=aggregate_weight, bias=None, stride=self.stride, padding=self.padding,
dilation=self.dilation, groups=self.groups * batch_size)
output = output.view(batch_size, self.out_planes, output.size(-2), output.size(-1))
output = output * filter_attention # 应用滤波器注意力
return output
def _forward_impl_pw1x(self, x):
# 点卷积1x1的特殊前向传播实现
channel_attention, filter_attention, spatial_attention, kernel_attention = self.attention(x)
x = x * channel_attention # 应用通道注意力
output = F.conv2d(x, weight=self.weight.squeeze(dim=0), bias=None, stride=self.stride, padding=self.padding,
dilation=self.dilation, groups=self.groups)
output = output * filter_attention # 应用滤波器注意力
return output
def forward(self, x):
# 根据初始化时选择的实现进行前向传播
return self._forward_impl(x)
task与yaml配置
详见:https://blog.csdn.net/shangyanaf/article/details/139389091