ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

yolov26改进 | 检测头篇 | 辅助特征融合检测头FASFFHead添加小目标检测头 (让小目标无所遁形、全网独家创新)

yolov26改进 | 检测头篇 | 辅助特征融合检测头FASFFHead添加小目标检测头 (让小目标无所遁形、全网独家创新) 开始正文前先向大家推荐我的YOLO专栏系列。本人持续更新 YOLOv8、YOLO11、YOLO26 等热门模型内容覆盖图像分类、目标检测、实例分割、多目标跟踪、姿态估计与关键点检测重点讲解 小目标检测、注意力机制、特征融合、损失函数改进、自定义数据集训练、消融实验及论文代码复现。同时分享如何使用 OpenAI Codex辅助撰写论文、配置实验环境、调试项目、改进模型和分析实验结果。 专栏目前正在进行限时优惠每周更新 5–7篇最新论文机制、YOLO改进方法和实战教程。订阅后可获得包含本人全部改进方案的代码与配置文件并加入专属技术交流群。我也会定期在群内分享 YOLO论文选题、创新点设计、实验方案、论文写作与投稿发表经验欢迎大家订阅交流一、本文介绍本文给大家带来的最新改进机制是本人基于ASFFHead二次创新设计的四尺度检测头——FASFFHead并将其完整集成到YOLOv26中。传统ASFFHead通常面向三层特征进行自适应空间融合虽然能够根据不同位置动态分配各尺度特征的融合权重但在增加第四个检测尺度后直接进行跨层融合容易受到分辨率差异和语义差距影响造成细节信息丢失或深层语义利用不足。针对这一问题FASFFHead重新设计了四尺度特征对齐、渐进融合和权重分配方式使不同层级特征在完成尺寸与通道统一后再进行更充分的自适应融合从而降低跨尺度传递过程中的特征损失。本文提供小目标版和大目标版两种设计思路小目标版增加高分辨率检测层进一步保留浅层纹理、边缘和位置信息强化对微小目标、密集目标及远距离目标的二次提取大目标版增加更深层检测分支扩大有效感受野增强对大型目标和完整结构信息的建模能力。该结构来源于专栏读者对四头ASFF检测头的实际需求具有较强的任务针对性、扩展能力和论文创新空间。本文将详细介绍FASFFHead的四尺度输入、特征对齐、自适应融合及检测分支设计并提供完整代码、配置文件、模块注册方法和Codex辅助修改思路。欢迎大家订阅我的专栏一起学习YOLO专栏链接YOLOv26有效涨点专栏包含Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制目录一、本文介绍二、原理介绍三、FASFFHead的核心代码四、手把手教你添加FASFFHead卷积4.1 修改一4.2 修改二4.3 修改三4.4 修改四4.5 修改五4.6 修改六4.7 修改七4.8 修改八4.9 修改九五、FASFFHead检测头的yaml文件六、完美运行记录七、本文总结二、原理介绍官方论文地址官方论文地址点击即可跳转官方代码地址官方代码地址点击即可跳转ASFF自适应空间特征融合方法针对单次对象检测任务提出解决了不同特征尺度间的一致性问题。其主要创新是引入了一种自适应的空间特征融合方式有效地过滤掉冲突信息从而增强了尺度不变性。研究表明将ASFF应用于YOLOv3可以显著提高在MS COCO数据集上的检测性能实现了速度与准确性的平衡。ASFF方法可以通过反向传播进行训练与模型无关并且引入的计算开销很小使其成为现有对象检测框架的一种实用增强。ASFF的创新点主要包括1. 自适应空间特征融合提出了一种新的金字塔特征融合策略能够空间过滤冲突信息压制不同尺度特征间的不一致性。2. 改善尺度不变性通过ASFF策略显著提升了特征的尺度不变性有助于提高对象检测的准确性。3. 低推理开销在提升检测性能的同时几乎不增加额外的推理开销。这些创新使ASFF成为单次对象检测领域的一个重要进展特别是对处理不同尺度对象的能力的提升所以将其对于一些单一尺度检测的Neck适合是不适用的大家需要注意这一点。这张图片展示了自适应空间特征融合ASFF机制的工作原理它是用于单次对象检测的。在这种结构中不同层级的特征表示为不同颜色的层首先通过各自的步幅stride进行下采样或上采样以便所有特征具有相同的空间维度。- Level 1、Level 2和Level 3指的是特征金字塔中不同层级的特征每个层级都有不同的空间分辨率。- ASFF-1、ASFF-2和ASFF-3表示应用了ASFF机制的不同层级的特征融合。- 在ASFF-3的放大部分我们可以看到来自其他层级的特征x1→3、x2→3被调整到与第三层x3→3相同的尺寸然后它们通过学习到的权重图进行加权融合生成最终用于预测的融合特征。通过这种方式ASFF能够在每个空间位置自适应地选择最有用的特征以提高检测的准确性。这种方法允许模型根据每个特定位置和尺度的上下文灵活地决定哪些特征层级对最终预测最为重要。三、FASFFHead的核心代码使用方法看章节四import copy import math from ultralytics.nn.modules import DFL import torch from torch import nn from ultralytics.utils.tal import dist2bbox, make_anchors import torch.nn.functional as F __all__ [FASFFHead] def autopad(k, pNone, d1): # kernel, padding, dilation Pad to same shape outputs. if d 1: k d * (k - 1) 1 if isinstance(k, int) else [d * (x - 1) 1 for x in k] # actual kernel-size if p is None: p k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad return p class Conv(nn.Module): Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation). default_act nn.SiLU() # default activation def __init__(self, c1, c2, k1, s1, pNone, g1, d1, actTrue): Initialize Conv layer with given arguments including activation. super().__init__() self.conv nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groupsg, dilationd, biasFalse) self.bn nn.BatchNorm2d(c2) self.act self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() def forward(self, x): Apply convolution, batch normalization and activation to input tensor. return self.act(self.bn(self.conv(x))) def forward_fuse(self, x): Perform transposed convolution of 2D data. return self.act(self.conv(x)) class DWConv(Conv): Depth-wise convolution module. def __init__(self, c1, c2, k1, s1, d1, actTrue): Initialize depth-wise convolution with given parameters. Args: c1 (int): Number of input channels. c2 (int): Number of output channels. k (int): Kernel size. s (int): Stride. d (int): Dilation. act (bool | nn.Module): Activation function. super().__init__(c1, c2, k, s, gmath.gcd(c1, c2), dd, actact) class DFL(nn.Module): Integral module of Distribution Focal Loss (DFL). Proposed in Generalized Focal Loss https://ieeexplore.ieee.org/document/9792391 def __init__(self, c116): Initialize a convolutional layer with a given number of input channels. super().__init__() self.conv nn.Conv2d(c1, 1, 1, biasFalse).requires_grad_(False) x torch.arange(c1, dtypetorch.float) self.conv.weight.data[:] nn.Parameter(x.view(1, c1, 1, 1)) self.c1 c1 def forward(self, x): Applies a transformer layer on input tensor x and returns a tensor. b, c, a x.shape # batch, channels, anchors return self.conv(x.view(b, 4, self.c1, a).transpose(2, 1).softmax(1)).view(b, 4, a) # return self.conv(x.view(b, self.c1, 4, a).softmax(1)).view(b, 4, a) class FASFF(nn.Module): def __init__(self, level, ch, multiplier1, rfbFalse, visFalse): super(FASFF, self).__init__() self.level level self.dim [int(ch[3] * multiplier), int(ch[2] * multiplier), int(ch[1] * multiplier), int(ch[0] * multiplier)] # print(self.dim) self.inter_dim self.dim[self.level] if level 0: self.stride_level_1 Conv(int(ch[2] * multiplier), self.inter_dim, 3, 2) self.stride_level_2 Conv(int(ch[1] * multiplier), self.inter_dim, 3, 2) self.expand Conv(self.inter_dim, int( ch[3] * multiplier), 3, 1) elif level 1: self.compress_level_0 Conv( int(ch[3] * multiplier), self.inter_dim, 1, 1) self.stride_level_2 Conv( int(ch[1] * multiplier), self.inter_dim, 3, 2) self.expand Conv(self.inter_dim, int(ch[2] * multiplier), 3, 1) elif level 2: self.compress_level_0 Conv( int(ch[2] * multiplier), self.inter_dim, 1, 1) self.stride_level_2 Conv( int(ch[0] * multiplier), self.inter_dim, 3, 2) self.expand Conv(self.inter_dim, int(ch[1] * multiplier), 3, 1) elif level 3: self.compress_level_0 Conv( int(ch[2] * multiplier), self.inter_dim, 1, 1) self.compress_level_1 Conv( int(ch[1] * multiplier), self.inter_dim, 1, 1) self.expand Conv(self.inter_dim, int( ch[0] * multiplier), 3, 1) # when adding rfb, we use half number of channels to save memory compress_c 8 if rfb else 16 self.weight_level_0 Conv( self.inter_dim, compress_c, 1, 1) self.weight_level_1 Conv( self.inter_dim, compress_c, 1, 1) self.weight_level_2 Conv( self.inter_dim, compress_c, 1, 1) self.weight_levels Conv( compress_c * 3, 3, 1, 1) self.vis vis def forward(self, x): # l,m,s # 128, 256, 512 512, 256, 128 from small - large x_level_add x[2] x_level_0 x[3] # l x_level_1 x[1] # m x_level_2 x[0] # s # print(x_level_0: , x_level_0.shape) # print(x_level_1: , x_level_1.shape) # print(x_level_2: , x_level_2.shape) if self.level 0: level_0_resized x_level_0 level_1_resized self.stride_level_1(x_level_add) level_2_downsampled_inter F.max_pool2d( x_level_1, 3, stride2, padding1) level_2_resized self.stride_level_2(level_2_downsampled_inter) elif self.level 1: level_0_compressed self.compress_level_0(x_level_0) level_0_resized F.interpolate( level_0_compressed, scale_factor2, modenearest) level_1_resized x_level_add level_2_resized self.stride_level_2(x_level_1) elif self.level 2: level_0_compressed self.compress_level_0(x_level_add) level_0_resized F.interpolate( level_0_compressed, scale_factor2, modenearest) level_1_resized x_level_1 level_2_resized self.stride_level_2(x_level_2) elif self.level 3: level_0_compressed self.compress_level_0(x_level_add) level_0_resized F.interpolate( level_0_compressed, scale_factor4, modenearest) x_level_1_compressed self.compress_level_1(x_level_1) level_1_resized F.interpolate( x_level_1_compressed, scale_factor2, modenearest) level_2_resized x_level_2 # print(level: {}, l1_resized: {}, l2_resized: {}.format(self.level, # level_1_resized.shape, level_2_resized.shape)) level_0_weight_v self.weight_level_0(level_0_resized) level_1_weight_v self.weight_level_1(level_1_resized) level_2_weight_v self.weight_level_2(level_2_resized) # print(level_0_weight_v: , level_0_weight_v.shape) # print(level_1_weight_v: , level_1_weight_v.shape) # print(level_2_weight_v: , level_2_weight_v.shape) levels_weight_v torch.cat( (level_0_weight_v, level_1_weight_v, level_2_weight_v), 1) levels_weight self.weight_levels(levels_weight_v) levels_weight F.softmax(levels_weight, dim1) fused_out_reduced level_0_resized * levels_weight[:, 0:1, :, :] \ level_1_resized * levels_weight[:, 1:2, :, :] \ level_2_resized * levels_weight[:, 2:, :, :] out self.expand(fused_out_reduced) if self.vis: return out, levels_weight, fused_out_reduced.sum(dim1) else: return out class FASFFHead(nn.Module): YOLO Detect head for object detection models. This class implements the detection head used in YOLO models for predicting bounding boxes and class probabilities. It supports both training and inference modes, with optional end-to-end detection capabilities. Attributes: dynamic (bool): Force grid reconstruction. export (bool): Export mode flag. format (str): Export format. end2end (bool): End-to-end detection mode. max_det (int): Maximum detections per image. shape (tuple): Input shape. anchors (torch.Tensor): Anchor points. strides (torch.Tensor): Feature map strides. legacy (bool): Backward compatibility for v3/v5/v8/v9/v11 models. xyxy (bool): Output format, xyxy or xywh. nc (int): Number of classes. nl (int): Number of detection layers. reg_max (int): DFL channels. no (int): Number of outputs per anchor. stride (torch.Tensor): Strides computed during build. cv2 (nn.ModuleList): Convolution layers for box regression. cv3 (nn.ModuleList): Convolution layers for classification. dfl (nn.Module): Distribution Focal Loss layer. one2one_cv2 (nn.ModuleList): One-to-one convolution layers for box regression. one2one_cv3 (nn.ModuleList): One-to-one convolution layers for classification. Methods: forward: Perform forward pass and return predictions. bias_init: Initialize detection head biases. decode_bboxes: Decode bounding boxes from predictions. postprocess: Post-process model predictions. Examples: Create a detection head for 80 classes detect Detect(nc80, ch(256, 512, 1024)) x [torch.randn(1, 256, 80, 80), torch.randn(1, 512, 40, 40), torch.randn(1, 1024, 20, 20)] outputs detect(x) dynamic False # force grid reconstruction export False # export mode format None # export format max_det 300 # max_det agnostic_nms False shape None anchors torch.empty(0) # init strides torch.empty(0) # init legacy False # backward compatibility for v3/v5/v8/v9 models xyxy False # xyxy or xywh output def __init__(self, nc: int 80, reg_max16, end2endFalse, ch: tuple (), multiplier1, rfbFalse): Initialize the YOLO detection layer with specified number of classes and channels. Args: nc (int): Number of classes. reg_max (int): Maximum number of DFL channels. end2end (bool): Whether to use end-to-end NMS-free detection. ch (tuple): Tuple of channel sizes from backbone feature maps. super().__init__() self.nc nc # number of classes self.nl len(ch) # number of detection layers self.reg_max reg_max # DFL channels (ch[0] // 16 to scale 4/8/12/16/20 for n/s/m/l/x) self.no nc self.reg_max * 4 # number of outputs per anchor self.stride torch.zeros(self.nl) # strides computed during build c2, c3 max((16, ch[0] // 4, self.reg_max * 4)), max(ch[0], min(self.nc, 100)) # channels self.cv2 nn.ModuleList( nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch ) self.cv3 ( nn.ModuleList(nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch) if self.legacy else nn.ModuleList( nn.Sequential( nn.Sequential(DWConv(x, x, 3), Conv(x, c3, 1)), nn.Sequential(DWConv(c3, c3, 3), Conv(c3, c3, 1)), nn.Conv2d(c3, self.nc, 1), ) for x in ch ) ) self.dfl DFL(self.reg_max) if self.reg_max 1 else nn.Identity() self.l0_fusion FASFF(level0, chch, multipliermultiplier, rfbrfb) self.l1_fusion FASFF(level1, chch, multipliermultiplier, rfbrfb) self.l2_fusion FASFF(level2, chch, multipliermultiplier, rfbrfb) self.l3_fusion FASFF(level3, chch, multipliermultiplier, rfbrfb) if end2end: self.one2one_cv2 copy.deepcopy(self.cv2) self.one2one_cv3 copy.deepcopy(self.cv3) property def one2many(self): Returns the one-to-many head components, here for v3/v5/v8/v9/v11 backward compatibility. return dict(box_headself.cv2, cls_headself.cv3) property def one2one(self): Returns the one-to-one head components. return dict(box_headself.one2one_cv2, cls_headself.one2one_cv3) property def end2end(self): Checks if the model has one2one for v3/v5/v8/v9/v11 backward compatibility. return getattr(self, _end2end, True) and hasattr(self, one2one) end2end.setter def end2end(self, value): Override the end-to-end detection mode. self._end2end value def forward_head( self, x: list[torch.Tensor], box_head: torch.nn.Module None, cls_head: torch.nn.Module None ) - dict[str, torch.Tensor]: Concatenates and returns predicted bounding boxes and class probabilities. if box_head is None or cls_head is None: # for fused inference return dict() bs x[0].shape[0] # batch size boxes torch.cat([box_head[i](x[i]).view(bs, 4 * self.reg_max, -1) for i in range(self.nl)], dim-1) scores torch.cat([cls_head[i](x[i]).view(bs, self.nc, -1) for i in range(self.nl)], dim-1) return dict(boxesboxes, scoresscores, featsx) def forward( self, x: list[torch.Tensor] ) - dict[str, torch.Tensor] | torch.Tensor | tuple[torch.Tensor, dict[str, torch.Tensor]]: Concatenates and returns predicted bounding boxes and class probabilities. x1 self.l0_fusion(x) x2 self.l1_fusion(x) x3 self.l2_fusion(x) x4 self.l3_fusion(x) x [x4, x3, x2, x1] preds self.forward_head(x, **self.one2many) if self.end2end: x_detach [xi.detach() for xi in x] one2one self.forward_head(x_detach, **self.one2one) preds {one2many: preds, one2one: one2one} if self.training: return preds y self._inference(preds[one2one] if self.end2end else preds) if self.end2end: y self.postprocess(y.permute(0, 2, 1)) return y if self.export else (y, preds) def _inference(self, x: dict[str, torch.Tensor]) - torch.Tensor: Decode predicted bounding boxes and class probabilities based on multiple-level feature maps. Args: x (dict[str, torch.Tensor]): Dictionary of predictions from detection layers. Returns: (torch.Tensor): Concatenated tensor of decoded bounding boxes and class probabilities. # Inference path dbox self._get_decode_boxes(x) return torch.cat((dbox, x[scores].sigmoid()), 1) def _get_decode_boxes(self, x: dict[str, torch.Tensor]) - torch.Tensor: Get decoded boxes based on anchors and strides. shape x[feats][0].shape # BCHW if self.dynamic or self.shape ! shape: self.anchors, self.strides (a.transpose(0, 1) for a in make_anchors(x[feats], self.stride, 0.5)) self.shape shape dbox self.decode_bboxes(self.dfl(x[boxes]), self.anchors.unsqueeze(0)) * self.strides return dbox def bias_init(self): Initialize Detect() biases, WARNING: requires stride availability. for i, (a, b) in enumerate(zip(self.one2many[box_head], self.one2many[cls_head])): # from a[-1].bias.data[:] 2.0 # box b[-1].bias.data[: self.nc] math.log( 5 / self.nc / (640 / self.stride[i]) ** 2 ) # cls (.01 objects, 80 classes, 640 img) if self.end2end: for i, (a, b) in enumerate(zip(self.one2one[box_head], self.one2one[cls_head])): # from a[-1].bias.data[:] 2.0 # box b[-1].bias.data[: self.nc] math.log( 5 / self.nc / (640 / self.stride[i]) ** 2 ) # cls (.01 objects, 80 classes, 640 img) def decode_bboxes(self, bboxes: torch.Tensor, anchors: torch.Tensor, xywh: bool True) - torch.Tensor: Decode bounding boxes from predictions. return dist2bbox( bboxes, anchors, xywhxywh and not self.end2end and not self.xyxy, dim1, ) def postprocess(self, preds: torch.Tensor) - torch.Tensor: Post-processes YOLO model predictions. Args: preds (torch.Tensor): Raw predictions with shape (batch_size, num_anchors, 4 nc) with last dimension format [x1, y1, x2, y2, class_probs]. Returns: (torch.Tensor): Processed predictions with shape (batch_size, min(max_det, num_anchors), 6) and last dimension format [x1, y1, x2, y2, max_class_prob, class_index]. boxes, scores preds.split([4, self.nc], dim-1) scores, conf, idx self.get_topk_index(scores, self.max_det) boxes boxes.gather(dim1, indexidx.repeat(1, 1, 4)) return torch.cat([boxes, scores, conf], dim-1) def get_topk_index(self, scores: torch.Tensor, max_det: int) - tuple[torch.Tensor, torch.Tensor, torch.Tensor]: Get top-k indices from scores. Args: scores (torch.Tensor): Scores tensor with shape (batch_size, num_anchors, num_classes). max_det (int): Maximum detections per image. Returns: (torch.Tensor, torch.Tensor, torch.Tensor): Top scores, class indices, and filtered indices. batch_size, anchors, nc scores.shape # i.e. shape(16,8400,84) # Use max_det directly during export for TensorRT compatibility (requires k to be constant), # otherwise use min(max_det, anchors) for safety with small inputs during Python inference k max_det if self.export else min(max_det, anchors) if self.agnostic_nms: scores, labels scores.max(dim-1, keepdimTrue) scores, indices scores.topk(k, dim1) labels labels.gather(1, indices) return scores, labels, indices ori_index scores.max(dim-1)[0].topk(k)[1].unsqueeze(-1) scores scores.gather(dim1, indexori_index.repeat(1, 1, nc)) scores, index scores.flatten(1).topk(k) idx ori_index[torch.arange(batch_size)[..., None], index // nc] # original index return scores[..., None], (index % nc)[..., None].float(), idx def fuse(self) - None: Remove the one2many head for inference optimization. self.cv2 self.cv3 None四、手把手教你添加FASFFHead卷积4.1 修改一首先我们将上面的代码复制粘贴到ultralytics/nn 目录下新建一个py文件复制粘贴进去具体名字自己来定我这里起名为FASFFHead.py。​4.2 修改二第二步我们在该目录下创建一个新的py文件名字为__init__.py(用群内的文件的话已经有了无需新建)然后在其内部导入我们的检测头如下图所示。​​4.3 修改三第三步我门中到如下文件ultralytics/nn/tasks.py进行导入和注册我们的模块(用群内的文件的话已经有了无需重新导入直接开始第四步即可)​​4.4 修改四第四步我门找到如下文件ultralytics/nn/tasks.py找到如下的代码进行将检测头添加进去这里给大家推荐个快速搜索的方法用ctrlf然后搜索Detect然后就能快速查找了。​​​4.5 修改五4.6 修改六同理​​​4.7 修改七同理4.8 修改八这里有一些不一样我们需要加一行代码else: return detect为啥呢不一样因为这里的m在代码执行过程中会将你的代码自动转换为小写所以直接else方便一点以后出现一些其它分割或者其它的教程的时候在提供其它的修改教程。​​​​4.9 修改九同理.​​​​到此就修改完成了大家可以复制下面的yaml文件运行。五、FASFFHead检测头的yaml文件此版本训练信息YOLO26-Head-FASFFHead summary: 260 layers, 2,506,140 parameters, 2,506,140 gradients, 5.8 GFLOPs# Ultralytics AGPL-3.0 License - https://ultralytics.com/license # Ultralytics YOLO26 object detection model with P2/4 - 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-p2.yaml will call yolo26-p2.yaml with scale n # [depth, width, max_channels] n: [0.50, 0.25, 1024] # summary: 329 layers, 2,662,400 parameters, 2,662,400 gradients, 9.5 GFLOPs s: [0.50, 0.50, 1024] # summary: 329 layers, 9,765,856 parameters, 9,765,856 gradients, 27.8 GFLOPs m: [0.50, 1.00, 512] # summary: 349 layers, 21,144,288 parameters, 21,144,288 gradients, 91.4 GFLOPs l: [1.00, 1.00, 512] # summary: 489 layers, 25,815,520 parameters, 25,815,520 gradients, 115.3 GFLOPs x: [1.00, 1.50, 512] # summary: 489 layers, 57,935,232 parameters, 57,935,232 gradients, 256.9 GFLOPs # YOLO26n backbone backbone: # [from, repeats, module, args] - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4 - [-1, 2, C3k2, [256, False, 0.25]] - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8 - [-1, 2, C3k2, [512, False, 0.25]] - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16 - [-1, 2, C3k2, [512, True]] - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32 - [-1, 2, C3k2, [1024, True]] - [-1, 1, SPPF, [1024, 5, 3, True]] # 9 - [-1, 2, C2PSA, [1024]] # 10 # YOLO26n head head: - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 6], 1, Concat, [1]] # cat backbone P4 - [-1, 2, C3k2, [512, True]] # 13 - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 4], 1, Concat, [1]] # cat backbone P3 - [-1, 2, C3k2, [256, True]] # 16 (P3/8-small) - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 2], 1, Concat, [1]] # cat backbone P2 - [-1, 2, C3k2, [128, True]] # 19 (P2/4-xsmall) - [-1, 1, Conv, [128, 3, 2]] - [[-1, 16], 1, Concat, [1]] # cat head P3 - [-1, 2, C3k2, [256, True]] # 22 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]] - [[-1, 13], 1, Concat, [1]] # cat head P4 - [-1, 2, C3k2, [512, True]] # 25 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]] - [[-1, 10], 1, Concat, [1]] # cat head P5 - [-1, 1, C3k2, [1024, True, 0.5, True]] # 28 (P5/32-large) - [[19, 22, 25, 28], 1, FASFFHead, [nc]] # Detect(P2, P3, P4, P5)六、完美运行记录最后提供一下完美运行的图片。​​​七、本文总结到此本文的正式分享内容就结束了在这里给大家推荐我的YOLOv26改进有效涨点专栏本专栏目前为新开的平均质量分98分后期我会根据各种最新的前沿顶会进行论文复现也会对一些老的改进机制进行补充如果大家觉得本文帮助到你了订阅本专栏关注后续更多的更新~专栏链接YOLOv26有效涨点专栏包含Conv、注意力机制、主干/Backbone、损失函数、优化器、后处理等改进机制​
返回列表