ReID数据集,到底该怎么选、怎么用、怎么造?
做行人重识别(Person Re-identification,简称 ReID)这几年,我最大的感触是:算法模型反而是最容易上手的部分,真正决定你实验成败的,往往是手里的数据集。数据和任务不匹配,再好的模型也白搭;评价协议没搞对,实验结果根本没法跟别人比较。这篇文章我不打算讲模型结构,专门聊聊ReID数据集——主流的、冷门的、公开的、自造的,从底层逻辑到实操细节一次说清楚。
如果你是刚入行ReID的算法工程师、研究生,或者正准备用ReID技术做安防、智慧零售、城市管理项目,这篇文章能帮你省下大量走弯路的时间。
1. ReID任务与数据集设计背后的核心逻辑
很多人拿到ReID数据集直接就开始训练,但连这个任务最根本的难点都没想明白。ReID和图像分类、人脸识别最大的区别在于——它面对的是跨摄像头、跨场景、跨时段的同一行人识别。一个行人在摄像头A出现,几分钟后又在摄像头B出现,穿同样的衣服但光照变了、角度变了、分辨率变了、遮挡情况也变了,模型要在这种极端条件下判断“这是同一个人”。
这样的任务特性,直接决定了数据集该怎么设计。
1.1 为什么ReID数据集不是“拿来就能用”的通用图像集
我看过不少新人犯同一个错误:把ReID数据集当成普通分类数据集来处理,随机切分训练集和测试集,结果模型精度虚高,换到真实场景立刻崩掉。
ReID数据集的核心设计原则是**“训练身份与测试身份完全隔离”**。训练集里的行人ID和测试集里的行人ID没有任何重叠,模型在训练阶段见过的所有身份,测试时一个都不会出现。这意味着模型不能靠“记住这张脸”来做识别,必须学到真正具有泛化能力的行人外观特征。
其次,ReID数据集的评价不是简单算准确率,而是遵循一套固定的协议(protocol)。以最经典的Market-1501为例,它把测试集分成query(查询集)和gallery(候选集),模型的任务是在gallery中找到与query属于同一行人的所有图片。这个设定模拟的是真实场景:你拿到一张目标行人照片,要在海量监控录像截图里找出这个人的所有出现记录。
1.2 评价指标背后的工程含义:从CMC到mAP
ReID领域最常用的两个指标是CMC(Cumulative Match Characteristic)和mAP(Mean Average Precision)。很多教程只给公式,不讲它们在实际工程里代表什么。
CMC的横轴是Rank@k,含义是“正确答案出现在前k个检索结果里的概率”。Rank@1最常用,它回答的问题是:“系统把目标行人排在候选列表第一位的准确率有多高?”在安防场景里,Rank@1就是一线民警最关心的数字——你给系统一张嫌疑人照片,它第一个推给你的到底是不是同一个人。
mAP则更严格,它同时关注“检索结果里所有正确结果的位置有多靠前”。举个直观例子:某个query在gallery里有4张同ID图片,系统A把这4张排在第1、2、3、4位,系统B排在第1、50、100、150位,两者的Rank@1都是100%,但mAP天差地别。在工程落地时,如果检索系统后面还接着人工二次确认环节,mAP高的系统能显著减少人工翻页成本。
这两个指标的计算流程决定了数据集必须包含完整的query/gallery划分信息,这也是我强调“别自己乱切数据”的原因——你用官方协议测试,结果才能和论文对比;你用自己的随机划分,结果只能自娱自乐。
2. 主流公开数据集拆解:选型与适用场景分析
ReID领域经过这些年的发展,公开数据集已经非常丰富。从早期的VIPeR、CUHK03,到中期的Market-1501、DukeMTMC-reID,再到当前最常用的大规模数据集MSMT17,每个数据集都有自己的脾性和适用场景。搞清楚它们的差异,才能根据你的任务需求做选型。
2.1 Market-1501为什么是“新手必刷”的数据集
Market-1501发布于2015年,采集自清华大学校园内的6个摄像头,总共包含1501个行人ID、32668张检测框图像。它最大的贡献在于确立了现代ReID数据集的标准范式:使用DPM检测器自动检测行人框、提供训练/查询/候选集的完整划分、发布标准评价代码。
这个数据集的训练集有751个ID、12936张图,测试集有750个ID、19732张图,query有3368张图(每个ID在每个摄像头下最多取一张)。它的gallery图片由DPM检测器自动生成,因此在测试时天然存在检测框不精确的问题,这反而更接近真实场景。
我在实际项目里把Market-1501当作用来“调通代码、验证baseline”的第一站。它的数据量适中,GPU显存需求不高,训练一轮很快,非常适合验证模型改动有没有效果。
2.2 更大规模的MSMT17与现代数据集的差异化选型
MSMT17是当前公认难度最高的公开ReID数据集之一,采集自北京大学校园,使用了15个摄像头,包含4101个ID、126441张图像,而且这些摄像头分布在校园的室内和室外不同场景,时间跨度从清晨到傍晚。
MSMT17的难度体现在三个方面:一是数据量级大幅提升,对模型的容量和训练效率提出更高要求;二是场景多样性显著增加,室内外光照差异、视角差异都非常大;三是数据集明确标注了每个摄像头的信息,方便研究者做域适应研究。
如果你的目标是发论文或者做相对深入的研究,MSMT17是更合适的benchmark。但要注意,MSMT17的标注质量存在一些争议,部分边界框定位不够精确。我自己处理时会额外加一个数据清洗环节,把明显错误的标注剔除掉,这个操作在实验记录里一定要说明,方便复现。
常用公开数据集特性对比表
| 数据集 | 发布于 | 摄像头数 | ID数量 | 图像数量 | 检测方式 | 场景类型 |
|---|---|---|---|---|---|---|
| Market-1501 | 2015 | 6 | 1501 | 32668 | DPM检测 | 校园 |
| DukeMTMC-reID | 2017 | 8 | 1812 | 36441 | 手工标注 | 校园 |
| MSMT17 | 2018 | 15 | 4101 | 126441 | Faster R-CNN检测 | 校园室内外 |
| CUHK03 | 2014 | 2 | 1467 | 13164 | DPM/手工标注 | 校园 |
| CUHK-SYSU | 2016 | - | 8432 | 34808 | 手工/检测 | 街景 |
2.3 城市管理场景的ReID延伸:POI数据集与占道经营数据集
近年来越来越多同行开始关注城市管理领域的ReID应用,典型场景包括流动摊贩识别、占道经营预警、重点区域人员追踪等。这些任务和传统的行人重识别不完全一样,但对ReID数据集的方法论有很强的借鉴意义。
POI(Point of Interest)数据集在城市计算领域指的是兴趣点数据,通常包含地理位置坐标、类别属性、名称、地址等字段。在做城市级人员流动分析时,POI数据集可以和ReID识别结果做关联分析——比如识别出某个行人在不同摄像头下的轨迹后,结合POI数据判断这个人频繁出入哪些类型的场所。
占道经营数据集则是另一个方向,它的核心任务是小商贩、摊位的检测与识别。这类数据集一般需要自行收集标注,因为公开资源极少。我在做一个智慧城管项目时,就是先借鉴ReID数据集的构建思路,把某个区域内固定摄像头拍摄的占道经营场景做行人/摊位检测框标注,再按ReID的数据组织方式管理。事实证明,这种跨任务的数据组织方法非常有效——检测模型负责找目标,ReID负责跨摄像头关联,两者结合才能完成完整的“发现—跟踪—预警”闭环。
3. 从下载到训练:打开数据集的正确姿势
我见过太多人倒在“打开了数据集,却不知道下一步该干什么”这个环节。公开数据集下载下来之后,到真正能送进模型训练,中间还有一段数据工程的路要走。这一步做得好不好,直接影响训练效率和最终精度。
3.1 数据目录结构与关键文件解读
以Market-1501为例,解压后你会得到以下结构:
Market-1501-v15.09.15/ ├── bounding_box_train/ # 训练集,文件名形如 0002_c1s1_000451_02.jpg ├── bounding_box_test/ # 测试集gallery ├── query/ # 查询集 ├── gt_bbox/ # 手工标注的行人框(用于评估检测器质量) ├── gt_query/ # 查询集对应的标注文件 └── readme.txt # 数据集说明很多新手被这里的文件名搞晕。其实命名规则非常清晰:0002_c1s1_000451_02.jpg可以拆成四段,0002是行人ID,c1s1表示摄像头1下的第1个片段(sequence),000451是帧号,02是检测框序号。这个命名规则里藏着一个容易被忽略的信息——同一个行人ID在不同摄像头下的数量分布,是评估数据集质量的重要指标。
训练脚本读取这个目录结构的核心代码一般长这样:
import os from torch.utils.data import Dataset from PIL import Image class ReIDDataset(Dataset): def __init__(self, data_dir, transform=None): self.data_dir = data_dir self.transform = transform self.images = [] self.labels = [] self.cameras = [] for filename in sorted(os.listdir(data_dir)): if not filename.endswith('.jpg'): continue # 从文件名解析ID和摄像头ID parts = filename.split('_') pid = int(parts[0]) camid = int(parts[1][1]) # c1 -> 1 self.images.append(os.path.join(data_dir, filename)) self.labels.append(pid) self.cameras.append(camid) def __len__(self): return len(self.images) def __getitem__(self, idx): img = Image.open(self.images[idx]).convert('RGB') if self.transform: img = self.transform(img) return img, self.labels[idx], self.cameras[idx]这段代码的关键在于同时返回行人ID和摄像头ID。摄像头ID是训练ReID模型的一个强监督信号,很多算法(比如PCB、MGN)在训练时用摄像头ID做辅助信息来缓解域偏移问题。
3.2 数据切分与train/query/gallery的正确配比
公开数据集自带的划分方案是经过严格设计的,不建议随意改动。但如果你使用自定义数据构建训练集,需要遵循几条基本原则:
- 训练集和测试集的ID不能有任何交集,这是ReID任务区别于普通分类任务的红线。
- 测试集中的每个ID至少出现在两个摄像头下,否则无法验证跨摄像头检索能力。
- query集通常每ID每摄像头取一张图,gallery则包含其余所有图像。
我曾经接手过一个项目,合作方自行收集了数据但不知道怎么划分,随手按8:2切分,结果query里的很多ID只在gallery中出现过一次,CMC指标虚高得离谱。后来我按照“训练/测试ID隔离 + 每ID至少2摄像头”的原则重新划分,模型精度才回归合理区间。
4. 自制ReID数据集的工程化路径
公开数据集虽多,但真实项目中几乎总会遇到需要自己造数据的场景——比如针对特定场所(商场、园区、工地)的ReID系统,或者针对特定装备(工服、安全帽)的识别需求。自制数据集的过程,本质上是一个数据工程的流程设计问题。
4.1 从监控视频到可用数据集:完整流水线
我在给一个园区做人员定位项目时,构建了一套相对标准的数据集制作流程,整个过程大约花了两周时间:
第一步是原始视频采集。使用园区现有的监控摄像头,确保同一行人在不同摄像头下都有足够的出现时间。我一般要求每个行人至少在两个摄像头下累计出现30秒以上,这样裁剪出来的图像数量和质量才够用。
第二步是行人检测与跟踪。用现成的检测器(比如YOLOv8)对视频逐帧检测行人框,再配合多目标跟踪算法(比如ByteTrack)把同一行人在同一个摄像头下的轨迹串起来。这一步可以自动完成,但输出结果必须人工复核。
第三步是跨摄像头关联。前面两步产生的是每个摄像头内的行人轨迹,还需要人工把不同摄像头下的同一行人轨迹关联起来,分配同一个ID。这是整个流程中人力成本最高的一环,需要有标注工具辅助。
第四步是数据清洗。把模糊的、遮挡过度的、检测框偏移严重的图像剔除掉。
当时我踩过最大的坑是没有在采集阶段控制行人的出现分布,导致某些ID在摄像头A下出现1000次、在摄像头B下只出现3次。这种极端不均衡的数据会让模型在训练时严重偏向数据多的摄像头视角,跨摄像头泛化能力大幅下降。
4.2 数据增强与模拟域偏移的取舍
自制数据集规模通常不会太大,数据增强就成了必要的补充手段。ReID领域常用的增强包括随机擦除(Random Erasing)、水平翻转、颜色抖动、Random Crop等。
但有一个原则我需要特别提醒:增强策略的选择要跟场景匹配。如果你做的是夜间安防场景的ReID,那训练时加入亮度扰动就非常合理;如果你做的是白天的园区人员管理,过强的颜色抖动反而会破坏行人外观的真实性,让模型学到虚假的颜色不变性。
另一个有效的做法是模拟域偏移。在训练阶段,把同一批图像用不同的色彩空间变换(灰度化、对比度调整、加噪声)复制成多份,相当于人为制造出不同摄像头风格的数据。这个技巧在自制小数据集上效果很明显,我的一个夜间场景项目靠这个手段把Rank-1指标从68%提到了76%。
4.3 小规模数据集的训练策略与迁移学习
自制数据集的规模往往只有几千张到一两万张,远不及MSMT17的量级。这种情况下从零训练一个深度ReID模型几乎必定过拟合。
我的做法分三步走。第一步,用MSMT17或Market-1501预训练一个骨干网络(ResNet-50或ViT-Base),保留到全局池化层之前的权重。第二步,把自制数据集的分类头换成新的全连接层,然后在自制数据上微调全部参数。第三步,微调时使用较小的初始学习率(一般为预训练阶段的十分之一),配合Warmup策略逐步升温。
这里有一个重要细节:预训练阶段用的数据集最好和自制数据在“域”上接近。做室外园区项目时,用Market-1501预训练效果就很好;做室内商场项目时,MSMT17的特征更通用。如果条件允许,可以分别尝试两种预训练权重,选验证集上mAP更高的那个。
5. 数据集的坑与避坑经验:问题排查实录
ReID数据集用久了,该踩的坑基本都踩遍了。我梳理几个高频问题,按我实际遇到的频率排序,给大伙儿做个避坑参考。
| 现象 | 根本原因 | 解决方案 |
|---|---|---|
| 训练loss正常下降,测试mAP极低 | 训练/测试ID未隔离或泄露 | 检查数据划分代码,确保ID无交集 |
| 同一ID在gallery中出现次数极少 | 数据集构建时未保证跨摄像头覆盖 | 采集阶段控制每ID至少2个摄像头视角 |
| CMC指标高但mAP低 | 检索结果“头准尾乱” | 优化特征粒度,尝试Part-based模型 |
| 摄像头ID参与推理 | 训练时把camID当分类特征 | 推理时特征层禁止camID参与计算 |
| 模型在不同数据集间精度暴跌 | 域偏移严重 | 引入域适应方法或大规模预训练 |
5.1 数据清洗的具体经验
公开数据集不等于干净数据。MSMT17的标注里有相当一部分边界框和行人身体贴合度很差,Market-1501的DPM检测框也有同样问题。
我一般会写一个简单的脚本,先把图像的宽高比筛一遍,剔除比例明显异常的(比如宽高比大于1或小于0.2的),再用一个人眼复核的子集抽样检查。如果发现数据集中混入了大量非行人图像(比如墙面、树木的误检),那这个数据集用来做定量实验就非常不靠谱了,宁可不用也不要硬上。
5.2 域偏移问题与域适应方法选择
ReID模型的域偏移问题我单独拎出来讲,因为这是实际落地时最容易让人头疼的问题。在Market-1501上Rank-1能做到95%以上的模型,换到商场真实环境里可能直接掉到60%,原因就是训练数据和目标数据之间的“域差距”。
解决域偏移大致有三条技术路线:一是基于特征对齐的域适应方法,通过在训练时加入域判别器让模型学到域无关特征;二是基于图像风格转换的方法,用CycleGAN之类的模型把源域图像转成目标域风格再训练;三是直接在目标域采一批无标注数据做伪标签自训练。
我的经验是:如果目标域数据能轻松得到,直接走伪标签自训练路线最省事;如果目标域数据本身极难获取(比如特殊环境),那域适应方法更合适。但无论哪条路线,都建议先在源域和目标域的混合数据上做一轮简单的微调,评估一下精度差距,再决定下一步策略。
写在最后
做ReID这几年,我越来越相信一句话:数据决定了模型的上限,算法只是去逼近这个上限。一个好的ReID数据集,不仅要有足够的规模、合理的划分,还要和你想要解决的实际问题匹配。公开数据集帮你验证想法,自制数据集帮你落地产品,两者缺一不可。
最后再分享一个小技巧:无论是训练还是测试,把每次实验用到的数据集版本、划分方式、清洗规则、预处理流程全部记录下来。ReID实验结果的可复现性很大程度上依赖这些细节,有了记录,你回头看自己的实验时才不会一头雾水。条件允许的话,可以把处理好的数据集连同一份说明文档存在团队共享盘里,后面来的同事能直接复用,节省的时间非常可观。