YOLOv11改进 | 主干/Backbone篇 | 华为移动端目标检测模型Ghostnetv1改进yolov11特征提取网络

一、本文介绍

本文给大家带来的改进机制是华为移动端模型 Ghostnetv1 ,华为的 GhostNet 是一种轻量级 卷积神经网络 ,旨在在计算资源有限的 嵌入式设备 上实现高性能的图像分类。 GhostNet的关键思想 在于通过引入Ghost模块,以较低的计算成本增加了特征图的数量,从而提高了模型的性能。这种方法在计算资源有限的情况下,尤其适用于图像分类任务,并在一些基准测试中表现出了很好的性能。 本文将通过首先介绍其主要原理,然后手把手教大家如何使用该网络结构改进我们的特征提取网络。

欢迎大家订阅我的专栏一起学习YOLO!


目录

一、本文介绍

二、GhostNet卷积原理

2.1 GhostNet的基本原理

2.2 Ghost Module

2.3 线性变换

2.4 Ghost Bottlenecks

三、 GhsetNetV1的核心代码

四、手把手教你添加GhsetNetV1

4.1 修改一

4.2 修改二

4.3 修改三

4.4 修改四

4.5 修改五

4.6 修改六

修改七

注意!!! 额外的修改!

打印计算量问题解决方案

注意事项!!!

五、GhsetNetV1的yaml文件

5.1 yaml文件

5.2 训练文件的代码

六、成功运行记录

七、本文总结


二、 GhostNet 卷积原理

论文地址: 官方论文地址

代码地址: 官方代码地址


2.1 GhostNet的基本原理

华为的 GhostNet 是一种轻量级卷积 神经网络 ,旨在在计算资源有限的嵌入式设备上实现高性能的图像分类。GhostNet的 基本原理 包括以下关键概念:

1. Ghost Module(幽灵模块): GhostNet引入了Ghost模块,这是其核心 组件 。Ghost模块的主要目标是生成更多的特征图,而不会增加过多的计算负担。Ghost模块的设计允许在特征图中引入额外的信息,以提高模型性能。

2. 线性变换: Ghost模块通过应用一系列廉价的线性变换(例如,卷积和标准化)来生成所谓的“幽灵”特征图。这些变换具有较低的计算成本,但可以生成额外的特征图,以丰富模型的表示能力。

3. Ghost Bottlenecks: 为了构建GhostNet,可以堆叠多个Ghost模块,形成所谓的Ghost Bottlenecks。这样可以创建深度轻量级网络,适用于嵌入式设备和移动应用。

GhostNet的关键思想 在于通过引入Ghost模块,以较低的计算成本增加了特征图的数量,从而提高了模型的性能。这种方法在计算资源有限的情况下,尤其适用于图像分类任务,并在一些基准测试中表现出了很好的性能。


2.2 Ghost Module

GhostNet中的 Ghost Module(幽灵模块) 是该网络的关键组件之一,旨在以低计算成本生成更多的特征图,从而提高模型的性能。以下是Ghost Module的 主要特点和原理

1. 生成额外特征图: Ghost Module的主要目标是生成额外的特征图,而不会增加大量的计算负担。这些额外的特征图有助于丰富模型的表示能力,提高图像分类性能。

2. 线性变换: Ghost Module使用一系列线性变换来生成这些额外的特征图。这些线性变换通常包括卷积和其他简单的操作,其计算成本远低于传统的卷积操作。这些线性操作 Φ 作用于每个通道,从而生成更多的特征图。

3. 输出特征图: Ghost Module的输出数据Y包括了生成的n个特征图,其中n = m · s,m是Ghost Module输入数据的通道数,s是线性变换的数量。这些特征图可以用于后续的任务,如图像分类。

4. 多种线性操作: 在实际应用中,Ghost Module可以包含多种不同的线性操作,例如3×3和5×5的线性核。这些不同的操作可以在实验中进行分析和比较,以确定哪种操作在特定任务上表现最佳。

下图对比了 卷积层和提出的Ghost模块:

可以看出Ghost模块与现有的高效卷积方案 存在以下差异 :

i) 与1×1逐点卷积单元相比,Ghost模块中的主要卷积可以具有 自定义的核大小

ii) 现有方法采用逐点卷积来处理跨通道的特征,然后采用深度卷积来处理空间信息。相比之下,Ghost模块采用 普通卷积 首先生成一些内在特征图,然后利用 廉价的线性操作 来增强特征并增加通道数。

iii) 处理每个特征图的操作在先前的高效架构中通常限于深度卷积或移位操作,而Ghost模块中的线性操作可以具有较大的 多样性

iv) 此外,在Ghost模块中, 恒等映射与线性变换并行使用 ,以保留内在特征图。

总结: GhostNet中的Ghost Module是一种旨在以低计算成本生成更多特征图的创新组件。它通过引入额外的特征图,丰富了模型的表示能力,提高了性能,特别适用于在计算资源有限的环境中实现高性能的图像分类模型。


2.3 线性变换

GhostNet中的 线性变换 用于 生成幽灵特征图 。Ghost Module通过一系列 廉价的线性变换 来增强模型的表示能力。

我总结其 主要特点和原理 如下:

1. 应用于内在特征: 线性变换是应用于Ghost Module中已生成的内在特征图(Intrinsic Feature Maps)的。这些内在特征图是由主要卷积操作生成的,通常包含有限数量的特征。

2. 生成幽灵特征: 每个内在特征图都会经过一系列线性变换,以生成幽灵特征图。这些幽灵特征图是额外生成的,用于丰富模型的特征表示。

3. 自定义操作: Ghost Module中的线性操作可以具有不同的形式,例如3×3和5×5的线性核。这些不同的操作允许模型根据任务的需要自定义特征生成过程。

5. 保留内在特征: Ghost Module中的最后一个线性变换通常是恒等映射,用于保留内在特征。这确保了生成的幽灵特征与原始特征之间的一致性。

总结: GhostNet中的线性变换是为了通过低成本的操作生成额外的特征,从而提高模型的性能。这种方法在计算资源受限的情况下尤其有用,可以帮助模型更好地处理图像分类等任务。Ghost Module中的线性操作具有灵活性,可以根据具体任务进行调整和优化。


2.4 Ghost Bottlenecks

GhostNet的 Ghost Bottlenecks(幽灵瓶颈) 专门为 小型卷积神经网络(CNNs) 设计。Ghost Bottlenecks采用了Ghost Module的概念,并结合了 残差块的思想 ,用于提高模型的性能。

GhostNet中Ghost Bottlenecks的 主要特点:

1. 模块组成: Ghost Bottlenecks主要由两个堆叠的Ghost模块组成。这些Ghost模块在Ghost Bottleneck内进行堆叠,以实现更强大的特征提取和表示。

2. 扩展层: 第一个Ghost模块充当扩展层,其主要功能是增加通道数。这个扩展层通过增加通道数来增强特征的表示能力,从而有助于提高模型性能。

3. 收缩层: 第二个Ghost模块充当收缩层,其主要功能是减少通道数,以与快捷路径匹配。这个步骤有助于控制模型的复杂性,并确保模型在不增加计算负担的情况下能够保持高性能。

4. 快捷连接: Ghost Bottlenecks中还包括快捷连接,它连接在两个Ghost模块的输入和输出之间。这种连接有助于信息的传递和梯度的流动,以更好地训练模型。

5. 非线性激活: 在每个Ghost Bottleneck内部,都应用批归一化(BN)和ReLU非线性激活 函数 。但是,根据MobileNetV2的建议,在第二个Ghost模块之后不使用ReLU。

接下来为大家展示 Ghost瓶颈(G-bneck)示意图:

(左边:步幅为1的Ghost瓶颈;右边:步幅为2的Ghost瓶颈)

Ghost瓶颈在外观上与ResNe中的基本残差块类似,其中集成了多个卷积层和快捷连接。

Ghost瓶颈主要由 两个堆叠的Ghost模块 组成。

第一个Ghost模块 充当扩展层,增加通道数。我们将输出通道数与输入通道数之间的比率称为扩展比。

第二个Ghost模块 将通道数减少以匹配快捷路径。然后,将快捷连接连接在这两个Ghost模块的输入和输出之间。在每个层之后都应用批归一化(BN)和ReLU非线性激活函数(但是根据MobileNetV2的建议,在第二个Ghost模块后不使用ReLU。)

总结: Ghost Bottlenecks的设计旨在在小型CNNs中提高性能,并通过Ghost Module的低成本特性减少计算开销。这使得GhostNet成为在计算资源有限的嵌入式设备上实现高性能图像分类的有力选择。 Ghost Bottlenecks的堆叠增加了模型的深度,从而提高了特征的抽象能力,有助于更好地适应各种视觉任务。


三、 GhsetNetV1的核心代码

代码的使用方式看章节四!

  1. import torch
  2. import torch.nn as nn
  3. import torch.nn.functional as F
  4. import math
  5. __all__ = ['Ghostnetv1']
  6. def _make_divisible(v, divisor, min_value=None):
  7. """
  8. This function is taken from the original tf repo.
  9. It ensures that all layers have a channel number that is divisible by 8
  10. It can be seen here:
  11. https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
  12. """
  13. if min_value is None:
  14. min_value = divisor
  15. new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
  16. # Make sure that round down does not go down by more than 10%.
  17. if new_v < 0.9 * v:
  18. new_v += divisor
  19. return new_v
  20. def hard_sigmoid(x, inplace: bool = False):
  21. if inplace:
  22. return x.add_(3.).clamp_(0., 6.).div_(6.)
  23. else:
  24. return F.relu6(x + 3.) / 6.
  25. class SqueezeExcite(nn.Module):
  26. def __init__(self, in_chs, se_ratio=0.25, reduced_base_chs=None,
  27. act_layer=nn.ReLU, gate_fn=hard_sigmoid, divisor=4, **_):
  28. super(SqueezeExcite, self).__init__()
  29. self.gate_fn = gate_fn
  30. reduced_chs = _make_divisible((reduced_base_chs or in_chs) * se_ratio, divisor)
  31. self.avg_pool = nn.AdaptiveAvgPool2d(1)
  32. self.conv_reduce = nn.Conv2d(in_chs, reduced_chs, 1, bias=True)
  33. self.act1 = act_layer(inplace=True)
  34. self.conv_expand = nn.Conv2d(reduced_chs, in_chs, 1, bias=True)
  35. def forward(self, x):
  36. x_se = self.avg_pool(x)
  37. x_se = self.conv_reduce(x_se)
  38. x_se = self.act1(x_se)
  39. x_se = self.conv_expand(x_se)
  40. x = x * self.gate_fn(x_se)
  41. return x
  42. class ConvBnAct(nn.Module):
  43. def __init__(self, in_chs, out_chs, kernel_size,
  44. stride=1, act_layer=nn.ReLU):
  45. super(ConvBnAct, self).__init__()
  46. self.conv = nn.Conv2d(in_chs, out_chs, kernel_size, stride, kernel_size//2, bias=False)
  47. self.bn1 = nn.BatchNorm2d(out_chs)
  48. self.act1 = act_layer(inplace=True)
  49. def forward(self, x):
  50. x = self.conv(x)
  51. x = self.bn1(x)
  52. x = self.act1(x)
  53. return x
  54. class GhostModule(nn.Module):
  55. def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True):
  56. super(GhostModule, self).__init__()
  57. self.oup = oup
  58. init_channels = math.ceil(oup / ratio)
  59. new_channels = init_channels*(ratio-1)
  60. self.primary_conv = nn.Sequential(
  61. nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False),
  62. nn.BatchNorm2d(init_channels),
  63. nn.ReLU(inplace=True) if relu else nn.Sequential(),
  64. )
  65. self.cheap_operation = nn.Sequential(
  66. nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False),
  67. nn.BatchNorm2d(new_channels),
  68. nn.ReLU(inplace=True) if relu else nn.Sequential(),
  69. )
  70. def forward(self, x):
  71. x1 = self.primary_conv(x)
  72. x2 = self.cheap_operation(x1)
  73. out = torch.cat([x1,x2], dim=1)
  74. return out[:,:self.oup,:,:]
  75. class GhostBottleneck(nn.Module):
  76. """ Ghost bottleneck w/ optional SE"""
  77. def __init__(self, in_chs, mid_chs, out_chs, dw_kernel_size=3,
  78. stride=1, act_layer=nn.ReLU, se_ratio=0.):
  79. super(GhostBottleneck, self).__init__()
  80. has_se = se_ratio is not None and se_ratio > 0.
  81. self.stride = stride
  82. # Point-wise expansion
  83. self.ghost1 = GhostModule(in_chs, mid_chs, relu=True)
  84. # Depth-wise convolution
  85. if self.stride > 1:
  86. self.conv_dw = nn.Conv2d(mid_chs, mid_chs, dw_kernel_size, stride=stride,
  87. padding=(dw_kernel_size-1)//2,
  88. groups=mid_chs, bias=False)
  89. self.bn_dw = nn.BatchNorm2d(mid_chs)
  90. # Squeeze-and-excitation
  91. if has_se:
  92. self.se = SqueezeExcite(mid_chs, se_ratio=se_ratio)
  93. else:
  94. self.se = None
  95. # Point-wise linear projection
  96. self.ghost2 = GhostModule(mid_chs, out_chs, relu=False)
  97. # shortcut
  98. if (in_chs == out_chs and self.stride == 1):
  99. self.shortcut = nn.Sequential()
  100. else:
  101. self.shortcut = nn.Sequential(
  102. nn.Conv2d(in_chs, in_chs, dw_kernel_size, stride=stride,
  103. padding=(dw_kernel_size-1)//2, groups=in_chs, bias=False),
  104. nn.BatchNorm2d(in_chs),
  105. nn.Conv2d(in_chs, out_chs, 1, stride=1, padding=0, bias=False),
  106. nn.BatchNorm2d(out_chs),
  107. )
  108. def forward(self, x):
  109. residual = x
  110. # 1st ghost bottleneck
  111. x = self.ghost1(x)
  112. # Depth-wise convolution
  113. if self.stride > 1:
  114. x = self.conv_dw(x)
  115. x = self.bn_dw(x)
  116. # Squeeze-and-excitation
  117. if self.se is not None:
  118. x = self.se(x)
  119. # 2nd ghost bottleneck
  120. x = self.ghost2(x)
  121. x += self.shortcut(residual)
  122. return x
  123. class GhostNet(nn.Module):
  124. def __init__(self, cfgs, num_classes=1000, width=1.0, dropout=0.2):
  125. super(GhostNet, self).__init__()
  126. # setting of inverted residual blocks
  127. self.cfgs = cfgs
  128. self.dropout = dropout
  129. # building first layer
  130. output_channel = _make_divisible(16 * width, 4)
  131. self.conv_stem = nn.Conv2d(3, output_channel, 3, 2, 1, bias=False)
  132. self.bn1 = nn.BatchNorm2d(output_channel)
  133. self.act1 = nn.ReLU(inplace=True)
  134. input_channel = output_channel
  135. # building inverted residual blocks
  136. stages = []
  137. block = GhostBottleneck
  138. for cfg in self.cfgs:
  139. layers = []
  140. for k, exp_size, c, se_ratio, s in cfg:
  141. output_channel = _make_divisible(c * width, 4)
  142. hidden_channel = _make_divisible(exp_size * width, 4)
  143. layers.append(block(input_channel, hidden_channel, output_channel, k, s,
  144. se_ratio=se_ratio))
  145. input_channel = output_channel
  146. stages.append(nn.Sequential(*layers))
  147. output_channel = _make_divisible(exp_size * width, 4)
  148. stages.append(nn.Sequential(ConvBnAct(input_channel, output_channel, 1)))
  149. input_channel = output_channel
  150. self.blocks = nn.Sequential(*stages)
  151. self.width_list = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]
  152. def forward(self, x):
  153. unique_tensors = {}
  154. x = self.conv_stem(x)
  155. x = self.bn1(x)
  156. x = self.act1(x)
  157. for model in self.blocks:
  158. x = model(x)
  159. if self.dropout > 0.:
  160. x = F.dropout(x, p=self.dropout, training=self.training)
  161. width, height = x.shape[2], x.shape[3]
  162. unique_tensors[(width, height)] = x
  163. result_list = list(unique_tensors.values())[-4:]
  164. return result_list
  165. def Ghostnetv1(**kwargs):
  166. """
  167. Constructs a GhostNet model
  168. """
  169. cfgs = [
  170. # k, t, c, SE, s
  171. # stage1
  172. [[3, 16, 16, 0, 1]],
  173. # stage2
  174. [[3, 48, 24, 0, 2]],
  175. [[3, 72, 24, 0, 1]],
  176. # stage3
  177. [[5, 72, 40, 0.25, 2]],
  178. [[5, 120, 40, 0.25, 1]],
  179. # stage4
  180. [[3, 240, 80, 0, 2]],
  181. [[3, 200, 80, 0, 1],
  182. [3, 184, 80, 0, 1],
  183. [3, 184, 80, 0, 1],
  184. [3, 480, 112, 0.25, 1],
  185. [3, 672, 112, 0.25, 1]
  186. ],
  187. # stage5
  188. [[5, 672, 160, 0.25, 2]],
  189. [[5, 960, 160, 0, 1],
  190. [5, 960, 160, 0.25, 1],
  191. [5, 960, 160, 0, 1],
  192. [5, 960, 160, 0.25, 1]
  193. ]
  194. ]
  195. return GhostNet(cfgs, **kwargs)
  196. if __name__=='__main__':
  197. model = Ghostnetv1()
  198. model.eval()
  199. input = torch.randn(16,3,224,224)
  200. y = model(input)
  201. print(y.size())

四、手把手教你添加GhsetNetV1

4.1 修改一

第一步还是建立文件,我们找到如下ultralytics/nn文件夹下建立一个目录名字呢就是'Addmodules'文件夹( !然后在其内部建立一个新的py文件将核心代码复制粘贴进去即可


4.2 修改二

第二步我们在该目录下创建一个新的py文件名字为'__init__.py'( ,然后在其内部导入我们的检测头如下图所示。


4.3 修改三

第三步我门中到如下文件'ultralytics/nn/tasks.py'进行导入和注册我们的模块( !


4.4 修改四

添加如下两行代码!!!

​​


4.5 修改五

找到七百多行大概把具体看图片,按照图片来修改就行,添加红框内的部分,注意没有()只是函数名。

  1. elif m in {自行添加对应的模型即可,下面都是一样的}:
  2. m = m(*args)
  3. c2 = m.width_list # 返回通道列表
  4. backbone = True


4.6 修改六

下面的两个红框内都是需要改动的。

​​

  1. if isinstance(c2, list):
  2. m_ = m
  3. m_.backbone = True
  4. else:
  5. m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module
  6. t = str(m)[8:-2].replace('__main__.', '') # module type
  7. m.np = sum(x.numel() for x in m_.parameters()) # number params
  8. m_.i, m_.f, m_.type = i + 4 if backbone else i, f, t # attach index, 'from' index, type


4.7 修改七

修改七和前面的都不太一样,需要修改前向传播中的一个部分, 已经离开了parse_model方法了。

可以在图片中开代码行数,没有离开task.py文件都是同一个文件。 同时这个部分有好几个前向传播都很相似,大家不要看错了, 是70多行左右的!!!,同时我后面提供了代码,大家直接复制粘贴即可,有时间我针对这里会出一个视频。

​​​

代码如下->

  1. def _predict_once(self, x, profile=False, visualize=False, embed=None):
  2. """
  3. Perform a forward pass through the network.
  4. Args:
  5. x (torch.Tensor): The input tensor to the model.
  6. profile (bool): Print the computation time of each layer if True, defaults to False.
  7. visualize (bool): Save the feature maps of the model if True, defaults to False.
  8. embed (list, optional): A list of feature vectors/embeddings to return.
  9. Returns:
  10. (torch.Tensor): The last output of the model.
  11. """
  12. y, dt, embeddings = [], [], [] # outputs
  13. for m in self.model:
  14. if m.f != -1: # if not from previous layer
  15. 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
  16. if profile:
  17. self._profile_one_layer(m, x, dt)
  18. if hasattr(m, 'backbone'):
  19. x = m(x)
  20. if len(x) != 5: # 0 - 5
  21. x.insert(0, None)
  22. for index, i in enumerate(x):
  23. if index in self.save:
  24. y.append(i)
  25. else:
  26. y.append(None)
  27. x = x[-1] # 最后一个输出传给下一层
  28. else:
  29. x = m(x) # run
  30. y.append(x if m.i in self.save else None) # save output
  31. if visualize:
  32. feature_visualization(x, m.type, m.i, save_dir=visualize)
  33. if embed and m.i in embed:
  34. embeddings.append(nn.functional.adaptive_avg_pool2d(x, (1, 1)).squeeze(-1).squeeze(-1)) # flatten
  35. if m.i == max(embed):
  36. return torch.unbind(torch.cat(embeddings, 1), dim=0)
  37. return x

到这里就完成了修改部分,但是这里面细节很多,大家千万要注意不要替换多余的代码,导致报错,也不要拉下任何一部,都会导致运行失败,而且报错很难排查!!!很难排查!!!


注意!!! 额外的修改!

关注我的其实都知道,我大部分的修改都是一样的,这个网络需要额外的修改一步,就是s一个参数,将下面的s改为640!!!即可完美运行!!


打印计算量问题解决方案

我们找到如下文件'ultralytics/utils/torch_utils.py'按照如下的图片进行修改,否则容易打印不出来计算量。

​​


注意事项!!!

如果大家在验证的时候报错形状不匹配的错误可以固定验证集的图片尺寸,方法如下 ->

找到下面这个文件ultralytics/ models /yolo/detect/train.py然后其中有一个类是DetectionTrainer class中的build_dataset函数中的一个参数rect=mode == 'val'改为rect=False


五、GhsetNetV1的yaml文件

5.1 yaml文件

训练信息:YOLO11-Ghostnetv1 summary: 610 layers, 5,096,511 parameters, 5,096,495 gradients, 6.7 GFLOPs

  1. # Ultralytics YOLO 🚀, AGPL-3.0 license
  2. # YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
  3. # Parameters
  4. nc: 80 # number of classes
  5. scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  6. # [depth, width, max_channels]
  7. n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  8. s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  9. m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  10. l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  11. x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs
  12. # 共四个版本 "mobile_vit_small, mobile_vit_x_small, mobile_vit_xx_small"
  13. # YOLO11n backbone
  14. backbone:
  15. # [from, repeats, module, args]
  16. - [-1, 1, Ghostnetv1, []] # 0-4 P1/2
  17. - [-1, 1, SPPF, [1024, 5]] # 5
  18. - [-1, 2, C2PSA, [1024]] # 6
  19. # YOLO11n head
  20. head:
  21. - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  22. - [[-1, 3], 1, Concat, [1]] # cat backbone P4
  23. - [-1, 2, C3k2, [512, False]] # 9
  24. - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  25. - [[-1, 2], 1, Concat, [1]] # cat backbone P3
  26. - [-1, 2, C3k2, [256, False]] # 12 (P3/8-small)
  27. - [-1, 1, Conv, [256, 3, 2]]
  28. - [[-1, 9], 1, Concat, [1]] # cat head P4
  29. - [-1, 2, C3k2, [512, False]] # 15 (P4/16-medium)
  30. - [-1, 1, Conv, [512, 3, 2]]
  31. - [[-1, 6], 1, Concat, [1]] # cat head P5
  32. - [-1, 2, C3k2, [1024, True]] # 18 (P5/32-large)
  33. - [[12, 15, 18], 1, Detect, [nc]] # Detect(P3, P4, P5)


5.2 训练文件的代码

可以复制我的运行文件进行运行。

  1. import warnings
  2. warnings.filterwarnings('ignore')
  3. from ultralytics import YOLO
  4. if __name__ == '__main__':
  5. model = YOLO("替换你的yaml文件地址")
  6. model.load('yolov8n.pt')
  7. model.train(data=r'你的数据集的地址',
  8. cache=False,
  9. imgsz=640,
  10. epochs=150,
  11. batch=4,
  12. close_mosaic=0,
  13. workers=0,
  14. device=0,
  15. optimizer='SGD'
  16. amp=False,
  17. )

六、成功运行记录

下面是成功运行的截图,已经完成了有1个epochs的训练,图片太大截不全第2个epochs了。


七、本文总结

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv11改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充 如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

​​​