yolov26改进 | 主干/Backbone篇 | 利用轻量化卷积二次创新PP-HGNetV2主干(轻量化版本,全网独家创新)
开始正文前先向大家推荐我的YOLO专栏系列。本人持续更新 YOLOv8、YOLO11、YOLO26 等热门模型内容覆盖图像分类、目标检测、实例分割、多目标跟踪、姿态估计与关键点检测重点讲解 小目标检测、注意力机制、特征融合、损失函数改进、自定义数据集训练、消融实验及论文代码复现。同时分享如何使用 OpenAI Codex辅助撰写论文、配置实验环境、调试项目、改进模型和分析实验结果。 专栏目前正在进行限时优惠每周更新 5–7篇最新论文机制、YOLO改进方法和实战教程。订阅后可获得包含本人全部改进方案的代码与配置文件并加入专属技术交流群。我也会定期在群内分享 YOLO论文选题、创新点设计、实验方案、论文写作与投稿发表经验欢迎大家订阅交流一、本文介绍本文介绍如何使用HGNetV2替换YOLOv26的主干网络。通过进一步分析HGNetV2的网络结构可以发现其内部包含大量卷积操作因此本文将在原始HGNetV2的基础上引入更加轻量、高效的卷积结构进行优化在尽量保留特征提取能力的同时进一步降低模型的参数量和计算量。经过本人实际测试优化后的HGNetV2不仅轻量化效果更加明显检测精度相比原始版本也有所提升非常适合希望兼顾模型精度、计算开销和部署效率的读者使用。由于目前网络上关于HGNetV2内部结构的详细解析相对较少本文将结合官方网络结构图和源码对其核心模块、特征提取流程以及轻量化修改思路进行详细讲解并手把手带大家完成代码替换与模型配置。专栏链接YOLOv26有效涨点专栏包含Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制目录一、本文介绍二、HGNetV2原理讲解2.1 HGNetV2的网络结构讲解2.2 轻量化卷积三、HGNetV2的代码四、手把手教你添加HGNetV24.1 修改一4.2 修改二4.3 修改三4.4 修改四4.5 修改五五、使用教程5.1 LightHGNet-l的yaml文件5.2 HGNetV2-x的yaml文件5.3 使用说明5.4 训练代码5.5 运行成功记录六、本文总结二、HGNetV2原理讲解本文论文地址RT-DETR论文地址本文代码来源HGNetV2的代码来源2.1 HGNetV2的网络结构讲解PP-HGNet 骨干网络的整体结构如下其中PP-HGNet是由多个HG-Block组成HG-Block的细节如下上面的图表是PP-HGNet神经网络架构的概览下面我对其中的每一个模块进行分析1. Stem层这是网络的初始预处理层通常包含卷积层开始从原始输入数据中提取特征。2. HG层次图块这些块是网络的核心组件设计用于以层次化的方式处理数据。每个HG块可能处理数据的不同抽象层次允许网络从低级和高级特征中学习。3. LDS可学习的下采样层位于HG块之间的这些层可能执行下采样操作减少特征图的空间维度减少计算负载并可能增加后续层的感受野。4. GAP全局平均池化在最终分类之前使用GAP层将特征图的空间维度减少到每个特征图一个向量有助于提高网络对输入数据空间变换的鲁棒性。5. 最终的卷积和全连接FC层网络以一系列执行最终分类任务的层结束。这通常涉及一个卷积层有时称为1x1卷积来组合特征然后是将这些特征映射到所需输出类别数量的全连接层。这种架构的主要思想是利用层次化的方法来提取特征其中复杂的模式可以在不同的规模和抽象层次上学习提高网络处理复杂图像数据的能力。这种分层和高效的处理对于图像分类等复杂任务非常有利在这些任务中精确预测至关重要的是在不同规模上识别复杂的模式和特征。图表还显示了HG块的扩展视图包括多个不同滤波器大小的卷积层以捕获多样化的特征然后通过一个元素级相加或连接的操作由符号表示在数据传递到下一层之前。2.2 轻量化卷积我这里利用的轻量化卷积只是官方仓库里面包含的四种这个文章其实是给大家打开一个思路这里的HGNet利用大量的卷积处理所以我们能够替换其中大量的卷积从而达到优化和涨点的效果。这几种卷积都是非常经典的了其中RepConv只支持卷积核为3所以我也进行了一定的处理原理就不再描述了。三、HGNetV2的代码核心代码使用方式看章节四import torch import torch.nn as nn import math import numpy as np __all__ [Light_HGBlock] def autopad(k, pNone, d1): # kernel, padding, dilation Pad to same shape outputs. if d 1: k d * (k - 1) 1 if isinstance(k, int) else [d * (x - 1) 1 for x in k] # actual kernel-size if p is None: p k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad return p class Conv(nn.Module): Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation). default_act nn.SiLU() # default activation def __init__(self, c1, c2, k1, s1, pNone, g1, d1, actTrue): Initialize Conv layer with given arguments including activation. super().__init__() self.conv nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groupsg, dilationd, biasFalse) self.bn nn.BatchNorm2d(c2) self.act self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() def forward(self, x): Apply convolution, batch normalization and activation to input tensor. return self.act(self.bn(self.conv(x))) def forward_fuse(self, x): Perform transposed convolution of 2D data. return self.act(self.conv(x)) class LightConv(nn.Module): Light convolution with args(ch_in, ch_out, kernel). https://github.com/PaddlePaddle/PaddleDetection/blob/develop/ppdet/modeling/backbones/hgnet_v2.py def __init__(self, c1, c2, k1, actnn.ReLU()): Initialize Conv layer with given arguments including activation. super().__init__() self.conv1 Conv(c1, c2, 1, actFalse) self.conv2 DWConv(c2, c2, k, actact) def forward(self, x): Apply 2 convolutions to input tensor. return self.conv2(self.conv1(x)) class DWConv(Conv): Depth-wise convolution. def __init__(self, c1, c2, k1, s1, d1, actTrue): # ch_in, ch_out, kernel, stride, dilation, activation Initialize Depth-wise convolution with given parameters. super().__init__(c1, c2, k, s, gmath.gcd(c1, c2), dd, actact) class DWConvTranspose2d(nn.ConvTranspose2d): Depth-wise transpose convolution. def __init__(self, c1, c2, k1, s1, p10, p20): # ch_in, ch_out, kernel, stride, padding, padding_out Initialize DWConvTranspose2d class with given parameters. super().__init__(c1, c2, k, s, p1, p2, groupsmath.gcd(c1, c2)) class ConvTranspose(nn.Module): Convolution transpose 2d layer. default_act nn.SiLU() # default activation def __init__(self, c1, c2, k2, s2, p0, bnTrue, actTrue): Initialize ConvTranspose2d layer with batch normalization and activation function. super().__init__() self.conv_transpose nn.ConvTranspose2d(c1, c2, k, s, p, biasnot bn) self.bn nn.BatchNorm2d(c2) if bn else nn.Identity() self.act self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() def forward(self, x): Applies transposed convolutions, batch normalization and activation to input. return self.act(self.bn(self.conv_transpose(x))) def forward_fuse(self, x): Applies activation and convolution transpose operation to input. return self.act(self.conv_transpose(x)) class Focus(nn.Module): Focus wh information into c-space. def __init__(self, c1, c2, k1, s1, pNone, g1, actTrue): Initializes Focus object with user defined channel, convolution, padding, group and activation values. super().__init__() self.conv Conv(c1 * 4, c2, k, s, p, g, actact) # self.contract Contract(gain2) def forward(self, x): Applies convolution to concatenated tensor and returns the output. Input shape is (b,c,w,h) and output shape is (b,4c,w/2,h/2). return self.conv(torch.cat((x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]), 1)) # return self.conv(self.contract(x)) class GhostConv(nn.Module): Ghost Convolution https://github.com/huawei-noah/ghostnet. def __init__(self, c1, c2, k1, s1, g1, actTrue): Initializes Ghost Convolution module with primary and cheap operations for efficient feature learning. super().__init__() c_ c2 // 2 # hidden channels self.cv1 Conv(c1, c_, k, s, None, g, actact) self.cv2 Conv(c_, c_, 5, 1, None, c_, actact) def forward(self, x): Forward propagation through a Ghost Bottleneck layer with skip connection. y self.cv1(x) return torch.cat((y, self.cv2(y)), 1) class RepConv(nn.Module): RepConv is a basic rep-style block, including training and deploy status. This module is used in RT-DETR. Based on https://github.com/DingXiaoH/RepVGG/blob/main/repvgg.py default_act nn.SiLU() # default activation def __init__(self, c1, c2, k3, s1, p1, g1, d1, actTrue, bnFalse, deployFalse): Initializes Light Convolution layer with inputs, outputs optional activation function. super().__init__() assert k 3 and p 1 self.g g self.c1 c1 self.c2 c2 self.act self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() self.bn nn.BatchNorm2d(num_featuresc1) if bn and c2 c1 and s 1 else None self.conv1 Conv(c1, c2, k, s, pp, gg, actFalse) self.conv2 Conv(c1, c2, 1, s, p(p - k // 2), gg, actFalse) def forward_fuse(self, x): Forward process. return self.act(self.conv(x)) def forward(self, x): Forward process. id_out 0 if self.bn is None else self.bn(x) return self.act(self.conv1(x) self.conv2(x) id_out) def get_equivalent_kernel_bias(self): Returns equivalent kernel and bias by adding 3x3 kernel, 1x1 kernel and identity kernel with their biases. kernel3x3, bias3x3 self._fuse_bn_tensor(self.conv1) kernel1x1, bias1x1 self._fuse_bn_tensor(self.conv2) kernelid, biasid self._fuse_bn_tensor(self.bn) return kernel3x3 self._pad_1x1_to_3x3_tensor(kernel1x1) kernelid, bias3x3 bias1x1 biasid staticmethod def _pad_1x1_to_3x3_tensor(kernel1x1): Pads a 1x1 tensor to a 3x3 tensor. if kernel1x1 is None: return 0 else: return torch.nn.functional.pad(kernel1x1, [1, 1, 1, 1]) def _fuse_bn_tensor(self, branch): Generates appropriate kernels and biases for convolution by fusing branches of the neural network. if branch is None: return 0, 0 if isinstance(branch, Conv): kernel branch.conv.weight running_mean branch.bn.running_mean running_var branch.bn.running_var gamma branch.bn.weight beta branch.bn.bias eps branch.bn.eps elif isinstance(branch, nn.BatchNorm2d): if not hasattr(self, id_tensor): input_dim self.c1 // self.g kernel_value np.zeros((self.c1, input_dim, 3, 3), dtypenp.float32) for i in range(self.c1): kernel_value[i, i % input_dim, 1, 1] 1 self.id_tensor torch.from_numpy(kernel_value).to(branch.weight.device) kernel self.id_tensor running_mean branch.running_mean running_var branch.running_var gamma branch.weight beta branch.bias eps branch.eps std (running_var eps).sqrt() t (gamma / std).reshape(-1, 1, 1, 1) return kernel * t, beta - running_mean * gamma / std def fuse_convs(self): Combines two convolution layers into a single layer and removes unused attributes from the class. if hasattr(self, conv): return kernel, bias self.get_equivalent_kernel_bias() self.conv nn.Conv2d( in_channelsself.conv1.conv.in_channels, out_channelsself.conv1.conv.out_channels, kernel_sizeself.conv1.conv.kernel_size, strideself.conv1.conv.stride, paddingself.conv1.conv.padding, dilationself.conv1.conv.dilation, groupsself.conv1.conv.groups, biasTrue, ).requires_grad_(False) self.conv.weight.data kernel self.conv.bias.data bias for para in self.parameters(): para.detach_() self.__delattr__(conv1) self.__delattr__(conv2) if hasattr(self, nm): self.__delattr__(nm) if hasattr(self, bn): self.__delattr__(bn) if hasattr(self, id_tensor): self.__delattr__(id_tensor) class Light_HGBlock(nn.Module): HG_Block of PPHGNetV2 with 2 convolutions and LightConv. https://github.com/PaddlePaddle/PaddleDetection/blob/develop/ppdet/modeling/backbones/hgnet_v2.py def __init__(self, c1, cm, c2, k3, n6, num1, shortcutFalse, actTrue): Initializes a CSP Bottleneck with 1 convolution using specified input and output channels. super().__init__() block Conv if num 1: block GhostConv elif num 2: block RepConv # RepConv Only supported k 3 k 3 elif num 3: block DWConv elif num 4: block LightConv self.m nn.ModuleList(block(c1 if i 0 else cm, cm, kk, actact) for i in range(n)) self.sc Conv(c1 n * cm, c2 // 2, 1, 1, actact) # squeeze conv self.ec Conv(c2 // 2, c2, 1, 1, actact) # excitation conv self.add shortcut and c1 c2 def forward(self, x): Forward pass of a PPHGNetV2 backbone layer. y [x] y.extend(m(y[-1]) for m in self.m) y self.ec(self.sc(torch.cat(y, 1))) return y x if self.add else y四、手把手教你添加HGNetV2下面的步骤如果你不会或者不想麻烦操作可以联系作者获得本专栏添加所有项目文件的源代码可直接训练.4.1 修改一第一还是建立文件我们找到如下ultralytics/nn文件夹下建立一个目录名字呢就是Addmodules文件夹4.2 修改二然后在Addmodules文件夹内建立一个新的py文件将本文章节三中的“核心代码复制粘贴进去。4.3 修改三第二步我们在该目录下创建一个新的py文件名字为__init__.py然后在其内部导入我们的文件如下图所示。4.4 修改四第三步我门中到如下文件ultralytics/nn/tasks.py进行导入和注册我们的模块(此处只需要添加一次即可如果你用我其它的改进机制这里的步骤只需要添加一次)4.5 修改五在ultralytics/nn/tasks.py文件内的parse_model方法函数内位置大概在1600行左右按照图示位置添加即可此处需要自己有一定的判别能力如果不会可联系作者获得视频教程。elif m in frozenset({HGStem, HGBlock, Light_HGBlock}): c1, cm, c2 ch[f], args[0], args[1] cm make_divisible(min(cm, max_channels) * width, 8) c2 make_divisible(min(c2, max_channels) * width, 8) n n_ max(round(n * depth), 1) if n 1 else n # depth gain args [c1, cm, c2, *args[2:]] if m in (HGBlock, Light_HGBlock): args.insert(4, n) # number of repeats n 1五、使用教程5.1 LightHGNet-l的yaml文件此版本训练信息YOLO26-Backbone-LightHGBlock-l summary: 288 layers, 1,986,820 parameters, 1,986,820 gradients, 4.7 GFLOPs# Ultralytics YOLO , AGPL-3.0 license # YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect # Parameters nc: 80 # number of classes end2end: True # whether to use end-to-end mode reg_max: 1 # DFL bins scales: # model compound scaling constants, i.e. modelyolo26n.yaml will call yolo26.yaml with scale n # [depth, width, max_channels] n: [0.50, 0.25, 1024] # summary: 260 layers, 2,572,280 parameters, 2,572,280 gradients, 6.1 GFLOPs s: [0.50, 0.50, 1024] # summary: 260 layers, 10,009,784 parameters, 10,009,784 gradients, 22.8 GFLOPs m: [0.50, 1.00, 512] # summary: 280 layers, 21,896,248 parameters, 21,896,248 gradients, 75.4 GFLOPs l: [1.00, 1.00, 512] # summary: 392 layers, 26,299,704 parameters, 26,299,704 gradients, 93.8 GFLOPs x: [1.00, 1.50, 512] # summary: 392 layers, 58,993,368 parameters, 58,993,368 gradients, 209.5 GFLOPs # YOLO26n backbone backbone: # [from, repeats, module, args] - [-1, 1, HGStem, [32, 48]] # 0-P2/4 - [-1, 6, Light_HGBlock, [48, 128, 3]] # stage 1 - [-1, 1, DWConv, [128, 3, 2, 1, False]] # 2-P3/8 - [-1, 6, Light_HGBlock, [96, 512, 3]] # stage 2 - [-1, 1, DWConv, [512, 3, 2, 1, False]] # 4-P3/16 - [-1, 6, Light_HGBlock, [192, 1024, 5, 3, True, False]] # cm, c2, k, light, shortcut - [-1, 6, Light_HGBlock, [192, 1024, 5, 3, True, True]] - [-1, 6, Light_HGBlock, [192, 1024, 5, 3, True, True]] # stage 3 - [-1, 1, DWConv, [1024, 3, 2, 1, False]] # 8-P4/32 - [-1, 6, Light_HGBlock, [384, 2048, 5, 3, True, False]] # stage 4 - [-1, 1, SPPF, [1024, 5, 3, True]] # 10 - [-1, 2, C2PSA, [1024]] # 11 # YOLO26n head head: - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 7], 1, Concat, [1]] # cat backbone P4 - [-1, 2, C3k2, [512, True]] # 14 - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 3], 1, Concat, [1]] # cat backbone P3 - [-1, 2, C3k2, [256, True]] # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]] - [[-1, 14], 1, Concat, [1]] # cat head P4 - [-1, 2, C3k2, [512, True]] # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]] - [[-1, 11], 1, Concat, [1]] # cat head P5 - [-1, 2, C3k2, [1024, True, 0.5, True]] # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc]] # Detect(P3, P4, P5)5.2 HGNetV2-x的yaml文件此版本训练信息YOLO26-Backbone-LightHGNetV2-x summary: 320 layers, 2,890,748 parameters, 2,890,748 gradients, 6.2 GFLOPs# Ultralytics YOLO , AGPL-3.0 license # YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect # Parameters nc: 80 # number of classes end2end: True # whether to use end-to-end mode reg_max: 1 # DFL bins scales: # model compound scaling constants, i.e. modelyolo26n.yaml will call yolo26.yaml with scale n # [depth, width, max_channels] n: [0.50, 0.25, 1024] # summary: 260 layers, 2,572,280 parameters, 2,572,280 gradients, 6.1 GFLOPs s: [0.50, 0.50, 1024] # summary: 260 layers, 10,009,784 parameters, 10,009,784 gradients, 22.8 GFLOPs m: [0.50, 1.00, 512] # summary: 280 layers, 21,896,248 parameters, 21,896,248 gradients, 75.4 GFLOPs l: [1.00, 1.00, 512] # summary: 392 layers, 26,299,704 parameters, 26,299,704 gradients, 93.8 GFLOPs x: [1.00, 1.50, 512] # summary: 392 layers, 58,993,368 parameters, 58,993,368 gradients, 209.5 GFLOPs # YOLO26n backbone backbone: # [from, repeats, module, args] - [-1, 1, HGStem, [32, 64]] # 0-P2/4 - [-1, 6, Light_HGBlock, [64, 128, 3]] # stage 1 - [-1, 1, DWConv, [128, 3, 2, 1, False]] # 2-P3/8 - [-1, 6, Light_HGBlock, [128, 512, 3]] - [-1, 6, Light_HGBlock, [128, 512, 3, 3, False, True]] # 4-stage 2 - [-1, 1, DWConv, [512, 3, 2, 1, False]] # 5-P3/16 - [-1, 6, Light_HGBlock, [256, 1024, 5, 3, True, False]] # cm, c2, k, light, shortcut - [-1, 6, Light_HGBlock, [256, 1024, 5, 3, True, True]] - [-1, 6, Light_HGBlock, [256, 1024, 5, 3, True, True]] - [-1, 6, Light_HGBlock, [256, 1024, 5, 3, True, True]] - [-1, 6, Light_HGBlock, [256, 1024, 5, 3, True, True]] # 10-stage 3 - [-1, 1, DWConv, [1024, 3, 2, 1, False]] # 11-P4/32 - [-1, 6, Light_HGBlock, [512, 2048, 5, 3, True, False]] - [-1, 6, Light_HGBlock, [512, 2048, 5, 3, True, True]] # 13-stage 4 - [-1, 1, SPPF, [1024, 5, 3, True]] # 14 - [-1, 2, C2PSA, [1024]] # 15 # YOLO26n head head: - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 10], 1, Concat, [1]] # cat backbone P4 - [-1, 2, C3k2, [512, True]] # 18 - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 4], 1, Concat, [1]] # cat backbone P3 - [-1, 2, C3k2, [256, True]] # 21 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]] - [[-1, 18], 1, Concat, [1]] # cat head P4 - [-1, 2, C3k2, [512, True]] # 24 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]] - [[-1, 15], 1, Concat, [1]] # cat head P5 - [-1, 2, C3k2, [1024, True, 0.5, True]] # 27 (P5/32-large) - [[21, 24, 27], 1, Detect, [nc]] # Detect(P3, P4, P5)5.3 使用说明这里有一个参数需要大家修改在章节3我说了我用了好几个卷积可以提供大家选择所以这里分别可以有四个卷积可以给大家使用大家可以看下面的代码。if num 1: block GhostConv elif num 2: block RepConv # RepConv Only supported k 3 k 3 elif num 3: block DWConv elif num 4: block LightConv如果我们想要使用RepConv为例那么我们修改图中的红框位置的地方我们设置为2此时使用的就是RepConv默认使用的是3也就是DWConv实验结果也是这个跑出来的。5.4 训练代码import warnings warnings.filterwarnings(ignore) from ultralytics import YOLO if __name__ __main__: model YOLO(ultralytics/cfg/models/v8/yolov8-C2f-FasterBlock.yaml) # model.load(yolov8n.pt) # loading pretrain weights model.train(datar替换数据集yaml文件地址, # 如果大家任务是其它的ultralytics/cfg/default.yaml找到这里修改task可以改成detect, segment, classify, pose cacheFalse, imgsz640, epochs150, single_clsFalse, # 是否是单类别检测 batch4, close_mosaic10, workers0, device0, optimizerSGD, # using SGD # resume, # 如过想续训就设置last.pt的地址 ampFalse, # 如果出现训练损失为Nan可以关闭amp projectruns/train, nameexp, )5.5 运行成功记录下面的图片是证明成功运行的截图确保我发的改进机制是可用的。六、本文总结到此本文的正式分享内容就结束了在这里给大家推荐我的YOLOv26改进有效涨点专栏本专栏目前为新开的平均质量分98分后期我会根据各种最新的前沿顶会进行论文复现也会对一些老的改进机制进行补充目前本专栏免费阅读(暂时大家尽早关注不迷路~)如果大家觉得本文帮助到你了订阅本专栏关注后续更多的更新~专栏链接YOLOv26有效涨点专栏包含Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制