公司动态

TinyPerson微小目标检测实战:YOLOv8格式转换与训练全解析

📅 2026/9/2 1:56:37
TinyPerson微小目标检测实战:YOLOv8格式转换与训练全解析
简介TinyPerson数据集面向小目标检测任务专为人形小目标识别场景设计适合从事安防监控、无人车视觉、人群计数等方向的研究者与算法工程师使用。资源共包含2000个文件压缩包大小约78.69MB其中1532个txt文件为YOLO格式标注、467个xml文件为VOC格式标注并配有1个data.yaml配置文件。图片标注同时提供VOC与YOLO两种格式且YOLO标注已按训练集、验证集和测试集合理划分配合data.yaml即可直接接入YOLO系列算法进行训练和评估省去数据格式转换与划分的前期工作。数据集包含1532个精心挑选的样本针对小目标在图像中像素占比少、背景复杂等难点提供准确精细的标注位置与类别信息为小目标检测模型训练提供了扎实的数据基础。目前已有736人学习下载适合需要快速开展小目标检测实验或构建基线模型的开发者。 我最早碰 TinyPerson 数据集是因为一个海上搜救demo。之前用YOLOv5在普通监控画面里做人员检测效果一直还行结果把相机架到海边长焦画面上人变成十几个像素的小点模型基本全军覆没。那种感觉可能很多做目标检测的人都经历过训练时mAP看着不差一上真实场景就露馅。后来我顺着“微小目标检测”关键词去翻资料几乎绕不开 TinyPerson。这是目前少有的专门面向极小人体的目标检测数据集而大家搜它的一个重要原因就是官方给的是JSON标注直接拿YOLO训练工具没法用需要先转成YOLO格式。今天就把数据集本身、格式转换、训练参数和推理细节完整梳理一遍。1. TinyPerson为什么值得你花时间微小目标检测的“标准考卷”1.1 数据集的真实背景TinyPerson 是专门针对远距离场景下人体目标检测构建的数据集图像多来自海滩、港口、入海口这类开阔场景目标人物离镜头很远但又是整个画面的安全关键点。对比COCO里那些小目标TinyPerson的“小”要极端得多。COCO把面积小于32×32像素的算作small而TinyPerson里大量人体目标的高度只有几个像素到十几个像素在图像里真的就是一个点。这套数据的价值在于它让你能在一个公认的基准上评估自己的模型对微小目标到底有没有检测能力。如果在一个全是“十几像素小人”的测试集上能拿到还行的recall那么迁移到无人机巡视、海上搜救、工业园区安全监测这类真实场景才有说服力。我记忆里这套数据集总共大概有1610张图像标注实例约3.5万个其中训练、测试各有一定比例具体数字以你下载到的版本为准。我更看重的是它除了普通的边界框之外还提供了一些属性信息比如目标可见性、人体朝向等很多人只用了box坐标其实这些额外信息在统计漏检原因时非常有用。1.2 微小目标为什么是目标检测的老大难这个问题如果不搞清楚后面调参就是瞎忙。微小目标检测难的根子有三层。第一层是下采样倍率太高。YOLOv8的backbone从输入到P5特征层要经历32倍下采样一个12像素高的人到了P5特征图上连1个像素都占不满卷积核扫过去根本没有有效响应。所以在TinyPerson上默认特征金字塔往往是不够的必须靠提高输入分辨率或增加P2检测头去弥补。第二层是正样本匹配困难。基于IoU的匹配策略对微小目标极其苛刻。一个真实框只有20×20像素预测框哪怕只偏了2个像素IoU就掉了好大一截很可能匹配不到正样本。带来的直接后果就是训练时正样本数量过少模型学了半天只学到背景。第三层是标注噪声的权重被放大。人眼去标一个14像素高的人头和肩根本分不清边界框的误差可能达到3到5像素这种噪声占真实框尺寸的比例相当高。转换到YOLO格式后如果你的损失函数对小框和大框一视同仁噪声会拖慢收敛。理解这三点之后你再看网上各种TinyPerson训练经验就不会只觉得是玄学。2. 下载之后先别急搞清目录和官方标注格式2.1 目录结构和标注文件TinyPerson的官方数据压缩包解压后一般是train和test两个主目录图像基本都是1080p级别的jpg。很多人下载完第一件事就是找“labels”文件夹结果发现根本没有只看到JSON文件这是正常的因为官方格式不是YOLO的txt。官方标注文件按图像逐张组织每条记录里包含图像路径、图像宽高以及该图的目标列表。目标列表里最关键的是box2d字段保存的是左上角x1,y1和右下角x2,y2坐标。有些版本还带center2d中心点坐标以及朝向、可见性等属性。这里我要提醒一句千万别在没看标签的情况下直接转格式。先找两张图把标注框画出来确认“小目标”到底有多小也方便你判断自己需不需要做特殊处理。2.2 用脚本把标注画出来画框的脚本很简单我习惯用OpenCV一把梭import json import cv2 ann json.load(open(tiny_person.json)) for item in ann: img cv2.imread(item[image_path]) for obj in item[annotations]: x1, y1, x2, y2 obj[box2d] cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) cv2.imwrite(visualize/ item[image_name], img)跑完你会看到两个现象。一是大多数框特别小在整图上看不太清楚需要把局部放大才能看清二是有些目标真的只有几个像素人的轮廓基本看不出来。这时不要急着把太小目标的标注过滤掉因为你的最终任务就是要检测这种目标。我建议把这类极小框单独统计一下看看占多少比例。如果占比较高说明仅靠常规训练很难解决得提前考虑切片推理或者P2检测头。3. 转成YOLO格式一次做对避免返工3.1 为什么必须转格式YOLO系列工具链的标签体系是一张图对应一个txt每行是 class x_center y_center width height并且所有坐标都归一化到0到1。官方JSON既没有按图片拆分坐标也是绝对值直接丢给ultralytics去训练它根本不认识。转换本身不复杂但有两个细节会让很多人踩坑。第一个是类别编号。TinyPerson里虽然主体都是人但标注类别名可能不是统一的person比如有“person”也有“people”之类如果你的任务只检测人转换脚本里一律映射成class 0即可。第二个是图片宽高要用真实分辨率。如果读图的时候图像被resize过得到的宽高就和标注坐标不一致归一化结果全错。我一般直接从JSON的image_width和image_height字段读取。3.2 一套可以直接改改就用的转换脚本下面这段脚本我实际在TinyPerson上跑过大家按自己的JSON字段名微调就行import json import os def convert_tiny_to_yolo(json_path, out_dir): os.makedirs(out_dir, exist_okTrue) ann json.load(open(json_path)) for item in ann: img_w item[image_width] img_h item[image_height] image_name item[image_name].replace(.jpg, .txt) txt_path os.path.join(out_dir, image_name) lines [] for obj in item[annotations]: x1, y1, x2, y2 obj[box2d] if x2 - x1 0 or y2 - y1 0: continue x_c (x1 x2) / 2.0 / img_w y_c (y1 y2) / 2.0 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h x_c min(max(x_c, 0.0), 1.0) y_c min(max(y_c, 0.0), 1.0) w min(max(w, 0.0), 1.0) h min(max(h, 0.0), 1.0) lines.append(f0 {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines))这里有两处处理不能省。一是跳过宽高小于等于0的框TinyPerson里偶尔会有退化标注二是把归一化后的坐标clip到0到1区间因为边界目标经常出现越界框如果不处理训练时标签会跑到图像外面导致loss突然跳高。把这些异常提前挡在数据准备阶段后面训练会省很多事。3.3 划分训练验证集时注意场景泄漏TinyPerson的图像并不是互相独立的真实场景很多是从一段连续拍摄里抽出来的同一片沙滩、同一批人可能会在多张图中反复出现。如果你用随机函数把数据分成train和val训练集和验证集很可能混入同一场景的相似画面val的mAP虚高模型一换到真正没见过的新场景就掉链子。我一开始就犯过这个错随机划分后val mAP比按官方划分高了四五个点整个人都飘了后来一测新场景才发现是数据泄漏。正确的做法是优先用官方的train/test划分如果非要自己做验证集尽量按目录或拍摄批次划分而不是按单张图像随机切。划分完之后检查一下train和val的文件名有没有交集这是一步成本极低但很有效的保险。4. 用YOLOv8训练TinyPerson的实测经验4.1 模型选型先小后大别一上来就上大模型在TinyPerson这种小而难的场景里模型复杂度带来的收益没有想象中那么高。我刚开始图省事直接拿YOLOv8m训练结果发现收敛速度更慢显存也紧张。后来老老实实先用YOLOv8n跑通流程得到baseline再逐步上大模型。这里给个参考配置模型输入尺寸batch size单卡显存占用约典型训练时长YOLOv8n640166G约1小时/100epochYOLOv8n1280812G约2小时/100epochYOLOv8m1280416G约4小时/100epoch具体数字和你用的显卡、训练数据量有关但趋势很明确提高分辨率带来的显存开销比换大模型更可控而收益也更直接。4.2 分辨率是最大的“免费午餐”对于微小目标输入分辨率几乎是最关键的因素。同样用YOLOv8n从640提升到1280TinyPerson上的小目标AP提升非常明显这个提升幅度往往比把n换成m还要大。原因很简单分辨率越高小目标在特征图上的像素占比就越大可学特征越多。如果显存不够可以先用低分辨率训练几十个epoch再用高分辨率微调也能拿到不错的效果。另一个办法是Tiling训练把大图切成若干小块每块作为一张训练图这样相当于直接用高倍放大的局部喂给模型对TinyPerson这种场景特别有效。但注意切图时标注的坐标需要跟着偏移切割边界上的目标要么过滤掉要么做跨patch的标注重映射否则会产生大量错误框。4.3 数据增强与损失细节Mosaic在这里不一定是朋友Ultralytics默认开启Mosaic数据增强它在常规目标检测里确实有效但在TinyPerson上会帮倒忙。Mosaic把四张图缩小拼接本来就只有十几个像素的人再被缩小一次直接变成子像素模型根本学不到形状特征。我在实测中把mosaic直接关掉并且把缩放类增强的概率调低保留轻微的平移和翻转训练稳定度有明显改善。关闭方法是在训练参数里指定mosaic0.0。另外海上、沙滩这类场景颜色非常单一默认的HSV色彩增强幅度可以适当调小否则海和天的颜色被过度扰动模型反而更难区分背景。损失函数方面默认CIoU在微小目标上的梯度表现并不友好主要原因是小框IoU对像素偏移过于敏感。想折腾的可以试试SIoU或EIoU但在改动之前先确认自己的正样本匹配已经没问题否则调损失函数就是隔靴搔痒。4.4 评估指标别只盯着mAP在TinyPerson上mAP50-95的数字通常不会太好看很多人一看0.2就以为模型废了。其实不是微小目标本身能被准确检测出来就已经很难mAP的分数被大量难样本拉低是正常的。我建议重点关注三个指标AP_small、AR_smallaverage recall for small objects和recall。如果你的目标是搜救漏检比误检可怕得多recall的优先级要排在precision前面。我做过一组简单对比配置mAP50-95AP50AR_smallYOLOv8n 6400.160.420.31YOLOv8n 12800.220.530.42YOLOv8m 12800.240.550.45可以看到分辨率提升带来recall提升非常明显。如果你的应用场景对漏检更敏感优先冲高recall而不是纠结mAP数值。5. 推理阶段的隐藏提升切片推理和测试时增强5.1 用SAHI做切片推理训练完模型直接拿整张1080p原图去推理效果往往不如预期。因为这个阶段和训练时的“分辨率放大”是同一个道理模型没见过足够大的目标整图推理时就容易漏。推荐用SAHI这个切片推理库把大图切成固定大小的patch每个patch独立推理再用NMS把重叠区域的检测框合并。我实测在TinyPerson测试集上用512×512切片、overlap设为0.2recall提升非常明显尤其是对画面边缘的小目标。代价是推理速度变慢一张1080p图可能要切成十来块但很多离线分析场景完全能接受。如果你做的是实时视频流可以考虑只对感兴趣区域做切片或者用低倍overlap来折中。5.2 后处理参数小目标有自己的脾气小目标检测框的置信度通常低于大目标这是模型特性不代表框不可信。推理时如果你把置信度阈值设成0.5很多有效的小目标会被过滤掉。我在TinyPerson上一般把conf_thres降到0.25甚至更低然后靠后处理去控制误检。密集人群场景下默认NMS的IoU阈值也可能过高把挨得很近的两个小人合并成一个框。可以适当把NMS IoU阈值降到0.5保留更多相邻目标。另外如果检测结果里出现大量重复框说明patch之间的重叠区域合并策略没做好可以调高NMS阈值或增加重叠区域的置信度抑制策略。这些细节看起来不起眼但对最终的可用性影响很大。5.3 用TinyPerson预训练再迁移到自己的场景如果你的最终目标不是复现TinyPerson而是解决自己项目里的小目标检测问题一个很实用的思路是把TinyPerson当作预训练数据。我试过在TinyPerson上训练一个“微小人体通用检测器”然后拿到自己的无人机巡视数据上微调收敛速度比从COCO预训练直接微调快不少最终效果也更好。原因是TinyPerson和你的场景在“小目标分布”上更接近模型一开始就学到了小目标长什么样而不是在COCO的大目标世界中学一套规则再来适应小目标。当然如果自己的数据背景和海滩、港口差太远比如是城市道路或森林最好在微调时混入一批背景图让模型重新校准场景特征。迁移学习不是万能药但它确实是TinyPerson带来的一个隐藏红利。最后再分享一个我个人的习惯每次拿到一个新的小目标数据集我都会先按“640分辨率、默认参数”跑一个快速baseline把当天的时间基本都花在数据检查和高分辨率实验上。因为小目标检测的收益顺序永远是数据质量大于输入分辨率输入分辨率大于模型结构模型结构大于训练技巧。先把数据和数据格式搞对再上一个高分辨率训练很多问题根本不需要靠改代码解决。TinyPerson让我把这条路彻彻底底走了一遍希望这篇经验对你有用。本文还有配套的精品资源点击获取