小目标检测实战:YOLO26 的四板斧与避坑清单

小目标检测实战:YOLO26 的四板斧与避坑清单

航拍里的车、巡检图像里的裂纹、PCB 上的焊点、遥感里的船只------小目标漏检是工业落地最常见也最头疼的问题

换更大的模型往往没用,因为根因不在模型容量,而在下采样把目标"采没了" 、以及训练时小目标被大目标抢走了标签

系列导航 :本篇专攻小目标。数据与评估的基础流程见《YOLO26 实战全流程》;训练侧的增强参数见《训练配方全解密》。


一、先搞懂小目标为什么难

一个 32×32 的目标,在网络里会经历:

特征层 下采样倍率 目标还剩多大
原图 32×32
P2 1/4 8×8
P3 1/8 4×4
P4 1/16 2×2
P5 1/32 约 1×1

到了 P5,这个目标基本已经"消失"了。 而默认 YOLO 的检测头就挂在 P3/P4/P5 上。

第二个问题在训练阶段:标签分配时,大目标会占据绝大多数正样本位置,小目标分到的正样本极少,梯度信号被淹没------模型"没学会"去关注它们。

所以解法只有两个方向

  1. 别让它被下采样掉 → 提高分辨率 / 用更浅的特征层(P2)
  2. 别让它在训练时被忽略 → 专门的标签分配策略(YOLO26 的 STAL)

二、四板斧

先说清楚:多大的目标算"小目标"

业界有个被广泛沿用的界定:COCO 把面积小于 32×32 像素的目标称为小目标(32~96 为中目标,96 以上为大目标)。

这个标准之所以好用,是因为它同时对应着网络的下采样层级------输入 640 时,P3 特征图是 80×80(stride 8)、P4 是 40×40(stride 16)、P5 只有 20×20(stride 32)。一个 32 像素的目标传到 P5 就只剩 1×1,几乎等于消失了。

所以直接在自己的数据上量一下就行:统计标注框的平均边长。如果普遍小于 32 像素,下面四板斧就都用得上。

第一斧:提高输入分辨率(先试这个,零成本)

python 复制代码
from ultralytics import YOLO

model = YOLO("yolo26s.pt")
model.train(data="visdrone.yaml", imgsz=1280, epochs=150, batch=16)

为什么它排第一:改一个数字、不用改代码、不用重标数据,通常就能拿到肉眼可见的提升。

代价 :显存与耗时约 4 倍(分辨率翻倍,像素数 ×4)。显存不够时:

  • 调小 batch
  • batch=-1 让 Ultralytics 自动探测最大可用 batch
  • 或开 amp=True(默认已开混合精度)

经验:小目标占比超过一半时,imgsz 从 640 提到 1280 的收益,经常大于把模型从 s 换到 m。

第二斧:用 P2 检测头(保留浅层细节)

P2 是 1/4 下采样层,空间细节最丰富。

python 复制代码
# 注意:P2 只有架构(yaml),没有预训练权重,需要自己训练
model = YOLO("yolo26s-p2.yaml")
model.train(data="visdrone.yaml", imgsz=960, epochs=200)
变体 加了什么 适用 注意
P2 1/4 尺度分支 小目标、密集目标 计算量更大、更慢
P6 1/64 尺度分支 大输入分辨率 显存更高

官方明确说明:yolo26*-p2.yaml-p6.yaml 只提供架构定义,不发布对应权重的 .pt,必须自己训练或做迁移。

第三斧:用带 STAL 的 YOLO26(官方已内置)

STAL(Small-Target-Aware Label Assignment,小目标感知标签分配) 是 YOLO26 官方训练方案的一部分。

人话版 :训练时网络要给每个预测位置分配"该去学哪个目标"(这一步叫标签分配)。大目标面积大、占的预测位置多,小目标占的位置少,很容易被大目标把学习名额抢光 ,结果就是模型根本没学会关注小目标。STAL 做的事就是给小目标预留名额,保证它们也有足够的学习信号。

你不需要额外配置------用 YOLO26 系列权重训练时默认就在用

python 复制代码
model = YOLO("yolo26s.pt")          # 已带 STAL
model.train(data="drone.yaml", imgsz=1280, epochs=150)

这也正是 YOLO26 相对 YOLO11 在航拍 / 无人机 / 密集小目标场景上最直接的优势来源。

第四斧:切片推理(大图兜底)

把大图切成有重叠的小块,每块单独推理,最后合并结果:

python 复制代码
import numpy as np
import cv2
from ultralytics import YOLO

model = YOLO("best.pt")

def tiled_predict(img_path, tile=640, overlap=0.2, conf=0.25):
    img = cv2.imread(img_path)
    H, W = img.shape[:2]
    step = int(tile * (1 - overlap))
    boxes_all = []

    for y in range(0, H, step):
        for x in range(0, W, step):
            y2, x2 = min(y + tile, H), min(x + tile, W)
            y1, x1 = max(0, y2 - tile), max(0, x2 - tile)   # 贴边时回退
            tile_img = img[y1:y2, x1:x2]

            res = model.predict(tile_img, conf=conf, imgsz=tile, verbose=False)[0]
            for b in res.boxes:
                x1g, y1g, x2g, y2g = b.xyxy[0].tolist()
                boxes_all.append([x1g + x1, y1g + y1, x2g + x2, y2g + y2,
                                  float(b.conf), int(b.cls)])

    # 跨块重复的框用 NMS 合并
    if not boxes_all:
        return []
    arr = np.array(boxes_all)
    idx = cv2.dnn.NMSBoxes(
        arr[:, :4].tolist(), arr[:, 4].tolist(), conf, 0.5)
    return arr[idx.flatten()] if len(idx) else []


dets = tiled_predict("aerial_4000x3000.jpg", tile=640, overlap=0.2)
print(f"共检出 {len(dets)} 个目标")

关键参数(这组是 SAHI 官方示例的常用取值):

  • 切片尺寸 :640×640,接近训练时的 imgsz
  • 重叠比例:0.2(即 20%),防止目标被切在边界上
  • 合并 NMS 的 IoU:0.5 左右

如果你不想自己写,SAHI 库已经把这套流程封装好了,YOLO 系列集成得很顺:

python 复制代码
from sahi import AutoDetectionModel
from sahi.predict import get_sliced_prediction

detection_model = AutoDetectionModel.from_pretrained(
    model_type='yolov8',          # 按你的版本选,YOLO26 用对应的类型名
    model_path='best.pt',
    confidence_threshold=0.3,
)

result = get_sliced_prediction(
    "aerial.jpg",
    detection_model,
    slice_height=640,
    slice_width=640,
    overlap_height_ratio=0.2,
    overlap_width_ratio=0.2,
)

代价 :推理次数从 1 变 N,耗时成倍增加 。所以它是兜底方案,别一上来就用。

有一条经验值得单独说:很多人第一反应是"加个 P2 检测头"。但 P2 特征图是 160×160,面积是 P3 的 4 倍 ,计算量和显存都会明显上升,边缘设备上往往直接不可用。改模型的代价通常比想象的大------先用切片推理兜底,确认收益值得再考虑动结构。


三、训练侧的四个补充技巧

3.1 增强要"保护"小目标

python 复制代码
model.train(data="drone.yaml", imgsz=1280,
            mosaic=1.0,        # mosaic 会缩小目标,小目标多时谨慎
            mixup=0.1,         # 别开太大,会模糊小目标
            copy_paste=0.3,    # 复制粘贴能增加小目标样本
            scale=0.5)         # 尺度抖动范围

反直觉提示:mosaic 会把 4 张图拼起来再缩放,等效让目标变得更小 。小目标极多时可以适当降低 mosaic 概率(0.5~0.7)或增大 scale,让目标在训练时保持较大尺寸。

以方向、颜色为判别特征的任务 (焊接缺陷、划痕、织物瑕疵这类),增强要克制。理由很直接:缺陷的方向和颜色本身就是判别特征,被增强改掉了,模型就学不到东西。所以这类任务通常把会破坏这些特征的增强关掉或调小:

python 复制代码
model.train(data="data.yaml", imgsz=1280,
            hsv_h=0.0,     # 色调不动:工业图像颜色稳定
            hsv_s=0.2,     # 饱和度轻微
            hsv_v=0.3,     # 亮度可以模拟光照变化
            degrees=5.0,   # 小角度:板子方向基本固定
            shear=0.0,     # 关掉错切:缺陷形状不能扭曲
            flipud=0.0,    # 不上下翻:有方向性
            fliplr=0.5,    # 左右翻可以:通常对称
            mosaic=0.0,    # 关掉:小目标缺陷会被拼接破坏
            mixup=0.0)     # 关掉:同上

他还给了一个方法值得照抄:先关掉所有增强训一个 baseline,再逐个打开看验证集变化。这比一上来就照搬 COCO 那套参数靠谱------COCO 的增强强度是为自然图像的通用性设计的,工业场景往往要反过来调。

3.2 类别均衡要看"目标数"而不是"图片数"

小目标类别常常是图片多但目标小 ------统计时看每类的实例数量,别只看图片数。

3.3 验证集必须包含最远/最小的样本

如果你的验证集都是"大又清晰"的目标,指标会虚高,上线必崩。

3.4 后处理阈值要单独调

小目标的置信度普遍偏低。用默认 0.25 可能全被滤掉:

python 复制代码
# 对小目标类别单独降低阈值
results = model.predict("img.jpg", conf=0.15, iou=0.6)

更稳妥的做法是按类别设定阈值 :先用 model.val() 找出每类的最佳 conf,再在业务代码里分阈值过滤。


四、选型速查

场景 推荐组合
航拍 / 无人机(几百米高空) YOLO26s + imgsz=1280 + 切片(overlap 0.2)
工业缺陷(焊点/划痕) YOLO26m + imgsz=1280 + P2 头
PCB / 密集元件 YOLO26m/l + P2 + copy_paste 增强
遥感船只 / 车辆 YOLO26-obb(旋转框)+ 高分辨率
医学小病灶 YOLO26l/x + 高分辨率 + 切片,阈值单独调
实时性要求高 YOLO26n/s + imgsz=960(放弃切片)

五、避坑清单

  1. 别一上来就换大模型 ------ 小目标漏检的主因是下采样和标签分配,不是模型容量。
  2. 别一上来就切片 ------ 先试 imgsz=1280,很多时候就够了,切片会让耗时翻倍。
  3. P2 没有预训练权重 ------ 用 -p2.yaml 意味着从头训练,数据量要够。
  4. mosaic 会缩小目标 ------ 小目标场景要重新评估它的强度。
  5. 验证集别只放"好图" ------ 必须包含最小、最模糊、最遮挡的样本。
  6. 阈值别用默认 ------ 小目标置信度天然偏低,0.25 可能滤掉一半。
  7. 切片后一定要 NMS 合并 ------ 否则边界处的目标会重复计数。
  8. 切片尺寸要接近训练 imgsz ------ 差太远会因尺度失配反而掉点。

六、小结

性价比排序依次尝试:

text 复制代码
① imgsz 640 → 1280        (零成本,先做)
② 用 YOLO26(自带 STAL)    (换模型的最小代价)
③ P2 检测头                (小目标占比极高时)
④ 切片推理                 (超大图兜底,最后考虑)

核心认知 :小目标检测不是"换个更强的模型"就能解决的工程问题,而是分辨率、特征层、标签分配、后处理阈值四个环节的系统性配合。


参考来源

  • Ultralytics 官方文档(YOLO26 模型页、P2/P6 架构说明、STAL 训练方案)
  • SAHI 官方示例(切片推理接口与参数取值)
  • COCO 数据集目标尺寸分级定义(小 / 中 / 大目标)

关键词小目标检测 YOLO26 STAL P2检测头 切片推理 SAHI 航拍 无人机 工业缺陷

环境:ultralytics 8.4+ / opencv-python / PyTorch 2.x

相关推荐
陈童学哦1 小时前
Codex配置瘦身实践:给Agent提示词做一次深度大扫除
人工智能
shark-chili1 小时前
关于AI辅助编程的认知
数据库·人工智能·redis·macos·缓存
机核研创社1 小时前
一次性内裤无人生产线详解:从裁片到成品 12–35 秒一件的整线自动化架构
人工智能·自动化
有Li1 小时前
【AI答疑】MR数据预处理步骤
人工智能·笔记·算法·语言模型·医学生
衡石科技1 小时前
让 BI 能力可编排:CLI、Headless API 与可治理执行
人工智能·chatbi
蓝速科技1 小时前
国产化信创终端等保合规核心防护与落地方案丨蓝速科技
大数据·运维·数据库·人工智能·科技
GEO实战经验分享2 小时前
王涛:GEO 服务商能力评估清单——基础、结构、战略、风控四层怎么核验
大数据·人工智能·chatgpt
干就完事了2 小时前
机器学习-音乐艺人流行趋势预测
人工智能·机器学习·阿里云
财经科技社2 小时前
从卧室到卫生间,流感季家庭环境消毒怎么做?
人工智能·科技