news 2026/11/5 20:18:28

无监督行人重识别:多标签分类如何破解伪标签噪声难题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
无监督行人重识别:多标签分类如何破解伪标签噪声难题

1. 从"没有标签"这个死结说起:行人重识别到底难在哪

行人重识别(Person Re-ID)这个方向,做过的人都知道,最折磨人的从来不是模型结构设计,而是标注数据。简单说,Re-ID要解决的问题是:给你一张某摄像头下拍到的人像,让你在另一个摄像头拍摄的海量图库里把同一个人找出来。听起来像"以图搜图",但难点在于——同一个人换件衣服、换个角度、光线一变,特征分布可能天差地别;而两个不同的人穿同款衣服,模型又容易认错。

传统做法是监督学习:拿一堆带身份标签的图片训练模型,让网络学会"哪些特征属于同一个人"。这套路在Market-1501、DukeMTMC这些经典数据集上刷得很高,但一到真实场景就露馅。为什么?因为真实世界里,摄像头每天新增的图片是海量的,你不可能给每一张图都标上"这是张三、那是李四"。标注成本高到什么程度?一个中等规模的项目,标几万张图,几个人干一个月,还容易标错。更麻烦的是,一旦场景换了(比如从商场换到地铁站),原来标好的数据分布就偏了,模型直接掉点。

所以无监督行人重识别(Unsupervised Person Re-ID)就成了绕不开的方向。它的目标很直接:不依赖任何人工身份标签,让模型自己从无标注数据里学出有判别力的特征。而这篇论文周报要拆的,就是其中一条很有代表性的技术路线——基于多标签分类(Multi-label Classification)的无监督Re-ID。

为什么是"多标签"?这里得先破一个常见的误解。很多人一听无监督,第一反应是聚类:把相似的图聚成一堆,每堆当成一个伪身份,然后当监督任务训。这思路没错,但聚类有个硬伤——一个样本只能属于一个簇。可现实中,一张行人图里包含的信息远不止"身份"这一个维度:他穿什么颜色的上衣、什么款式的裤子、背没背包、戴没戴帽子,这些都是可以独立描述的属性。硬把一个样本塞进单一簇,等于把这些信息全丢了。多标签分类的思路就是:让每个样本同时携带多个标签(比如"红衣+黑裤+背包"),用这些标签组合来刻画身份,而不是用一个孤立的ID。

这篇周报适合谁看?如果你正在做Re-ID相关的毕设、论文,或者刚进实验室被导师扔了一个无监督方向让你啃,那这篇内容能帮你把这条技术路线的来龙去脉、核心机制、实操坑点理清楚。我会尽量少堆公式,多讲"为什么这么设计"和"实际跑起来会遇到什么"。

2. 多标签分类这条路线,到底在解决聚类的哪个痛点

2.1 聚类伪标签的"硬伤":一个样本只能进一个桶

先把这个痛点讲透,不然后面理解不了多标签的价值。

假设你用DBSCAN或者K-means对一批无标注行人图做聚类,聚出500个簇,每个簇给一个伪ID。接下来训练时,网络看到某张图,就被要求"你必须预测成第237号簇"。问题来了:这张图可能和237号簇里的其他图只是"部分相似"——比如都穿了红上衣,但裤子颜色完全不同。可损失函数不管这些,它逼着网络把整张图的特征往237号簇的中心拉。结果就是,网络学到的特征被"平均化"了,那些真正有区分度的细节(裤子的颜色、鞋子的款式)反而被抹平。

更糟的是,聚类边界本身就不靠谱。无监督场景下,簇的数量、簇的形状都是拍脑袋定的。一个样本落在两个簇的边界上,今天被分到A,明天特征微调一下又被分到B,训练信号来回震荡,模型根本收敛不稳。这就是所谓的伪标签噪声问题。

2.2 多标签的破局逻辑:把"身份"拆成可组合的属性

多标签分类的核心洞察是:身份不是一个原子标签,而是多个属性的组合。

打个比方。你要描述一个人,不会只说"这是编号237",而会说"穿红上衣、黑裤子、背双肩包、戴眼镜"。这四句话里,每一句都是一个独立的二分类问题(是/不是红上衣、是/不是黑裤子……)。网络不需要预测一个500类的softmax,而是同时预测几十个二分类标签。这样一来:

  • 一个样本可以同时激活多个标签,不再被强行塞进单一簇;
  • 标签之间可以自由组合,红上衣+黑裤子的组合,和红上衣+蓝裤子的组合,天然就是两个不同的身份表征;
  • 训练信号更稠密,每个属性维度都在提供梯度,而不是只靠一个簇ID。

从信息论的角度看,这相当于把原来"一个样本→一个ID"的低熵映射,升级成了"一个样本→一个属性向量"的高熵映射。网络被迫去学更细粒度的特征,而不是偷懒记住簇中心。

2.3 关键问题:无监督场景下,标签从哪来

这里肯定有人要问:多标签分类是监督任务啊,标签哪来的?无监督场景下哪来的"红上衣""黑裤子"标注?

答案是:标签不是人工标的,而是模型自己"造"出来的。具体做法通常分两步:

  1. 属性挖掘:先用一个在通用数据上预训练好的模型(比如在ImageNet上训过的骨干网络),对无标注行人图提取特征,然后通过聚类或者相似度传播,把特征空间里反复出现的"模式"识别出来,当作候选属性。比如发现有一批图的特征在某个子空间里聚得很紧,那这个子空间可能就对应"背包"这个属性。
  2. 伪标签分配:对每张图,根据它和各个属性原型的相似度,决定它是否携带该属性。相似度超过阈值就置1,否则置0。这样就得到了一张图的多热向量(multi-hot vector)。

这个过程是迭代的:先用初始伪标签训一轮,模型特征更新后,重新挖掘属性、重新分配伪标签,再训下一轮。伪标签的质量随着训练逐步提升,这也是这类方法能work的关键。

注意:这里的"属性"不一定是人类可命名的语义属性(如"红色"),更多时候是网络自己学出来的抽象模式。你不需要知道第17号标签到底代表什么,只要它在特征空间里稳定、可区分就行。

3. 把方法拆开看:多标签无监督Re-ID的完整训练链路

3.1 骨干网络与特征提取:为什么通常选ResNet-50起步

这条路线里,骨干网络基本是ResNet-50打底,少数工作会用ResNet-50-IBN或者更强的ViT。为什么?因为无监督场景下,预训练权重的质量直接决定初始伪标签的质量。ImageNet预训练的ResNet-50在通用视觉特征上足够稳,参数量适中(约25M),单卡就能跑,适合反复迭代。

特征提取部分有个细节容易被忽略:全局平均池化(GAP)之后要不要接BNNeck。在监督Re-ID里,BNNeck几乎是标配——它把特征分成两部分,一部分过BN层用于分类损失,一部分不过BN用于三元组损失,避免两个损失互相拉扯。在多标签无监督里,这个设计同样有用,因为多标签分类用的是BCE损失(二分类交叉熵),而对比学习用的是三元组或InfoNCE,两者对特征分布的要求不一样。我的经验是:BNNeck加上去,收敛稳定性明显好于不加,尤其是训练前期伪标签噪声大的时候。

3.2 多标签头怎么设计:BCE损失与标签平滑

多标签分类头就是一个全连接层,输出维度等于标签总数(比如50~200个),每个维度过Sigmoid,然后用BCE损失:

loss_cls = BCE(sigmoid(logits), multi_hot_labels)

这里有几个实操要点:

  • 标签总数不能太少。如果只设10个标签,表达能力不够,退化成粗聚类;设太多(比如1000个),大部分标签是噪声,反而拖累训练。经验值在50到200之间,具体看数据集规模。Market-1501这种量级,100左右比较合适。
  • 必须用标签平滑。因为伪标签本身有噪声,硬标签(0/1)会让网络对错误标签过度自信。把1平滑成0.9、0平滑成0.1,能显著缓解过拟合。我试过不平滑的版本,训练loss降得很快但mAP上不去,就是典型的过拟合伪标签。
  • 正负样本极度不平衡。一张图可能只激活5个标签,剩下95个都是0。直接算BCE,负样本的梯度会淹没正样本。常见做法是给正样本加权,或者用Focal Loss的变体。实测下来,正样本权重设为负样本的3~5倍比较稳。

3.3 伪标签的迭代更新:什么时候该重新聚类

这是整条链路里最需要经验的部分。伪标签不是标一次就完事,而是要周期性刷新。刷新太频繁,训练不稳定;刷新太慢,伪标签跟不上模型进化。

我的做法是:每训练5~10个epoch刷新一次。刷新时,用当前模型对所有训练图提特征,然后:

  1. 对特征做L2归一化;
  2. 用DBSCAN或者层次聚类,把特征聚成若干组;
  3. 对每组,统计各个标签的激活频率,频率超过阈值的标签保留,作为该组的新伪标签;
  4. 对每张图,根据它所属的组,重新分配多热向量。

这里有个坑:聚类数量会随训练变化。前期特征乱,聚出来的组多且碎;后期特征紧,组少而精。如果你强行固定组数,后期会出现大量样本挤在少数组里,标签失去区分度。所以DBSCAN这种不需要预设簇数的方法更合适,但它的eps参数要调——太小了全是噪声点,太大了全并成一坨。我一般从0.5开始试,看噪声点比例,控制在10%以内比较健康。

3.4 对比学习的辅助作用:为什么光靠多标签不够

只用多标签分类损失,模型容易学出"属性判别力"但缺乏"身份判别力"。什么意思?网络能准确判断"这是红上衣",但未必能把"穿红上衣的张三"和"穿红上衣的李四"区分开。所以几乎所有的多标签无监督工作,都会叠加一个对比学习损失。

常见的是簇对比(Cluster Contrast)或者记忆库(Memory Bank)机制:为每个伪身份维护一个特征中心,训练时拉近样本与自身中心的距离,推远与其他中心的距离。这样多标签负责"细粒度属性",对比学习负责"粗粒度身份",两者互补。

损失权重怎么配?我的经验是分类损失:对比损失 = 1:1 到 1:2。对比损失权重太低,身份判别力不够;太高,属性信息被压制。这个比例在Market-1501上从1:1调到1:2,mAP大概能涨1~2个点,但再往上调就开始掉。

4. 实测中那些文档不会写的坑

4.1 伪标签冷启动:第一轮聚类全是噪声怎么办

这是最容易被低估的问题。训练刚开始,模型就是ImageNet预训练的水平,对行人图像的特征提取能力很弱。这时候聚类,聚出来的组基本是乱的——同一组的图可能毫无关系,不同组的图反而可能是同一个人。

我踩过的坑:第一轮直接上DBSCAN,聚出300多个组,噪声点占了40%。拿这种伪标签去训,模型直接崩,loss震荡不收敛。

后来调整策略,冷启动阶段用更保守的方案:

  • 先不做聚类,而是用k近邻(k-NN)构建初始伪标签。对每张图,找特征空间里最近的k张图(k=10~20),认为它们共享标签。这样虽然粗糙,但比全局聚类稳。
  • 或者用层次聚类,先聚成很少的组(比如20组),保证每组内部足够纯,再逐步细分。
  • 前3~5个epoch用较小的学习率(比如1e-4),让模型慢慢适应伪标签,别一上来就猛冲。

提示:冷启动阶段的目标不是"聚得准",而是"别聚得太离谱"。宁可组少一点、粗一点,也不要引入大量错误标签。

4.2 标签坍塌:所有样本都预测成同一组标签

训练到中期,你可能会发现一个诡异现象:不管输入什么图,模型输出的多热向量几乎一样,mAP死活上不去。这就是标签坍塌。

根因通常是:某个标签在伪标签里出现频率极高(比如80%的图都被标了"标签7"),BCE损失会倾向于让模型对所有输入都预测"标签7=1",因为这样能降低平均损失。一旦模型学会这个"偷懒策略",其他标签的梯度就被压制了。

解决办法有三个,我一般组合使用:

  1. 标签频率过滤:伪标签刷新时,统计每个标签的激活率,激活率超过70%或低于5%的标签直接剔除,不参与训练。
  2. 重加权:对高频标签降权,低频标签升权,让每个标签对损失的贡献更均衡。
  3. 多样性正则:在损失里加一项,惩罚输出向量的平均激活率过于集中。具体就是计算一个batch内所有样本输出均值的熵,熵越低惩罚越大。

4.3 跨域测试掉点:训练集和测试集摄像头不重叠

无监督Re-ID的标准评测协议里,有个很关键的设定:训练集和测试集的摄像头ID不重叠。也就是说,你在摄像头1、2、3的数据上无监督训练,然后要在摄像头4、5、6上测试。这个设定非常贴近真实场景,但也非常残酷——模型很容易过拟合到训练集的摄像头风格上(比如某个摄像头的色调偏暖、分辨率偏低)。

我实测下来,颜色抖动(Color Jitter)和随机灰度化这两个数据增强,对跨域性能提升最明显。原理很简单:强迫模型不要依赖颜色这种摄像头相关的浅层特征,去学更本质的纹理和结构。另外,随机擦除(Random Erasing)也有帮助,能缓解遮挡问题。

还有一个技巧:在测试时做特征归一化。把训练集和测试集的特征分别做Z-score标准化后再算距离,能消除一部分域偏移。这个操作不改变模型,纯后处理,但mAP能涨0.5~1个点,性价比很高。

4.4 训练时长与显存:单卡怎么把实验跑起来

多标签无监督Re-ID的训练开销比监督版本大,因为要反复提特征、聚类、刷新伪标签。以Market-1501为例,完整跑一轮(比如60个epoch,每10个epoch刷新一次伪标签),单张24G显存的卡大概需要8~12小时。

显存优化上,几个实用手段:

  • 混合精度训练(AMP):显存占用直接砍半,速度提升30%左右,精度损失可以忽略。
  • 特征提取阶段用半精度+no_grad:刷新伪标签时不需要梯度,用torch.no_grad()包起来,batch size可以开大很多。
  • 记忆库用半精度存储:如果对比学习用了Memory Bank,存特征时用float16,能省一半显存。

另外,伪标签刷新那一步是CPU密集型的,聚类算法(尤其是DBSCAN)在大规模数据上很慢。我的做法是把特征提到CPU后,先用FAISS做近邻搜索加速,再在近邻图上跑聚类,比直接对全量特征跑DBSCAN快好几倍。

5. 这套方法的上限在哪,以及还能往哪走

5.1 当前路线的天花板:伪标签噪声的累积

多标签无监督Re-ID在Market-1501上,mAP大概能做到60%~70%区间(不同实现差异较大),相比监督版本的90%+还有明显差距。这个差距的核心来源就是伪标签噪声的累积——每一轮刷新都会引入新错误,错误标签又反过来污染模型,形成负反馈。

要突破这个天花板,光调参不够,得从机制上改。目前看到几个有希望的方向:

  • 置信度加权的伪标签:不是所有伪标签一视同仁,而是根据模型对每个标签的预测置信度给权重。置信度低的标签,损失贡献小,减少噪声影响。
  • 标签关系建模:多标签之间不是独立的,"红上衣"和"黑裤子"可能经常共现。用图神经网络或者标签共现矩阵来建模标签间关系,能让伪标签分配更合理。
  • 跨数据集联合训练:把多个无标注数据集混在一起训,用数据集ID作为额外的域标签,让模型学域不变特征。这个方向在跨域Re-ID里已经有不少工作。

5.2 工程落地时的取舍:精度 vs 复杂度

如果你是要把这套方法用到实际项目里,而不是刷论文指标,那得算一笔账:多标签无监督的pipeline比监督版本复杂得多——要维护伪标签、要周期性聚类、要调一堆阈值。如果项目场景相对固定(比如就一个园区的摄像头),其实半监督可能更划算:标少量数据(比如每个摄像头标100张),用监督+无监督混合训练,精度能接近纯监督,复杂度又比纯无监督低。

纯无监督多标签路线的真正价值场景是:摄像头持续新增、场景频繁变化、标注完全不可行。这种场景下,它的"自迭代"能力才是核心竞争力。

5.3 一个容易被忽视的评估细节

最后说个评估上的坑。无监督Re-ID论文里,大家习惯报mAP和Rank-1,但这两个指标对伪标签质量的反应不一样。Rank-1对簇的纯度更敏感,mAP对簇的召回更敏感。有时候你看到Rank-1涨了但mAP没动,说明模型把某些簇分得很纯,但漏掉了很多本该召回的样本。反过来,mAP涨Rank-1不动,说明召回上去了但排序质量没提升。

我的建议是:调参时两个指标一起看,别只盯一个。如果Rank-1高mAP低,去检查是不是聚类太保守(簇多而小);如果mAP高Rank-1低,去检查是不是簇太大导致混淆。这个诊断思路比盲目调学习率有用得多。

我个人在实际跑这类实验时的体会是,多标签无监督Re-ID的调参空间比监督版本大得多,但真正决定成败的往往不是超参,而是伪标签刷新的节奏和冷启动策略。这两点做对了,后面基本是顺水推舟;做错了,再怎么调学习率、换骨干网络,都很难救回来。所以如果你刚开始做这个方向,建议先把刷新周期和冷启动方案固定下来,跑通一个baseline,再去动其他模块。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/5 20:18:05

PHP在线音乐播放器MKOnlinePlayer v2.4部署与优化实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/5 20:18:04

Python爬虫实战:论坛多页数据采集与CSV存储

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/25 22:43:35

SpringBoot 项目基于 GitLab CI 与 Docker 的自动化部署实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/25 13:35:31

从零实现一个“答案能指回原文“的最小 RAG——Python 实战

关键词:RAG、检索增强生成、父子分块、混合检索、答案溯源、Python、Chromadb、Sentence-Transformers把 PDF、论文、产品文档丢给大模型聊天,最让人不安的不是它答得慢,而是它答出来的东西你没法验证。RAG(Retrieval-Augmented G…

作者头像 李华
网站建设 2026/10/26 6:59:06

开发者成长路径:从技术筑基到商业价值实现

1. 个人开发者成长全景图刚入行时我以为学会编程语言就能成为合格开发者,直到第一次独立交付项目时才意识到:从代码搬运工到具备完整交付能力的开发者之间,隔着产品思维、工程化能力、用户洞察等多重维度。真正的成长路径应该像建造金字塔——…

作者头像 李华
网站建设 2026/10/25 22:34:15

IIFE立即调用函数表达式:从语法解析到模块化实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华