💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡
轻量级卷积神经网络由于其低计算预算限制了CNNs的深度(卷积层数)和宽度(通道数),导致了性能下降和表示能力受限的问题。而动态卷积恰好能解决这一问题,这是一种增加模型复杂性而不增加网络深度或宽度的新设计。本文给大家带来的教程是将YOLOv8的Conv用Dynamic_conv替换来提取特征。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。此外还增加了进阶模块,来提高学有能力的同学进一步增长知识。帮助您更好地学习深度学习目标检测YOLO系列的挑战。
专栏地址:YOLOv8改进——更新各种有效涨点方法——点击即可跳转
1. 原理
动态卷积的是基于注意力机制的,它允许网络动态地选择和组合多个卷积核,以适应输入数据的不同部分或特征。
- 多个卷积核的选择:
在传统的卷积操作中,每个卷积层通常使用固定的卷积核。而在动态卷积中,会事先定义一组多个卷积核,这些卷积核可能具有不同的大小和形状。
- 注意力机制:
动态卷积通过引入注意力机制来决定在每个位置使用哪些卷积核。这个注意力可以根据输入数据的不同部分或特征动态地调整,以使网络能够更好地捕捉输入数据的相关信息。
- 卷积核的组合:
根据注意力机制的输出,动态卷积会动态地选择并组合多个卷积核。这种组合可以通过加权求和的方式进行,其中每个卷积核的权重由注意力机制确定。
- 非线性激活:
组合后的卷积核将应用于输入数据,并通过非线性激活函数(如ReLU)产生输出特征图。
- 网络训练:
在训练过程中,网络将根据损失函数反向传播并更新注意力机制的参数,以使网络能够学习到适合任务的最佳注意力分配方式。
总的来说,动态卷积通过引入注意力机制和动态地选择和组合多个卷积核,使网络能够更灵活地适应输入数据的不同部分或特征,从而提高网络的表征能力和性能。
YOLOv8 | 卷积模块 | 提高网络的灵活性和表征能力的动态卷积【附代码+小白可上手】——完整代码点击即可跳转
2. 代码实现
2.1 将代码添加到YOLOv8中
关键步骤一:将下面代码粘贴到在/ultralytics/ultralytics/nn/modules/conv.py中,并在该文件的all中添加“Dynamic_conv2d”
import torch
import torch.nn as nn
import torch.nn.functional as F
class attention2d(nn.Module):
def __init__(self, in_planes, ratios, K, temperature, init_weight=True):
super(attention2d, self).__init__()
assert temperature%3==1
self.avgpool = nn.AdaptiveAvgPool2d(1)
if in_planes!=3:
hidden_planes = int(in_planes*ratios)
else:
hidden_planes = K
self.fc1 = nn.Conv2d(in_planes, hidden_planes, 1, bias=False)
self.fc2 = nn.Conv2d(hidden_planes, K, 1, bias=False)
self.temperature = temperature
if init_weight:
self._initialize_weights()
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
if m.bias is not None:
nn.init.constant_(m.bias, 0)
def updata_temperature(self):
if self.temperature!=1:
self.temperature -=3
print('Change temperature to:', str(self.temperature))
def forward(self, x):
x = self.avgpool(x)
x = self.fc1(x)
x = F.relu(x)
x = self.fc2(x).view(x.size(0), -1)
return F.softmax(x/self.temperature, 1)
class Dynamic_conv2d(nn.Module):
def __init__(self, in_planes, out_planes, kernel_size, ratio=0.25, stride=1, padding=0, dilation=1, groups=1, bias=True, K=4,temperature=34, init_weight=True):
super(Dynamic_conv2d, self).__init__()
assert in_planes%groups==0
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.bias = bias
self.K = K
self.attention = attention2d(in_planes, ratio, K, temperature)
self.weight = nn.Parameter(torch.Tensor(K, out_planes, in_planes//groups, kernel_size, kernel_size), requires_grad=True)
if bias:
self.bias = nn.Parameter(torch.Tensor(K, out_planes))
else:
self.bias = None
if init_weight:
self._initialize_weights()
#TODO 初始化
def _initialize_weights(self):
for i in range(self.K):
nn.init.kaiming_uniform_(self.weight[i])
def update_temperature(self):
2.2 更改init.py文件
然后在下面的all中声明函数
2.3 在task.py中进行注册
2.4 添加yaml文件
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
# [depth, width, max_channels]
n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers, 3157200 parameters, 3157184 gradients, 8.9 GFLOPs
# YOLOv8.0n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f, [512, True]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f, [1024, True]]
- [-1, 1, SPPF, [1024, 5]] # 9
# YOLOv8.0n head
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 12
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 15 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 18 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [1024]] # 21 (P5/32-large)
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
温馨提示:因为本文只是对yolov8n基础上添加模块,如果要对yolov8n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。或者指定某个模型即可
# YOLOv8n
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple
# YOLOv8s
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
# YOLOv8l
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
# YOLOv8m
depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple
# YOLOv8x
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
2.5 执行程序
from ultralytics import YOLO
# Load a model
# model = YOLO('yolov8n.yaml') # build a new model from YAML
# model = YOLO('yolov8n.pt') # load a pretrained model (recommended for training)
model = YOLO(r'/projects/ultralytics/ultralytics/cfg/models/v8/yolov8_dynamic.yaml') # build from YAML and transfer weights
# Train the model
model.train(device = [2], batch=16)
建议大家写绝对路径,确保一定能找到
🚀运行程序,如果出现下面的内容则说明添加成功🚀
3. 完整代码分享
YOLOv8 | 卷积模块 | 提高网络的灵活性和表征能力的动态卷积【附代码+小白可上手】——完整代码点击即可跳转
提取码: ypir
4. 进阶
如果想计算量变化更小,如何修改呢,看过我的修改你是否学会了呢?不如动手试试吧
如果你想尝试但又不知从何下手,可以在评论区问问大家,我看到后也会及时回复
5. 总结
动态卷积是一种通过引入注意力机制,动态选择和组合多个卷积核的方法,以提高卷积神经网络的表征能力和性能。通过在每个位置上根据输入数据的不同部分或特征动态调整卷积核的选择和权重,动态卷积能够更灵活地捕获输入数据的相关信息,并产生更具表征能力的特征表示。在训练过程中,网络通过反向传播算法优化注意力机制的参数,并更新卷积核的参数,从而学习到适合任务的最佳注意力分配方式和特征表示,进而提高了网络的性能,优化图像分类或目标检测的准确率。