本文主要是介绍主干网络篇 | YOLOv8更换主干网络之ShuffleNetV2(包括完整代码+添加步骤+网络结构图),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言:Hello大家好,我是小哥谈。ShuffleNetV2是一种轻量级的神经网络架构,用于图像分类和目标检测任务。它是ShuffleNet的改进版本,旨在提高模型的性能和效率。ShuffleNetV2相比于之前的版本,在保持模型轻量化的同时,提高了模型的准确性和性能。它在计算资源有限的设备上具有较好的应用潜力!~🌈
目录
🚀1. 基础概念
🚀2.网络结构
🚀3.添加步骤
🚀4.改进方法
🍀🍀步骤1:block.py文件修改
🍀🍀步骤2:__init__.py文件修改
🍀🍀步骤3:tasks.py文件修改
🍀🍀步骤4:创建自定义yaml文件
🍀🍀步骤5:新建train.py文件
🍀🍀步骤6:模型训练测试
🚀1. 基础概念
ShuffleNetV2是一种轻量级的神经网络架构,用于图像分类和目标检测任务。它是ShuffleNet的改进版本,旨在提高模型的性能和效率。
ShuffleNetV2的主要特点包括:
- 分组卷积:通过将输入通道分成多个组,并在组内进行卷积操作,减少了计算量和参数数量。
- 逐点卷积:使用1x1的卷积核进行逐点卷积,用于调整通道数和特征图的维度。
- 通道重排:通过将输入特征图按通道进行重排,实现信息的混洗和交互,增强了特征的表达能力。
- 瓶颈结构:采用瓶颈结构,即先降维再升维,减少了计算量和参数数量。
- 网络设计:ShuffleNet V2通过堆叠多个ShuffleNet单元来构建整个网络,可以根据任务的需求进行不同层数和宽度的配置。
ShuffleNetV2相比于之前的版本,在保持模型轻量化的同时,提高了模型的准确性和性能。它在计算资源有限的设备上具有较好的应用潜力。
shuffleNetV2这篇论文比较硬核,提出了不少新的思想,推荐大家可以看看论文原文。主要思想包括:
- 模型的计算复杂度不能只看FLOPs,还需要参考一些其他的指标
- 作者提出了4条如何设计高效网络的准则
- 基于该准则提出了新的block设置
FLOPS网上有两种:FLOPS和 FLOPs
FLOPS:全大写,指每秒浮点运算次数,可以理解为计算的速度,是衡量硬件性能的一个指标 (硬件)
FLOPs:s小写,指浮点运算数,理解为计算量,可以用来衡量算法/模型的复杂度,(模型)在论文中常用GFLOPs(1 GFLOPs = 10^9FLOPs)
ShuffleNetV2网络结构:
原理图:
其中,a、b为ShuffleNetV1原理图,c、d为ShuffleNetV2原理图。
论文题目:《ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design》
论文地址: https://arxiv.org/pdf/1807.11164.pdf
代码实现: GitHub - megvii-model/ShuffleNet-Series
🚀2.网络结构
本文的改进是基于YOLOv8,关于其网络结构具体如下图所示:
YOLOv8官方仓库地址:
GitHub - ultralytics/ultralytics: NEW - YOLOv8 🚀 in PyTorch > ONNX > OpenVINO > CoreML > TFLite
针对本文的改进,作者将所使用的含有预训练权重文件的YOLOv8完整源码进行了上传,大家可在我的“资源”中自行下载。
🚀3.添加步骤
针对本文的改进,具体步骤如下所示:👇
步骤1:block.py文件修改
步骤2:__init__.py文件修改
步骤3:tasks.py文件修改
步骤4:创建自定义yaml文件
步骤5:新建train.py文件
步骤6:模型训练测试
🚀4.改进方法
🍀🍀步骤1:block.py文件修改
在源码中找到block.py文件,具体位置是ultralytics/nn/modules/block.py,然后将ShuffleNetV2模块代码添加到block.py文件末尾位置。
ShuffleNetV2模块代码:
# ShuffleNetv2核心代码
# By CSDN 小哥谈
import torch
import torch.nn as nndef channel_shuffle(x, groups):batchsize, num_channels, height, width = x.data.size()channels_per_group = num_channels // groupsx = x.view(batchsize, groups, channels_per_group, height, width)x = torch.transpose(x, 1, 2).contiguous()x = x.view(batchsize, -1, height, width)return xclass CBRM(nn.Module): # Conv BN ReLU Maxpool2ddef __init__(self, c1, c2):super(CBRM, self).__init__()self.conv = nn.Sequential(nn.Conv2d(c1, c2, kernel_size=3, stride=2, padding=1, bias=False),nn.BatchNorm2d(c2),nn.ReLU(inplace=True),)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)def forward(self, x):return self.maxpool(self.conv(x))class Shuffle_Block(nn.Module):def __init__(self, ch_in, ch_out, stride):super(Shuffle_Block, self).__init__()if not (1 <= stride <= 2):raise ValueError('illegal stride value')self.stride = stridebranch_features = ch_out // 2assert (self.stride != 1) or (ch_in == branch_features << 1)if self.stride > 1:self.branch1 = nn.Sequential(self.depthwise_conv(ch_in, ch_in, kernel_size=3, stride=self.stride, padding=1),nn.BatchNorm2d(ch_in),nn.Conv2d(ch_in, branch_features, kernel_size=1, stride=1, padding=0, bias=False),nn.BatchNorm2d(branch_features),nn.ReLU(inplace=True),)self.branch2 = nn.Sequential(nn.Conv2d(ch_in if (self.stride > 1) else branch_features,branch_features, kernel_size=1, stride=1, padding=0, bias=False),nn.BatchNorm2d(branch_features),nn.ReLU(inplace=True),self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1),nn.BatchNorm2d(branch_features),nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False),nn.BatchNorm2d(branch_features),nn.ReLU(inplace=True),)@staticmethoddef depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False):return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i)def forward(self, x):if self.stride == 1:x1, x2 = x.chunk(2, dim=1)out = torch.cat((x1, self.branch2(x2)), dim=1)else:out = torch.cat((self.branch1(x), self.branch2(x)), dim=1)out = channel_shuffle(out, 2)return out
再然后,在block.py文件最上方下图所示位置加入CBRM、Shuffle_Block。
🍀🍀步骤2:__init__.py文件修改
在源码中找到__init__.py文件,具体位置是ultralytics/nn/modules/__init__.py。
修改1:加入CBRM、Shuffle_Block,具体如下图所示:
修改2:加入CBRM、Shuffle_Block,具体如下图所示:
🍀🍀步骤3:tasks.py文件修改
在源码中找到tasks.py文件,具体位置是ultralytics/nn/tasks.py。
修改1:在下图所示位置导入类名CBRM、Shuffle_Block。
修改2:找到parse_model函数(736行左右),在下图中所示位置添加如下代码。
# -------ShuffleNetv2------------elif m in [CBRM, Shuffle_Block]:c1, c2 = ch[f], args[0]if c2 != nc:c2 = make_divisible(min(c2, max_channels) * width, 8)args = [c1, c2, *args[1:]]# --------------------------------
具体添加位置如下图所示:
🍀🍀步骤4:创建自定义yaml文件
在源码ultralytics/cfg/models/v8目录下创建yaml文件,并命名为:yolov8_ShuffleNetV2.yaml。具体如下图所示:
yolov8_ShuffleNetV2.yaml文件完整代码如下所示:
# 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, CBRM, [ 32 ] ] # 0-P2/4- [ -1, 1, Shuffle_Block, [ 128, 2 ] ] # 1-P3/8- [ -1, 3, Shuffle_Block, [ 128, 1 ] ] # 2- [ -1, 1, Shuffle_Block, [ 256, 2 ] ] # 3-P4/16- [ -1, 7, Shuffle_Block, [ 256, 1 ] ] # 4- [ -1, 1, Shuffle_Block, [ 512, 2 ] ] # 5-P5/32- [ -1, 3, Shuffle_Block, [ 512, 1 ] ] # 6# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 3], 1, Concat, [1]] # cat backbone P4- [-1, 3, C2f, [512]] # 9- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 2], 1, Concat, [1]] # cat backbone P3- [-1, 3, C2f, [256]] # 12 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 9], 1, Concat, [1]] # cat head P4- [-1, 3, C2f, [512]] # 15 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 6], 1, Concat, [1]] # cat head P5- [-1, 3, C2f, [1024]] # 18 (P5/32-large)- [[12, 15, 18], 1, Detect, [nc]] # Detect(P3, P4, P5)
🍀🍀步骤5:新建train.py文件
在源码根目录下新建train.py文件,文件完整代码如下所示:
from ultralytics import YOLO# Load a model
model = YOLO(r'C:\Users\Lenovo\PycharmProjects\ultralytics-main\ultralytics\cfg\models\v8\yolov8_ShuffleNetV2.yaml') # build a new model from YAML
model = YOLO('yolov8n.pt') # load a pretrained model (recommended for training)
model = YOLO(r'C:\Users\Lenovo\PycharmProjects\ultralytics-main\ultralytics\cfg\models\v8\yolov8_ShuffleNetV2.yaml').load('yolov8n.pt') # build from YAML and transfer weights# Train the model
model.train(data=r'C:\Users\Lenovo\PycharmProjects\ultralytics-main\ultralytics\cfg\datasets\helmet.yaml', epochs=100, imgsz=640)
注意:一定要用绝对路径,以防发生报错。
🍀🍀步骤6:模型训练测试
在train.py文件,点击“运行”,在作者自制的安全帽佩戴检测数据集上,模型可以正常训练。
模型训练过程:
模型训练结果:
关于本次改进所使用的安全帽佩戴检测数据集,已上传至我的“资源”中,大家可免费下载。
这篇关于主干网络篇 | YOLOv8更换主干网络之ShuffleNetV2(包括完整代码+添加步骤+网络结构图)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!