YOLOv5改进 | Head | 将yolov5的检测头替换为ASFF_Detect

简介: 本文介绍了为解决目标检测中尺度变化问题而提出的自适应空间特征融合(ASFF)技术。ASFF通过动态调整不同尺度特征的贡献,增强特征一致性,提高检测器性能,尤其适用于多尺度目标检测。文章提供了ASFF的基本原理和实现步骤,并详细说明如何将ASFF集成到YOLOv5的检测头中,提供了相关代码片段。此外,还分享了完整的实现教程链接,便于读者实践学习。

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡

在目标检测中,为了解决尺度变化的问题,通常采用金字塔特征表示。然而,对于基于特征金字塔的单次检测器来说,不同特征尺度之间的不一致性是一个主要限制。为此,研究人员提出了一种新颖的、基于数据的策略,用于金字塔特征融合,称为自适应空间特征融合(ASFF)。它学习了一种方法,用以在空间上过滤冲突信息,从而抑制不一致性,提高了特征的尺度不变性,并且几乎不引入额外的推理开销。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。

专栏地址: YOLOv5改进+入门——持续更新各种有效涨点方法 点击即可跳转

1.原理

image.png

自适应空间特征融合(ASFF)的主要原理旨在解决单次检测器中不同尺度特征的不一致性问题。具体来说,ASFF通过动态调整来自不同尺度特征金字塔层的特征贡献,确保每个检测对象的特征表示是一致且最优的。以下是ASFF的主要原理:

原理概述

  • 多尺度特征的融合:

传统的特征金字塔网络(FPN)在不同尺度上提取特征,但这些特征在空间位置上可能存在不一致性,导致检测效果不佳。

ASFF通过一个自适应融合模块,动态地结合来自不同尺度的特征图,使得每个像素点能够获得来自各个尺度的最优特征表示。

  • 自适应权重学习:

ASFF在训练过程中通过一个轻量级的网络结构(如1x1卷积层)学习自适应权重,这些权重用于加权组合来自不同尺度的特征。

这个学习过程是自适应的,即权重会根据输入图像的特征和目标物体的位置进行调整,从而确保融合后的特征在空间和语义上都是最优的。

  • 特征一致性:

通过自适应权重,ASFF能有效地调节各尺度特征的贡献,解决了特征金字塔中不同层次特征之间的空间位置不一致性问题。

这种融合方式不仅增强了特征的一致性,还提高了检测器对各种尺度目标的响应能力。

  • 具体步骤

1.特征提取:

输入图像通过基础卷积神经网络(如ResNet)提取特征,并通过特征金字塔网络(FPN)生成不同尺度的特征图。

2.权重生成:

对每个尺度的特征图,ASFF使用一个小型网络(如1x1卷积层)生成对应的自适应权重图。

3.特征融合:

将不同尺度的特征图与其对应的权重图逐像素相乘,然后进行加权求和,生成最终的融合特征图。

4.检测输出:

最终的融合特征图输入到检测头中,生成检测结果(如边界框和类别预测)。
优势

性能提升:通过自适应融合不同尺度的特征,ASFF显著提升了检测精度,特别是在复杂场景和多尺度目标检测任务中。

高效性:ASFF在提高性能的同时,保持了较低的计算开销,仅增加了极少的推理时间,适合实时应用。

ASFF的方法通过动态调整特征贡献,确保每个像素点在不同尺度特征上的最优组合,从而提高了单次检测器的整体检测性能。

2. 将ASFF_DETECT代码实现

2.1 ASFF_DETECT添加到YOLOv5中

关键步骤一:将下面代码粘贴到/yolov5-6.1/models/yolo.py文件中

class ASFF_Detect(nn.Module):   #add ASFFV5 layer and Rfb 
    stride = None  # strides computed during build
    onnx_dynamic = False  # ONNX export parameter
    export = False  # export mode

    def __init__(self, nc=80, anchors=(), ch=(), multiplier=0.5,rfb=False,inplace=True):  # detection layer
        super().__init__()
        self.nc = nc  # number of classes
        self.no = nc + 5  # number of outputs per anchor
        self.nl = len(anchors)  # number of detection layers
        self.na = len(anchors[0]) // 2  # number of anchors
        self.grid = [torch.zeros(1)] * self.nl  # init grid
        self.l0_fusion = ASFFV5(level=0, multiplier=multiplier,rfb=rfb)
        self.l1_fusion = ASFFV5(level=1, multiplier=multiplier,rfb=rfb)
        self.l2_fusion = ASFFV5(level=2, multiplier=multiplier,rfb=rfb)
        self.anchor_grid = [torch.zeros(1)] * self.nl  # init anchor grid
        self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2))  # shape(nl,na,2)
        self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch)  # output conv
        self.inplace = inplace  # use in-place ops (e.g. slice assignment)

    def forward(self, x):
        z = []  # inference output
        result=[]

        result.append(self.l2_fusion(x))
        result.append(self.l1_fusion(x))
        result.append(self.l0_fusion(x))
        x=result      
        for i in range(self.nl):
            x[i] = self.m[i](x[i])  # conv
            bs, _, ny, nx = x[i].shape  # x(bs,255,20,20) to x(bs,3,20,20,85)
            x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()

            if not self.training:  # inference
                if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]:
                    self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i)

                y = x[i].sigmoid() # https://github.com/iscyy/yoloair
                if self.inplace:
                    y[..., 0:2] = (y[..., 0:2] * 2 + self.grid[i]) * self.stride[i]  # xy
                    y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i]  # wh
                else:  # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953
                    xy, wh, conf = y.split((2, 2, self.nc + 1), 4)  # y.tensor_split((2, 4, 5), 4)  # torch 1.8.0
                    xy = (xy * 2 + self.grid[i]) * self.stride[i]  # xy
                    wh = (wh * 2) ** 2 * self.anchor_grid[i]  # wh
                    y = torch.cat((xy, wh, conf), 4)
                z.append(y.view(bs, -1, self.no))

        return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x)

    def _make_grid(self, nx=20, ny=20, i=0):
        d = self.anchors[i].device
        t = self.anchors[i].dtype
        shape = 1, self.na, ny, nx, 2  # grid shape
        y, x = torch.arange(ny, device=d, dtype=t), torch.arange(nx, device=d, dtype=t)
        if check_version(torch.__version__, '1.10.0'):  # torch>=1.10.0 meshgrid workaround for

完整内容:YOLOv5改进 | Head | 将yolov5的检测头替换为ASFF_Detect ——点击即可跳转

相关文章
|
6月前
|
计算机视觉
YOLOv5改进 | 检测头篇 | 增加辅助检测头利用AFPN改进Head(附详细修改教程)
YOLOv5改进 | 检测头篇 | 增加辅助检测头利用AFPN改进Head(附详细修改教程)
443 0
|
机器学习/深度学习 编解码 算法
yolo原理系列——yolov1--yolov5详细解释
yolo原理系列——yolov1--yolov5详细解释
1219 0
yolo原理系列——yolov1--yolov5详细解释
|
5月前
|
计算机视觉
【CV大模型SAM(Segment-Anything)】如何保存分割后的对象mask?并提取mask对应的图片区域?
【CV大模型SAM(Segment-Anything)】如何保存分割后的对象mask?并提取mask对应的图片区域?
【CV大模型SAM(Segment-Anything)】如何保存分割后的对象mask?并提取mask对应的图片区域?
|
6月前
|
机器学习/深度学习 编解码 算法
ADA-YOLO | YOLOv8+注意力+Adaptive Head,相对YOLOv8,mAP提升3%+118FPS
ADA-YOLO | YOLOv8+注意力+Adaptive Head,相对YOLOv8,mAP提升3%+118FPS
301 0
|
6月前
|
索引
yolov5--detect.py --v5.0版本-最新代码详细解释-2021-6-29号更新
yolov5--detect.py --v5.0版本-最新代码详细解释-2021-6-29号更新
252 0
yolov5--detect.py --v5.0版本-最新代码详细解释-2021-6-29号更新
|
6月前
|
机器学习/深度学习 索引
yolov5--loss.py --v5.0版本-最新代码详细解释-2021-7-1更新
yolov5--loss.py --v5.0版本-最新代码详细解释-2021-7-1更新
291 0
|
6月前
yolov5--datasets.py --v5.0版本-数据集加载 最新代码详细解释2021-7-5更新
yolov5--datasets.py --v5.0版本-数据集加载 最新代码详细解释2021-7-5更新
269 0
|
计算机视觉 索引
YOLOv5的Tricks | 【Trick14】YOLOv5的val.py脚本的解析
YOLOv5的Tricks | 【Trick14】YOLOv5的val.py脚本的解析
1332 0
YOLOv5的Tricks | 【Trick14】YOLOv5的val.py脚本的解析
|
机器学习/深度学习 定位技术 文件存储
再改YOLO | YOLO-ReT让边缘端也可以实时检测(一)
再改YOLO | YOLO-ReT让边缘端也可以实时检测(一)
188 0
再改YOLO | YOLO-ReT让边缘端也可以实时检测(一)
再改YOLO | YOLO-ReT让边缘端也可以实时检测(二)
再改YOLO | YOLO-ReT让边缘端也可以实时检测(二)
98 0
再改YOLO | YOLO-ReT让边缘端也可以实时检测(二)