简介本资源面向计算机视觉方向的学习者与开发者聚焦小目标检测这一难点场景提供基于YOLOv8n轻量级网络的完整算法实现与配套流程教程适合具备一定深度学习基础、希望快速复现并落地小目标检测方案的高校学生与工程师。压缩包共约2000个文件以txt文本为主辅以yaml模型配置文件与md说明文档整体约336MByaml可用于模型与数据集参数配置md与txt则承载流程说明及训练记录目录结构便于按模块查阅。目前已有80人学习下载。项目源码覆盖数据预处理、模型配置、训练推理与性能评估等环节教程从环境安装、数据集准备到结果解读逐步展开读者可据此掌握YOLOv8n在小目标场景下的网络结构、特征融合与损失函数设计思路并作为优质项目实战案例迁移到嵌入式或移动端等资源受限平台。1. 小目标检测为什么总在 YOLOv8n 上翻车从 320 像素的裂缝说起一张 1920×1080 的工地巡检图裂缝宽度可能只有 6 到 10 个像素。把它塞进 YOLOv8n 默认的 640 输入再经过 8 倍、16 倍、32 倍下采样到 P3 特征图时这条裂缝只剩不到 1 个像素的响应模型基本等于瞎了。这不是调参能救的是信息在骨干网络里被物理抹掉了。小目标检测基于 YOLOv8n 实现核心矛盾就一句话n 版本参数量只有 3.2M 左右轻量到能跑在边缘设备上但它的感受野和高分辨率特征保留能力天生对小目标不友好。这个标题对应的方案解决的就是「在算力受限的前提下怎么让 YOLOv8n 把小于 32×32 像素的目标检出来」。适合两类人一是做工业质检、无人机巡检、遥感、安防的算法工程师二是想拿一个完整可复现项目练手的学生和转行者。项目源码和流程教程的价值不在于跑通一个 demo而在于把 P2 层、切片推理、数据增强这几件事串成一条能落地的链路。下面按「先立住原理、再动手复现、最后避坑」的顺序拆开讲。2. 小目标检测的判定标准与 YOLOv8n 的能力边界2.1 多大算小目标COCO 定义与工程口径的差异学术界常用 COCO 的定义面积小于 32×32 像素的算小目标32×32 到 96×96 算中等大于 96×96 算大目标。但这个口径在工程里经常不够用因为它是按绝对像素面积算的没考虑输入分辨率。一张 4000×3000 的遥感图缩到 640 输入原本 200×200 的建筑物就变成了 32×32按 COCO 标准它「降级」成了小目标。所以我一般用相对口径目标在网络输入尺寸下的像素面积小于 32×32或者目标短边小于 16 像素就按小目标处理。这个区分直接影响你的技术选型。如果目标在原图里就很小比如 8×8那缩放到 640 后基本消失必须靠切片推理或者提高输入分辨率如果目标原图不小、只是被缩放压小了那优先考虑提高输入尺寸而不是改网络结构。搞混这两类后面所有优化都是白费力气。2.2 YOLOv8n 的三层检测头为什么漏小目标YOLOv8 的检测头挂在三个尺度上P380×80stride 8、P440×40stride 16、P520×20stride 32对应 640 输入。P3 是分辨率最高的那一层理论上负责小目标。问题出在两点第一P3 的特征来自骨干网络第 4 阶段此时已经做过 3 次下采样每个特征点对应原图 8×8 的区域。一个 6 像素宽的裂缝在 P3 上只覆盖不到一个格子卷积核根本提取不到稳定的纹理响应。第二YOLOv8n 为了压参数量骨干的宽度通道数和深度都砍得很狠。n 版本的 P3 通道数只有 64相比 m 版本的 128特征表达能力差一大截。小目标本来就靠细节纹理区分通道一少背景和目标的边界就糊了。所以「基于 YOLOv8n 实现小目标检测」这件事本质是在不显著增加参数量的前提下把高分辨率特征救回来。主流思路有三条加 P2 检测层、切片推理SAHI、针对性数据增强。下面分别讲。2.3 三条主流路线的选型对比路线核心做法参数量增幅推理速度影响适用场景加 P2 检测层在 stride 4 的特征图上加检测头15%~25%下降 20%~35%目标密集、尺寸 8~32 像素切片推理 SAHI大图切小块分别推理再合并不变成倍增加超大分辨率图、目标极稀疏数据增强马赛克、复制粘贴小目标不变训练变慢小目标样本少、分布不均实际项目里这三条经常组合用。加 P2 是改动网络结构收益最直接但要重训切片推理是纯推理侧技巧不改模型适合已经训练好的权重数据增强是训练侧的基本功成本最低。我一般先上数据增强再评估要不要加 P2切片推理留给那些原图分辨率超过 2000 像素的场景。3. 给 YOLOv8n 加 P2 检测层改配置文件与重训流程3.1 从 yaml 入手P2 层怎么接进 neckYOLOv8 的网络结构定义在yolov8.yaml里。默认的 head 部分只用了 P3、P4、P5要加 P2得先在 backbone 里把 stride 4 的特征引出来再在 neck 里做一次自顶向下的融合。下面是我常用的改法基于 Ultralytics 的 yaml 格式# yolov8n-p2.yaml backbone: # [from, repeats, module, args] - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4 - [-1, 3, C2f, [128, True]] - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8 - [-1, 6, C2f, [256, True]] - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16 - [-1, 6, C2f, [512, True]] - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32 - [-1, 3, C2f, [1024, True]] - [-1, 1, SPPF, [1024, 5]] # 9 head: - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 6], 1, Concat, [1]] # cat backbone P4 - [-1, 3, C2f, [512]] # 12 - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 4], 1, Concat, [1]] # cat backbone P3 - [-1, 3, C2f, [256]] # 15 (P3/8-small) - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 2], 1, Concat, [1]] # cat backbone P2 -- 新增 - [-1, 3, C2f, [128]] # 18 (P2/4-xsmall) -- 新增 - [-1, 1, Conv, [128, 3, 2]] - [[-1, 15], 1, Concat, [1]] # cat head P3 - [-1, 3, C2f, [256]] # 21 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]] - [[-1, 12], 1, Concat, [1]] # cat head P4 - [-1, 3, C2f, [512]] # 24 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]] - [[-1, 9], 1, Concat, [1]] # cat head P5 - [-1, 3, C2f, [1024]] # 27 (P5/32-large) - [[18, 21, 24, 27], 1, Detect, [nc]] # Detect(P2, P3, P4, P5)关键改动有三处backbone 第 2 层P2/4被引出来参与 neck 融合head 里多了一次上采样和 Concat生成 stride 4 的 P2 特征最后的 Detect 层从三个输入变成四个输入[18, 21, 24, 27]。注意 P2 层的通道数我压到了 128如果直接给 256参数量和显存会涨得很难看。3.2 训练命令与关键超参改完 yaml训练命令和标准 YOLOv8 一样但有几个参数必须调yolo detect train \ modelyolov8n-p2.yaml \ datamy_dataset.yaml \ imgsz1024 \ epochs200 \ batch8 \ lr00.01 \ lrf0.01 \ warmup_epochs5 \ mosaic1.0 \ copy_paste0.3 \ scale0.5 \ patience50 \ device0逐条说imgsz1024是因为加了 P2 后输入越大 P2 层的信息越丰富640 输入下 P2 只有 160×160对小目标帮助有限batch8是显存妥协1024 输入加 P2 层24G 显存大概只能跑到 8copy_paste0.3是专门针对小目标的增强把标注的小目标复制粘贴到其他图上直接增加小目标样本密度scale0.5控制缩放增强幅度太大反而会把小目标缩没patience50给足早停耐心小目标收敛比常规检测慢。3.3 训练日志里该盯哪几个指标跑起来之后别只看 mAP50。小目标检测要重点看metrics/mAP50-95(B)和验证集里小目标类别的单独 AP。Ultralytics 默认不按尺寸分组统计我一般会在验证后自己跑一遍按面积分桶的脚本import numpy as np from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.val(datamy_dataset.yaml, imgsz1024) # 按目标面积分桶统计 areas results.box.areas.cpu().numpy() ap50 results.box.ap50 small_mask areas 32 * 32 print(f小目标数量: {small_mask.sum()}) print(f小目标平均 AP50: {ap50[small_mask].mean():.4f}) print(f全部目标平均 AP50: {ap50.mean():.4f})这段脚本的逻辑是从验证结果里取出每个框的面积和对应的 AP50按 32×32 阈值分桶看小目标单独的表现。如果小目标 AP 比整体低 15 个点以上说明 P2 层没起到预期作用得回头检查 P2 的通道数是不是被压得太狠或者数据里小目标标注质量有问题。参数上areas是像素面积ap50是每个框的 AP注意这两个数组是按检测框顺序对齐的。4. 切片推理与数据增强不改模型也能提点的两条路4.1 SAHI 切片推理的最小可用配置SAHISlicing Aided Hyper Inference的思路很朴素把大图切成有重叠的小块每块单独送进模型推理最后把结果映射回原图坐标做 NMS 合并。它不改模型、不重训适合已经有一个训练好的 YOLOv8n 权重、但原图分辨率很高的场景。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathruns/detect/train/weights/best.pt, confidence_threshold0.25, devicecuda:0, ) result get_sliced_prediction( test_large.jpg, detection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2, perform_standard_predTrue, ) result.export_visuals(export_diroutput/)参数说明slice_height/width640是切片尺寸一般设成和训练输入一致overlap_*_ratio0.2是切片重叠比例太小会漏掉跨边界的目标太大会增加推理量0.2 到 0.3 是常用区间perform_standard_predTrue表示除了切片推理还对整图做一次常规推理防止大目标被切片切碎后漏检。代价是推理时间成倍增加一张 4000×3000 的图切片推理大概是常规推理的 8 到 15 倍耗时实时场景要慎重。4.2 小目标专属的数据增强组合数据增强是小目标检测里性价比最高的一环。除了 YOLOv8 自带的 mosaic我一般还会开 copy_paste并针对小目标做几件事第一检查标注框的最小尺寸。如果数据里有大量小于 4×4 像素的框这些框在训练时基本是噪声建议过滤掉或者放大图像重新标注。第二用 mosaic 的mosaic1.0配合close_mosaic10最后 10 个 epoch 关掉 mosaic让模型在真实分布上收敛。小目标在 mosaic 拼接后尺寸会进一步缩小长期开 mosaic 反而有害。第三如果小目标类别不平衡用cls损失权重或者过采样含小目标的图。Ultralytics 没有直接的类别权重参数常见做法是在数据集 yaml 里复制小目标样本或者自己写 sampler。4.3 输入分辨率与 batch 的显存权衡加 P2 层之后显存是绕不开的坎。1024 输入、P2 层、batch 8在 24G 卡上大概占 20G 左右。如果显存不够有三个选择降 batch 到 4 并开梯度累积、用imgsz896折中、或者把 P2 层通道数从 128 降到 96。我一般优先降 batch 开累积因为输入分辨率对小目标的影响比 batch 大得多。梯度累积在 Ultralytics 里没有直接参数需要自己改训练循环或者用batch4跑两次模拟。这个取舍没有标准答案得看你的目标尺寸分布和硬件。5. 小目标检测的避坑清单五个真实翻车现场5.1 加了 P2 层 mAP 反而降了现象改完 yaml 重训整体 mAP50 掉了 2 到 3 个点小目标 AP 也没涨。原因P2 层引入后正样本数量暴增但标注里很多小目标框本身不准或者存在大量背景误标。P2 的高分辨率把这些噪声也放大了模型学到了错误的边界。另一个常见原因是 P2 通道数给太高比如 256导致训练早期梯度爆炸。解决先把 P2 通道压到 96 或 128再检查标注质量过滤掉面积小于 16 像素的框。如果还不行用freeze参数冻结 backbone 前几层只训 neck 和 head让模型先适应新的检测层。5.2 切片推理后目标被重复框现象SAHI 推理结果里同一个目标出现多个重叠框NMS 没合并干净。原因切片之间的重叠区域同一个目标被两个切片分别检出坐标映射回原图后 IoU 很高但没超过 NMS 阈值。默认 NMS IoU 是 0.7跨切片的框可能因为坐标舍入误差卡在 0.65 左右。解决把 SAHI 的postprocess_match_threshold调到 0.5 到 0.6或者用postprocess_typeNMM非极大值合并替代 NMS。另外切片重叠比例别低于 0.15否则边界目标会被切碎。5.3 训练 loss 正常但验证集小目标全漏现象训练 loss 稳定下降验证集整体 mAP 还行但小目标类别 AP 接近 0。原因验证集的输入尺寸和训练不一致。训练用 1024验证默认用 640小目标在验证时被缩小了一半自然检不出。这是最隐蔽的坑因为 Ultralytics 的 val 默认继承训练 imgsz但如果你手动改了 val 参数就会踩。解决显式指定yolo detect val imgsz1024确保训练和验证输入一致。另外检查验证集的标注格式有些数据集验证集的小目标标注被误删了。5.4 copy_paste 增强导致过拟合现象开了 copy_paste 后训练集 mAP 很高验证集不涨反降。原因copy_paste 把目标复制粘贴时如果粘贴位置的背景和原背景差异大会产生不自然的边缘模型学到的是这些伪影而不是目标本身。小目标尤其明显因为它的上下文信息本来就少。解决把 copy_paste 概率从 0.5 降到 0.2 到 0.3并且限制粘贴区域必须在同类背景附近。Ultralytics 的 copy_paste 实现比较简单如果效果不好建议关掉改用 mosaic scale 组合。5.5 推理速度断崖式下降现象加 P2 后单张推理从 8ms 涨到 25ms边缘设备上跑不动。原因P2 层的特征图是 160×1601024 输入下通道 128计算量比 P3 层还大。加上四个检测头后处理 NMS 的候选框数量也翻倍。解决如果部署在边缘设备P2 层通道压到 64或者只在 P3 上做检测、P2 只参与特征融合不输出。另一个办法是导出时用 TensorRT 的 FP16 量化P2 层的计算密集特性对量化比较友好通常能挽回 30% 到 40% 的速度。6. 用 TensorRT 部署 P2 版 YOLOv8n 的量化技巧训练完之后真正落地还得过部署这一关。P2 版模型比原版大FP32 推理在 Jetson 这类设备上基本没法看必须上量化。我一般走 TensorRT 的 FP16 路线INT8 对小目标检测风险太大量化误差会把小目标的微弱响应直接抹平。导出 ONNX 的时候有个细节P2 层的输出维度是 160×160ONNX 的动态轴设置要确认imgsz固定否则 TensorRT 构建引擎时会因为动态 shape 导致 P2 层的内存分配异常。命令如下yolo export modelruns/detect/train/weights/best.pt \ formatonnx \ imgsz1024 \ opset12 \ simplifyTrue \ dynamicFalsedynamicFalse是关键固定输入尺寸能让 TensorRT 充分优化 P2 层的卷积。导出后用trtexec构建 FP16 引擎trtexec --onnxbest.onnx \ --saveEnginebest_fp16.engine \ --fp16 \ --workspace4096 \ --minShapesimages:1x3x1024x1024 \ --optShapesimages:1x3x1024x1024 \ --maxShapesimages:1x3x1024x1024workspace4096给 4G 显存做优化空间P2 层计算量大workspace 太小会导致某些层回退到 FP32。构建完之后用trtexec --loadEnginebest_fp16.engine --shapesimages:1x3x1024x1024跑一下 benchmark看 P2 层的耗时占比。如果 P2 层占了总时间的 40% 以上说明它成了瓶颈可以考虑把 P2 的通道再压一档或者用 depthwise 卷积替换部分标准卷积。验证量化后精度有没有掉别只看整体 mAP。我习惯拿 50 张小目标密集的图分别用 PyTorch 权重和 TensorRT 引擎跑一遍逐图对比小目标检出数量。如果 TensorRT 版本平均每张少检 2 个以上小目标说明 FP16 的精度损失已经影响到小目标了这时候要么回退 FP32要么对 P2 层单独保留 FP32 精度TensorRT 支持逐层精度设置。最后说个我自己的习惯每次改完网络结构先别急着跑 200 个 epoch。用 20 个 epoch 跑个小实验看小目标 AP 有没有涨的趋势涨了再上全量训练。小目标检测这事情玄学成分不少但大部分翻车都能在早期实验里暴露出来。希望帮到你。本文还有配套的精品资源点击获取