yolov26改进 | 主干/Backbone篇 | 反向残差块目标检测网络EMO一种轻量级的CNN架构(支持yolov26全系列轻量化) 开始讲解之前推荐一下我的专栏本专栏的内容支持(分类、检测、分割、追踪、关键点检测),专栏目前为限时折扣欢迎大家订阅本专栏本专栏每周更新3-5篇最新机制更有包含我所有改进的文件和交流群提供给大家。一、本文介绍本文给大家带来的改进机制是由反向残差块构建的轻量级网络——EMO。EMO的核心构成模块为iRMB该模块此前已经为大家进行过详细介绍同时本专栏还在其基础上完成了二次创新提出了改进模块iEMA。因此iEMA同样可以进一步应用到EMO网络中对其基础构建单元进行替换或融合从而形成新的二次创新方案为模型精度提升和结构优化提供更多思路。EMO本身是一种轻量级CNN架构在控制模型参数量和计算量的同时兼顾局部特征提取与全局信息建模能力适合用于目标检测、图像分类以及边缘端部署等视觉任务。本文将对EMO主干网络进行适配并将其应用到YOLOv26中用于替换和改进原有的特征提取网络。本文支持YOLOv26全系列模型放缩即n、s、m、l、x五个版本可根据不同模型规模和实际任务需求灵活选择。本文相关结构适配、代码修改及组合方式均为个人独家创新内容未经允许禁止搬运和抄袭。专栏链接YOLOv26有效涨点专栏包含Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制目录一、本文介绍二、EMO模型原理三、EMO的核心代码四、手把手教你添加EMO4.1 修改一4.2 修改二4.3 修改三4.4 修改四4.5 修改五4.6 修改六4.7 修改七4.8 修改八4.9 修改九五、EMO的yaml文件5.1 EMO的yaml文件5.2 训练文件的代码六、成功运行记录七、本文总结二、EMO模型原理论文地址官方论文地址代码地址官方代码地址Efficient MOdel (EMO)模型基于反向残差块Inverted Residual Block, IRB这是一种轻量级CNN的基础架构同时融合了Transformer的有效组件。通过这种结合EMO实现了一个统一的视角来处理轻量级模型的设计创新地将CNN和注意力机制相结合。此外EMO模型在各种基准测试中展示出优越的性能特别是在ImageNet-1K、COCO2017和ADE20K等数据集上的表现。该模型不仅在效率和精度方面取得了平衡而且在轻量级设计方面实现了突破。EMO的基本原理可以分为以下几个要点1. 反向残差块IRB的应用IRB作为轻量级CNN的基础架构EMO将其扩展到基于注意力的模型。2. 元移动块MMB的抽象化EMO提出了一种新的轻量级设计方法即单残差的元移动块MMB这是从IRB和Transformer的有效组件中抽象出的。3. 现代反向残差移动块iRMB的构建基于简单但有效的设计标准EMO推导出了iRMB并以此构建了类似于ResNet的高效模型EMO。在下面这个图中我们可以看到EMO模型的结构细节左侧是一个抽象统一的元移动块Meta-Mobile Block它融合了多头自注意力机制Multi-Head Self-Attention、前馈网络Feed-Forward Network和反向残差块Inverted Residual Block。这个复合模块通过不同的扩展比率和高效的操作符进行具体化。右侧展示了一个类似于ResNet的EMO模型架构它完全由推导出的iRMB组成。图中突出了EMO模型中微操作组合如深度可分卷积、窗口Transformer等和不同尺度的网络层次这些都是用于分类CLS、检测Det和分割Seg任务的。这种设计强调了EMO模型在处理不同下游任务时的灵活性和效率。三、EMO的核心代码EMO的核心代码如下使用方法看章节四from timm.models.layers import trunc_normal_ import math import torch import torch.nn as nn import torch.nn.functional as F from functools import partial from einops import rearrange, reduce from timm.models.layers import DropPath inplace True __all__ [EMO_1M, EMO_2M, EMO_5M, EMO_6M] class SELayerV2(nn.Module): def __init__(self, in_channel, reduction1): super(SELayerV2, self).__init__() assert in_channel reduction and in_channel % reduction 0, invalid in_channel in SaElayer self.reduction reduction self.cardinality 4 self.avg_pool nn.AdaptiveAvgPool2d(1) # cardinality 1 self.fc1 nn.Sequential( nn.Linear(in_channel, in_channel // self.reduction, biasFalse), nn.ReLU(inplaceTrue) ) # cardinality 2 self.fc2 nn.Sequential( nn.Linear(in_channel, in_channel // self.reduction, biasFalse), nn.ReLU(inplaceTrue) ) # cardinality 3 self.fc3 nn.Sequential( nn.Linear(in_channel, in_channel // self.reduction, biasFalse), nn.ReLU(inplaceTrue) ) # cardinality 4 self.fc4 nn.Sequential( nn.Linear(in_channel, in_channel // self.reduction, biasFalse), nn.ReLU(inplaceTrue) ) self.fc nn.Sequential( nn.Linear(in_channel // self.reduction * self.cardinality, in_channel, biasFalse), nn.Sigmoid() ) def forward(self, x): b, c, _, _ x.size() y self.avg_pool(x).view(b, c) y1 self.fc1(y) y2 self.fc2(y) y3 self.fc3(y) y4 self.fc4(y) y_concate torch.cat([y1, y2, y3, y4], dim1) y_ex_dim self.fc(y_concate).view(b, c, 1, 1) return x * y_ex_dim.expand_as(x) def get_act(act_layerrelu): act_dict { none: nn.Identity, relu: nn.ReLU, relu6: nn.ReLU6, silu: nn.SiLU, gelu: nn.GELU } return act_dict[act_layer] class LayerNorm2d(nn.Module): def __init__(self, normalized_shape, eps1e-6, elementwise_affineTrue): super().__init__() self.norm nn.LayerNorm(normalized_shape, eps, elementwise_affine) def forward(self, x): x rearrange(x, b c h w - b h w c).contiguous() x self.norm(x) x rearrange(x, b h w c - b c h w).contiguous() return x def get_norm(norm_layerin_1d): eps 1e-6 norm_dict { none: nn.Identity, in_1d: partial(nn.InstanceNorm1d, epseps), in_2d: partial(nn.InstanceNorm2d, epseps), in_3d: partial(nn.InstanceNorm3d, epseps), bn_1d: partial(nn.BatchNorm1d, epseps), bn_2d: partial(nn.BatchNorm2d, epseps), # bn_2d: partial(nn.SyncBatchNorm, epseps), bn_3d: partial(nn.BatchNorm3d, epseps), gn: partial(nn.GroupNorm, epseps), ln_1d: partial(nn.LayerNorm, epseps), ln_2d: partial(LayerNorm2d, epseps), } return norm_dict[norm_layer] class LayerScale(nn.Module): def __init__(self, dim, init_values1e-5, inplaceTrue): super().__init__() self.inplace inplace self.gamma nn.Parameter(init_values * torch.ones(1, 1, dim)) def forward(self, x): return x.mul_(self.gamma) if self.inplace else x * self.gamma class LayerScale2D(nn.Module): def __init__(self, dim, init_values1e-5, inplaceTrue): super().__init__() self.inplace inplace self.gamma nn.Parameter(init_values * torch.ones(1, dim, 1, 1)) def forward(self, x): return x.mul_(self.gamma) if self.inplace else x * self.gamma class ConvNormAct(nn.Module): def __init__(self, dim_in, dim_out, kernel_size, stride1, dilation1, groups1, biasFalse, skipFalse, norm_layerbn_2d, act_layerrelu, inplaceTrue, drop_path_rate0.): super(ConvNormAct, self).__init__() self.has_skip skip and dim_in dim_out padding math.ceil((kernel_size - stride) / 2) self.conv nn.Conv2d(dim_in, dim_out, kernel_size, stride, padding, dilation, groups, bias) self.norm get_norm(norm_layer)(dim_out) self.act nn.GELU() self.drop_path DropPath(drop_path_rate) if drop_path_rate else nn.Identity() def forward(self, x): shortcut x x self.conv(x) x self.norm(x) x self.act(x) if self.has_skip: x self.drop_path(x) shortcut return x # Multi-Scale Populations, for down-sampling and inductive bias class MSPatchEmb(nn.Module): def __init__(self, dim_in, emb_dim, kernel_size2, c_group-1, stride1, dilations[1, 2, 3], norm_layerbn_2d, act_layersilu): super().__init__() self.dilation_num len(dilations) assert dim_in % c_group 0 c_group math.gcd(dim_in, emb_dim) if c_group -1 else c_group self.convs nn.ModuleList() for i in range(len(dilations)): padding math.ceil(((kernel_size - 1) * dilations[i] 1 - stride) / 2) self.convs.append(nn.Sequential( nn.Conv2d(dim_in, emb_dim, kernel_size, stride, padding, dilations[i], groupsc_group), get_norm(norm_layer)(emb_dim), get_act(act_layer)(emb_dim))) def forward(self, x): if self.dilation_num 1: x self.convs[0](x) else: x torch.cat([self.convs[i](x).unsqueeze(dim-1) for i in range(self.dilation_num)], dim-1) x reduce(x, b c h w n - b c h w, mean).contiguous() return x class iRMB(nn.Module): def __init__(self, dim_in, dim_out, norm_inTrue, has_skipTrue, exp_ratio1.0, norm_layerbn_2d, act_layerrelu, v_projTrue, dw_ks3, stride1, dilation1, se_ratio0.0, dim_head64, window_size7, attn_sTrue, qkv_biasFalse, attn_drop0., drop0., drop_path0., v_groupFalse, attn_preFalse): super().__init__() self.norm get_norm(norm_layer)(dim_in) if norm_in else nn.Identity() dim_mid int(dim_in * exp_ratio) self.has_skip (dim_in dim_out and stride 1) and has_skip self.attn_s attn_s if self.attn_s: assert dim_in % dim_head 0, dim should be divisible by num_heads self.dim_head dim_head self.window_size window_size self.num_head dim_in // dim_head self.scale self.dim_head ** -0.5 self.attn_pre attn_pre self.qk ConvNormAct(dim_in, int(dim_in * 2), kernel_size1, biasqkv_bias, norm_layernone, act_layernone) self.v ConvNormAct(dim_in, dim_mid, kernel_size1, groupsself.num_head if v_group else 1, biasqkv_bias, norm_layernone, act_layeract_layer, inplaceinplace) self.attn_drop nn.Dropout(attn_drop) else: if v_proj: self.v ConvNormAct(dim_in, dim_mid, kernel_size1, biasqkv_bias, norm_layernone, act_layeract_layer, inplaceinplace) else: self.v nn.Identity() self.conv_local ConvNormAct(dim_mid, dim_mid, kernel_sizedw_ks, stridestride, dilationdilation, groupsdim_mid, norm_layerbn_2d, act_layersilu, inplaceinplace) self.se SELayerV2(dim_mid) self.proj_drop nn.Dropout(drop) self.proj ConvNormAct(dim_mid, dim_out, kernel_size1, norm_layernone, act_layernone, inplaceinplace) self.drop_path DropPath(drop_path) if drop_path else nn.Identity() def forward(self, x): shortcut x x self.norm(x) B, C, H, W x.shape if self.attn_s: # padding if self.window_size 0: window_size_W, window_size_H W, H else: window_size_W, window_size_H self.window_size, self.window_size pad_l, pad_t 0, 0 pad_r (window_size_W - W % window_size_W) % window_size_W pad_b (window_size_H - H % window_size_H) % window_size_H x F.pad(x, (pad_l, pad_r, pad_t, pad_b, 0, 0,)) n1, n2 (H pad_b) // window_size_H, (W pad_r) // window_size_W x rearrange(x, b c (h1 n1) (w1 n2) - (b n1 n2) c h1 w1, n1n1, n2n2).contiguous() # attention b, c, h, w x.shape qk self.qk(x) qk rearrange(qk, b (qk heads dim_head) h w - qk b heads (h w) dim_head, qk2, headsself.num_head, dim_headself.dim_head).contiguous() q, k qk[0], qk[1] attn_spa (q k.transpose(-2, -1)) * self.scale attn_spa attn_spa.softmax(dim-1) attn_spa self.attn_drop(attn_spa) if self.attn_pre: x rearrange(x, b (heads dim_head) h w - b heads (h w) dim_head, headsself.num_head).contiguous() x_spa attn_spa x x_spa rearrange(x_spa, b heads (h w) dim_head - b (heads dim_head) h w, headsself.num_head, hh, ww).contiguous() x_spa self.v(x_spa) else: v self.v(x) v rearrange(v, b (heads dim_head) h w - b heads (h w) dim_head, headsself.num_head).contiguous() x_spa attn_spa v x_spa rearrange(x_spa, b heads (h w) dim_head - b (heads dim_head) h w, headsself.num_head, hh, ww).contiguous() # unpadding x rearrange(x_spa, (b n1 n2) c h1 w1 - b c (h1 n1) (w1 n2), n1n1, n2n2).contiguous() if pad_r 0 or pad_b 0: x x[:, :, :H, :W].contiguous() else: x self.v(x) x x self.se(self.conv_local(x)) if self.has_skip else self.se(self.conv_local(x)) x self.proj_drop(x) x self.proj(x) x (shortcut self.drop_path(x)) if self.has_skip else x return x class EMO(nn.Module): def __init__(self, dim_in3,factor1, depths[1, 2, 4, 2], stem_dim16, embed_dims[64, 128, 256, 512], exp_ratios[4., 4., 4., 4.], norm_layers[bn_2d, bn_2d, bn_2d, bn_2d], act_layers[relu, relu, relu, relu], dw_kss[3, 3, 5, 5], se_ratios[0.0, 0.0, 0.0, 0.0], dim_heads[32, 32, 32, 32], window_sizes[7, 7, 7, 7], attn_ss[False, False, True, True], qkv_biasTrue, attn_drop0., drop0., drop_path0., v_groupFalse, attn_preFalse, pre_dim0): super().__init__() # 放缩系数 scale_factor factor # 比如放大 1.5 倍 # exp_ratios放缩比例不缩放 # 放缩后的 embed_dims每个元素都被乘以 scale_factor 并转化为整形 embed_dims [int(dim * scale_factor) for dim in embed_dims] dprs [x.item() for x in torch.linspace(0, drop_path, sum(depths))] self.stage0 nn.ModuleList([ MSPatchEmb( # down to 112 dim_in, stem_dim, kernel_sizedw_kss[0], c_group1, stride2, dilations[1], norm_layernorm_layers[0], act_layernone), iRMB( # ds stem_dim, stem_dim, norm_inFalse, has_skipFalse, exp_ratio1, norm_layernorm_layers[0], act_layeract_layers[0], v_projFalse, dw_ksdw_kss[0], stride1, dilation1, se_ratio1, dim_headdim_heads[0], window_sizewindow_sizes[0], attn_sFalse, qkv_biasqkv_bias, attn_dropattn_drop, dropdrop, drop_path0., attn_preattn_pre ) ]) emb_dim_pre stem_dim for i in range(len(depths)): layers [] dpr dprs[sum(depths[:i]):sum(depths[:i 1])] for j in range(depths[i]): if j 0: stride, has_skip, attn_s, exp_ratio 2, False, False, exp_ratios[i] * 2 else: stride, has_skip, attn_s, exp_ratio 1, True, attn_ss[i], exp_ratios[i] layers.append(iRMB( emb_dim_pre, embed_dims[i], norm_inTrue, has_skiphas_skip, exp_ratioexp_ratio, norm_layernorm_layers[i], act_layeract_layers[i], v_projTrue, dw_ksdw_kss[i], stridestride, dilation1, se_ratiose_ratios[i], dim_headdim_heads[i], window_sizewindow_sizes[i], attn_sattn_s, qkv_biasqkv_bias, attn_dropattn_drop, dropdrop, drop_pathdpr[j], v_groupv_group, attn_preattn_pre )) emb_dim_pre embed_dims[i] self.__setattr__(fstage{i 1}, nn.ModuleList(layers)) self.norm get_norm(norm_layers[-1])(embed_dims[-1]) if pre_dim 0: self.pre_head nn.Sequential(nn.Linear(embed_dims[-1], pre_dim), get_act(act_layers[-1])(inplaceinplace)) self.pre_dim pre_dim else: self.pre_head nn.Identity() self.pre_dim embed_dims[-1] 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.Linear): trunc_normal_(m.weight, std.02) if m.bias is not None: nn.init.zeros_(m.bias) elif isinstance(m, (nn.LayerNorm, nn.GroupNorm, nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d, nn.InstanceNorm1d, nn.InstanceNorm2d, nn.InstanceNorm3d)): nn.init.zeros_(m.bias) nn.init.ones_(m.weight) torch.jit.ignore def no_weight_decay(self): return {token} torch.jit.ignore def no_weight_decay_keywords(self): return {alpha, gamma, beta} torch.jit.ignore def no_ft_keywords(self): # return {head.weight, head.bias} return {} torch.jit.ignore def ft_head_keywords(self): return {head.weight, head.bias}, self.num_classes def get_classifier(self): return self.head def reset_classifier(self, num_classes): self.num_classes num_classes self.head nn.Linear(self.pre_dim, num_classes) if num_classes 0 else nn.Identity() def check_bn(self): for name, m in self.named_modules(): if isinstance(m, nn.modules.batchnorm._NormBase): m.running_mean torch.nan_to_num(m.running_mean, nan0, posinf1, neginf-1) m.running_var torch.nan_to_num(m.running_var, nan0, posinf1, neginf-1) def forward(self, x): unique_tensors {} for blk in self.stage0: x blk(x) width, height x.shape[2], x.shape[3] unique_tensors[(width, height)] x for blk in self.stage1: x blk(x) width, height x.shape[2], x.shape[3] unique_tensors[(width, height)] x for blk in self.stage2: x blk(x) width, height x.shape[2], x.shape[3] unique_tensors[(width, height)] x for blk in self.stage3: x blk(x) width, height x.shape[2], x.shape[3] unique_tensors[(width, height)] x for blk in self.stage4: x blk(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 EMO_1M(factor1): model EMO( factorfactor, depths[2, 2, 8, 3], stem_dim24, embed_dims[32, 48, 80, 168], exp_ratios[2., 2.5, 3.0, 3.5], norm_layers[bn_2d, bn_2d, ln_2d, ln_2d], act_layers[silu, silu, gelu, gelu], dw_kss[3, 3, 5, 5], dim_heads[16, 16, 20, 21], window_sizes[7, 7, 7, 7], attn_ss[False, False, True, True], qkv_biasTrue, attn_drop0., drop0., drop_path0.04036, v_groupFalse, attn_preTrue, pre_dim0) return model def EMO_2M(factor1): model EMO( factorfactor, depths[3, 3, 9, 3], stem_dim24, embed_dims[32, 48, 120, 200], exp_ratios[2., 2.5, 3.0, 3.5], norm_layers[bn_2d, bn_2d, ln_2d, ln_2d], act_layers[silu, silu, gelu, gelu], dw_kss[3, 3, 5, 5], dim_heads[16, 16, 20, 20], window_sizes[7, 7, 7, 7], attn_ss[False, False, True, True], qkv_biasTrue, attn_drop0., drop0., drop_path0.05, v_groupFalse, attn_preTrue, pre_dim0) return model def EMO_5M(factor1): model EMO( factorfactor, depths[3, 3, 9, 3], stem_dim24, embed_dims[48, 72, 160, 288], exp_ratios[2., 3., 4., 4.], norm_layers[bn_2d, bn_2d, ln_2d, ln_2d], act_layers[silu, silu, gelu, gelu], dw_kss[3, 3, 5, 5], dim_heads[24, 24, 32, 32], window_sizes[7, 7, 7, 7], attn_ss[False, False, True, True], qkv_biasTrue, attn_drop0., drop0., drop_path0.05, v_groupFalse, attn_preTrue, pre_dim0) return model def EMO_6M(factor1): model EMO( factorfactor, depths[3, 3, 9, 3], stem_dim24, embed_dims[48, 72, 160, 320], exp_ratios[2., 3., 4., 5.], norm_layers[bn_2d, bn_2d, ln_2d, ln_2d], act_layers[silu, silu, gelu, gelu], dw_kss[3, 3, 5, 5], dim_heads[16, 24, 20, 32], window_sizes[7, 7, 7, 7], attn_ss[False, False, True, True], qkv_biasTrue, attn_drop0., drop0., drop_path0.05, v_groupFalse, attn_preTrue, pre_dim0) return model if __name__ __main__: # Generating Sample image image_size (1, 3, 640, 640) image torch.rand(*image_size) # Model model EMO_6M() out model(image) print(len(out))四、手把手教你添加EMO4.1 修改一我们复制网络结构代码到“ultralytics/nn”目录下创建一个py文件复制粘贴进去 我这里起的名字是EMO。​4.2 修改二第二步我们在该目录下创建一个新的py文件名字为__init__.py(用群内的文件的话已经有了无需新建)然后在其内部导入我们的检测头如下图所示。4.3 修改三第三步我门中到如下文件ultralytics/nn/tasks.py进行导入和注册我们的模块(用群内的文件的话已经有了无需重新导入直接开始第四步即可)从今天开始以后的教程就都统一成这个样子了因为我默认大家用了我群内的文件来进行修改4.4 修改四添加如下两行代码​4.5 修改五找到1600多行大概把具体看图片按照图片来修改就行添加红框内的部分注意没有()只是函数名我这里只添加了部分的版本大家有兴趣这个ShuffleNetV1还有更多的版本可以添加看我给的代码函数头即可。​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按照如下的图片进行修改否则容易打印不出来计算量。​五、EMO的yaml文件5.1 EMO的yaml文件训练信息YOLO26-Backbone-EMO summary: 661 layers, 15,031,868 parameters, 15,031,868 gradients, 7.1 GFLOPs# 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 # 我提供了版本分别是对应是 [EMO_1M, EMO_2M, EMO_5M, EMO_6M] # 其中n是对应yolo的版本通道放缩 large 和 small 是模型官方本身自带的版本 # YOLO26 backbone backbone: # [from, repeats, module, args] - [-1, 1, EMO_1M, [0.25]] # 0-4 P1/2 这里是四层大家不要被yaml文件限制住了思维不会画图进群看视频. # 注意args位置的参数对应模型的通道放缩系数width在上面scales位置, 假设你用yolov11n那么可以设置0.25 如果你用yolov11s可以设置0.5 - [-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(yolov8-MLLA.yaml) # 如何切换模型版本, 上面的ymal文件可以改为 yolov8s.yaml就是使用的v8s, # 类似某个改进的yaml文件名称为yolov8-XXX.yaml那么如果想使用其它版本就把上面的名称改为yolov8l-XXX.yaml即可改的是上面YOLO中间的名字不是配置文件的 # model.load(yolov8n.pt) # 是否加载预训练权重,科研不建议大家加载否则很难提升精度 model.train(datarC:\Users\Administrator\PycharmProjects\yolov5-master\yolov5-master\Construction Site Safety.v30-raw-images_latestversion.yolov8\data.yaml, # 如果大家任务是其它的ultralytics/cfg/default.yaml找到这里修改task可以改成detect, segment, classify, pose cacheFalse, imgsz640, epochs150, single_clsFalse, # 是否是单类别检测 batch16, close_mosaic0, workers0, device0, optimizerSGD, # using SGD # resumeruns/train/exp21/weights/last.pt, # 如过想续训就设置last.pt的地址 ampTrue, # 如果出现训练损失为Nan可以关闭amp projectruns/train, nameexp, )六、成功运行记录下面是成功运行的截图已经完成了有1个epochs的训练图片太大截不全第2个epochs了。​七、本文总结到此本文的正式分享内容就结束了在这里给大家推荐我的YOLOv26改进有效涨点专栏本专栏目前为新开的平均质量分98分后期我会根据各种最新的前沿顶会进行论文复现也会对一些老的改进机制进行补充如果大家觉得本文帮助到你了订阅本专栏关注后续更多的更新~专栏链接YOLOv26有效涨点专栏包含Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制​​