1.SPD-Conv简介
摘要:卷积神经网络(CNN)在许多计算机视觉任务中取得了显著的成功,例如图像分类和目标检测。然而,它们的性能在图像分辨率低或对象较小的更艰难任务中会急剧下降。在本文中,我们指出这一问题源于现有CNN架构中一个有缺陷但常见的设计,即使用步长卷积和/或池化层,这导致了细微信息的丢失和较少有效特征表示的学习。为此,我们提出了一个新的CNN构建模块称为
SPD-Conv,用来替换每个步长卷转层和每个池化层(从而完全消除它们)
。SPD-Conv由一个空间到深度(SPD)层和一个非步长卷积(Conv)层组成,可以应用于大部分(如果不是全部的话)CNN架构。我们在两个最有代表性的计算机视觉任务下解释了这种新设计:目标检测和图像分类。然后,我们通过将SPD-Conv应用于YOLOv5和ResNet创建了新的CNN架构,并通过实验证明,我们的方法显著优于最先进的深度学习模型,尤其是在图像分辨率低和对象较小的更艰难任务上。
论文主要亮点如下:
- 我们发现了现有CNN架构中一个有缺陷但常见的设计,并提出了一种新的构建模块,称为SPD-Conv,以取代旧的设计。SPD-Conv在不丢失可学习信息的情况下下采样特征图,彻底抛弃了如今广泛使用的带步长的卷积和池化操作。
- SPD-Conv代表一种通用且统一的方法,可以很容易地应用于大部分(如果不是全部的话)基于深度学习的计算机视觉任务。
- 使用两个最具代表性的计算机视觉任务,目标检测和图像分类,来评估SPD-Conv的性能。具体来说,我们构建了YOLOv5-SPD、ResNet18-SPD和ResNet50-SPD,并在COCO-2017、Tiny ImageNet和CIFAR-10数据集上与几种最先进的深度学习模型进行了比较。结果显示在AP和top-1精度上都有显著的性能提升,特别是在小物体和低分辨率图像上。
1.1 网络结构
1.2 性能对比
2.YOLOv8添加SPD-Conv
YOLOv8网络结构前后对比
定义FasterNet相关类
在ultralytics/nn/modules/block.py
中添加如下代码块,为space_to_depth
模块代码:
并在ultralytics/nn/modules/block.py
中最上方添加如下代码:
修改指定文件
在ultralytics/nn/modules/__init__.py
文件中的添加如下代码:
在 ultralytics/nn/tasks.py
上方导入相应类名,并在parse_model
解析函数中添加如下代码:
elif m is space_to_depth: c2 = 4 * ch[f]
在ultralytics/cfg/models/v8
文件夹下新建yolov8-FasterNet.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 s: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPs m: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPs l: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs x: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs # YOLOv8.0n backbone backbone: # [from, repeats, module, args] - [-1, 1, Conv, [64, 3, 1]] # 0-P1/2 - [-1, 1, Conv, [128, 3, 1]] # 1-P2/4 - [-1, 1, space_to_depth, [1]] # 2 -P2/4 - [-1, 3, C2f, [128, True]] - [-1, 1, Conv, [256, 3, 1]] # 4-P3/8 - [-1, 1, space_to_depth, [1]] - [-1, 6, C2f, [256, True]] - [-1, 1, Conv, [512, 3, 1]] # 7-P4/16 - [-1, 1, space_to_depth, [1]] - [-1, 6, C2f, [512, True]] - [-1, 1, Conv, [1024, 3, 1]] # 10-P5/32 - [-1, 1, space_to_depth, [1]] - [-1, 3, C2f, [1024, True]] - [-1, 1, SPPF, [1024, 5]] # 13 # YOLOv8.0n head head: - [-1, 1, nn.Upsample, [None, 2, 'nearest']] - [[-1, 8], 1, Concat, [1]] # cat backbone P4 - [-1, 3, C2f, [512]] # 16 - [-1, 1, nn.Upsample, [None, 2, 'nearest']] - [[-1, 5], 1, Concat, [1]] # cat backbone P3 - [-1, 3, C2f, [256]] # 19 (P3/8-small) - [-1, 1, Conv, [256, 3, 1]] - [-1, 1, space_to_depth, [1]] - [[-1, 16], 1, Concat, [1]] # cat head P4 - [-1, 3, C2f, [512]] # 23 (P4/16-medium) - [-1, 1, Conv, [512, 3, 1]] - [-1, 1, space_to_depth, [1]] - [[-1, 13], 1, Concat, [1]] # cat head P5 - [-1, 3, C2f, [1024]] # 27 (P5/32-large) - [ [ 19, 23, 27 ], 1, Detect, [ nc ] ] # Detect(P3, P4, P5)
3.加载配置文件并训练
加载yolov8-BiLevelRoutingAttention.yaml
配置文件,并运行train.py
训练代码:
#coding:utf-8 from ultralytics import YOLO if __name__ == '__main__': model = YOLO('ultralytics/cfg/models/v8/yolov8-SPD-Conv.yaml') model.load('yolov8n.pt') # loading pretrain weights model.train(data='datasets/TomatoData/data.yaml', epochs=50, batch=4)
注意观察,打印出的网络结构是否正常修改,如下图所示:
4.模型推理
模型训练完成后,我们使用训练好的模型对图片进行检测:
#coding:utf-8 from ultralytics import YOLO import cv2 # 所需加载的模型目录 # path = 'models/best2.pt' path = 'runs/detect/train/weights/best.pt' # 需要检测的图片地址 img_path = "TestFiles/Riped tomato_8.jpeg" # 加载预训练模型 # conf 0.25 object confidence threshold for detection # iou 0.7 intersection over union (IoU) threshold for NMS model = YOLO(path, task='detect') # 检测图片 results = model(img_path) res = results[0].plot() # res = cv2.resize(res,dsize=None,fx=2,fy=2,interpolation=cv2.INTER_LINEAR) cv2.imshow("YOLOv8 Detection", res) cv2.waitKey(0)