【YOLO v5 v7 v8小目标改进】SPD-Conv

SPD-Conv

    • 提出背景
      • SPD-Conv
    • YOLO v5 小目标改进
      • 定义 SPD-Conv
      • 导入`SPD`模块
      • 修改 .yaml 文件
    • YOLO v7 小目标改进
    • YOLO v8 小目标改进

 


提出背景

论文:https://arxiv.org/pdf/2208.03641v1.pdf

代码:https://github.com/labsaint/spd-conv

在这里插入图片描述

 
文章提出一个新的卷积神经网络(CNN)构建块,称为SPD-Conv,旨在替代传统CNN架构中的步长卷积和池化层,以提高在处理低分辨率图像和小对象时的性能。

  • 问题: CNN在处理低分辨率图像和小对象时性能下降的问题,指出这一问题根源于使用步长卷积和池化层导致的细粒度信息丢失。

解法:SPD-Conv = SPD层 + 非步长卷积层:

  • 空间到深度(SPD)层: 一个转换层,将输入图像的空间维度转换为深度维度,从而在不丢失信息的情况下增加特征图的深度。

    之所以使用SPD层,是因为在处理低分辨率图像和小对象时,需要保留尽可能多的空间信息。

    SPD层通过将空间维度的信息转换为深度维度,避免了传统步长卷积和池化操作中的信息丢失。

  • 非步长卷积层: 在SPD转换后应用的卷积层,不使用步长,以保留细粒度信息。

    在SPD层之后应用非步长卷积层,是因为非步长卷积能够在不减少特征图尺寸的情况下进行特征提取,进一步保持了图像的细粒度信息,这对于提高低分辨率图像和小对象的识别性能至关重要。

假设我们有一个低分辨率的图像,其中包含几个小的物体,我们需要对这些物体进行识别和分类。

在传统的CNN架构中,如果我们直接应用步长卷积和池化层,随着网络层次的加深,图像的空间分辨率会逐渐减少,导致小物体的细节信息丢失,从而使得网络难以准确识别这些小物体。

使用 SPD-Conv 代替 步长卷积和池化层:

  1. 空间到深度(SPD)层的应用:

    • 初始特征图尺寸为 ( 32 × 32 ) (32 \times 32) (32×32),包含小物体的细节信息。
    • 应用SPD层后,假设将空间分辨率降低为 ( 16 × 16 ) (16 \times 16) (16×16),同时将这部分减少的空间信息转移到通道维度上,从而通道数增加但没有信息丢失。
    • 这样,原本在 ( 32 × 32 ) (32 \times 32) (32×32) 分辨率上分散的细节信息,现在被压缩和保留在更深的通道中。
  2. 非步长卷积层的应用:

    • 经过SPD层处理后,特征图的尺寸变为 ( 16 × 16 ) (16 \times 16) (16×16),但通道数增加,假设从原来的64通道增加到128通道。
    • 在这个增加通道数的特征图上应用非步长卷积层,这个卷积层不减少特征图的空间尺寸,而是通过学习这些增加的通道中的信息来提取重要特征。
    • 这样,即使是在较小的空间分辨率上,模型也能有效捕捉到小物体的细节信息。

这种结合使用SPD层和非步长卷积层的方法,使得CNN能够更好地处理小物体和低分辨率图像中的挑战,提高了模型在这些复杂场景下的性能和鲁棒性。

SPD-Conv

在这里插入图片描述
当尺度为2时的SPD-Conv图

  • (a)显示了标准的特征图
  • (b)展示了空间到深度操作,其中空间信息被重新排列到深度通道
  • (c)显示了结果特征图的深度增加
  • (d)表示在SPD操作之后应用的非步长卷积层
  • (e)展示了经过步长为1的卷积后的输出特征图,该特征图保持了空间分辨率但改变了深度维度

 

  1. 空间到深度(SPD)层 - 特征图切片阶段:

    • 从中间特征图 ( X ) 开始,大小为 S × S × C 1 S \times S \times C_1 S×S×C1
    • 使用 scale 因子进行下采样,将 ( X ) 划分为 scale 2 \text{scale}^2 scale2 个子特征图 f x , y f_{x,y} fx,y。每个子特征图是 ( X ) 的一部分,其中 X ( i , j ) X(i, j) X(i,j) 中的索引 ( i ) 和 ( j ) 被 scale 整除。
    • 这个阶段通过降低特征图的空间分辨率来增加特征图的深度(通道数)。
  2. 子图串联阶段:

    • 这些子特征图沿通道维度合并,形成新的特征图 X 0 X_0 X0
    • X 0 X_0 X0 的空间维度是原来的 1 scale \frac{1}{\text{scale}} scale1,但通道维度增加了 scale 2 \text{scale}^2 scale2 倍。
    • 这一阶段保持了原始特征图 ( X ) 中的全部信息,即使其空间分辨率减小。
  3. 非步长卷积层阶段:

    • 接着对 X 0 X_0 X0 应用步长为1的卷积层,这意味着特征图的每个像素都会被卷积核覆盖,没有信息被跳过。
    • 使用的过滤器数量 C 2 C_2 C2 少于 X 0 X_0 X0 的通道数 scale 2 C 1 \text{scale}^2 C_1 scale2C1,目的是提取重要的特征并降低通道维度。
    • 结果得到特征图 X 00 X_{00} X00,其空间维度保持不变,但通道维度减少到 $C_2$。

假设我们有一个中间特征图 ( X ) 的大小为 8 × 8 × 3 8 \times 8 \times 3 8×8×3(宽、高、通道),scale 设定为2。

  1. 特征图切片(SPD层之前) - 我们将 ( X ) 切分为四个 4 × 4 × 3 4 \times 4 \times 3 4×4×3 的子特征图 f 0 , 0 , f 1 , 0 , f 0 , 1 , f 1 , 1 f_{0,0}, f_{1,0}, f_{0,1}, f_{1,1} f0,0,f1,0,f0,1,f1,1

  2. 子图串联(SPD层) - 然后将这四个 4 × 4 × 3 4 \times 4 \times 3 4×4×3 的子特征图沿通道维度合并,形成一个新的特征图 X 0 X_0 X0 的大小为 4 × 4 × 12 4 \times 4 \times 12 4×4×12

  3. 非步长卷积(非步长卷积层) - 在 X 0 X_0 X0 上应用步长为1的卷积层,假设使用8个过滤器,则最终输出特征图 KaTeX parse error: Expected '}', got 'EOF' at end of input: X_{00 的大小为 4 × 4 × 8 4 \times 4 \times 8 4×4×8

通过这个链条,原始的特征图 ( X ) 经过一系列变换后,空间分辨率降低,但通道数增加并在非步长卷积后得到更有判别性的特征表示。

这种方法尤其适用于小对象检测和低分辨率图像分类,因为它通过增加通道深度来保留更多的信息,而非过减少像素点数来损失信息。

YOLO v5 SPD-Conv版:
在这里插入图片描述

  • 红色框标出的部分是使用SPD-Conv构建块替换了原有步长为2的卷积层的位置。
  • 结构被分为三个主要部分:骨干网络(Backbone)、颈部网络(Neck)和检测头(Head)。
  • 骨干网络负责特征提取,颈部网络用于特征融合和处理,头部网络执行对象的分类和定位。

 
YOLOv5-SPD通过用SPD-Conv构建块替换YOLOv5中的步长为2的卷积层:

  • SPD层替换: 在YOLOv5和ResNet中,将所有步长为2的卷积层替换为SPD-Conv构建块,因为这些步长卷积层导致特征图下采样,可能会丢失低分辨率图像和小尺寸物体的重要信息。
  • 池化层移除: 对于低分辨率图像,移除最大池化层是合理的,因为在这些情况下,下采样可能不是必要的,且进一步的下采样可能导致更多信息的丢失。
  • 可伸缩性设计: 通过调整非步长卷积层中的滤波器数量和C3模块的重复次数,可以根据需要轻松地放大或缩小模型,这是为了满足不同应用或硬件的需求。

在这里插入图片描述
YOLOv5-SPD-m能够检测到YOLOv5m漏检的被遮挡的长颈鹿。

在这里插入图片描述

)进一步展示了YOLOv5-SPD-m在检测非常小的对象(一个面孔和两个长凳)方面的能力,而YOLOv5m则未能检测到这些对象。

YOLO v5 小目标改进

改好的代码:https://github.com/labsaint/spd-conv

也可以自己调一下,有时候我们还得组合改进。

YOLO v5:https://github.com/ultralytics/yolov5

  1. 定义SPD模块:确保你已经在models/common.py中定义了SPD`类。

  2. 导入SPD模块:在yolo.py的顶部导入SPD类。

    from models.common import SPD
    
  3. 修改parse_model函数:在parse_model函数中处理SPD模块的情况。

    找到parse_model函数,并在其中添加处理SPD的逻辑。

    例如,如果你的模型配置文件中有指示使用SPD的地方,你需要检测它并相应地构造模块。

  4. 更新模型配置文件:你可能需要在YOLOv5的模型配置文件(通常是.yaml格式)中指明哪些卷积层应该被SPD替换。

    例如,你可能会在配置文件中添加一个新的模块类型- SPD

  5. 替换卷积层:在parse_model中添加逻辑,以便在解析模型时用SPD`模块替换步长为2的卷积层。

定义 SPD-Conv

yolov5/models/common.py 添加 SPD-Conv 代码

import torch
import torch.nn as nn

class SPD(nn.Module):   # SPD 层
    """
    这个模块实现了空间到深度的操作,它重新排列空间数据块到深度维度,
    通过块大小增加通道数并减少空间维度。在卷积神经网络中常用此方法保持
    下采样图像的高分辨率信息。
    """
    def __init__(self, block_size=2):
        """
        初始化 SPD 模块。
        
        参数:
            block_size (int): 每个块的大小。它定义了空间维度的下采样因子。
                              输出通道的数量将增加 block_size**2 倍。
        """
        super(SPD, self).__init__()
        self.block_size = block_size  # 块大小

    def forward(self, x):
        """
        在输入张量上应用空间到深度操作。
        
        参数:
            x (torch.Tensor): 形状为 (N, C, H, W) 的输入张量。
        
        返回:
            torch.Tensor: 重新排列块后的输出张量。如果块大小为 2,
                          输出张量的形状将为 (N, C*4, H/2, W/2)。
        """
        N, C, H, W = x.size()  # 输入张量的维度
        block_size = self.block_size  # 块大小

        # 确保高度和宽度可以被 block_size 整除
        assert H % block_size == 0 and W % block_size == 0, \
            f"空间维度必须能被 block_size 整除。得到的 H: {H}, W: {W}"

        # 将空间块重新排列到深度
        x_reshaped = x.view(N, C, H // block_size, block_size, W // block_size, block_size)
        x_permuted = x_reshaped.permute(0, 3, 5, 1, 2, 4).contiguous()
        out = x_permuted.view(N, C * block_size**2, H // block_size, W // block_size)
        return out

在 YOLOv5 的项目结构中,yolov5/models/common.py 通常包含定义模型中使用的通用层和模块的 Python 代码。

这个文件是模型架构的一部分,它定义了可以在模型的不同部分重复使用的层,比如卷积层、上采样层、激活函数等。

例如,在 YOLOv5 的实现中,common.py 可能包含以下内容:

  • 自定义卷积层类(有时为了特殊的初始化或行为)
  • 激活函数(如 Mish 激活函数)
  • 层组合(如 CSP 结构)
  • SPP (Spatial Pyramid Pooling) 结构
  • Focus 层(一种特殊的切片和重排层,用于改变输入特征图的空间分辨率)

在模型定义文件中(如 yolov5/models/yolov5s.py),这些通用层会被实例化并组合成完整的神经网络。

这种模块化的方法可以让代码更加整洁,并且可以更容易地在不同的模型配置文件中重复使用相同的层定义。

导入SPD模块

yolo.py的顶部导入SPD类。

   from models.common import SPD

parse_model中实现更改:

在这里插入图片描述

elif m is SPD:
	c2 = 4 * ch[f]    
	# 将输入通道数 ch[f] 增加了四倍
	# 4 是基于 SPD 的 block_size 为 2 的假设。如果 block_size 有所不同,这个数字应该是 block_size 的平方
	# ch 是一个包含前面所有层输出通道数的列表,f 是指向前面某层的索引

修改 .yaml 文件

在 YOLOv5 的项目中,.yaml 文件通常用来定义模型的架构。

yaml 文件分为:

  • 参数部分:nc(数据集类别数量)、
  • 网络结构部分:from(从哪层获取输入), repeats(模块重复次数), module(模块名字), args
  • 头部部分

文件名中的 yolov5s, yolov5m, yolov5l, yolov5x 等分别代表了不同大小和复杂性的模型配置:

  1. yolov5s.yaml - “s” 代表 “small”(小)。

    这是 YOLOv5 系列中最小的模型,拥有最少的层数和参数,适用于速度要求较高或计算资源有限的环境。

  2. yolov5m.yaml - “m” 代表 “medium”(中等)。

    这个配置是介于小型和大型模型之间的中等大小的模型,它在速度和准确性之间提供了一个平衡。

  3. yolov5l.yaml - “l” 代表 “large”(大)。

    这个配置用于更大的模型,它具有更多的层数和参数,通常能够提供更高的准确性,但需要更多的计算资源。

  4. yolov5x.yaml - “x” 代表 “extra large”(特大)。

    这是 YOLOv5 系列中最大的模型,有最多的层数和参数,通常在准确性方面表现最好,但也是计算成本最高的。

  5. yolov5n.yaml - “n” 代表 “nano”(纳米)。

    这是一个非常小的模型,旨在在非常资源有限的设备上运行,比如在边缘计算设备或移动设备上。

这些文件中定义的参数包括了模型的层数、每一层的类型(如卷积层、上采样层等)、每一层的参数(如滤波器数量、步长、激活函数等),以及如何将这些层连接起来。

用户可以根据自己的需求和资源选择合适的模型大小。

例如,如果你需要在移动设备上进行实时物体检测,可能会选择 yolov5syolov5n;如果你在服务器上进行高准确性的物体检测并且不太关心推理时间,可能会选择 yolov5lyolov5x

我们选第一个:yolov5S.yaml

修改 backbone 部分:在 backbone 配置中,找到所有步长为2的 Conv 层。

例如,[-1, 1, Conv, [128, 3, 2]] 表示一个从上一个层(-1 表示上一层)接收输入的卷积层,具有128个输出通道,使用3x3的卷积核,步长为2。

backbone:
  # [from, number, module, args]
  [
    [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
    [-1, 1, SPD, [1]],    # 1-P2/4 replaced Conv with SPD
    [-1, 3, C3, [128]],            # 2
    [-1, 1, SPD, [1]],    # 3-P3/8 replaced Conv with SPD
    # ... [continue with other layers] ...
  ]

SPD 不需要像 Conv 那样指定过滤器的数量和大小,因为它是一个重新排列输入的操作,而不是学习过滤器权重的操作。

参数 [1] 可以表示 block_size,如果SPD 实现时接受这个参数的话。

调整后续层的通道数:由于 SPD 操作会增加通道数,你可能需要调整后续层以匹配新的通道数。这可能包括更改后面的 C3 层的通道数。

总结,YOLO v5 修改三步:

  • 把 XXX模块 放入 common.py
  • yolo.py 放入类名
  • 修改 yolov5.yaml

YOLO v7 小目标改进

https://github.com/WongKinYiu/yolov7

逻辑同上。

YOLO v8 小目标改进

在 v8 文件夹下新建一个 xxx.yaml

SPD-Conv 代码添加到 ultralytics 文件中:

  • 在 block.py 的 all = {各种模块},把 SPD 代码函数名字添加进来
  • 在 block.py 下面添加 SPD 代码
  • 在 modules/init.py 中 from .block import (各种模块),把 SPD 代码函数名字添加进来
  • 在 task.py 中 from ultralyics.nm.modules import (各种模块),把 SPD 代码函数名字添加进来

SPD-Conv 函数名字加入到 ultralytics/nn/tasks.py 中;

修改 xxx.yaml ,用 SPD 构建 SPD-Conv 主干网络 ;

修改 ultralytics/yolo/cfg/default.yaml 文件的 ‘–model’ 参数,或使用指令训练。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法刷题训练营day23

代码随想录算法刷题训练营day23:LeetCode(669)修剪二叉搜索树、LeetCode(108)将有序数组转换为二叉搜索树、LeetCode(538)把二叉树转化为累加树 LeetCode(669)修剪二叉搜索树 题目 代码 /*** Definition for a binary tree node.* public class TreeNode {* …

数据安全之路:深入了解MySQL的行锁与表锁机制

欢迎来到我的博客,代码的世界里,每一行都是一个故事 数据安全之路:深入了解MySQL的行锁与表锁机制 前言基础innodb中锁与索引的关系如何避免表锁 前言 在当今数据密集的应用中,数据库锁成为了确保数据一致性和并发操作的关键工具…

Linux字符设备驱动中同类型多设备节点的创建---一个驱动程序支持多个同类型设备

文章目录 前言1 代码解析1.1 驱动层1.2 应用层 2 运行结果总结 前言 本期分享的内容相对比较简单,那就是同时注册多个同类型的字符设备驱动,那么这样我们就可以同时支持多个同类型的设备了!下面来带大家看一下: 1 代码解析 1.1 …

【Flink精讲】Flink性能调优:内存调优

内存调优 内存模型 JVM 特定内存 JVM 本身使用的内存,包含 JVM 的 metaspace 和 over-head 1) JVM metaspace: JVM 元空间 taskmanager.memory.jvm-metaspace.size,默认 256mb 2) JVM over-head 执行开销&#xff1…

深入探讨基于大语言模型的数据标注

文章地址: https://arxiv.org/pdf/2402.13446 数据标注是将原始数据用相关信息进行标注,对于提高机器学习模型的效果至关重要。然而,这一过程往往需要大量人力和资金支持。先进大语言模型(LLMs)的出现,例如…

小程序--事件处理

一、事件对象 给小程序的事件传递参数&#xff0c;有以下两种方法&#xff1a; 1、自定义属性 <view class"item" wx:for"{{ 5 }}" wx:key"*this" data-index"{{index}}" bind:tap"onClick"></view> Page({o…

spss常用检验方法

spss常用检验方法 1 数据是否符合正态分布1.1符合正态分布1.1.1怎样的数据符合正态分布1.1.2 spss怎么统计正态分布1.1.3 方差齐性检验1.1.4 具体统计学分析 1.2 不符合正态分布1.2.1 Mann-Whitney U检验1.2.2 Wilcoxon符号秩检验1.2.3 Kruskal-Wallis H检验1.2.4 Friedman检验…

CCF-CSP: 因子化简(100分)

第一次提交的时候90分&#xff0c;显示的超时&#xff0c;第一反应是难道有死循环? 检查一遍发现并没有&#xff0c;那就是真的超时了&#xff0c;然后翻阅blog,发现不需要去做判断是否是素数这一步&#xff0c;原因是任意一个非素数都是素数乘积构成&#xff0c;比如说&#…

提高移动应用的安全性:策略与实践

提高移动应用的安全性&#xff1a;策略与实践 随着移动应用的普及&#xff0c;安全性问题变得日益重要。用户数据保护、应用逻辑安全、以及防止恶意攻击都是开发者必须关注的重点。本文将探讨如何通过一系列策略和实践来提高移动应用的安全性。 1. 数据加密与保护 敏感数据加…

ABAP - Function ALV 05 添加选择框列、全选、取消全选

很多用户不习惯原生GRID的选择模式&#xff0c;所以业务需要用到自定义的选择框来进行数据的操作&#xff0c;显示效果如图所示&#xff0c;增加一条选择列&#xff0c;且配置全选和全选全选的按钮功能&#xff0c;如下图所示。 实现这种功能需要用到Fieldcat的参数控制以及GUI…

c#高级-正则表达式

正则表达式是由普通字符和元字符&#xff08;特殊符号&#xff09;组成的文字形式 应用场景 1.用于验证输入的邮箱是否合法。 2.用于验证输入的电话号码是否合法。 3.用于验证输入的身份证号码是否合法。等等 正则表达式常用的限定符总结&#xff1a; 几种常用的正则简写表达式…

力扣--动态规划1027.最长等差数列

思路分析&#xff1a; 使用动态规划的思想&#xff0c;定义二维数组dp&#xff0c;其中dp[i][j]表示以nums[i]为结尾&#xff0c;公差为(j-1000)的等差数列长度。为了适应负数的情况&#xff0c;将公差的范围设为[-1000, 1000]&#xff0c;并且加上1000作为数组索引。 初始化r…

javaApI(Application Programming Interface)应用程序编程接口

ApI概念 Apl:指的是官方给开发人员提供的说明文档&#xff0c;对语言中有哪些类&#xff0c;类中有哪些方法进行说明 Objict 类 java.lang.Object 是java类体系结构中最顶层的类 Object可以表示java中任意的类 Object类中的方法 toString() 输出一个对象&#xff0c;但是…

Python服务器监测测试策略与工具:确保应用的高可用性!

在构建高可用性的应用程序时&#xff0c;服务器监测测试是至关重要的一环。Python作为一种强大的编程语言&#xff0c;提供了丰富的工具和库来帮助我们进行服务器监测测试。本文将介绍一些关键的策略和工具&#xff0c;帮助你确保应用的高可用性。 1. 监测策略的制定&#xff…

matlab|基于DistFlow潮流的配电网故障重构(输入任意线路)

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 程序采用适用于辐射状网络的DistFlow潮流模型&#xff0c;可输入任意故障线路编号&#xff0c;得到优化重构结果。这个程序是配电网故障重构可视化matlabyalmip的升级版&#xff0c;原来的程序是以电压质量作…

介绍 PIL+IPython.display+mtcnn for 音视频读取、标注

1. nn.NLLLoss是如何计算误差的? nn.NLLLoss是负对数似然损失函数&#xff0c;用于多分类问题中。它的计算方式如下&#xff1a;首先&#xff0c;对于每个样本&#xff0c;我们需要将其预测结果通过softmax函数转换为概率分布。softmax函数可以将一个向量映射为一个概率分布&…

第四套CCF信息学奥赛c++ CSP-J认证初级组 中小学信奥赛入门组初赛考前模拟冲刺题(阅读程序题)

第四套中小学信息学奥赛CSP-J考前冲刺题 二、阅读程序题 (程序输入不超过数组或字符串定义的范围&#xff0c;判断题正确填√错误填X;除特殊说明外&#xff0c;判断题 1.5分&#xff0c;选择题3分&#xff0c;共计40分) 第一题 归并排序 1 #include <iostream> 2 usi…

【Java程序设计】【C00285】基于Springboot的游戏分享网站(有论文)

基于Springboot的游戏分享网站&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的游戏分享网站 本系统分为系统功能模块、管理员功能模块以及用户功能模块。 系统功能模块&#xff1a;在网站首页可以查看首页、游戏…

Linux环境基础开发工具使用篇(三) git 与 gdb

一、版本控制器-git 1.简单理解: ①git既是服务端&#xff0c;又是客户端 ②git会记录版本的变化 ③git是一个去中心化的分布式软件 git/gitee 是基于git仓库搭建的网站&#xff0c;让版本管理可视化 2.git 三板斧提交代码 查看安装的git版本 git--version 命令行提交代…

SpringMVC 学习(四)之获取请求参数

目录 1 通过 HttpServletRequest 获取请求参数 2 通过控制器方法的形参获取请求参数 3 通过 POJO 获取请求参数&#xff08;重点&#xff09; 1 通过 HttpServletRequest 获取请求参数 public String handler1(HttpServletRequest request) <form action"${pageCont…