一、本文介绍
本文给大家带来的最新改进机制是 华为VanillaNet主干 配合 HSFPN 实现融合涨点,这个主干是一种注重极简主义和效率的 神经网络 我也将其进行了实验, 其中的HSFPN其是一种为白细胞检测设计的网络结构,主要用于解决白细胞数据集中的 多尺度 挑战。它的基本原理包括两个关键部分: 特征选择模块 和 特征融合模块, 在本文的下面均会有讲解,这个结构是非常新颖的。其可以起到 特征选择 的作用,我将其融合在一起,大家可以复制过去在其基础上配合我的 损失函数 ,然后再加一个检测头如果在你的数据上有涨点效果大家就可以开始撰写论文了。我发的改进机制已经有多名读者在Qq私聊我已经有涨点效果了,均有记录证明! 欢迎大家订阅本专栏,本专栏每周更新3-5篇最新机制,更有包含我所有改进的文件和交流群提供给大家。
欢迎大家订阅我的专栏一起学习YOLO!
二、手把手教你添加华为VanillaNet主干
2.1 VanillaNet核心代码
- # Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved.
- # This program is free software; you can redistribute it and/or modify it under the terms of the MIT License.
- # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MIT License for more details.
- import torch
- import torch.nn as nn
- from timm.layers import weight_init
- __all__ = ['vanillanet_5', 'vanillanet_6', 'vanillanet_7', 'vanillanet_8', 'vanillanet_9', 'vanillanet_10',
- 'vanillanet_11', 'vanillanet_12', 'vanillanet_13', 'vanillanet_13_x1_5', 'vanillanet_13_x1_5_ada_pool']
- class activation(nn.ReLU):
- def __init__(self, dim, act_num=3, deploy=False):
- super(activation, self).__init__()
- self.deploy = deploy
- self.weight = torch.nn.Parameter(torch.randn(dim, 1, act_num * 2 + 1, act_num * 2 + 1))
- self.bias = None
- self.bn = nn.BatchNorm2d(dim, eps=1e-6)
- self.dim = dim
- self.act_num = act_num
- weight_init.trunc_normal_(self.weight, std=.02)
- def forward(self, x):
- if self.deploy:
- return torch.nn.functional.conv2d(
- super(activation, self).forward(x),
- self.weight, self.bias, padding=(self.act_num * 2 + 1) // 2, groups=self.dim)
- else:
- return self.bn(torch.nn.functional.conv2d(
- super(activation, self).forward(x),
- self.weight, padding=self.act_num, groups=self.dim))
- def _fuse_bn_tensor(self, weight, bn):
- kernel = weight
- running_mean = bn.running_mean
- running_var = bn.running_var
- gamma = bn.weight
- beta = bn.bias
- eps = bn.eps
- std = (running_var + eps).sqrt()
- t = (gamma / std).reshape(-1, 1, 1, 1)
- return kernel * t, beta + (0 - running_mean) * gamma / std
- def switch_to_deploy(self):
- if not self.deploy:
- kernel, bias = self._fuse_bn_tensor(self.weight, self.bn)
- self.weight.data = kernel
- self.bias = torch.nn.Parameter(torch.zeros(self.dim))
- self.bias.data = bias
- self.__delattr__('bn')
- self.deploy = True
- class Block(nn.Module):
- def __init__(self, dim, dim_out, act_num=3, stride=2, deploy=False, ada_pool=None):
- super().__init__()
- self.act_learn = 1
- self.deploy = deploy
- if self.deploy:
- self.conv = nn.Conv2d(dim, dim_out, kernel_size=1)
- else:
- self.conv1 = nn.Sequential(
- nn.Conv2d(dim, dim, kernel_size=1),
- nn.BatchNorm2d(dim, eps=1e-6),
- )
- self.conv2 = nn.Sequential(
- nn.Conv2d(dim, dim_out, kernel_size=1),
- nn.BatchNorm2d(dim_out, eps=1e-6)
- )
- if not ada_pool:
- self.pool = nn.Identity() if stride == 1 else nn.MaxPool2d(stride)
- else:
- self.pool = nn.Identity() if stride == 1 else nn.AdaptiveMaxPool2d((ada_pool, ada_pool))
- self.act = activation(dim_out, act_num)
- def forward(self, x):
- if self.deploy:
- x = self.conv(x)
- else:
- x = self.conv1(x)
- x = torch.nn.functional.leaky_relu(x, self.act_learn)
- x = self.conv2(x)
- x = self.pool(x)
- x = self.act(x)
- return x
- def _fuse_bn_tensor(self, conv, bn):
- kernel = conv.weight
- bias = conv.bias
- running_mean = bn.running_mean
- running_var = bn.running_var
- gamma = bn.weight
- beta = bn.bias
- eps = bn.eps
- std = (running_var + eps).sqrt()
- t = (gamma / std).reshape(-1, 1, 1, 1)
- return kernel * t, beta + (bias - running_mean) * gamma / std
- def switch_to_deploy(self):
- if not self.deploy:
- kernel, bias = self._fuse_bn_tensor(self.conv1[0], self.conv1[1])
- self.conv1[0].weight.data = kernel
- self.conv1[0].bias.data = bias
- # kernel, bias = self.conv2[0].weight.data, self.conv2[0].bias.data
- kernel, bias = self._fuse_bn_tensor(self.conv2[0], self.conv2[1])
- self.conv = self.conv2[0]
- self.conv.weight.data = torch.matmul(kernel.transpose(1, 3),
- self.conv1[0].weight.data.squeeze(3).squeeze(2)).transpose(1, 3)
- self.conv.bias.data = bias + (self.conv1[0].bias.data.view(1, -1, 1, 1) * kernel).sum(3).sum(2).sum(1)
- self.__delattr__('conv1')
- self.__delattr__('conv2')
- self.act.switch_to_deploy()
- self.deploy = True
- class VanillaNet(nn.Module):
- def __init__(self, in_chans=3, num_classes=1000, dims=[96, 192, 384, 768],
- drop_rate=0, act_num=3, strides=[2, 2, 2, 1], deploy=False, ada_pool=None, **kwargs):
- super().__init__()
- self.deploy = deploy
- if self.deploy:
- self.stem = nn.Sequential(
- nn.Conv2d(in_chans, dims[0], kernel_size=4, stride=4),
- activation(dims[0], act_num)
- )
- else:
- self.stem1 = nn.Sequential(
- nn.Conv2d(in_chans, dims[0], kernel_size=4, stride=4),
- nn.BatchNorm2d(dims[0], eps=1e-6),
- )
- self.stem2 = nn.Sequential(
- nn.Conv2d(dims[0], dims[0], kernel_size=1, stride=1),
- nn.BatchNorm2d(dims[0], eps=1e-6),
- activation(dims[0], act_num)
- )
- self.act_learn = 1
- self.stages = nn.ModuleList()
- for i in range(len(strides)):
- if not ada_pool:
- stage = Block(dim=dims[i], dim_out=dims[i + 1], act_num=act_num, stride=strides[i], deploy=deploy)
- else:
- stage = Block(dim=dims[i], dim_out=dims[i + 1], act_num=act_num, stride=strides[i], deploy=deploy,
- ada_pool=ada_pool[i])
- self.stages.append(stage)
- self.depth = len(strides)
- self.apply(self._init_weights)
- self.width_list = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]
- def _init_weights(self, m):
- if isinstance(m, (nn.Conv2d, nn.Linear)):
- weight_init.trunc_normal_(m.weight, std=.02)
- nn.init.constant_(m.bias, 0)
- def change_act(self, m):
- for i in range(self.depth):
- self.stages[i].act_learn = m
- self.act_learn = m
- def forward(self, x):
- unique_tensors = {}
- if self.deploy:
- x = self.stem(x)
- else:
- x = self.stem1(x)
- x = torch.nn.functional.leaky_relu(x, self.act_learn)
- x = self.stem2(x)
- width, height = x.shape[2], x.shape[3]
- unique_tensors[(width, height)] = x
- for i in range(self.depth):
- x = self.stages[i](x)
- width, height = x.shape[2], x.shape[3]
- unique_tensors[(width, height)] = x
- result_list = list(unique_tensors.values())[-4:]
- return result_list
- def _fuse_bn_tensor(self, conv, bn):
- kernel = conv.weight
- bias = conv.bias
- running_mean = bn.running_mean
- running_var = bn.running_var
- gamma = bn.weight
- beta = bn.bias
- eps = bn.eps
- std = (running_var + eps).sqrt()
- t = (gamma / std).reshape(-1, 1, 1, 1)
- return kernel * t, beta + (bias - running_mean) * gamma / std
- def switch_to_deploy(self):
- if not self.deploy:
- self.stem2[2].switch_to_deploy()
- kernel, bias = self._fuse_bn_tensor(self.stem1[0], self.stem1[1])
- self.stem1[0].weight.data = kernel
- self.stem1[0].bias.data = bias
- kernel, bias = self._fuse_bn_tensor(self.stem2[0], self.stem2[1])
- self.stem1[0].weight.data = torch.einsum('oi,icjk->ocjk', kernel.squeeze(3).squeeze(2),
- self.stem1[0].weight.data)
- self.stem1[0].bias.data = bias + (self.stem1[0].bias.data.view(1, -1, 1, 1) * kernel).sum(3).sum(2).sum(1)
- self.stem = torch.nn.Sequential(*[self.stem1[0], self.stem2[2]])
- self.__delattr__('stem1')
- self.__delattr__('stem2')
- for i in range(self.depth):
- self.stages[i].switch_to_deploy()
- self.deploy = True
- def vanillanet_5(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(dims=[128 * 4, 256 * 4, 512 * 4, 1024 * 4], strides=[2, 2, 2], **kwargs)
- return model
- def vanillanet_6(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(dims=[128 * 4, 256 * 4, 512 * 4, 1024 * 4, 1024 * 4], strides=[2, 2, 2, 1], **kwargs)
- return model
- def vanillanet_7(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(dims=[128 * 4, 128 * 4, 256 * 4, 512 * 4, 1024 * 4, 1024 * 4], strides=[1, 2, 2, 2, 1], **kwargs)
- return model
- def vanillanet_8(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(dims=[128 * 4, 128 * 4, 256 * 4, 512 * 4, 512 * 4, 1024 * 4, 1024 * 4],
- strides=[1, 2, 2, 1, 2, 1], **kwargs)
- return model
- def vanillanet_9(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(dims=[128 * 4, 128 * 4, 256 * 4, 512 * 4, 512 * 4, 512 * 4, 1024 * 4, 1024 * 4],
- strides=[1, 2, 2, 1, 1, 2, 1], **kwargs)
- return model
- def vanillanet_10(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(
- dims=[128 * 4, 128 * 4, 256 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 1024 * 4, 1024 * 4],
- strides=[1, 2, 2, 1, 1, 1, 2, 1],
- **kwargs)
- return model
- def vanillanet_11(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(
- dims=[128 * 4, 128 * 4, 256 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 1024 * 4, 1024 * 4],
- strides=[1, 2, 2, 1, 1, 1, 1, 2, 1],
- **kwargs)
- return model
- def vanillanet_12(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(
- dims=[128 * 4, 128 * 4, 256 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 1024 * 4, 1024 * 4],
- strides=[1, 2, 2, 1, 1, 1, 1, 1, 2, 1],
- **kwargs)
- return model
- def vanillanet_13(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(
- dims=[128 * 4, 128 * 4, 256 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 512 * 4, 1024 * 4,
- 1024 * 4],
- strides=[1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1],
- **kwargs)
- return model
- def vanillanet_13_x1_5(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(
- dims=[128 * 6, 128 * 6, 256 * 6, 512 * 6, 512 * 6, 512 * 6, 512 * 6, 512 * 6, 512 * 6, 512 * 6, 1024 * 6,
- 1024 * 6],
- strides=[1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1],
- **kwargs)
- return model
- def vanillanet_13_x1_5_ada_pool(pretrained=False, in_22k=False, **kwargs):
- model = VanillaNet(
- dims=[128 * 6, 128 * 6, 256 * 6, 512 * 6, 512 * 6, 512 * 6, 512 * 6, 512 * 6, 512 * 6, 512 * 6, 1024 * 6,
- 1024 * 6],
- strides=[1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1],
- ada_pool=[0, 38, 19, 0, 0, 0, 0, 0, 0, 10, 0],
- **kwargs)
- return model
2.2 修改教程
2.2.1 修改一
第一步还是建立文件,我们找到如下 ultralytics /nn/modules文件夹下建立一个目录名字呢就是'Addmodules'文件夹( 用群内的文件的话已经有了无需新建) !然后在其内部建立一个新的py文件将核心代码复制粘贴进去即可。
2.2.2 修改二
第二步我们在该目录下创建一个新的py文件名字为'__init__.py'( 用群内的文件的话已经有了无需新建) ,然后在其内部导入我们的检测头如下图所示。
2.2.3 修改三
第三步我门中到如下文件'ultralytics/nn/tasks.py'进行导入和注册我们的模块( 用群内的文件的话已经有了无需重新导入直接开始第四步即可) !
从今天开始以后的教程就都统一成这个样子了,因为我默认大家用了我群内的文件来进行修改!!
2.2.4 修改四
添加如下两行代码!!!
2.2.5 修改五
找到七百多行大概把具体看图片,按照图片来修改就行,添加红框内的部分,注意没有()只是函数名。
- elif m in {自行添加对应的模型即可,下面都是一样的}:
- m = m(*args)
- c2 = m.width_list # 返回通道列表
- backbone = True
2.2.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, type
2.2.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)
2.2.8 修改八
修改七和前面的都不太一样,需要修改前向传播中的一个部分, 已经离开了parse_model方法了。
可以在图片中开代码行数,没有离开task.py文件都是同一个文件。 同时这个部分有好几个前向传播都很相似,大家不要看错了, 是70多行左右的!!!,同时我后面提供了代码,大家直接复制粘贴即可,有时间我针对这里会出一个视频。
代码如下->
- def _predict_once(self, x, profile=False, visualize=False):
- """
- 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.
- Returns:
- (torch.Tensor): The last output of the model.
- """
- y, dt = [], [] # outputs
- 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_dir=visualize)
- 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
三、HSFPN的核心代码
- import torch
- import torch.nn as nn
- import torch.nn.functional as F
- __all__ = ['CA', 'multiply', 'Add']
- class Add(nn.Module):
- # Concatenate a list of tensors along dimension
- def __init__(self, ch=256):
- super().__init__()
- def forward(self, x):
- input1, input2 = x[0], x[1]
- x = input1 + input2
- return x
- class multiply(nn.Module):
- def __init__(self):
- super().__init__()
- def forward(self, x):
- x = x[0] * x[1]
- return x
- class CA(nn.Module):
- def __init__(self, in_planes, ratio = 4, flag=True):
- super(CA, self).__init__()
- self.avg_pool = nn.AdaptiveAvgPool2d(1)
- self.max_pool = nn.AdaptiveMaxPool2d(1)
- self.conv1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)
- self.relu = nn.ReLU()
- self.conv2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)
- self.flag = flag
- self.sigmoid = nn.Sigmoid()
- nn.init.xavier_uniform_(self.conv1.weight)
- nn.init.xavier_uniform_(self.conv2.weight)
- def forward(self, x):
- avg_out = self.conv2(self.relu(self.conv1(self.avg_pool(x))))
- max_out = self.conv2(self.relu(self.conv1(self.max_pool(x))))
- out = avg_out + max_out
- out = self.sigmoid(out) * x if self.flag else self.sigmoid(out)
- return out
- class FeatureSelectionModule(nn.Module):
- def __init__(self, in_chan, out_chan):
- super(FeatureSelectionModule, self).__init__()
- self.conv_atten = nn.Conv2d(in_chan, in_chan, kernel_size=1)
- self.group_norm1 = nn.GroupNorm(32, in_chan)
- self.sigmoid = nn.Sigmoid()
- self.conv = nn.Conv2d(in_chan, out_chan, kernel_size=1)
- self.group_norm2 = nn.GroupNorm(32, out_chan)
- nn.init.xavier_uniform_(self.conv_atten.weight)
- nn.init.xavier_uniform_(self.conv.weight)
- def forward(self, x):
- atten = self.sigmoid(self.group_norm1(self.conv_atten(F.avg_pool2d(x, x.size()[2:]))))
- feat = torch.mul(x, atten)
- x = x + feat
- feat = self.group_norm2(self.conv(x))
- return feat
- if __name__ == "__main__":
- # Generating Sample image
- image_size = (1, 64, 240, 240)
- image = torch.rand(*image_size)
- # Model
- mobilenet_v3 = FeatureSelectionModule(64, 64)
- out = mobilenet_v3(image)
- print(out.size())
四、手把手教你添加HS-FPN
4.1 修改一
第一还是建立文件,我们找到如下ultralytics/nn文件夹下建立一个目录名字呢就是'Addmodules'文件夹( 用群内的文件的话已经有了无需新建) !然后在其内部建立一个新的py文件将核心代码复制粘贴进去即可。
4.2 修改二
第二步我们在该目录下创建一个新的py文件名字为'__init__.py'( 用群内的文件的话已经有了无需新建) ,然后在其内部导入我们的检测头如下图所示。
4.3 修改三
第三步我门中到如下文件'ultralytics/nn/tasks.py'进行导入和注册我们的模块( 用群内的文件的话已经有了无需重新导入直接开始第四步即可) !
4.4 修改四
按照我的添加在parse_model里添加即可。
4.5 修改五
按照我的添加在parse_model里添加即可。
- elif m in {'此处添加大家修改的对应机制即可'}:
- c2 = ch[f]
- args = [c2, *args]
- elif m is multiply:
- c2 = ch[f[0]]
- elif m is Add:
- c2 = ch[f[-1]]
到此就修改完成了,大家可以复制下面的yaml文件运行。
五、融合后的yaml文件
5.1 yaml文件
训练信息:YOLO11-vanillanet-HSFPN summary: 265 layers, 3,128,418 parameters, 3,128,402 gradients, 12.8 GFLOPs
- # 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
- # 下面 [-1, 1, vanillanet_5, [0.25]] 参数位置的0.25是通道放缩的系数, YOLOv11N是0.25 YOLOv11S是0.5 YOLOv11M是1. YOLOv11l是1 YOLOv11是1.5大家根据自己训练的YOLO版本设定即可.
- # 本文支持版本有 vanillanet_5, vanillanet_6, vanillanet_7, vanillanet_8, vanillanet_9, vanillanet_10, vanillanet_11, vanillanet_12, vanillanet_13, vanillanet_13_x1_5, vanillanet_13_x1_5_ada_pool
- # YOLO11n backbone
- backbone:
- # [from, repeats, module, args]
- - [-1, 1, vanillanet_5, [0.25]] # 0-4 P1/2 这里是四层大家不要被yaml文件限制住了思维,不会画图进群看视频.
- - [-1, 1, SPPF, [1024, 5]] # 5
- - [-1, 2, C2PSA, [1024]] # 6
- # YOLO11n head
- head:
- - [-1, 1, CA, []] # 11
- - [-1, 1, nn.Conv2d, [256, 1]] # 12
- - [-1, 2, C3k2, [256, False]] # 13 P5
- - [3, 1, CA, []]
- - [-1, 1, nn.Conv2d, [256, 1]] # 15
- - [8, 1, nn.ConvTranspose2d, [256, 3, 2, 1, 1]] # 16
- - [-1, 1, CA, [4, False]]
- - [[-1, 11], 1, multiply, []] # 18
- - [[-1, 12], 1, Add, []] # 19
- - [-1, 2, C3k2, [256, False]] # 20 P4
- - [2, 1, CA, []] # 21
- - [-1, 1, nn.Conv2d, [256, 1]] # 22
- - [12, 1, nn.ConvTranspose2d, [256, 3, 2, 1, 1]] # 23
- - [-1, 1, CA, [4, False]] # 24
- - [[-1, 18], 1, multiply, []] # 25
- - [[-1, 19], 1, Add, []] # 26
- - [-1, 2, C3k2, [256, True]] # 27 P3
- - [[23, 16, 9], 1, Detect, [nc]] # Det
5.2 运行文件
可以复制我的运行文件进行运行,
- import warnings
- warnings.filterwarnings('ignore')
- from ultralytics import YOLO
- if __name__ == '__main__':
- model = YOLO("替换你的yaml文件地址")
- # model.load('yolov8n.pt') # 不建议大家加载初始化权重尤其这种替换主干和Neck的改进机制
- model.train(data=r'你的数据集的地址',
- cache=False,
- imgsz=640,
- epochs=150,
- batch=4,
- close_mosaic=0,
- workers=0,
- device=0,
- optimizer='SGD'
- amp = False,
- )
5.3 运行记录
五、本文总结
到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv11改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,目前本专栏免费阅读(暂时,大家尽早关注不迷路~),如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~