
简介面向计算机视觉开发者与研究人员基于YOLOv8n的小目标检测实战项目旨在解决小目标因像素少、特征弱而难以被常规算法准确识别的痛点。项目在YOLOv8轻量级版本基础上通过改进网络结构、特征融合策略与损失函数设计在保持较高准确度的同时更适合计算资源受限的嵌入式环境。资源不仅提供完整可运行的Python源码还配有从环境安装、数据集准备到模型训练评估的流程教程便于初学者逐步上手也有助于工程师快速复用。压缩包共2000个文件以txt、yaml、md为主要类型其中大量txt文件承担数据或标注信息存储yaml用于模型与训练配置md为项目说明文档整体约336.37MB目录结构清晰。目前已有80人学习项目被标记为优质项目实战具备很强的实践与参考价值可作为深度学习和目标检测领域的可靠起步点。1. 小目标检测为什么难从“看不见”到“测不准”YOLOv8n 能救哪一部分做小目标检测的人都会经历一次心态崩塌模型在公开数据集上 mAP 高得漂亮一到自己的业务图上几万个像素里那个目标就是测不出来。不是模型菜而是小目标本身的物理条件太苛刻——一个 8×8 像素的目标经过 YOLOv8n 的第一层卷积和 32 倍下采样之后在特征图里只剩不到 1 个像素点信息几乎被抹平。这时候再好的分类头也分不出它是什么。所以“小目标检测”从来不是单纯换模型的问题而是数据、预处理、训练策略和推断方式四件事一起做对。这篇就是围绕 YOLOv8n 把这四件事讲透怎么做数据集、怎么调参数、怎么排查翻车点以及拿到一个标题里这种“源码流程教程”项目包后怎么验收和改造。适合手里有具体小目标检测需求、想快速落地而不是只看原理的工程师。2. YOLOv8n 的小目标能力边界DFL 头、SPPF 与高分辨率输入的取舍2.1 为什么小目标任务优先选 YOLOv8n 而不是大模型直觉上模型越大越强小目标应该选 YOLOv8x但真实落地里 n 版本反而更常用。原因是小目标检测的主要矛盾不在参数量而在输入分辨率和训练策略。YOLOv8n 的 backbone 用 CSPDarknet 结构FLOPs 只有 8.7G 左右在 640 输入下单张前向非常快这给了我们一个关键操作空间——把输入分辨率从 640 拉到 1024 甚至 1280让目标在图上占据更多像素。如果用 YOLOv8x显存先撑不住batch 被迫降低训练反而更不稳定。另外一点容易被忽略YOLOv8n 的检测头是 anchor-free 的 Decoupled Head分类和回归分支分开回归分支还带了 DFLDistribution Focal Loss。DFL 的作用是把边界框坐标建模成概率分布而不是直接回归一个值这对小目标尤其友好。小目标的位置往往只占几个像素标注框的抖动在小目标上占比很大DFL 相当于给这种抖动加了一个概率约束不会因为一两像素的标注噪声就跑偏。小目标场景还有一个关键需求是“快”。很多小目标检测业务是实时的比如无人机画面、机器人巡检、产线质检模型需要在边端设备上跑。YOLOv8n 的轻量结构配合 TensorRT 或 OpenVINO 可以很容易推到百帧级别而大模型即便精度高一点部署成本也高一个量级。我一般会这样选型先跑 YOLOv8n 拿一个 baseline再考虑用 YOLOv8s 或者加 P2 层做精度提升而不是一上来就上大模型。2.2 模型结构上的两个硬伤深下采样与感受野矛盾YOLOv8 默认是 32 倍下采样输出三个尺度的特征图分别是 8 倍、16 倍和 32 倍下采样。小目标检测的常见定义是目标尺寸小于 32×32 像素也就是说最小的目标在 32 倍下采样的特征图上连一个格子都占不满。这意味着大部分小目标信息集中在前两层特征图上而 P38 倍下采样是 80×80 的特征图每个格子对应的原图感受野约为 8×8 像素。这里存在一个天然矛盾小目标需要高分辨率特征图来保留空间细节但高分辨率特征图的语义信息不够。浅层特征图经过的卷积层少目标类别信息弱深层特征图有语义但空间分辨率已经被抹掉了。YOLOv8 的 neck 部分用 FPNPAN 结构做了一次多尺度融合理论上可以让深层语义信息回流到浅层但实际上对小目标来说这种融合还不够。常见做法是给模型加 P2 检测头也就是 4 倍下采样输出。P2 层的特征图是 160×160一个 8×8 的目标在 P2 上还能占 2×2 个格子定位精度上了一个台阶。YOLOv8 官方没有提供带 P2 的预训练权重需要自己改 yaml 结构这会丢掉预训练的参数优势。所以我更推荐先用“高分辨率输入 切片推理”的组合方案这样不需要改模型结构完全复用官方权重训练和部署的坑要少很多。2.3 输入分辨率涨上去之后哪些代价先找上门把训练分辨率从 640 提到 1024参数量不增加但计算量和显存占用是平方增长。YOLOv8n 在 640 下 batch16 大概要 6G 显存到 1280 分辨率同样的 batch 直接超过 24G。这里有几个应对手段降低 batch 同时开梯度累积、开启 AMP 混合精度、把 mosaic 增强的拼图数从 4 降到 2 以减少显存峰值。另外要小心的是提升分辨率并不总是带来收益。如果你的数据集里大部分目标本来就是中大型物体只是偶尔有几个小目标那提升分辨率只会让训练变慢模型对小目标的提升有限。正确做法是先统计数据集里目标尺寸的分布确认小目标占比足够大再去提分辨率。这一步我一般会在数据准备阶段用脚本扫一遍标注框算一下每个目标相对原图的面积比然后画个分布直方图再做决定。还有一点是数据增强策略要跟着分辨率走。高分辨率输入下的 random crop 很容易把一个小目标从上下文里切掉一半导致模型学到残缺样本。我习惯在增强配置里把 scale 的范围收窄比如 0.5~1.5同时把 hsv_h、hsv_s 这些颜色增强参数调低因为颜色变化对小目标的影响比大目标更敏感目标本身像素就少再一变色就彻底认不出来了。3. 构建小目标数据集红外小目标与可见光小目标的标注、切图与上下文3.1 先给目标量尺寸为什么 80% 的失败来自数据没准备好所有小目标检测项目的第一个坑不是模型而是数据。YOLO 的标注格式是归一化的中心点坐标加宽高这本身对小目标就不友好——一个 5×5 像素的目标在 1920×1080 图上的宽高分别是 0.0026 和 0.0046数值非常小训练时哪怕标注偏差一个像素归一化坐标的误差都会被放大。更麻烦的是很多标注工具在缩小图片显示时根本看不清小目标标注员漏标、错标是常态。我先讲一个我常用的统计脚本拿到数据集第一步就扫一遍标注框的尺寸分布。脚本逻辑很简单读每张图的宽高读对应 txt 标注的每个框计算 w/width 和 h/height再把结果按区间累加。这一步帮我在实际项目中筛掉过两个不靠谱的数据集——其中一个号称小目标数据集扫完才发现超过 60% 的目标框面积占比在 10% 以上根本是普通目标检测的难度。import os from collections import defaultdict def stat_target_size(img_dir, label_dir): # 统计每个标注框相对原图的面积占比 size_buckets defaultdict(int) total_boxes 0 for img_file in os.listdir(img_dir): if not img_file.endswith((.jpg, .png)): continue img_w, img_h get_image_size(os.path.join(img_dir, img_file)) label_file os.path.join(label_dir, os.path.splitext(img_file)[0] .txt) if not os.path.exists(label_file): continue for line in open(label_file): parts line.strip().split() if len(parts) 5: continue _, cx, cy, bw, bh parts[:5] w_pix float(bw) * img_w h_pix float(bh) * img_h area_ratio (w_pix * h_pix) / (img_w * img_h) total_boxes 1 if area_ratio 0.003: # 约小于 0.3% 面积视为小目标 size_buckets[small] 1 elif area_ratio 0.01: size_buckets[medium] 1 else: size_buckets[large] 1 return dict(size_buckets), total_boxes这个脚本的作用不是精确评估而是帮你快速判断“这个数据集值不值得花时间训练”。当一个数据集里小目标占比低于 20% 时我建议先做采样或切图而不是直接开训。切图是让小目标变成“相对大目标”的核心手段——把一张 1920×1080 的大图切成 640×640 的块原本 16×16 像素的目标在切图后变成 5.3% 的相对尺寸模型的检测难度就从“几乎不可能”变成了“有点难”。这也是红外小目标检测数据集最常见的预处理方式之一。3.2 滑窗切图与标注坐标变换切不好会把标注全切丢切图这个操作看起来简单但翻车点极多。最典型的问题是目标刚好落在切片边界上被一刀切成两半导致两个残缺框都成为训练样本或者切片之间的重叠率设计不合理目标在训练集和验证集里出现重叠造成数据泄漏。前者会让模型学出“半个人”这种错误特征后者会让验证集 mAP 虚高真实场景一测就现原形。我采用的切图方案一般是这样设置切片大小为 640×640重叠率按 stride 计算常用 stride 取 320 或 480。stride 越小目标越不容易被切碎但训练样本数量会大增。同时要在切图时保留坐标映射关系——原图上的目标框减去切片左上角偏移量后得到新图上的坐标如果该框被边界截断超过 30%直接丢弃这半个框不强行保留。def slice_image_with_labels(img, labels, slice_size640, stride320): # img: PIL Image, labels: list of [cls, cx, cy, bw, bh] in absolute pixels h, w img.size[1], img.size[0] patches [] patch_labels [] for y in range(0, h, stride): for x in range(0, w, stride): box (x, y, min(x slice_size, w), min(y slice_size, h)) patch img.crop(box) keep [] for cls, cx, cy, bw, bh in labels: # 目标框中心点在切片内且框主体在切片内 if x cx x slice_size and y cy y slice_size: nx, ny cx - x, cy - y # 计算被截断的比例超过阈值则丢弃 inter_w min(cx bw/2, x slice_size) - max(cx - bw/2, x) inter_h min(cy bh/2, y slice_size) - max(cy - bh/2, y) if inter_w bw * 0.7 and inter_h bh * 0.7: keep.append([cls, nx, ny, bw, bh]) if len(keep) 0: patches.append(patch) patch_labels.append(keep) return patches, patch_labels这个函数有几个值得细看的参数。第一个是判断“目标是否保留”的方式我选择“中心点必须在切片内”作为硬条件这比“框与切片有交集就保留”更稳健能避免一个目标同时出现在多个切片里却都是半截框的情况。第二个是截断阈值 0.7也就是目标被切掉超过 30% 就丢弃。第三个是切片尺寸和步长640×320 的 stride 意味着相邻切片有 320 像素重叠一个目标最多出现在两个切片里不会过度重复训练。切完后记得把标注从像素坐标换成归一化坐标YOLO 格式要求除以切片宽高。3.3 红外小目标数据集与上下文增强小目标不能脱离背景学红外小目标检测是最近很热的场景机场跑道、森林防火、电力巡检里都有红外小目标需求。这类数据集和可见光小目标有个本质差异目标没有颜色和纹理信息只有 3~10 个像素的灰度突变模型能依赖的只有目标与周围背景的对比度。直接把普通可见光的预训练权重拿来做红外小目标效果往往很差因为模型的浅层特征提取器学到的是 RGB 纹理不是灰度对比。对于这种场景常见做法是先用目标的邻域裁剪上下文块把目标周围一定范围比如 32×32 或 64×64 邻域的背景同时送入模型让模型学习“什么背景、什么对比度下会出现目标”。这本质上是一种上下文增强。还有一种更直接的做法把红外单通道图复制成三通道再叠加一个高斯差分滤波后的边缘通道等于在输入侧就帮模型把“灰突变”这个特征增强出来。不管是红外还是可见光小目标一个共同的增强原则是不引入会破坏“目标-背景关系”的增强。比如 random erasing 这种把随机区域涂黑的增强对大目标无伤大雅对小目标可能就是灭顶之灾——目标本来就只有 10 个像素再被涂掉 5 个模型学到的是一个残缺目标。另一个要慎用的是上下翻转和 90 度旋转如果目标本身有方向性比如飞机头朝向这类增强会创造不存在的样本干扰分类器。我一般只保留轻微的色彩抖动和 10 度以内的随机旋转这是小目标增强策略里的保守路线。4. 训练与评估落地的完整操作YOLOv8n 最小训练配置与参数调整4.1 从“源码流程教程”项目包里快速搭建项目目录拿到一个标题里这种“YOLOv8n 小目标检测项目源码流程教程”的压缩包很多人第一件事是直接解压跑 training.py这是个坏习惯。项目包质量参差不齐我需要先检查它的结构是否完整再决定怎么跑。一般一个规范的小目标项目包应该包含这几块数据集目录或数据集下载脚本、模型配置文件yaml、训练入口脚本、评估脚本和推理脚本外加一个 README 写明环境版本。我一般按这套目录来梳理和改造project/ ├── data/ │ ├── images/train/ # 训练图像 │ ├── labels/train/ # 训练标注 │ ├── images/val/ # 验证图像 │ └── labels/val/ # 验证标注 ├── models/ │ ├── yolo11n_small.yaml # 自定义模型配置 │ └── yolo11n.pt # 预训练权重 ├── configs/ │ └── small_target.yaml # 数据与训练参数 ├── scripts/ │ ├── train.py # 训练入口 │ ├── val.py # 评估入口 │ └── infer.py # 推理与可视化 └── runs/ # 训练输出目录这套结构的核心是“数据和配置分离”。很多项目包把数据集路径写死在脚本里换机器就要改代码很浪费时间。我习惯把数据集路径统一放在一个 data.yaml 里让训练脚本读取这样换数据集不需要动脚本。用 ultralytics 的 YOLO API 时最标准的做法就是传一个 data.yaml 路径给模型其余交给框架处理。4.2 核心训练命令配置项拆开讲清楚每个参数怎么定用 YOLOv8n 训练小目标模型我很少改动模型结构而是把重点放在训练参数上。一个比较稳妥的起步配置是这样的yolo train \ modelyolo11n.pt \ datasmall_target.yaml \ epochs150 \ imgsz1024 \ batch8 \ optimizerAdamW \ lr00.001 \ lrf0.01 \ mosaic1.0 \ cos_lrTrue \ patience30 \ ampTrue \ device0,1逐个说下关键参数。imgsz1024 是抬升空间分辨率的默认值如果你的目标特别小比如 10×10 以内还可以尝试 1280batch8 在 1024 分辨率下约为 12G 显存如果显存不够就减到 4 然后开 amp 和梯度累积。optimizer 选 AdamW 而不是默认的 SGD这是小目标任务的一个习惯——AdamW 对稀疏梯度的处理更稳小目标的梯度本来就稀疏用 SGD 容易被噪声冲歪。lr0 设为 0.001 而非默认 0.01因为小目标的损失面更崎岖学习率大容易震荡。cos_lrTrue 的效果是把学习率按余弦曲线衰减到后期逐步降低更新幅度这对小目标稳定收敛有帮助。mosaic1.0 表示开局一张图随机拼接 4 张图能有效增加上下文多样性但小目标本身像素少拼接后可能被缩得更小。如果训练后发现小目标漏检严重可以把 mosaic 降到 0.5 甚至关掉对比一下效果再决定。ampTrue 是混合精度训练显存不够时必开。4.3 评估阶段要看哪些指标mAP50 与 mAP50-95 怎么取舍小目标检测的评估有个特殊现象模型在 mAP50 上表现尚可在 mAP50-95 上惨不忍睹。原因是 mAP50-95 对预测框和真实框的 IoU 要求很高从 0.5 一路算到 0.95 取平均而小目标本身只有几十个像素差两三个像素 IoU 就从 0.7 掉到 0.5得分自然难看。所以小目标项目里mAP50 才是主要参考指标mAP50-95 只做辅助参考。评估命令如下yolo val \ modelruns/train/exp/weights/best.pt \ datasmall_target.yaml \ imgsz1024 \ conf0.001 \ iou0.6 \ save_jsonTrue这里把 conf 设为 0.001 是为了保留足够多的低置信度预测框。小目标在模型输出时置信度普遍偏低如果把 conf 设为默认的 0.25很多真目标被过滤掉mAP 严重低估。iou0.6 是 NMS 的 IoU 阈值小目标重叠场景多阈值设低一点能减少同类目标互相抑制。save_jsonTrue 会把结果导出成 JSON 格式方便后续按类别和尺寸分析漏检情况。评估完还要看一个指标Precision 和 Recall 的平衡点。小目标检测最常见的问题是 Recall 上不去也就是漏检多。如果 Recall 明显低于 Precision说明模型“宁缺毋滥”可以从两个方向调一是降低 conf 阈值二是检查数据集里小目标样本是不是太少需要回数据准备阶段重新做切图和采样。4.4 训练曲线怎么看三个关键信号与对应动作训练过程里输出一堆日志和曲线图但真正有判读价值的就三处loss 曲线的下降形态、验证集 mAP 曲线的拐点、以及 Precision 和 Recall 的交叉点。第一个信号loss 曲线在 50 轮之后仍然剧烈震荡不下降。这通常是学习率偏高或者 batch 太小的问题降低 lr0 到 0.0005 并把 batch 提高到 16 或以上震荡会明显收敛。如果震荡伴随 loss 值特别高还要检查数据标注里有没有大量空标注文件——YOLO 框架对空 txt 和缺失 txt 的处理方式不同容易带来脏训练信号。第二个信号mAP 曲线在 100 轮左右还在缓慢上升但没有平台期趋势。这说明训练还没收敛可以把 epochs 加到 300或关闭早停。注意 patience30 的意思是最多容忍 30 轮没有改进就停止如果数据集较小这个值可以放大到 50。第三个信号验证集 Precision 和 Recall 两条曲线交叉位置偏离。正常模型交叉点在 0.5 附近表示平衡如果交叉点 Recall 只有 0.3说明大量目标根本没被模型召回来。这时不要再调训练超参了先回去看数据集的小目标占比多数情况是样本不足或标注错误。5. 小目标训练避坑从项目实战里翻车次数最多的 5 个故障排查记录5.1 翻车现场loss 降得很好验证集 mAP 却是 0这是一个非常多见的诡异现象训练时损失函数一路下降得很顺利验证集 mAP 却是 0模型看起来什么都没学会。排查下来发现原因往往不在训练参数而在数据集与模型的匹配上——标注框尺寸小于模型下采样后特征图的最小粒度网络根本没有机会学到这个目标。检查方法很简单用脚本统计训练集里目标框的最小尺寸再对照模型的下采样倍数。YOLOv8n 最小输出层是 8 倍下采样也就是 8×8 像素以内的目标在特征图上小于 1 个像素这类目标基本是白标。解决路径是按 3.2 节的切图方案把小目标切出来放大或者增加 P2 检测头让模型看到更细粒度的特征。如果确认数据没问题另一个可能是模型配置加载错了。项目包时常见的问题是把数据集路径写错训练时无标签可读loss 掉到很低是因为模型在学“输出空框”。这种要检查 data.yaml 里的路径是不是绝对路径以及训练日志里 YOLO 框架打印出的图片数和标注框数是否合理。5.2 红外小目标加载预训练权重效果差是继续微调还是从头训红外小目标数据集和 ImageNet 预训练权重之间的域差异太大直接续训的效果常常不理想。现象是训练初期 loss 不降反升之后虽然降下来最终的 mAP 也不如预期。原因在于预训练模型的前几层卷积提取的是自然图像的边缘、颜色、纹理特征而红外小目标只有低对比度的灰度梯度两套特征分布完全不匹配。我处理这个问题的顺序是先冻结模型的前 10 层只训练 head 和 neck 部分等 loss 稳定后再解冻全部层做完整热身。做法是在代码里用 model.model前面的参数设置 requires_gradFalse把一个阶段训练完后再设置回 True 继续训练。这样能避免预训练特征被红外样本粗暴冲刷保留一部分基础卷积特征。另外输入侧做红外单通道转三通道时建议加一个对比度拉伸否则模型会把“几乎纯黑”的背景当成主要特征去拟合。5.3 1024 分辨率训练 OOMbatch 调小后精度跟着崩高分辨率输入是把双刃剑OOM 是必经之路。常见应对是 batch 减半但减半后精度也跟着掉。原因是 batch 太小导致 BN 层的统计量估计不准小目标的梯度信号本来弱再叠加不稳定的 BN训练很容易亮红灯。解决这个问题的顺序是先开启 amp再同时开梯度累积而不是只减 batch。梯度累积把多个 step 的梯度累加后一次性更新相当于等效 batch 不变。具体做法是 batch 调到 4然后设置 accumulate4等效 batch 16。显存如果再不够再把 mosaic 关闭或降到 0.5因为 mosaic 拼图占用的显存峰值很高。如果还撑不住最后才考虑把 imgsz 降到 896。5.4 小目标漏检多NMS 参数是背锅侠还是真凶很多同学发现模型漏检小目标第一反应是调低 confidence 阈值。这个操作没错但只调 conf 不调 iou 的话漏检改善有限。原因是小目标经常密集分布两个目标挨得很近NMS 会把置信度低的一个框当成重叠框抑制掉。也就是“漏检”其实是“被抑制”。正确的调整顺序是先降低 iou 阈值从默认 0.5 调到 0.3 或 0.25让 NMS 更保守不轻易合并相邻框训练结束后再用验证集做一次 conf 扫描找到 Recall 和 Precision 的交叉点确定部署用的 conf 值。另一种做法是尝试给检测头加一个“针对小目标的第二路输出”也就是 4.2 节 P2 头的思路但那是结构改造建议在 NMS 调参无效后再考虑。5.5 训练到一半 mAP 突然掉头向下是正常波动还是翻车拐点训练到后期验证集 mAP 出现一次明显下跌很多人会认为这是噪声继续跑完。实际上这往往是“灾难性遗忘”的先兆——后期学习率还偏高模型在小目标上的特征被新样本冲掉。关键看 mAP 下跌后能否在 10 轮内回升如果连续 20 轮不回升说明最优权重已经出现在下跌点之前训练参数需要回退。此时不要手动中断先用框架保存的 last.pt 和 best.pt 做对比验证确认 best.pt 对应的 mAP 确实更高。然后重启一段超短训练把 epochs 重置为原来的一半lr0 降低到原来的 1/5warmup_epochs 设成 3模型加载 best.pt 继续跑通常能在一个较小的学习率下再次拉升 mAP 并稳定到平台期。这是我在小目标训练中用过最频繁的“后悔药”操作。6. 从验证到落地的一点进阶技巧切片推断与可视化误差分析小目标模型的训练告一段落后真正决定能不能用的环节是推断策略。YOLOv8n 在 1024 输入下推理一张 4K 图如果直接整图送入模型小目标依然很难保住细节因为 4K 图被缩小到 1024 时目标可能小于 5 个像素。正确做法是切片推理在推断阶段同样把大图切块每个切片分别送入模型再把检测框映射回原图坐标。只是切片的步长比训练时更大通常取 1024, stride 取 512因为推断时没有增强需求重叠率可以低一些。切片推理的代码核心是保持和训练时一致的坐标变换只是方向反过来——模型输出的归一化框乘以切片宽高再加上切片左上角坐标就能还原回原图位置。切块之间的重叠区域允许同一个目标被重复检测后处理时按标准 NMS 合并用小目标场景的个人经验重叠 80% 以上的同类框保留置信度高的那条即可。这部分逻辑不复杂但实测量级是 4K 图上推断耗时翻 3 倍左右如果你的业务对实时性有硬要求就要在精度和速度之间做取舍。另一个值得做的验证手段是可视化误差分析把预测框、真实框和置信度画在同一张图上按目标尺寸分组看漏检模式。你很快会发现一个规律漏检的往往集中在某几个尺寸区间而不是均匀分布。我一般用这段代码快速输出误检和漏检图from ultralytics import YOLO import cv2 model YOLO(best.pt) img cv2.imread(val_sample.jpg) results model.predict(img, imgsz1024, conf0.1, iou0.3) boxes results[0].boxes.xyxy.cpu().numpy() clss results[0].boxes.cls.cpu().numpy() # 在原图上画预测框之后和标注框做逐像素比对 for box, cls in zip(boxes, clss): cv2.rectangle(img, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), (0, 255, 0), 2) cv2.putText(img, str(int(cls)), (int(box[0]), int(box[1]) - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) cv2.imwrite(pred_vis.jpg, img)把预测框画出来后拿 benchmark 工具按目标尺寸分组统计 Recall基本就能定位是哪一类尺寸漏得最凶。如果是“极小目标整体漏检”回数据准备阶段做切图放大如果是“特定背景下的目标漏检”回到数据增强补那类背景的样本。这套误差分析流程是我每次小目标检测项目收尾时的固定动作它比多看几篇论文和调参更能把效果往上拉一截。做过的几个小目标项目里让我印象最深的一次是项目上线前才发现训练时把 mosaic 开得太猛大量小目标在拼图里被缩成了 1~2 个像素模型压根没学过“完整的小目标”。后来直接把 mosaic 在最后 50 轮里降到 0精度提升明显。所以如果你是第一次跑小目标检测我的建议是先把一个 baseline 完整跑通确认标注和数据没问题再逐项加增强和加分辨率最后再谈调模型结构。小目标检测的难点不在算法有多深而在每一步都要保住目标的“像素生命”。希望帮到你。本文还有配套的精品资源点击获取