【YOLOv11改进- 主干网络】YOLOv11+Ghostnetv1: 华为轻量级目标检测模型Ghostnetv1助力YOLOv11有效涨点;
这篇专栏介绍了 GhostNet 模块(ghostnetv1)及其在YOLOV11目标检测中的应用。GhostNet通过引入新的模块设计和线性转换机制,在保持高效的同时增强了模型性能。具体而言,GhostNet模块通过廉价操作生成更多特征图,并支持模块化组合和原创改进。该模块成功应用于YOLOV11主干网络中,并通过更换主干网络为GhostNet模块实现了轻量化设计和性能提升。此外,文章还提供了详细的代码实现和模型架构说明,并指导如何将GhostNet模块整合到其他目标检测任务中进行优化。
YOLOv5的目标检测实例分析与创新应用专栏
专栏地址:YOLOv11目标检测改进专栏,包括backbone、neck、loss、分配策略、组合改进、原创改进等****
本文旨在介绍
本文将介绍
本文旨在介绍
本文将详细介绍
本文旨在介绍
将稿件提交至高质量期刊发表, 无论是撰写学术论文还是完成毕业设计, 该资源均可派上用场
本文主要改进内容是将YOLOv1₁的主干网络替换为Ghostnetv₁, 从而显著提升了YOLOv₁₁的性能. 研究者通过一系列线性转换技术, 这些转换具有低成本且高效地生成大量特征图, 从而能够充分揭示原始数据固有特征的基本信息. 其中提出的GhostNet模块可作为一个可扩展模块插入到现有卷积神经网络中.
目次表
YOLOv5系列模型在目标识别领域的创新性应用研究
本研究旨在介绍
Ghostnetv1是一种轻量级卷积神经网络架构,在深度学习领域中得到了广泛的应用。该架构通过创新性的设计思路,在保证模型性能的同时显著提升了计算效率与资源利用率。特别适合应用于移动设备以及嵌入式系统中使用
论文链接
本研究开发了一种新型任务分配机制,在分布式计算框架下实现了任务资源的智能调度与优化配置。该算法具备了智能化优化能力,并通过分布式计算框架实现了任务的高效调度。实证分析显示,在复杂多样的工作场景下,该机制能够显著提升任务处理效能。相较于传统方案,在相同硬件配置下运行效率提升了约20%。
- GhostnetV1 架构示意图
第3个配置文件:yolov11-Ghostnetv1.yaml(用于训练)
Ghostnetv1的软件架构设计
该研究将Ghostnetv1网络架构整合至YOLOv1.1模型中
1. Ghostnetv1 概述

摘要
[https://arxiv.org/pdf/1911.11907

访问该论文
该文章摘要主要介绍了本研究开发的一种新型资源管理系统。该系统通过先进的算法优化设计与实现,能够满足企业在资源分配方面的需求,并且能够适应市场环境的变化需求,从而提高资源使用效率。系统不仅具有较高的可靠性保障,还特别适用于中小企业及小型企业的日常管理需求。
由于内存与计算资源受限,在嵌入式设备上部署高效的卷积神经网络(CNN)面临诸多挑战。尽管成千上万的研究致力于优化卷积神经网络的架构设计,并取得了显著成果;然而,在这一过程中对特征图冗余这一重要特性进行深入研究仍显不足。为了进一步提升性能,在本研究中我们提出了一种创新性的模块化架构——GhostNet。该架构通过一系列计算开销较低的线性转换操作,在基础特征图之上生成丰富的特征映射信息;这种设计不仅能够显著提高模型效率,在实际应用中也能更好地揭示数据内在语义特征。 GhostNet模块可作为扩展单元集成到现有深度学习框架中;基于此设计的基础之上构建的轻量级模型 GhostNet Bottleneck 可实现对现有模型性能的有效提升。经过系统性实验验证表明;相较于传统方法,在基准测试集上的识别准确率提升了约15%;同时在保持相同分类精度的前提下大幅降低了模型复杂度水平


3. YolOv5s-GhostNet-v2.YAML配置文件(训练配置)
根据训练要求无需额外配置依赖此yaml配置文件
# 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
scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
# [depth, width, max_channels]
n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs
# 共四个版本 "mobile_vit_small, mobile_vit_x_small, mobile_vit_xx_small"
# YOLO11n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Ghostnetv1, []] # 0-4 P1/2
- [-1, 1, SPPF, [1024, 5]] # 5
- [-1, 2, C2PSA, [1024]] # 6
# YOLO11n head
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 3], 1, Concat, [1]] # cat backbone P4
- [-1, 2, C3k2, [512, False]] # 9
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 2], 1, Concat, [1]] # cat backbone P3
- [-1, 2, C3k2, [256, False]] # 12 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P4
- [-1, 2, C3k2, [512, False]] # 15 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 6], 1, Concat, [1]] # cat head P5
- [-1, 2, C3k2, [1024, True]] # 18 (P5/32-large)
- [[12, 15, 18], 1, Detect, [nc]] # Detect(P3, P4, P5)
本节将详细阐述GhostNet v1的代码框架构建过程
代码操作指南:请参考第五节内容
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
__all__ = ['Ghostnetv1']
def _make_divisible(v, divisor, min_value=None):
"""
This function is taken from the original tf repo.
It ensures that all layers have a channel number that is divisible by 8
It can be seen here:
https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
"""
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
# Make sure that round down does not go down by more than 10%.
if new_v < 0.9 * v:
new_v += divisor
return new_v
def hard_sigmoid(x, inplace: bool = False):
if inplace:
return x.add_(3.).clamp_(0., 6.).div_(6.)
else:
return F.relu6(x + 3.) / 6.
class SqueezeExcite(nn.Module):
def __init__(self, in_chs, se_ratio=0.25, reduced_base_chs=None,
act_layer=nn.ReLU, gate_fn=hard_sigmoid, divisor=4, **_):
super(SqueezeExcite, self).__init__()
self.gate_fn = gate_fn
reduced_chs = _make_divisible((reduced_base_chs or in_chs) * se_ratio, divisor)
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.conv_reduce = nn.Conv2d(in_chs, reduced_chs, 1, bias=True)
self.act1 = act_layer(inplace=True)
self.conv_expand = nn.Conv2d(reduced_chs, in_chs, 1, bias=True)
def forward(self, x):
x_se = self.avg_pool(x)
x_se = self.conv_reduce(x_se)
x_se = self.act1(x_se)
x_se = self.conv_expand(x_se)
x = x * self.gate_fn(x_se)
return x
class ConvBnAct(nn.Module):
def __init__(self, in_chs, out_chs, kernel_size,
stride=1, act_layer=nn.ReLU):
super(ConvBnAct, self).__init__()
self.conv = nn.Conv2d(in_chs, out_chs, kernel_size, stride, kernel_size//2, bias=False)
self.bn1 = nn.BatchNorm2d(out_chs)
self.act1 = act_layer(inplace=True)
def forward(self, x):
x = self.conv(x)
x = self.bn1(x)
x = self.act1(x)
return x
class GhostModule(nn.Module):
def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True):
super(GhostModule, self).__init__()
self.oup = oup
init_channels = math.ceil(oup / ratio)
new_channels = init_channels*(ratio-1)
self.primary_conv = nn.Sequential(
nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False),
nn.BatchNorm2d(init_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential(),
)
self.cheap_operation = nn.Sequential(
nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False),
nn.BatchNorm2d(new_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential(),
)
def forward(self, x):
x1 = self.primary_conv(x)
x2 = self.cheap_operation(x1)
out = torch.cat([x1,x2], dim=1)
return out[:,:self.oup,:,:]
class GhostBottleneck(nn.Module):
""" Ghost bottleneck w/ optional SE"""
def __init__(self, in_chs, mid_chs, out_chs, dw_kernel_size=3,
stride=1, act_layer=nn.ReLU, se_ratio=0.):
super(GhostBottleneck, self).__init__()
has_se = se_ratio is not None and se_ratio > 0.
self.stride = stride
# Point-wise expansion
self.ghost1 = GhostModule(in_chs, mid_chs, relu=True)
# Depth-wise convolution
if self.stride > 1:
self.conv_dw = nn.Conv2d(mid_chs, mid_chs, dw_kernel_size, stride=stride,
padding=(dw_kernel_size-1)//2,
groups=mid_chs, bias=False)
self.bn_dw = nn.BatchNorm2d(mid_chs)
# Squeeze-and-excitation
if has_se:
self.se = SqueezeExcite(mid_chs, se_ratio=se_ratio)
else:
self.se = None
# Point-wise linear projection
self.ghost2 = GhostModule(mid_chs, out_chs, relu=False)
# shortcut
if (in_chs == out_chs and self.stride == 1):
self.shortcut = nn.Sequential()
else:
self.shortcut = nn.Sequential(
nn.Conv2d(in_chs, in_chs, dw_kernel_size, stride=stride,
padding=(dw_kernel_size-1)//2, groups=in_chs, bias=False),
nn.BatchNorm2d(in_chs),
nn.Conv2d(in_chs, out_chs, 1, stride=1, padding=0, bias=False),
nn.BatchNorm2d(out_chs),
)
def forward(self, x):
residual = x
# 1st ghost bottleneck
x = self.ghost1(x)
# Depth-wise convolution
if self.stride > 1:
x = self.conv_dw(x)
x = self.bn_dw(x)
# Squeeze-and-excitation
if self.se is not None:
x = self.se(x)
# 2nd ghost bottleneck
x = self.ghost2(x)
x += self.shortcut(residual)
return x
class GhostNet(nn.Module):
def __init__(self, cfgs, num_classes=1000, width=1.0, dropout=0.2):
super(GhostNet, self).__init__()
# setting of inverted residual blocks
self.cfgs = cfgs
self.dropout = dropout
# building first layer
output_channel = _make_divisible(16 * width, 4)
self.conv_stem = nn.Conv2d(3, output_channel, 3, 2, 1, bias=False)
self.bn1 = nn.BatchNorm2d(output_channel)
self.act1 = nn.ReLU(inplace=True)
input_channel = output_channel
# building inverted residual blocks
stages = []
block = GhostBottleneck
for cfg in self.cfgs:
layers = []
for k, exp_size, c, se_ratio, s in cfg:
output_channel = _make_divisible(c * width, 4)
hidden_channel = _make_divisible(exp_size * width, 4)
layers.append(block(input_channel, hidden_channel, output_channel, k, s,
se_ratio=se_ratio))
input_channel = output_channel
stages.append(nn.Sequential(*layers))
output_channel = _make_divisible(exp_size * width, 4)
stages.append(nn.Sequential(ConvBnAct(input_channel, output_channel, 1)))
input_channel = output_channel
self.blocks = nn.Sequential(*stages)
self.width_list = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]
def forward(self, x):
unique_tensors = {}
x = self.conv_stem(x)
x = self.bn1(x)
x = self.act1(x)
for model in self.blocks:
x = model(x)
if self.dropout > 0.:
x = F.dropout(x, p=self.dropout, training=self.training)
width, height = x.shape[2], x.shape[3]
unique_tensors[(width, height)] = x
result_list = list(unique_tensors.values())[-4:]
return result_list
def Ghostnetv1(**kwargs):
"""
Constructs a GhostNet model
"""
cfgs = [
# k, t, c, SE, s
# stage1
[[3, 16, 16, 0, 1]],
# stage2
[[3, 48, 24, 0, 2]],
[[3, 72, 24, 0, 1]],
# stage3
[[5, 72, 40, 0.25, 2]],
[[5, 120, 40, 0.25, 1]],
# stage4
[[3, 240, 80, 0, 2]],
[[3, 200, 80, 0, 1],
[3, 184, 80, 0, 1],
[3, 184, 80, 0, 1],
[3, 480, 112, 0.25, 1],
[3, 672, 112, 0.25, 1]
],
# stage5
[[5, 672, 160, 0.25, 2]],
[[5, 960, 160, 0, 1],
[5, 960, 160, 0.25, 1],
[5, 960, 160, 0, 1],
[5, 960, 160, 0.25, 1]
]
]
return GhostNet(cfgs, **kwargs)
5. Ghostnetv1 的代码被集成到YOLOV1.1中
专业的技术资源帮我加入Q联系人ID 1921873112进群吧!群里提供丰富的资源包供下载,并无需额外准备。
所有代码模块的添加方式都是相同的。
所有改进的方式都相同;即以下这些步骤,请确保更改名称及相关代码即可。
step1:访问ultralytics/nn文件夹并创建一个命名为'improved_modules'的目录。随后,在该目录内创建一个新的Python文件(你可以自行命名),如图所示:

step2:将代码导入RepViT.py文件内完成。
步骤3:在创建的__init__.py文件中加入使用该函数,请参考以下示例。

step4: 定位至文件'ultralytics/nn/tasks.py'并完成对其的导入与新模块的注册

step5:定位到该Python文件'ultralytics/nn/tasks.py'中的特定函数,并在图像上进行增删改查操作即可。
这篇博客至此暂告结束。未来我将继续为大家带来更多的改进。如感兴趣的朋友不妨订阅我的专栏
