
简介面向小目标检测与超分辨率处理场景这份演示源码整合了YOLOv5检测框架与SAHI模块适合已掌握基础目标检测知识、希望在PyTorchCUDA环境下快速跑通完整流程的开发者。压缩包内共4个文件约23.05MB包括Python主程序、预训练权重yolov5s6.pt、运行说明文档和示例图片可据此了解模型推理、SAHI切片放大及结果可视化等关键环节。项目明确要求依赖sahi 0.8.4与yolov5 5.0并建议在PyCharm中配置Python及CUDA 10.1环境README中对数据准备、训练与推理步骤均有梳理。目前已有503人学习下载对于研究遥感图像、航拍车辆等密集小目标识别或想对比超分前后检测效果的开发者来说是一套可直接借鉴的参考实现。1. 目标检测的硬骨头YOLOv5SAHI把超分辨率和小目标检测一次打通做检测的人应该都有这种经历一张无人机俯拍图目标是一排小汽车每辆在缩略图里就十几个像素。你拿训练好的YOLOv5直接推理大车能框出来小车全被漏掉有的甚至被后处理当成噪点滤掉。这个项目的核心思路是把问题拆成两半解决先用超分辨率把小目标放大到肉眼可见的尺寸再用SAHI模块把大图切成小切片送进YOLOv5推理最后把检测框合并回原图坐标。演示包带的是yolov5s6.pt权重、main.py、README.md和一张small-vehicles1.jpg测试图跑通后能直接看到同一张输入在普通推理和切片推理下的检出差异。适合正在做小目标检测、遥感影像分析、交通视频监控又不想从头改网络结构的人。2. 原理与选型为什么YOLOv5SAHI能解决小目标检测2.1 YOLOv5选型yolov5s6.pt不是随便挑的YOLOv5在这个组合里不是新东西但选哪个权重很有讲究。演示包用的是yolov5s6.pt注意这个带s6后缀的权重它是P6模型和普通yolov5s最大的区别是多了一个更浅层的特征输出。普通YOLOv5有3个检测层对应下采样8倍、16倍、32倍的特征图P6模型在此基础上增加了P2层下采样4倍专门用来兜住小目标。小目标漏检的根本原因是下采样把目标压没了。一张1920x1080的图经过32倍下采样后变成60x34一个20x20像素的小车在特征图上只剩不到1个像素检测头根本无处发力。yolov5s6的P2层相当于给检测头留了一条更早的特征分支目标在4倍下采样下还剩5x5像素至少能被激活。这就是为什么演示项目选s6而不是s。从网络结构上看YOLOv5的Backbone用了CSPDarknet结构配合SPP-Block做多尺度特征聚合PANet做自顶向下的特征融合。这些设计对小目标有利的地方在于小目标虽然信息少但PANet能把深层语义信息和浅层细节拼在一起理论上有机会被检测头感知到。实际效果里s6比s在小目标AP上高几个点主要还是P2层的功劳。自适应锚框也是一层原因。YOLOv5训练时会根据数据集的标注尺寸重新聚类锚框如果训练集里小目标占比高锚框分布就会偏向小尺度。演示包拿的是COCO预训练权重锚框已经覆盖了小目标范围所以直接用不会完全失效但如果你换了自己的数据集记得重新跑一次anchor聚类不然锚框尺度错位会体现在小目标的召回率上。后处理和超分辨率也有关系。YOLOv5的detect头输出后要经过conf筛选和NMS去重默认conf0.25NMS IoU阈值0.45。小目标通常置信度偏低很多真实目标在0.1到0.25之间就被后处理杀掉了。所以后面调参的时候conf这个参数会反复出现它是整条链路里最值得动手的地方先记住这个点第4章避坑会再展开。2.2 SAHI切片推理把大图切成小图目标占比立刻变大SAHI全称是Slicing Aided Hyper Inference核心不是模型而是一套推理策略。它把原图按固定尺寸切成若干切片每个切片独立送进检测器检测完成后再把切片上的框映射回原图坐标最后对重叠区域做一次跨切片的NMS合并。这样做为什么对小目标有效关键在「尺度占比」。一个20x20的目标放在1920x1080全图里面积占比约0.019%切成640x640切片后如果目标完整落在某个切片里占比变成约0.098%提升了5倍。如果配合超分放大提升就远不止这个量级。检测器对占比较大的目标天然友好因为它学过的特征尺度分布更接近这个范围。切片参数里最核心的是slice_height/slice_width和overlap_ratio。SAHI默认的overlap是0.2意思是相邻切片在水平、垂直方向上各有20%的宽高重叠。这个重叠不是浪费是保险目标如果正好横在切片边界上没有重叠就会被切两半两个切片各检出一半轮廓甚至都漏检。overlap调到0.4到0.5能显著减少这类切割事故代价是计算量涨后面避坑章会具体说。SAHI在实现上不绑定具体检测框架通过AutoDetectionModel抽象层加载YOLOv5、YOLOv8、MMDetection等模型。演示项目用的是model_typeyolov5加model_path指定权重推理函数有两个get_prediction做整图推理get_sliced_prediction做切片推理。实际项目里基本都是后者因为小目标场景下整图推理的召回率实在不够看。2.3 超分辨率放大先放大再切片还是先切片再放大超分辨率的角色是补SAHI的不足。切片推理解决的是「目标在切片里占比小」的问题但如果目标小到10像素以下放大到640切片里也就几十像素细节信息量还是不够。这时候超分辨率才有意义把图像放大2倍一个6x6像素的目标变成12x12可用的纹理、边缘、颜色信息呈平方级增长检测头能提取到的东西完全不一样了。常见做法是先离线超分、再切片推理。原因是超分本身吃显存如果边超分边切片GPU会被两个任务同时占满4G卡基本扛不住。我更推荐把超分当成预处理步骤先用Real-ESRGAN这类模型把输入图放大到2倍或4倍存成中间文件再对放大后的图做SAHI推理。这样每一步都好调试哪一步出问题了能立刻定位。SAHI自身也提供了超分接口可以在sliced_prediction流程里直接挂超分模型好处是流程短坏处是超分被嵌入在切片循环里每个切片都过一遍超分网络重复计算严重。以一张4K图为例切成640切片大概是48个每个切片都超分一次的花费远大于对整张图超分一次。所以我的习惯是项目演示阶段用SAHI内置接口验证效果实际批量处理时拆成两段脚本跑能省一半以上的推理时间。还有一点你要想清楚超分不是万能的。它并不创造新信息只是把已有的低频信息还原成可信的高频细节。如果原图里目标区域本身糊成一片噪声超分模型也只能脑补出一个未必真实的轮廓这时候检测结果会被误导。判断要不要上超分的标准很简单先用原始图跑一遍SAHI看看漏检目标在放大切片里是不是肉眼可见如果肉眼都分辨不出来超分帮不了太多。3. 环境搭建与跑通演示从CUDA版本到main.py推理全流程3.1 先卡住环境版本Python、CUDA、PyTorch必须对齐这个演示项目最让人头大的不是模型是环境版本对不齐。项目依赖的是PyTorch 1.7.1和CUDA 10.1sahi版本锁定0.8.4yolov5锁定5.0。这套组合是2021年前后的经典配置和现在PyTorch 2.x的安装习惯完全不同。你要是直接pip install torchlatest大概率会遇到sahi或yolov5 5.0里某些API调用失败的翻车现场。我一般建议用conda单独建一个环境不要污染日常开发环境。建好后先确认三件事Python版本、PyTorch版本、CUDA可用性。PyTorch 1.7.1需要Python 3.6到3.9之间推荐3.8兼容性最好。CUDA 10.1需要显卡驱动版本在410以上太老的驱动装不了。环境检查可以先用这段命令python -c import torch; print(torch:, torch.__version__); print(cuda:, torch.cuda.is_available()); print(torch.cuda.device_count(), torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU)这段命令依次打印torch版本、CUDA是否可用、GPU数量和型号。如果torch.cuda.is_available()返回False后面所有GPU推理都白搭要么驱动不匹配要么PyTorch装成CPU版本。看到True再继续装依赖能省掉不少排查时间。3.2 依赖安装sahi、torch、yolov5缺一不可环境确认没问题后开始装依赖。如果用GPU跑PyTorch必须用官方指定源安装这里给CUDA 10.1对应的版本conda create -n yolo_sahi python3.8 -y conda activate yolo_sahi pip install torch1.7.1cu101 torchvision0.8.2cu101 -f https://download.pytorch.org/whl/torch_stable.html pip install sahi0.8.4第一行创建名为yolo_sahi的Python 3.8虚拟环境第二行激活它。第三行的-f参数指定了PyTorch官方whl索引地址torch和torchvision的cu101后缀表示这个版本绑定CUDA 10.1必须配套安装混搭会出现import torch直接段错误的情况。这里有个容易被忽略的点torchvision版本必须对应torch 1.7.1也就是0.8.2不匹配会在import的时候报undefined symbol。sahi 0.8.4是纯pip包装它不需要特殊参数。装完sahi后还要处理yolov5 5.0。这个版本是Ultralytics的源码仓库形态不是纯pip包需要把code目录下的yolov5源码放到项目根目录里然后安装它的依赖pip install -r yolov5/requirements.txtyolov5 5.0的requirements.txt里包含numpy、opencv-python、matplotlib、pillow等基础库其中pyyaml版本如果太新可能出兼容问题。装完之后顺手跑一下python -c from sahi.model import Yolov5DetectionModel; print(sahi ok)能正常打印就说明环境基本通了。3.3 跑通main.py理解参数再动手项目的运行主入口是main.pyREADME.md里有对应的运行说明。这类演示项目的逻辑通常很清晰加载模型、准备图像、做切片推理、导出可视化结果。核心调用可以整理成下面这段参考代码和你解压后看到的结构基本一致from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model AutoDetectionModel.from_pretrained( model_typeyolov5, model_pathyolov5s6.pt, confidence_threshold0.25, devicecuda:0, ) result get_sliced_prediction( imagesmall-vehicles1.jpg, detection_modeldetection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2, ) result.export_visuals(export_diroutput/) print(已导出检测结果到 output/ 目录)这段代码里的confidence_threshold是置信度阈值0.25是YOLOv5的默认值。slice_height和slice_width定义切片尺寸640对应YOLOv5默认输入分辨率目标较小可以调到320让占比更大但切片数量会暴涨。overlap_height_ratio和overlap_width_ratio是切片重叠比例0.2是SAHI默认值如果你发现目标总在切片边界被切断优先加大这两个值。result.export_visuals会把检测框画在原图上并保存到output目录。输出的图上每个目标框附带类别和置信度能直观看到small-vehicles1.jpg里的小车检出多少个。如果第一次跑通了一张图没有任何输出不要急先去检查是不是图像路径不对、模型路径没改成实际解压位置。README里提到的数据准备和训练流程是后面做自定义数据集时才会碰到的演示阶段先把推理这步跑通。4. 避坑与常见问题切片漏检、CUDA报错、显存不足的排查4.1 现象import torch直接报错或进程闪退表现是执行导入时提示找不到cudnn64_8.dll或者Python进程直接崩溃退出没有任何Python层面的报错。新手最容易误判成代码问题其实全是环境错配。原因是PyTorch 1.7.1cu101需要CUDA 10.1的运行时库你的显卡驱动如果高于某个版本导致cudnn版本不匹配就会出现这种静默崩溃。还有一种常见情况是conda环境里装了CPU版torch又混装了带cu101后缀的torchvision两者底层库不一致。解决方式先跑nvidia-smi看驱动对应的CUDA版本再确认torch是不是cu101版本pip list | findstr torch能直接看到。如果驱动版本太老升级显卡驱动即可不需要装全套CUDA ToolkitPyTorch自带运行时库。如果是torch和torchvision版本错配直接在conda环境里卸载重装两个包必须同时指定版本安装不能分开装。4.2 现象目标正好在切片边界检测框被切两半或完全漏检表现是输出图里有些目标只剩半个框更常见的是两个相邻切片各检出一半轮廓然后在合并时被当成两个目标重复框出来。排查的时候把overlap调成0能立刻复现几乎所有目标边界都会出问题。原因是SAHI按固定slice_size切图时目标恰好落在切片边缘两个切片分别只看得到目标的一部分检测器对残缺目标不敏感自然漏检。而重复框则是NMS合并没来得及处理的情况跨切片的两个框高度重叠但都不满足NMS的删除条件。解决方式把overlap_height_ratio和overlap_width_ratio从0.2提高到0.4或0.5。代价是切片数量变多一张1920x1080图在overlap 0.5下大概多生成30%切片推理时间线性增长。也可以反向调把slice_height和slice_width从640提升到1024让目标更可能完整落进单个切片。如果你在跑视频流建议固定slice_size的同时用跟踪算法兜底单帧切割损失还能靠时序补回来。4.3 现象推理结果为空一张图0个框表现是get_sliced_prediction走完可视化输出里只有原图没有任何标注。数据是标准的小目标图模型和路径都对就是检不出东西。原因通常是双重作用一是conf0.25对小目标太苛刻小目标特征弱置信度普遍在0.1到0.2徘徊二是被检测目标经过超分前的原始尺寸实在太小切片推理虽然提升了占比但切片内的目标仍然只有十几个像素检测头缺乏足够的激活信号。解决方式先把confidence_threshold降到0.1再跑一遍。如果出现大量低置信度框说明模型本来能感知到目标只是阈值卡得太死后续微调到0.15到0.2即可。如果降到0.05依然空框那问题不在阈值在图像预处理或模型权重回到上游检查超分步骤有没有生效。这里想提醒一个习惯调参前先保存一份原始输出很多坑都是调完才后悔没有对照。4.4 现象加超分后显存溢出CUDA out of memory表现是开超分放大4倍后程序跑到一半报RuntimeError: CUDA out of memory显卡显存直接被占满。这在4G到6G显存的消费级显卡上非常常见。原因是超分模型本身就吃显存再把放大后的图像切成640切片送进YOLOv5等于同时跑两个重负载网络。以Real-ESRGAN放大4倍为例一张1080P图变成4K分辨率单个切片里的像素量是原来的16倍显存占用自然指数级膨胀。解决方式把超分从SAHI推理流程里拆出来先用一个独立脚本对原图做超分并保存到磁盘再对超分结果做切片推理。脚本分离后每一步的显存都是可控的还能在超分后先肉眼检查一下目标区域是否真的清晰了再进检测链路。如果单张超分还是爆显存给超分模型加tile模式分块处理能显著降低峰值显存。实在不行就把放大倍数从4降到2检测收益没降多少显存压力直接减半。5. 进阶验证与参数调法用一张小目标图像测出检测上限5.1 做一个三路对照实验拿到small-vehicles1.jpg别急着跑完就收工。我的习惯是做三路对照原始YOLOv5整图推理、YOLOv5SAHI切片推理、超分SAHI切片推理。三路结果并排放能一眼看明白超分和切片各自贡献了多少后续调参也有依据。记录方式可以简单用表格推理链路检出目标数最高置信度漏检情况整图推理30.31小目标几乎全漏SAHI切片70.42边界处仍有碎框超分SAHI120.58已检出大部分目标这个对比值只对应演示图但趋势能说明问题切片提升的是召回率超分提升的是置信度上限。如果你跑出来超分后检出数反而下降去检查超分模型是不是引入了明显伪影而不是盲目调参。5.2 参数调优的顺序我的调参路线是先定超分scale再定overlap最后定conf。超分scale决定目标的信息量上限先试1、2、4三档看检出数边际变化停在哪个档位取收益最高的倍数然后固定scale试overlap 0.2/0.4/0.5目标在边界被切的问题此时最明显最后再降conf从0.25逐步降到0.1每次降完关注新增框里真实目标的比例降到某个点全是假阳性就收回去。这套顺序比一上来就乱试要省时间。还有个小技巧把结果导出成带坐标的JSON用脚本统计检测框的尺寸分布能看出当前漏检目标是集中在10像素以下还是20像素附近这对后续决定要不要换P6权重或者训练自己的数据集很有参考价值。5.3 边界与后续SAHI和超分的组合不是终点只是一个不修改网络结构就能吃到小目标增益的中间方案。如果你手上的数据分布和COCO差异很大正确的路径还是用YOLOv5训练自己的数据集在训练阶段就把高分辨率切片喂进去配合mosaic、copy-paste这类数据增强让模型本身学会小目标特征。到那时候SAHI可以作为推理阶段的增强手段保留但超分就不一定要了。我之前在一个遥感车辆检测项目里踩过一次改装学数据集里的车最小只有8像素靠这套组合硬拉到12个检测框但误检率也跟着涨了3个百分点。后来重训了一个3000张的自定义数据模型推理阶段只保留SAHI效果反而比超分链路干净。从那以后我每次换数据集都会先跑一遍三路对照确认超分是增益还是噪声再决定用不用这已经成了固定的验证流程。希望帮到你。本文还有配套的精品资源点击获取