首页 > 其他分享 >修改模型Backbone 、Neck 和Head :以 Yolov5 结构为例

修改模型Backbone 、Neck 和Head :以 Yolov5 结构为例

时间:2025-01-20 10:30:26浏览次数:3  
标签:Yolov5 Neck nn 为例 self channels 模型 out

一、引言

目标检测是计算机视觉领域的重要任务之一,在众多目标检测算法中,Yolov5 以其高效、准确的特点受到了广泛关注。我以 Yolov5 的模型结构为例,研究其 Backbone、Neck、Head 等各个部分的详细内容,为日后优化模型做示例。

二、Yolov5 模型结构之概述

(一)Yolov5 模型的整体架构

Yolov5 模型主要由 Backbone、Neck 和 Head 三大部分组成,这三个部分协同工作,共同完成目标检测任务。Backbone 负责提取图像的特征,Neck 对特征进行融合和增强,Head 则根据融合后的特征进行目标的预测和分类,一个模型若想得到优化,需要从以下三点着手:Backbone 、Neck 和Head。

(二)Yolov5 模型结构的优势与特点

  • 高效性:Yolov5 在模型结构和算法优化上进行了诸多改进,使得模型在保持较高检测精度的同时,具有更快的检测速度,能够满足实时目标检测的需求。
  • 灵活性:官网提供了不同大小的模型版本(如 s、m、l、x 等),我们可以根据实际应用场景和硬件资源选择合适的模型,方便在不同设备上部署和运行。
  • 易用性:代码实现相对简洁,易于理解和修改,同时社区支持丰富,有大量的教程和示例可供参考,降低了初学者的入门门槛。

三、Backbone 之 CSP(Cross Stage Partial DenseNet)

(一)CSP 结构的基本原理

CSP 是 Yolov5 Backbone 的核心结构,它将基础层分为两部分,一部分直接连接到 Transition 层,另一部分则经过 Dense Block 后再连接到 Transition 层。这种设计有效地减少了计算量,同时缓解了模型的过拟合问题,提高了特征提取的效率和质量。

(二)CSP 与传统 DenseNet 的对比

  • 传统 DenseNet:通过密集连接的方式,使每一层都能直接与前面的所有层相连,实现了特征的充分复用,但也带来了计算量过大和容易过拟合的问题。
  • CSP 的改进:在保留 DenseNet 特征复用优点的基础上,通过跨阶段的部分连接,降低了模型的复杂度和计算量,并且能够更好地平衡模型的精度和速度。

(三)CSP 模块的代码实现(以 PyTorch 为例)

import torch
import torch.nn as nn

class CSPBlock(nn.Module):
    def __init__(self, in_channels, out_channels, num_blocks):
        super(CSPBlock, self).__init__()
        self.part1_conv = nn.Conv2d(in_channels, out_channels // 2, kernel_size=1)
        self.part2_conv1 = nn.Conv2d(in_channels, out_channels // 2, kernel_size=1)
        self.part2_bn1 = nn.BatchNorm2d(out_channels // 2)
        self.part2_relu1 = nn.ReLU(inplace=True)
        self.part2_blocks = nn.Sequential(*[BasicBlock(out_channels // 2) for _ in range(num_blocks)])
        self.part2_conv2 = nn.Conv2d(out_channels // 2, out_channels // 2, kernel_size=1)
        self.part2_bn2 = nn.BatchNorm2d(out_channels // 2)
        self.part2_relu2 = nn.ReLU(inplace=True)
        self.transition_conv = nn.Conv2d(out_channels, out_channels, kernel_size=1)
        self.transition_bn = nn.BatchNorm2d(out_channels)
        self.transition_relu = nn.ReLU(inplace=True)

    def forward(self, x):
        x1 = self.part1_conv(x)
        x2 = self.part2_conv1(x)
        x2 = self.part2_bn1(x2)
        x2 = self.part2_relu1(x2)
        x2 = self.part2_blocks(x2)
        x2 = self.part2_conv2(x2)
        x2 = self.part2_bn2(x2)
        x2 = self.part2_relu2(x2)
        out = torch.cat([x1, x2], dim=1)
        out = self.transition_conv(out)
        out = self.transition_bn(out)
        out = self.transition_relu(out)
        return out

class BasicBlock(nn.Module):
    def __init__(self, in_channels):
        super(BasicBlock, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size=3, padding=1)
        self.bn1 = nn.BatchNorm2d(in_channels)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(in_channels, in_channels, kernel_size=3, padding=1)
        self.bn2 = nn.BatchNorm2d(in_channels)

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out += residual
        out = self.relu(out)
        return out

在上述代码中,CSPBlock类实现了 CSP 模块的结构。__init__方法中定义了各个卷积层、批归一化层和 ReLU 激活函数等组件。forward方法中,输入x被分成两部分,分别经过不同的处理路径后再进行拼接和进一步的处理,最终输出融合后的特征。BasicBlock类则定义了 CSP 模块中使用的基本残差块结构。

四、Neck 之 PANet(Path Aggregation Network)

(一)PANet 在 Yolov5 中的作用

PANet 在 Yolov5 中作为 Neck 部分,主要用于对 Backbone 提取的特征进行融合和增强。它在 FPN(Feature Pyramid Network)的基础上进行了改进,增加了自底向上的路径,形成了一个双向的特征融合网络,使得不同尺度的特征能够更好地交互和融合,从而提高模型对不同大小目标的检测能力。

(二)PANet 与 FPN 的区别

  • FPN 结构:通过自顶向下的方式,将高层的语义强但分辨率低的特征与底层的语义弱但分辨率高的特征进行融合,构建了一个特征金字塔。然而,底层特征向高层传递的路径较长,可能会导致信息丢失。
  • PANet 的改进:除了自顶向下的路径外,还增加了自底向上的路径,底层特征可以更快速地传递到高层,高层特征也能更好地指导底层特征的学习,进一步增强了特征的表达能力和模型的检测性能。

(三)PANet 的代码实现

class PANet(nn.Module):
    def __init__(self, in_channels_list, out_channels):
        super(PANet, self).__init__()
        self.lateral_convs = nn.ModuleList()
        self.top_down_convs = nn.ModuleList()
        self.bottom_up_convs = nn.ModuleList()
        for in_channels in in_channels_list:
            self.lateral_convs.append(nn.Conv2d(in_channels, out_channels, kernel_size=1))
            self.top_down_convs.append(nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1))
            self.bottom_up_convs.append(nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1))

    def forward(self, x):
        # 自顶向下的路径
        c = len(x)
        top_down_feats = [self.lateral_convs[-1](x[-1])]
        for i in range(c - 2, -1, -1):
            top_down_feat = F.interpolate(top_down_feats[-1], scale_factor=2, mode='nearest')
            top_down_feat += self.lateral_convs[i](x[i])
            top_down_feats.append(self.top_down_convs[i](top_down_feat))

        # 自底向上的路径
        bottom_up_feats = [top_down_feats[-1]]
        for i in range(c - 1):
            bottom_up_feat = F.max_pool2d(bottom_up_feats[-1], kernel_size=2, stride=2)
            bottom_up_feat += top_down_feats[i]
            bottom_up_feats.append(self.bottom_up_convs[i](bottom_up_feat))

        return bottom_up_feats

在上述PANet类的代码中,__init__方法初始化了侧向连接卷积层、自顶向下卷积层和自底向上卷积层。forward方法中,首先通过自顶向下的路径将高层特征与底层特征进行融合,然后再通过自底向上的路径进一步增强特征,最终返回融合后的特征列表,这些特征将被传递到 Head 部分进行目标检测。

五、Head 之 output(Dense Prediction)

(一)Yolov5 Head 的输出特点

  • 与 YOLOv3、YOLOv4 的相似性:Yolov5 的 Head 输出与 YOLOv3、YOLOv4 在某些方面具有相似性,例如输出的格式和处理方式,这使得熟悉前几代 YOLO 模型的开发者能够更快地理解和上手 Yolov5。
  • 三个输出层:对应不同的分辨率,分别用于检测不同尺度的目标。这种多尺度输出的设计能够更好地适应目标在图像中大小的变化,提高模型对各种尺度目标的检测精度和召回率。

(二)输出信息的详细解释

输出信息的格式为[NxCxHxWx(num + 5)],其中:

  • N:表示批量大小,即一次处理的图像数量。在实际应用中,可以根据硬件资源和任务需求设置合适的批量大小。
  • C:通常与输入图像的通道数相关,一般为 3(RGB 图像)。
  • HW:分别表示输出特征图的高度和宽度,不同的输出层具有不同的HW值,以适应不同尺度的目标检测。例如,对于输入为640x640的图像,可能会得到三个输出层大小分别为204080
  • num:表示检测目标的类别数,num + 5则表示每个检测框的相关信息,包括目标的类别概率、边界框的位置信息(如中心坐标cx, cy、宽度w和高度h等)以及目标的置信度得分score
  • 一般需要使用tensor的方式将NCWH转换为NCHW,将数据以 NCHW 的方式组织 tensor 在深度学习中具有诸多优势,包括硬件加速友好、深度学习框架的优化支持以及算法实现的便利性等,这些因素共同促使 NCHW 成为深度学习中常用的数据格式。

(三)输出层演化(以 Yolov5 版本更新为例)

  • 早期版本:输出层较为复杂,可能有多个不同名称和格式的输出,例如name: 397type: float32[1,3,80,80,85]等,这些输出分别对应不同分辨率的特征图和相关信息,需要进行较为繁琐的解析和处理。
  • 高版本(如 6.x):进行了简化,只需要解析最后一个输出层即可,输出层格式为cx, cy, w, h, score后面跟着num个类别得分(例如80MSCOCO的分类得分)。这种简化使得模型的后处理更加方便和高效,同时也减少了计算量和存储空间的需求。

以下是一个简单的输出解析示例代码(假设输出为output张量):

def parse_output(output, num_classes):
    batch_size, _, height, width = output.shape
    predictions = []
    for b in range(batch_size):
        for h in range(height):
            for w in range(width):
                values = output[b, :, h, w]
                obj_score = values[4]
                if obj_score > 0.5:  # 设定置信度阈值
                    class_scores = values[5:]
                    class_id = torch.argmax(class_scores)
                    class_prob = class_scores[class_id]
                    if class_prob > 0.5:  # 设定类别概率阈值
                        cx = w + values[0]
                        cy = h + values[1]
                        w_box = values[2]
                        h_box = values[3]
                        prediction = {
                            'class_id': class_id.item(),
                            'class_prob': class_prob.item(),
                            'bbox': [cx.item(), cy.item(), w_box.item(), h_box.item()]
                        }
                        predictions.append(prediction)
    return predictions

在上述代码中,parse_output函数用于解析模型的输出。首先,获取输出张量的维度信息。然后,通过遍历输出张量的每个元素,根据置信度阈值和类别概率阈值筛选出有效的检测结果,并将检测到的目标类别、概率以及边界框信息存储在predictions列表中返回。

六、模型结构之输入

(一)输入图像的格式和要求

Yolov5 模型的输入图像格式为[1xNxHxW] = [1x3x640x640],即NCHW,其中:

  • 1:表示批量大小为 1,即一次处理一张图像。在实际应用中,可以根据需要调整批量大小,但需要注意硬件的内存限制。
  • 3:表示图像的通道数,通常为 RGB 三通道彩色图像。
  • 640x640:表示输入图像的高度和宽度,将图像统一 resize 到这个尺寸可以方便模型进行处理和计算,利用Opencv的resize即可达到此效果,同时也能保证模型在不同大小的输入图像上具有一定的稳定性和一致性。

(二)输入图像预处理的重要性和方法

输入图像预处理是模型训练和推理过程中的重要环节,它可以提高模型的性能和稳定性。以下是一些常见的预处理方法及其代码示例:

1. 图像缩放与裁剪

将图像 resize 到指定的尺寸(如640x640),可以使用 OpenCV 库实现:

import cv2

def resize_image(image_path, target_size=(640, 640)):
    image = cv2.imread(image_path)
    resized_image = cv2.resize(image, target_size)
    return resized_image

在上述代码中,resize_image函数读取指定路径的图像,并将其 resize 到target_size指定的尺寸。

2. 图像归一化

将图像的像素值归一化到一个较小的范围内,如[0, 1][-1, 1],可以加快模型的收敛速度,提高训练的稳定性和效果。以下是将图像像素值归一化到[0, 1]的示例代码:

import numpy as np

def normalize_image(image):
    return image / 255.0

在上述代码中,normalize_image函数将输入图像的像素值除以 255,像素值最大就是255,因此此操作可以将其归一化到[0, 1]范围内。

3. 数据增强

通过对输入图像进行随机裁剪、翻转、缩放、旋转等操作,可以增加训练数据的多样性,提高模型的泛化能力。以下是使用torchvision.transforms实现数据增强的示例代码:

import torchvision.transforms as transforms

transform = transforms.Compose([
    transforms.RandomResizedCrop((640, 640)),
    transforms.RandomHorizontalFlip(),
    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

def augment_image(image):
    augmented_image = transform(image)
    return augmented_image

在上述代码中,transform定义了一系列的数据增强操作,包括随机裁剪、随机水平翻转、颜色抖动、转换为张量以及归一化等。augment_image函数将输入图像应用这些数据增强操作后返回增强后的图像。

七、Yolov5 模型的训练与优化

(一)训练数据集的准备

训练一个高质量的 Yolov5 模型需要大量的标注数据。数据集的标注通常包括目标的类别和边界框信息。可以使用一些开源的标注工具,如 LabelImg 等,来标注图像数据。标注完成后,将数据集按照一定的比例划分为训练集、验证集和测试集,以便在训练过程中进行模型评估和调优。

(二)训练参数的设置

  • 学习率:学习率是影响模型训练速度和效果的重要参数。通常可以采用学习率衰减策略,在训练初期使用较大的学习率,随着训练的进行逐渐减小学习率,以帮助模型更好地收敛。
  • 批次大小:批次大小决定了一次训练中处理的图像数量。较大的批次大小可以提高 GPU 的利用率,但可能会导致内存不足;较小的批次大小则可以使模型训练更加稳定,但训练速度可能会较慢。需要根据硬件资源和数据集大小进行合理设置。
  • 训练轮数:训练轮数表示模型遍历整个训练数据集的次数。过多的训练轮数可能会导致过拟合,而过少的训练轮数则可能使模型无法充分学习数据的特征。可以通过观察验证集上的损失函数和准确率等。

标签:Yolov5,Neck,nn,为例,self,channels,模型,out
From: https://blog.csdn.net/weixin_52603404/article/details/145249269

相关文章

  • 爬虫实战带上代码讲解(以爬取好大夫为例)
    前言:我感觉之前讲的爬虫,太纸面化了,需要给一些实例来帮助理解。毕竟爬虫这项技能,我们经常可能用到,通常用于爬虫数据来训练模型。延续上一篇文章所说将爬虫分为四个主要部分:获取网页源代码解析网页并提取数据实现自动化抓取逻辑保存数据到文件(如execl)第一步:获取网页源代码......
  • 【行空板K10】第三方库在行空板K10显示不可用怎么办?以CodeBlock为例
    目录引言问题用户库的修改测试 本文首发与DFRobot论坛:第三方库在行空板K10显示不可用怎么办?以CodeBlock为例DF创客社区https://mc.dfrobot.com.cn/thread-323692-1-1.html引言试用了一段时间Mind+图形化编程和行空板K10,感觉非常好用。官方的库基本都已经适配行空板K......
  • 利用坦克PWA3快速为应用配置域名:以Gogs为例
    全文概述本文介绍了如何利用坦克PWA3平台快速为Gogs应用配置域名的过程。随着互联网技术的发展,自托管Git服务变得越来越受欢迎,其中Gogs凭借其轻量级和易于安装的特点受到众多开发者的青睐。为提高用户体验,为应用配置一个易记且专业的域名至关重要。文中详细阐述了在坦克PWA3平台......
  • 机器学习算法深度解析与实践案例:以随机森林为例
    机器学习算法深度解析与实践案例:以随机森林为例在当今大数据驱动的时代,机器学习作为人工智能的一个核心分支,正以前所未有的速度改变着各行各业。从金融风控到医疗健康,从自动驾驶到智能推荐系统,机器学习算法的应用无处不在。本文将深入探讨一种广泛应用于分类和回归任务的强......
  • yolov5输出解码实现
    yolov5输出解释--以yolov5s.pt为例写在前面。这几天在用Tensort部署一个工训赛检测圆环的模型,发现输出怎么都对不上,通过查阅各方资料,便有了这篇文章,希望能帮助到大家输出维度在yolov5中,常见的输入为640*640,官方给出的yolov5s.pt正是如此,可以将其转换为onnx模型后在Netron上......
  • YOLOv11改进策略【Neck】| NeurIPS 2023 融合GOLD-YOLO颈部结构,强化小目标检测能力
    一、本文介绍本文主要利用GOLD-YOLO中的颈部结构优化YOLOv11的网络模型。GOLD-YOLO颈部结构中的GD机制借鉴了全局信息融合的理念,通过独特的模块设计,在不显著增加延迟的情况下,高效融合不同层级的特征信息。将其应用于YOLOv11的改进过程中,能够使模型更有效地整合多尺度特......
  • 深度学习图像算法中的网络架构:Backbone、Neck 和 Head 详解
    深度学习已经成为图像识别领域的核心技术,特别是在目标检测、图像分割等任务中,深度神经网络的应用取得了显著进展。在这些任务的网络架构中,通常可以分为三个主要部分:Backbone、Neck和Head。这些部分在整个网络中扮演着至关重要的角色,它们各自处理不同的任务,从特征提取到最......
  • 前端新手如何用vite构建小程序中使用的模块(以AES加密模块crypto-js为例)
    如果你只是想简单地把在vite项目中使用的模块引入到小程序中,不妨试试库模式。以crypto-js为例,你需要写两个JS文件:一个是构建脚本,类似于vite.config.js;//build.cjsconst{build}=require('vite'),path=require('path');build({publicDir:false,configFile:false......
  • 【01】vs-code如何配置flutter环境-开发完整的社交APP-前端客户端开发+数据联调|以优
    【01】vs-code如何配置flutter环境-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈-供大大的学习提升章节内容【01】章节内容【01】vs-code配置flutter环境开发背景优雅草央千澈对本项目的描......
  • 基于YOLOv5的手语识别系统:深度学习应用与实现
    手语是聋人和听力障碍者与他人交流的主要方式之一。随着社会的进步,手语的识别技术逐渐成为研究的热点,尤其在智能助残设备和多模态人机交互中,手语识别的应用越来越广泛。尽管手语是一种自然语言,但其表达方式非常丰富,包括了不同的手势、姿势、动作轨迹和面部表情等。为了能够......