yolov26改进 | 主干/Backbone篇 | 利用目标检测移动端网络MobileNetV1替换Backbone(支持v26n、v26s、v26m)

yolov26改进 | 主干/Backbone篇 | 利用目标检测移动端网络MobileNetV1替换Backbone(支持v26n、v26s、v26m) 开始讲解之前推荐一下我的专栏本专栏的内容支持(分类、检测、分割、追踪、关键点检测),专栏目前为限时折扣欢迎大家订阅本专栏本专栏每周更新3-5篇最新机制更有包含我所有改进的文件和交流群提供给大家。一、本文介绍本文给大家带来的改进机制是经典轻量级网络——MobileNetV1。该网络专为移动端和嵌入式视觉应用设计其核心是使用深度可分离卷积替代传统卷积将空间卷积和通道融合过程进行拆分从而在保证特征提取能力的同时有效降低模型的参数量和计算量。MobileNetV1还引入了宽度系数和分辨率系数两个全局超参数可以根据实际设备性能在模型精度、推理速度和计算开销之间进行灵活权衡。相关实验表明MobileNetV1在资源消耗与模型精度之间具有较好的平衡并已应用于目标检测、细粒度分类、面部属性识别和大规模地理定位等多种视觉任务。对于希望降低模型复杂度、提升推理速度或开展边缘端部署的读者来说MobileNetV1是一种非常实用的轻量化改进方案。本文基于官方MobileNetV1结构进行了进一步适配和修改分别设计了对应YOLOv26n、YOLOv26s和YOLOv26m的三个版本方便大家根据模型规模和实际任务需求进行选择。相关网络结构、配置方式和改进内容均为本人在官方实现基础上的原创修改本文将结合完整代码手把手讲解如何将MobileNetV1集成到YOLOv26中用于改进模型的特征提取网络。专栏链接YOLOv26有效涨点专栏包含Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制目录一、本文介绍二、MobileNetV1的框架原理三、MobileNetV1的核心代码四、手把手教你添加MobileNetV1网络结构4.1 修改一4.2 修改二4.3 修改三4.4 修改四4.5 修改五4.6 修改六4.7 修改七4.8 修改八4.9 修改九五、MobileNetV1的yaml文件5.1 yaml文件5.2 训练文件的代码六、成功运行记录七、本文总结二、MobileNetV1的框架原理​官方论文地址论文地址点击即可跳转官方代码地址官方代码地址MobileNetV1的论文《MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications》介绍了一种高效的模型集合专为移动和嵌入式视觉应用设计。这些模型基于简化的架构并利用深度可分离卷积构建轻量级深度神经网络从而适应移动和嵌入式设备的计算和存储限制。这种架构包含两个步骤深度卷积Depthwise Convolution用于单独处理每个输入通道然后是逐点卷积Pointwise Convolution用于整合深度卷积的输出。通过这种分解MobileNet显著减少了模型的大小和计算复杂度同时保持了良好的性能。论文还引入了两个全局超参数允许在网络大小、速度和准确性之间进行灵活的权衡。MobileNet的主要创新点包括1. 深度可分离卷积该网络架构使用深度可分离卷积代替标准卷积显著减少模型参数和计算量。2. 宽度乘数提供了一个超参数来调节网络的宽度从而使得模型可以根据需要进行缩放适应不同的性能和资源要求。3. 分辨率乘数允许调整输入图像的分辨率进一步减少计算量。其中第二点和第三点在代码中很清楚的就能看到如下图红框的所示分别对应第二点和第三点。深度可分离卷积如下图所示这张图片描绘了深度可分离卷积的概念其中标准的卷积滤波器a被分解为两个独立的层深度卷积b和逐点卷积c。在深度卷积中每个输入通道独立应用一个滤波器而逐点卷积则使用1x1的卷积核来组合深度卷积的输出。这种分解方法显著减少了计算量因为它将卷积操作分为两个更简单的步骤一个是应用于每个通道的滤波深度卷积另一个是这些滤波输出的组合逐点卷积。三、MobileNetV1的核心代码下面的代码是整个MobileNetV1的核心代码大家如果想学习可以和上面的框架原理对比着看一看估计会有一定的收获使用方式看章节四。import torch from torch import nn __all__ [MobileNetV1] class DepthwiseSepConvBlock(nn.Module): def __init__( self, in_channels: int, out_channels: int, stride: int 1, use_relu6: bool True, ): Constructs Depthwise seperable with pointwise convolution with relu and batchnorm respectively. Args: in_channels (int): input channels for depthwise convolution out_channels (int): output channels for pointwise convolution stride (int, optional): stride paramemeter for depthwise convolution. Defaults to 1. use_relu6 (bool, optional): whether to use standard ReLU or ReLU6 for depthwise separable convolution block. Defaults to True. super().__init__() # Depthwise conv self.depthwise_conv nn.Conv2d( in_channels, in_channels, (3, 3), stridestride, padding1, groupsin_channels, ) self.bn1 nn.BatchNorm2d(in_channels) self.relu1 nn.ReLU6() if use_relu6 else nn.ReLU() # Pointwise conv self.pointwise_conv nn.Conv2d(in_channels, out_channels, (1, 1)) self.bn2 nn.BatchNorm2d(out_channels) self.relu2 nn.ReLU6() if use_relu6 else nn.ReLU() def forward(self, x): Perform forward pass. x self.depthwise_conv(x) x self.bn1(x) x self.relu1(x) x self.pointwise_conv(x) x self.bn2(x) x self.relu2(x) return x class MobileNetV1(nn.Module): def __init__( self, input_channel: int 3, depth_multiplier: float 1.0, use_relu6: bool True, ): Constructs MobileNetV1 architecture Args: n_classes (int, optional): count of output neuron in last layer. Defaults to 1000. input_channel (int, optional): input channels in first conv layer. Defaults to 3. depth_multiplier (float, optional): network width multiplier ( width scaling ). Suggested Values - 0.25, 0.5, 0.75, 1.. Defaults to 1.0. use_relu6 (bool, optional): whether to use standard ReLU or ReLU6 for depthwise separable convolution block. Defaults to True. super().__init__() # The configuration of MobileNetV1 # input channels, output channels, stride config ( (32, 64, 1), (64, 128, 2), (128, 128, 1), (128, 256, 2), (256, 256, 1), (256, 512, 2), (512, 512, 1), (512, 512, 1), (512, 512, 1), (512, 512, 1), (512, 512, 1), (512, 1024, 2), (1024, 1024, 1), ) self.model nn.Sequential( nn.Conv2d( input_channel, int(32 * depth_multiplier), (3, 3), stride2, padding1 ) ) # Adding depthwise block in the model from the config for in_channels, out_channels, stride in config: self.model.append( DepthwiseSepConvBlock( int(in_channels * depth_multiplier), # input channels int(out_channels * depth_multiplier), # output channels stride, use_relu6use_relu6, ) ) self.index [128, 256, 512, 1024] self.width_list [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))] def forward(self, x): Perform forward pass. results [None, None, None, None] for model in self.model: x model(x) if x.size(1) in self.index: position self.index.index(x.size(1)) # Find the position in the index list results[position] x return results if __name__ __main__: # Generating Sample image image_size (1, 3, 224, 224) image torch.rand(*image_size) # Model mobilenet_v1 MobileNetV1(depth_multiplier1) out mobilenet_v1(image) print(out)四、手把手教你添加MobileNetV1网络结构4.1 修改一我们复制网络结构代码到“ultralytics/nn”目录下创建一个py文件复制粘贴进去 我这里起的名字是MobileNetV1。​4.2 修改二第二步我们在该目录下创建一个新的py文件名字为__init__.py(用群内的文件的话已经有了无需新建)然后在其内部导入我们的检测头如下图所示。4.3 修改三第三步我门中到如下文件ultralytics/nn/tasks.py进行导入和注册我们的模块(用群内的文件的话已经有了无需重新导入直接开始第四步即可)从今天开始以后的教程就都统一成这个样子了因为我默认大家用了我群内的文件来进行修改4.4 修改四添加如下两行代码​4.5 修改五找到1600多行大概把具体看图片按照图片来修改就行添加红框内的部分注意没有()只是函数名我这里只添加了部分的版本大家有兴趣这个MobileNetV1还有更多的版本可以添加看我给的代码函数头即可。​elif m in {自行添加对应的模型即可下面都是一样的}: m m() c2 m.width_list # 返回通道列表 backbone True4.6 修改六按图修改。​if isinstance(c2, list): m_ m m_.backbone True else: m_ nn.Sequential(*(m(*args) for _ in range(n))) if n 1 else m(*args) # module t str(m)[8:-2].replace(__main__., ) # module type m.np sum(x.numel() for x in m_.parameters()) # number params m_.i, m_.f, m_.type i 4 if backbone else i, f, t # attach index, from index, type4.7 修改七如下的也需要修改全部按照我的来。​代码如下把原先的代码替换了即可。if verbose: LOGGER.info(f{i:3}{str(f):20}{n_:3}{m.np:10.0f} {t:45}{str(args):30}) # print save.extend(x % (i 4 if backbone else i) for x in ([f] if isinstance(f, int) else f) if x ! -1) # append to savelist layers.append(m_) if i 0: ch [] if isinstance(c2, list): ch.extend(c2) if len(c2) ! 5: ch.insert(0, 0) else: ch.append(c2)4.8 修改八修改七和前面的都不太一样需要修改前向传播中的一个部分 已经离开了parse_model方法了。可以在图片中看代码行数没有离开task.py文件都是同一个文件。 同时这个部分有好几个前向传播都很相似大家不要看错了是160多行左右的不同仓库版本可能有些差异同时我后面提供了代码大家直接复制粘贴即可不会修改联系博主获取视频教程。​​代码如下-def _predict_once(self, x, profileFalse, visualizeFalse, embedNone): 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. visualize (bool): Save the feature maps of the model if True. embed (list, optional): A list of layer indices to return embeddings from. Returns: (torch.Tensor): The last output of the model. y, dt, embeddings [], [], [] # outputs embed frozenset(embed) if embed is not None else {-1} max_idx max(embed) for m in self.model: if m.f ! -1: # if not from previous layer x y[m.f] if isinstance(m.f, int) else [x if j -1 else y[j] for j in m.f] # from earlier layers if profile: self._profile_one_layer(m, x, dt) if hasattr(m, backbone): x m(x) if len(x) ! 5: # 0 - 5 x.insert(0, None) for index, i in enumerate(x): if index in self.save: y.append(i) else: y.append(None) x x[-1] # 最后一个输出传给下一层 else: x m(x) # run y.append(x if m.i in self.save else None) # save output if visualize: feature_visualization(x, m.type, m.i, save_dirvisualize) if embed and m.i in embed: embeddings.append(nn.functional.adaptive_avg_pool2d(x, (1, 1)).squeeze(-1).squeeze(-1)) # flatten if m.i max_idx: return torch.unbind(torch.cat(embeddings, 1), dim0) return x4.9 修改九我们找到如下文件ultralytics/utils/torch_utils.py按照如下的图片进行修改否则容易打印不出来计算量。​五、MobileNetV1的yaml文件5.1 yaml文件训练信息YOLO11-MobileNetV1 summary: 302 layers, 1,851,375 parameters, 1,851,359 gradients, 4.4 GFLOPs# 这里需要注意的是比如你用的YOLOv11s那么你就用本文机制的s版本.# Ultralytics AGPL-3.0 License - https://ultralytics.com/license # Ultralytics YOLO26 object detection model with P3/8 - P5/32 outputs # Model docs: https://docs.ultralytics.com/models/yolo26 # Task docs: 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 # YOLO26 backbone backbone: # [from, repeats, module, args] - [-1, 1, MobileNetV1, []] # 0-4 P1/2 - [-1, 1, SPPF, [1024, 5, 3, True]] # 5 - [-1, 2, C2PSA, [1024]] # 6 # YOLO26 head head: - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 3], 1, Concat, [1]] # cat backbone P4 - [-1, 2, C3k2, [512, True]] # 9 - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 2], 1, Concat, [1]] # cat backbone P3 - [-1, 2, C3k2, [256, True]] # 12 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]] - [[-1, 9], 1, Concat, [1]] # cat head P4 - [-1, 2, C3k2, [512, True]] # 15 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]] - [[-1, 6], 1, Concat, [1]] # cat head P5 - [-1, 2, C3k2, [1024, True, 0.5, True]] # 18 (P5/32-large) - [[12, 15, 18], 1, Detect, [nc]] # Detect(P3, P4, P5)5.2 训练文件的代码可以复制我的运行文件进行运行。import warnings warnings.filterwarnings(ignore) from ultralytics import YOLO if __name__ __main__: model YOLO(替换你的yaml文件地址) model.load(yolov8n.pt) model.train(datar你的数据集的地址, cacheFalse, imgsz640, epochs150, batch4, close_mosaic0, workers0, device0, optimizerSGD ampFalse, )六、成功运行记录下面是成功运行的截图已经完成了有1个epochs的训练图片太大截不全第2个epochs了。​​七、本文总结到此本文的正式分享内容就结束了在这里给大家推荐我的YOLOv26改进有效涨点专栏本专栏目前为新开的平均质量分98分后期我会根据各种最新的前沿顶会进行论文复现也会对一些老的改进机制进行补充如果大家觉得本文帮助到你了订阅本专栏关注后续更多的更新~专栏链接YOLOv26有效涨点专栏包含Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制​​​