YOLOv8改进 | 主干网络 | 将backbone替换为MobileNetV4【小白必备教程+附完整代码】

 秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转


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


专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有80+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转


本文介绍了最新一代的MobileNets,即MobileNetV4(MNv4),它具有针对移动设备的通用高效架构设计。在其核心部分,我们引入了通用倒瓶颈(UIB)搜索块,这是一个统一且灵活的结构,它融合了倒瓶颈(IB)、ConvNext、前馈网络(FFN)以及一种新颖的额外深度wise(ExtraDW)变体。与UIB相结合,我们推出了专为移动加速器设计的Mobile MQA注意力块,文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。   

 专栏地址YOLOv8改进——更新各种有效涨点方法——点击即可跳转 订阅学习不迷路  

目录

1. 原理

2.  将MobileNetV4添加到YOLOv8中

2.1 MobileNetV4的代码实现

2.2 更改init.py文件

2.3 添加yaml文件

2.4 注册模块

2.5 替换函数

2.6 执行程序

3. 完整代码分享

4. GFLOPs

5. 进阶

6. 总结


1. 原理

论文地址:MobileNetV4 - Universal Models for the Mobile Ecosystem——点击即可跳转

官方代码:  MobileNetV4代码仓库——点击即可跳转

MobileNetV4 (MNv4) 是最新一代 MobileNets,旨在优化各种移动设备的性能。以下是其架构背后的关键原则和组件:

通用倒置瓶颈 (UIB)

  • 倒置瓶颈块:MobileNetV4 以倒置瓶颈 (IB) 块的成功为基础,这是之前 MobileNets 的核心功能。

  • 灵活性和统一性:UIB 结合了多种微架构,包括倒置瓶颈、ConvNext、前馈网络 (FFN) 和创新的额外深度 (ExtraDW) 变体。这种统一使其能够有效地处理不同类型的操作。

  • 可选深度卷积:UIB 包括可选深度卷积,可增强其混合空间和通道信息的计算效率和灵活性。

移动 MQA(移动量化注意力)

  • 效率:此注意力模块专门针对移动加速器进行了优化,与传统的多头注意力 (MHSA) 相比,推理速度显著提高了 39%。

  • 移动设备上的性能:移动 MQA 模块经过量身定制,可充分利用移动硬件的功能,确保更快的处理速度和更低的延迟。

神经架构搜索 (NAS)

  • 优化的搜索方案:MobileNetV4 引入了一种改进的 NAS 流程,其中包括一个两阶段方法:粗粒度搜索和细粒度搜索。此方法提高了搜索过程的效率和有效性,从而可以创建高性能模型。

  • 硬件感知:NAS 方法考虑了各种移动硬件平台的限制和功能,确保生成的模型针对各种设备进行了优化,从 CPU 到专用加速器,如 Apple Neural Engine 和 Google Pixel EdgeTPU。

蒸馏技术

  • 准确度增强:MobileNetV4 采用了一种新颖的蒸馏技术,该技术使用具有不同增强的混合数据集和平衡的类内数据。该技术提高了模型的泛化能力和准确性。

  • 性能:通过这种蒸馏技术增强的 MNv4-Hybrid-Large 模型在 ImageNet-1K 上实现了令人印象深刻的 87% 的准确率,在 Pixel 8 EdgeTPU 上的运行时间仅为 3.8 毫秒。

帕累托最优

  • 性能平衡:MobileNetV4 模型旨在在各种硬件平台上实现帕累托最优,这意味着它们在计算效率和准确性之间提供了最佳平衡。

  • 独立于硬件的效率:这些模型经过测试,证明在不同类型的硬件上表现良好,从 CPU 和 GPU 到 DSP 和专用加速器,使其用途广泛且适用性广泛。

设计考虑

  • 运算强度:MobileNetV4 的设计考虑了不同硬件的运算强度,平衡了计算负载和内存带宽,以最大限度地提高性能。

  • 层优化:MobileNetV4 的初始层设计为计算密集型,以提高模型容量和准确性,而最终层则专注于即使在高 RP(脊点)硬件上也能保持准确性。

总之,MobileNetV4 集成了先进的技术和创新,创建了一系列在各种移动设备上都高效准确的模型。其设计原则强调灵活性、硬件感知优化以及计算效率和模型性能之间的平衡。

2.  将MobileNetV4添加到YOLOv8中

2.1 MobileNetV4的代码实现

关键步骤一在/ultralytics/ultralytics/nn/modules/下新建MobileNetV4.py,并粘贴下面代码

"""
Creates a MobileNetV4 Model as defined in:
Danfeng Qin, Chas Leichner, Manolis Delakis, Marco Fornoni, Shixin Luo, Fan Yang, Weijun Wang, Colby Banbury, Chengxi Ye, Berkin Akin, Vaibhav Aggarwal, Tenghui Zhu, Daniele Moro, Andrew Howard. (2024).
MobileNetV4 - Universal Models for the Mobile Ecosystem
arXiv preprint arXiv:2404.10518.
"""import torch
import torch.nn as nn
import math__all__ = ['mobilenetv4_conv_small', 'mobilenetv4_conv_medium', 'mobilenetv4_conv_large']def make_divisible(value, divisor, min_value=None, round_down_protect=True):if min_value is None:min_value = divisornew_value = max(min_value, int(value + divisor / 2) // divisor * divisor)# Make sure that round down does not go down by more than 10%.if round_down_protect and new_value < 0.9 * value:new_value += divisorreturn new_valueclass ConvBN(nn.Module):def __init__(self, in_channels, out_channels, kernel_size, stride=1):super(ConvBN, self).__init__()self.block = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size, stride, (kernel_size - 1) // 2, bias=False),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True),)def forward(self, x):return self.block(x)class UniversalInvertedBottleneck(nn.Module):def __init__(self,in_channels,out_channels,expand_ratio,start_dw_kernel_size,middle_dw_kernel_size,stride,middle_dw_downsample: bool = True,use_layer_scale: bool = False,layer_scale_init_value: float = 1e-5):super(UniversalInvertedBottleneck, self).__init__()self.start_dw_kernel_size = start_dw_kernel_sizeself.middle_dw_kernel_size = middle_dw_kernel_sizeif start_dw_kernel_size:self.start_dw_conv = nn.Conv2d(in_channels, in_channels, start_dw_kernel_size,stride if not middle_dw_downsample else 1,(start_dw_kernel_size - 1) // 2,groups=in_channels, bias=False)self.start_dw_norm = nn.BatchNorm2d(in_channels)expand_channels = make_divisible(in_channels * expand_ratio, 8)self.expand_conv = nn.Conv2d(in_channels, expand_channels, 1, 1, bias=False)self.expand_norm = nn.BatchNorm2d(expand_channels)self.expand_act = nn.ReLU(inplace=True)if middle_dw_kernel_size:self.middle_dw_conv = nn.Conv2d(expand_channels, expand_channels, middle_dw_kernel_size,stride if middle_dw_downsample else 1,(middle_dw_kernel_size - 1) // 2,groups=expand_channels, bias=False)self.middle_dw_norm = nn.BatchNorm2d(expand_channels)self.middle_dw_act = nn.ReLU(inplace=True)self.proj_conv = nn.Conv2d(expand_channels, out_channels, 1, 1, bias=False)self.proj_norm = nn.BatchNorm2d(out_channels)if use_layer_scale:self.gamma = nn.Parameter(layer_scale_init_value * torch.ones((out_channels)), requires_grad=True)self.use_layer_scale = use_layer_scaleself.identity = stride == 1 and in_channels == out_channelsdef forward(self, x):shortcut = xif self.start_dw_kernel_size:x = self.start_dw_conv(x)x = self.start_dw_norm(x)x = self.expand_conv(x)x = self.expand_norm(x)x = self.expand_act(x)if self.middle_dw_kernel_size:x = self.middle_dw_conv(x)x = self.middle_dw_norm(x)x = self.middle_dw_act(x)x = self.proj_conv(x)x = self.proj_norm(x)if self.use_layer_scale:x = self.gamma * xreturn x + shortcut if self.identity else xclass MobileNetV4(nn.Module):def __init__(self, block_specs, num_classes=1000):super(MobileNetV4, self).__init__()c = 3layers = []for block_type, *block_cfg in block_specs:if block_type == 'conv_bn':block = ConvBNk, s, f = block_cfglayers.append(block(c, f, k, s))elif block_type == 'uib':block = UniversalInvertedBottleneckstart_k, middle_k, s, f, e = block_cfglayers.append(block(c, f, e, start_k, middle_k, s))else:raise NotImplementedErrorc = fself.features = nn.Sequential(*layers)self.channels = [64, 128, 256, 512]self.indexs=[2,4,15,28]self._initialize_weights()def forward(self, x):out=[]for i in range(len(self.features)):x = self.features[i](x)if i in self.indexs:out.append(x)# print(x.shape)return outdef _initialize_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):n = m.kernel_size[0] * m.kernel_size[1] * m.out_channelsm.weight.data.normal_(0, math.sqrt(2. / n))if m.bias is not None:m.bias.data.zero_()elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_()def mobilenetv4_conv_small(**kwargs):"""Constructs a MobileNetV4-Conv-Small model"""block_specs = [# conv_bn, kernel_size, stride, out_channels# uib, start_dw_kernel_size, middle_dw_kernel_size, stride, out_channels, expand_ratio# 112px('conv_bn', 3, 2, 32),# 56px('conv_bn', 3, 2, 32),('conv_bn', 1, 1, 32),# 28px('conv_bn', 96, 3, 2),('conv_bn', 64, 1, 1),# 14px('uib', 5, 5, 2, 96, 3.0),  # ExtraDW('uib', 0, 3, 1, 96, 2.0),  # IB('uib', 0, 3, 1, 96, 2.0),  # IB('uib', 0, 3, 1, 96, 2.0),  # IB('uib', 0, 3, 1, 96, 2.0),  # IB('uib', 3, 0, 1, 96, 4.0),  # ConvNext# 7px('uib', 3, 3, 2, 128, 6.0),  # ExtraDW('uib', 5, 5, 1, 128, 4.0),  # ExtraDW('uib', 0, 5, 1, 128, 4.0),  # IB('uib', 0, 5, 1, 128, 3.0),  # IB('uib', 0, 3, 1, 128, 4.0),  # IB('uib', 0, 3, 1, 128, 4.0),  # IB('conv_bn', 1, 1, 960),  # Conv]return MobileNetV4(block_specs, **kwargs)def mobilenetv4_conv_medium(**kwargs):"""Constructs a MobileNetV4-Conv-Medium model"""block_specs = [('conv_bn', 3, 2, 32),('conv_bn', 3, 2, 128),('conv_bn', 1, 1, 48),# 3rd stage('uib', 3, 5, 2, 80, 4.0),('uib', 3, 3, 1, 80, 2.0),# 4th stage('uib', 3, 5, 2, 160, 6.0),('uib', 3, 3, 1, 160, 4.0),('uib', 3, 3, 1, 160, 4.0),('uib', 3, 5, 1, 160, 4.0),('uib', 3, 3, 1, 160, 4.0),('uib', 3, 0, 1, 160, 4.0),('uib', 0, 0, 1, 160, 2.0),('uib', 3, 0, 1, 160, 4.0),# 5th stage('uib', 5, 5, 2, 256, 6.0),('uib', 5, 5, 1, 256, 4.0),('uib', 3, 5, 1, 256, 4.0),('uib', 3, 5, 1, 256, 4.0),('uib', 0, 0, 1, 256, 4.0),('uib', 3, 0, 1, 256, 4.0),('uib', 3, 5, 1, 256, 2.0),('uib', 5, 5, 1, 256, 4.0),('uib', 0, 0, 1, 256, 4.0),('uib', 0, 0, 1, 256, 4.0),('uib', 5, 0, 1, 256, 2.0),]return MobileNetV4(block_specs, **kwargs)def mobilenetv4_conv_large(**kwargs):"""Constructs a MobileNetV4-Conv-Large model"""block_specs = [('conv_bn', 3, 2, 24),('conv_bn', 3, 2, 96),('conv_bn', 1, 1, 64),('uib', 3, 5, 2, 128, 4.0),('uib', 3, 3, 1, 128, 4.0),('uib', 3, 5, 2, 256, 4.0),('uib', 3, 3, 1, 256, 4.0),('uib', 3, 3, 1, 256, 4.0),('uib', 3, 3, 1, 256, 4.0),('uib', 3, 5, 1, 256, 4.0),('uib', 5, 3, 1, 256, 4.0),('uib', 5, 3, 1, 256, 4.0),('uib', 5, 3, 1, 256, 4.0),('uib', 5, 3, 1, 256, 4.0),('uib', 5, 3, 1, 256, 4.0),('uib', 3, 0, 1, 256, 4.0),('uib', 5, 5, 2, 512, 4.0),('uib', 5, 5, 1, 512, 4.0),('uib', 5, 5, 1, 512, 4.0),('uib', 5, 5, 1, 512, 4.0),('uib', 5, 0, 1, 512, 4.0),('uib', 5, 3, 1, 512, 4.0),('uib', 5, 0, 1, 512, 4.0),('uib', 5, 0, 1, 512, 4.0),('uib', 5, 3, 1, 512, 4.0),('uib', 5, 5, 1, 512, 4.0),('uib', 5, 0, 1, 512, 4.0),('uib', 5, 0, 1, 512, 4.0),('uib', 5, 0, 1, 512, 4.0),]return MobileNetV4(block_specs, **kwargs)

 MobileNetV4处理图像的主要步骤可以概括为以下几个关键阶段:

1. 图像预处理

在输入模型之前,图像会经过一些预处理步骤,这通常包括:

  • 缩放:将图像调整到指定的输入大小(如224x224)。

  • 归一化:对图像像素值进行归一化处理,使其值在特定范围内(如0到1或-1到1)。

2. 初始卷积层

图像首先通过一个标准卷积层,该层具有较大的卷积核(如3x3或5x5),用于捕捉低级别的特征,例如边缘和纹理。这一层通常是计算密集型的,以便在早期捕获更多的信息。

3. 倒瓶颈块(Inverted Bottleneck Block)

在MobileNetV4中,倒瓶颈块(IB块)是核心组件之一。每个倒瓶颈块包含以下子步骤:

  • 扩展卷积:首先使用1x1卷积扩展特征图的通道数。

  • 深度可分离卷积:然后使用深度可分离卷积(Depthwise Separable Convolution)在空间维度上进行卷积操作。

  • 压缩卷积:最后通过1x1卷积将通道数压缩回去。

4. 通用倒瓶颈块(Universal Inverted Bottleneck, UIB)

MobileNetV4引入了UIB,这种块可以灵活地调整,以适应不同的计算需求:

  • 标准倒瓶颈:与传统倒瓶颈类似,但增加了更多的灵活性。

  • ConvNext变体:结合了现代卷积架构的优点。

  • 前馈网络(FFN):适用于需要更多非线性变换的场景。

  • 额外深度可分离卷积(ExtraDW):用于提高计算效率和特征提取能力。

5. Mobile MQA注意力块

这个模块是优化后的注意力机制,专门设计用于移动设备:

  • 注意力计算:对特征图进行加权操作,以增强重要特征并抑制不重要的部分。

  • 快速推理:该模块在硬件加速器上实现了快速的推理速度,提高了整体的处理效率。

6. 全局平均池化

在最后的卷积层之后,模型会对特征图进行全局平均池化(Global Average Pooling),将特征图转化为固定长度的向量。这一步骤通过取每个特征图的平均值,将空间维度消除,仅保留通道维度的信息。

7. 全连接层和分类层

最后,通过全连接层(Fully Connected Layer)和Softmax分类层,将特征向量转换为最终的分类结果。

通过上述步骤,MobileNetV4能够高效地处理和分类输入图像,特别适用于资源受限的移动设备上,同时保证了较高的精度和性能。

2.2 更改init.py文件

关键步骤二:修改modules文件夹下的__init__.py文件,先导入函数  

然后在下面的__all__中声明函数

2.3 添加yaml文件

关键步骤三:在/ultralytics/ultralytics/cfg/models/v8下面新建文件yolov8_MobileNetV4.yaml文件,粘贴下面的内容

  • OD【目标检测】
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 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=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPss: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPsm: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPsl: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, mobilenetv4_conv_large, []]  # 0-P1/2   可以替换为 mobilenetv4_conv_small, mobilenetv4_conv_medium, mobilenetv4_conv_large中任意一个- [-1, 1, SPPF, [1024, 5]]  # 5# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, 'nearest']] #6- [[-1, 3], 1, Concat, [1]]  # cat backbone P4 7- [-1, 3, C2f, [512]]  # 12 8- [-1, 1, nn.Upsample, [None, 2, 'nearest']] #9- [[-1, 2], 1, Concat, [1]]  # cat backbone P3 10- [-1, 3, C2f, [256]]  # 15 (P3/8-small) 11- [-1, 1, Conv, [256, 3, 2]] #12- [[-1, 8], 1, Concat, [1]]  # cat head P4 13- [-1, 3, C2f, [512]]  # 18 (P4/16-medium) 14- [-1, 1, Conv, [512, 3, 2]] #15- [[-1, 5], 1, Concat, [1]]  # cat head P5 16- [-1, 3, C2f, [1024]]  # 21 (P5/32-large) 17- [[11, 14, 17], 1, Detect, [nc]]  # Detect(P3, P4, P5)
  • Seg【语义分割】
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 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=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPss: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPsm: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPsl: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, mobilenetv4_conv_large, []]  # 0-P1/2  # 可以替换为 mobilenetv4_conv_small, mobilenetv4_conv_medium, mobilenetv4_conv_large中任意一个- [-1, 1, SPPF, [1024, 5]]  # 5# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, 'nearest']] #6- [[-1, 3], 1, Concat, [1]]  # cat backbone P4 7- [-1, 3, C2f, [512]]  # 12 8- [-1, 1, nn.Upsample, [None, 2, 'nearest']] #9- [[-1, 2], 1, Concat, [1]]  # cat backbone P3 10- [-1, 3, C2f, [256]]  # 15 (P3/8-small) 11- [-1, 1, Conv, [256, 3, 2]] #12- [[-1, 8], 1, Concat, [1]]  # cat head P4 13- [-1, 3, C2f, [512]]  # 18 (P4/16-medium) 14- [-1, 1, Conv, [512, 3, 2]] #15- [[-1, 5], 1, Concat, [1]]  # cat head P5 16- [-1, 3, C2f, [1024]]  # 21 (P5/32-large) 17- [[11, 14, 17], 1, Segment, [nc, 32, 256]] # Segment(P3, P4, P5)
  • OBB【旋转检测】
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 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=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPss: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPsm: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPsl: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, mobilenetv4_conv_large, []]  # 0-P1/2  # 可以替换为 mobilenetv4_conv_small, mobilenetv4_conv_medium, mobilenetv4_conv_large中任意一个- [-1, 1, SPPF, [1024, 5]]  # 5# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, 'nearest']] #6- [[-1, 3], 1, Concat, [1]]  # cat backbone P4 7- [-1, 3, C2f, [512]]  # 12 8- [-1, 1, nn.Upsample, [None, 2, 'nearest']] #9- [[-1, 2], 1, Concat, [1]]  # cat backbone P3 10- [-1, 3, C2f, [256]]  # 15 (P3/8-small) 11- [-1, 1, Conv, [256, 3, 2]] #12- [[-1, 8], 1, Concat, [1]]  # cat head P4 13- [-1, 3, C2f, [512]]  # 18 (P4/16-medium) 14- [-1, 1, Conv, [512, 3, 2]] #15- [[-1, 5], 1, Concat, [1]]  # cat head P5 16- [-1, 3, C2f, [1024]]  # 21 (P5/32-large) 17- [[11, 14, 17], 1, OBB, [nc, 1]] # OBB(P3, P4, P5)

温馨提示:因为本文只是对yolov8基础上添加模块,如果要对yolov8n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。不明白的同学可以看这篇文章: yolov8yaml文件解读——点击即可跳转  


# YOLOv8n
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.25  # layer channel multiple
max_channels: 1024 # max_channels# YOLOv8s
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
max_channels: 1024 # max_channels# YOLOv8l 
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
max_channels: 512 # max_channels# YOLOv8m
depth_multiple: 0.67  # model depth multiple
width_multiple: 0.75  # layer channel multiple
max_channels: 768 # max_channels# YOLOv8x
depth_multiple: 1.33  # model depth multiple
width_multiple: 1.25  # layer channel multiple
max_channels: 512 # max_channels

2.4 注册模块

关键步骤四:在task.py的parse_model函数替换为下面的内容

def parse_model(d, ch, verbose=True):  # model_dict, input_channels(3)"""Parse a YOLO model.yaml dictionary into a PyTorch model."""import ast# Argsmax_channels = float("inf")nc, act, scales = (d.get(x) for x in ("nc", "activation", "scales"))depth, width, kpt_shape = (d.get(x, 1.0) for x in ("depth_multiple", "width_multiple", "kpt_shape"))if scales:scale = d.get("scale")if not scale:scale = tuple(scales.keys())[0]LOGGER.warning(f"WARNING ⚠️ no model scale passed. Assuming scale='{scale}'.")depth, width, max_channels = scales[scale]if act:Conv.default_act = eval(act)  # redefine default activation, i.e. Conv.default_act = nn.SiLU()if verbose:LOGGER.info(f"{colorstr('activation:')} {act}")  # printif verbose:LOGGER.info(f"\n{'':>3}{'from':>20}{'n':>3}{'params':>10}  {'module':<45}{'arguments':<30}")ch = [ch]is_backbone = Falselayers, save, c2 = [], [], ch[-1]  # layers, savelist, ch outfor i, (f, n, m, args) in enumerate(d["backbone"] + d["head"]):  # from, number, module, argsm = getattr(torch.nn, m[3:]) if "nn." in m else globals()[m]  # get modulefor j, a in enumerate(args):if isinstance(a, str):with contextlib.suppress(ValueError):args[j] = locals()[a] if a in locals() else ast.literal_eval(a)n = n_ = max(round(n * depth), 1) if n > 1 else n  # depth gainif m in (Classify,Conv,ConvTranspose,GhostConv,Bottleneck,GhostBottleneck,SPP,SPPF,DWConv,Focus,BottleneckCSP,C1,C2,C2f,C2fAttn,C3,C3TR,C3Ghost,nn.ConvTranspose2d,DWConvTranspose2d,C3x,RepC3,):c1, c2 = ch[f], args[0]if c2 != nc:  # if c2 not equal to number of classes (i.e. for Classify() output)c2 = make_divisible(min(c2, max_channels) * width, 8)if m is C2fAttn:args[1] = make_divisible(min(args[1], max_channels // 2) * width, 8)  # embed channelsargs[2] = int(max(round(min(args[2], max_channels // 2 // 32)) * width, 1) if args[2] > 1 else args[2])  # num headsargs = [c1, c2, *args[1:]]if m in (BottleneckCSP, C1, C2, C2f, C2fAttn, C3, C3TR, C3Ghost, C3x, RepC3):args.insert(2, n)  # number of repeatsn = 1elif m is AIFI:args = [ch[f], *args]elif m in (HGStem, HGBlock):c1, cm, c2 = ch[f], args[0], args[1]args = [c1, cm, c2, *args[2:]]if m is HGBlock:args.insert(4, n)  # number of repeatsn = 1elif m in (mobilenetv4_conv_small, mobilenetv4_conv_medium, mobilenetv4_conv_large):m = m(*args)c2 = m.channels# print(m.channels)elif m is ResNetLayer:c2 = args[1] if args[3] else args[1] * 4elif m is nn.BatchNorm2d:args = [ch[f]]elif m is Concat:c2 = sum(ch[x] for x in f)elif m in (Detect, WorldDetect, Segment, Pose, OBB, ImagePoolingAttn):args.append([ch[x] for x in f])if m is Segment:args[2] = make_divisible(min(args[2], max_channels) * width, 8)elif m is RTDETRDecoder:  # special case, channels arg must be passed in index 1args.insert(1, [ch[x] for x in f])else:c2 = ch[f]if isinstance(c2, list):is_backbone = Truem_ = mm_.backbone = Trueelse:m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args)  # modulet = str(m)[8:-2].replace('__main__.', '')  # module typem.np = sum(x.numel() for x in m_.parameters())  # number paramsm_.i, m_.f, m_.type, m_.np = i + 4 if is_backbone else i, f, t, m.np  # attach index, 'from' index, type, number paramsif verbose:LOGGER.info(f'{i:>3}{str(f):>20}{n_:>3}{m.np:10.0f}  {t:<45}{str(args):<30}')  # printsave.extend(x % (i + 4 if is_backbone else i) for x in ([f] if isinstance(f, int) else f) ifx != -1)  # append to savelistlayers.append(m_)if i == 0:ch = []if isinstance(c2, list):ch.extend(c2)for _ in range(5 - len(ch)):ch.insert(0, 0)else:ch.append(c2)return nn.Sequential(*layers), sorted(save)

2.5 替换函数

关键步骤五:在task.py的BaseModel类下的_predict_once函数替换为下面的内容

    def _predict_once(self, x, profile=False, visualize=False, embed=None):"""Perform a forward pass through the network.Args:x (torch.Tensor): The input tensor to the model.profile (bool):  Print the computation time of each layer if True, defaults to False.visualize (bool): Save the feature maps of the model if True, defaults to False.embed (list, optional): A list of feature vectors/embeddings to return.Returns:(torch.Tensor): The last output of the model."""y, dt, embeddings = [], [], []  # outputsfor m in self.model:if m.f != -1:  # if not from previous layerx = (y[m.f]if isinstance(m.f, int)else [x if j == -1 else y[j] for j in m.f])  # from earlier layersif profile:self._profile_one_layer(m, x, dt)if hasattr(m, "backbone"):x = m(x)for _ in range(5 - len(x)):x.insert(0, None)for i_idx, i in enumerate(x):if i_idx in self.save:y.append(i)else:y.append(None)# for i in x:#     if i is not None:#         print(i.size())x = x[-1]else:x = m(x)  # runy.append(x if m.i in self.save else None)  # save outputif visualize:feature_visualization(x, m.type, m.i, save_dir=visualize)if embed and m.i in embed:embeddings.append(nn.functional.adaptive_avg_pool2d(x, (1, 1)).squeeze(-1).squeeze(-1))  # flattenif m.i == max(embed):return torch.unbind(torch.cat(embeddings, 1), dim=0)return x

2.6 执行程序

在train.py中,将model的参数路径设置为yolov8_MobileNetv4.yaml的路径

建议大家写绝对路径,确保一定能找到

from ultralytics import YOLO# Load a model
# model = YOLO('yolov8n.yaml')  # build a new model from YAML
# model = YOLO('yolov8n.pt')  # load a pretrained model (recommended for training)model = YOLO(r'/projects/ultralytics/ultralytics/cfg/models/v8/yolov8_MobilenetV4.yaml')  # build from YAML and transfer weights# Train the model
model.train(batch=16)

🚀运行程序,如果出现下面的内容则说明添加成功🚀 

1                  -1  1    394240  ultralytics.nn.modules.block.SPPF            [512, 256, 5]                 2                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          3             [-1, 3]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           4                  -1  1    164608  ultralytics.nn.modules.block.C2f             [512, 128, 1]                 5                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          6             [-1, 2]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           7                  -1  1     41344  ultralytics.nn.modules.block.C2f             [256, 64, 1]                  8                  -1  1     36992  ultralytics.nn.modules.conv.Conv             [64, 64, 3, 2]                9             [-1, 8]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           10                  -1  1    123648  ultralytics.nn.modules.block.C2f             [192, 128, 1]                 11                  -1  1    147712  ultralytics.nn.modules.conv.Conv             [128, 128, 3, 2]              12             [-1, 5]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           13                  -1  1    493056  ultralytics.nn.modules.block.C2f             [384, 256, 1]                 14        [11, 14, 17]  1    897664  ultralytics.nn.modules.head.Detect           [80, [64, 128, 256]]          
YOLOv8_mobilenetv4 summary: 418 layers, 34655800 parameters, 34655784 gradients

3. 完整代码分享

https://pan.baidu.com/s/12_qtwlKNeSiycQY_EKPV-w?pwd=h13b

提取码: h13b 

4. GFLOPs

关于GFLOPs的计算方式可以查看百面算法工程师 | 卷积基础知识——Convolution

未改进的YOLOv8nGFLOPs

img

改进后的GFLOPs

现在手上没有卡了,等过段时候有卡了把这补上,需要的同学自己测一下

5. 进阶

可以与其他的注意力机制或者损失函数等结合,进一步提升检测效果

6. 总结

MobileNetV4(MNv4)是最新一代的MobileNet,其核心原理在于实现了跨各种移动设备的高效性能。它引入了通用倒瓶颈(UIB)搜索块,这是一种统一且灵活的结构,结合了倒瓶颈、ConvNext、前馈网络(FFN)和新的额外深度可分离卷积(ExtraDW)变体。与此同时,MobileNetV4还推出了专为移动加速器优化的Mobile MQA注意力块,提高了39%的推理速度。通过改进的神经架构搜索(NAS)方法,MobileNetV4显著提高了搜索效率,创建了在CPU、DSP、GPU以及专用加速器(如Apple Neural Engine和Google Pixel EdgeTPU)上表现优异的模型。此外,MobileNetV4还采用了一种新的蒸馏技术,进一步提高了模型的准确性。整体上,MobileNetV4通过整合UIB、Mobile MQA和改进的NAS方法,成功打造出一系列在移动设备上表现最优的模型,兼顾计算效率和精度,实现了在多种硬件平台上的帕累托最优性能。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux PCI和PCIe总线

1 PCIe中断 - PCI/PCIe设备中断都是level触发&#xff0c;并且请求信号为低电平有效 - PCI总线一般只有INTA#到INTD#的4个中断引脚&#xff0c;所以PCI多功能设备的func一般不会超过4个&#xff0c;但是共享中断除外 2 IOMMU 2.1 ARM SMMU v2 Refer to my blog ARM SMMU v2. 2.…

【机器学习】重塑游戏世界:机器学习如何赋能游戏创新与体验升级

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f50d;1. 引言&#xff1a;游戏世界的变革前夜&#x1f4d2;2. 机器学习驱动的游戏创新&#x1f31e;智能化游戏设计与开发&…

OJ-0807

题目 参考 import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);String input in.nextLine();String[] numStrs inp…

身体出现这5种异常,可能是甲状腺在求救,千万别扛着!

甲状腺&#xff0c;被誉为人体新陈代谢的“发动机”&#xff0c;是调节我们身体能量和代谢的重要器官。然而&#xff0c;当甲状腺出现问题时&#xff0c;它往往会通过身体的一些异常信号向我们求救。北京精诚博爱医院张维一主任提醒&#xff1a;以下是五种常见的甲状腺异常表现…

您知道Jmeter中Redirect Automatically 和 Follow Redirects的使用场景吗?

相信很多使用过jmeter的同学都没有关注过请求中的Redirect Automatically 和 Follow Redirects选项&#xff0c;如下图&#xff1a; 在 JMeter 中&#xff0c;Redirect Automatically 和 Follow Redirects 是与 HTTP 请求重定向相关的两个选项&#xff0c;它们之间是有很大区别…

速度规划之:起点速度和终点速度不为零的非对称梯形速度规划

起点速度和终点速度不为零的非对称梯形速度规划 一、引言二、理论基础1. 梯形速度规划概述2.数学建模- 变量定义- 约束关系- 公式推导 三、计算过程1.只存在减速段2.只存在加速段3.存在加速段和减速段4.存在加速度段、匀速段和减速段 四、仿真实现五、优缺点优点缺点 六、总结 …

亚马逊等跨境电商平台怎么找到好的测评资源?

如何找到好的测评资源呢&#xff1f; 目前常规卖家找测评资源主要通过以下途径&#xff1a; 联系自己在海外的亲友帮忙测评&#xff0c;不过海外的亲友会比较有限安排业务员在facebook等社交平台找老外测评&#xff0c;但社交平台找老外很难掌控留评时效&#xff0c;甚至会遇…

破解USB设备通讯协议实现自定义软件控制的步骤与方法

在设备和计算机之间通过USB进行通讯的情况下&#xff0c;厂家提供的软件可以控制设备&#xff0c;但没有提供任何其他资料和支持&#xff0c;这种情况下&#xff0c;若希望自行开发软件来实现同样的功能&#xff0c;可以通过以下步骤破解通讯协议并开发自定义程序。 1. 捕获US…

2-57 基于matlab 实现了气缸的充气和放气的仿真

基于matlab 实现了气缸的充气和放气的仿真&#xff0c;在等温情况和绝热两种情况下分别进行了仿真&#xff0c;并给多变过程下的理论计算公式。程序已调通&#xff0c;可直接运行。 2-57 matlab 气缸充气和放气仿真 - 小红书 (xiaohongshu.com)

【论文阅读】PETRv2: A Unified Framework for 3D Perception from Multi-Camera Images

Q: 论文如何解决这个问题&#xff1f; A: 论文通过提出PETRv2框架来解决多相机图像的3D感知问题&#xff0c;具体方法包括以下几个关键点&#xff1a; 时间建模&#xff08;Temporal Modeling&#xff09;&#xff1a; 通过3D坐标对齐&#xff08;3D Coordinates Alignment&…

ASP.Net Core设置接口根路径的方法

使用asp.net core开发微服务项目&#xff0c;需要给每个服务设置不同的根路径&#xff0c;这样既能使用网关转发请求&#xff0c;又方便对单个服务进行测试&#xff0c;保证请求路径的统一。 设置方法需要使用中间件&#xff0c;在Program.cs添加如下代码 app.UsePathBase(&qu…

通过ZRender画一个大屏的顶部样式标题

介绍&#xff1a;通过ZRender画一个大屏项目的顶部样式&#xff0c;在其中放入大屏的标题。ZRender 是二维绘图引擎&#xff0c;它提供 Canvas、SVG、VML 等多种渲染方式。ZRender 也是 ECharts 的渲染器。 一、下载 npm install zrender终端输入以上命令下载包即可。 二、导…

记忆化搜索——1

目录 1.斐波那契数 2.不同路径 3.最长递增子序列 4.猜数字大小2 5.矩阵中的最长递增路径 1.斐波那契数 该题规律很明显&#xff0c;就直接放记忆化搜索的版本了 class Solution { public:int dfs(int n){if(n0||n1)//递归出口{return n;}if(f[n-1]-1)//检查是否已经记忆过…

JVM 加载阶段 Class对象加载位置是在 堆中还是方法区?

在JVM&#xff08;Java虚拟机&#xff09;的类加载过程中&#xff0c;Class对象的加载位置涉及到堆&#xff08;Heap&#xff09;和方法区&#xff08;Method Area&#xff09;两个关键区域。具体来说&#xff0c;类的加载阶段涉及到将类的.class文件中的二进制数据读入到内存中…

黑丝或者白丝,都可以用LoRA(Stable Diffusion进阶篇:ComfyUI 附加网络)

前言 在学习WebUI的那些基础知识点的时候&#xff0c;有一个东西是每一个初学者都绕不开的大山-附加网络。 这个东西对于每一个接触Stable Diffusion的小伙伴来说就像是小学门口小卖部卖的辣条、初中课本上的涂鸦、高中数学卷解不开的最后一道大题。 学习过WebUI里Stable Di…

揭秘亚马逊新手快速成长背后的秘密:从入门到精通

在亚马逊这个充满机遇与挑战的市场平台上&#xff0c;作为一名深耕多年的卖家&#xff0c;我积累了宝贵的经验和见解。随着市场环境的不断变化&#xff0c;我意识到&#xff0c;无论是新加入的创业者还是经验丰富的老手&#xff0c;都需要不断学习和适应&#xff0c;以在这个平…

游戏行业报告(一)| 中国占全球头部上市游戏企业34%,“智能NPC”竞争方向较受关注

近日&#xff0c;伽马数据发布了《2024中国上市/非上市游戏企业竞争力报告》&#xff0c;本篇文章仅采用《2024中国上市/非上市游戏企业竞争力报告》的部分数据。由于文章太长&#xff0c;所以分了下集&#xff0c;大家可以收藏关注~ 企业全球资本市场竞争现状 全球TOP50上市游…

Motionface ai工具有哪些?

Motionface Android/PC 用一张静态含有人脸相片来生成一个能说会唱的虚拟主播。使用简单便捷&#xff0c;极致的流畅度体验超乎您的想象。 免费下载 Respeak PC电脑软件 任意视频一键生成虚拟主播&#xff0c;匹配音频嘴型同步&#xff0c;保留原视频人物神态和动作&#xff0c…

什么是柔性生产?

柔性生产&#xff0c;是一种能够迅速调整生产流程、产品种类及产量&#xff0c;以低成本、高效率响应市场多样化需求的生产方式。它不仅仅是对生产线硬件的升级&#xff0c;更是对生产组织、管理模式及信息技术的全面革新。柔性生产的核心在于“灵活”二字&#xff0c;即企业能…

JVM(面试用)

目录 一、JVM运行时数据区 二、JVM类加载 类加载过程 1、加载&#xff08;loading&#xff09; 2、验证&#xff08;Verification&#xff09; 3、准备&#xff08;Perparation&#xff09; 4、解析&#xff08;Resolution&#xff09; 5、初始化&#xff08;Initializ…