遮挡行人重识别:锚点重建为何比Mamba时序聚合提升10.6个点

发布时间:2026/10/25 13:23:40
遮挡行人重识别:锚点重建为何比Mamba时序聚合提升10.6个点

遮挡行人重识别这个方向,做过的人都知道它有多磨人。正常行人重识别已经够难了,遮挡场景直接把难度拉满——一个人被车挡住半截、被广告牌切掉一条腿、被另一个行人叠在身后,模型拿到的往往是一堆残缺不全的碎片。更麻烦的是,遮挡位置随机、遮挡比例不定,同一张图里可能同时出现"几乎完整"和"只剩一个头"两种极端情况。过去两年,大家把希望寄托在时序聚合上,尤其是Mamba这类状态空间模型火起来之后,很多人觉得用Mamba把多帧信息串起来就能解决遮挡。但我实测下来,这条路在遮挡行人重识别上的收益远没有想象中大,真正把指标拉起来的是另一件事——锚点重建。这次我做的方案,在标准遮挡评测协议下比基线提升了10.6个点,核心改动不是换更强的时序模块,而是把"重建"这件事做对了。下面我把整个思路、踩过的坑、以及为什么锚点重建能赢过Mamba时序聚合,完整拆一遍。

1. 遮挡行人重识别的真实难点在哪里

1.1 遮挡不是"信息缺失"这么简单

很多人把遮挡理解成"某些像素被盖住了",然后想当然地认为只要把盖住的部分补回来就行。这个理解只对了一半。遮挡在行人重识别里真正致命的地方,是它破坏了身份判别性特征的分布。一个行人之所以能被认出来,靠的是若干关键判别区域——比如背包的肩带走向、鞋子的颜色和款式、裤子的侧条纹、上衣的logo位置。这些区域一旦被遮挡,模型不是"少看了一点",而是"看错了重点"。

我做过一个可视化实验:把同一张行人图分别做随机遮挡和固定区域遮挡,然后看模型注意力热力图。随机遮挡时,注意力会散到背景和相邻行人身上;固定遮挡时,注意力会死死盯住遮挡物边缘,把遮挡边界当成了判别特征。这两种情况都会导致检索时把不同的人判成同一个。所以遮挡问题的本质,是特征选择机制被带偏了,而不只是特征值缺失。

1.2 时序聚合为什么被寄予厚望

单帧解决不了,自然想到多帧。视频行人重识别里,同一个行人在不同帧的遮挡情况往往不同——这一帧被车挡了腿,下一帧车开走了腿就露出来了。理论上,只要把多帧信息聚合起来,就能互相补全。这就是时序聚合的核心逻辑。

Mamba之所以在这两年被大量引入,是因为它用选择性状态空间做序列建模,理论上能在线性复杂度下捕捉长程依赖,比Transformer的二次复杂度更省算力,又比RNN更能记住长序列。听起来完美契合"多帧互补"的需求。我一开始也是这么想的,于是搭了一个Mamba时序聚合模块,把每帧的特征当成序列输入,让状态空间去融合。

1.3 实测结果给时序聚合泼了冷水

搭完Mamba模块跑第一轮,结果很尴尬:相比单帧基线只涨了1.8个点,而且训练极不稳定,不同随机种子之间波动能到2个点以上。我一开始以为是超参没调好,于是做了网格搜索,学习率、状态维度、序列长度都试了一遍,最好也就涨到2.5个点。更奇怪的是,把Mamba换成最简单的平均池化,居然也有2.1个点。这说明什么?说明在这个任务里,时序聚合带来的增益主要来自"多帧平均降噪",而不是Mamba的序列建模能力。

这个发现很关键。它意味着Mamba那套选择性机制在遮挡场景下没有发挥出应有的作用。我后来分析原因,主要有两点:一是遮挡帧本身携带的噪声太大,状态空间在传播时会把噪声也一路带下去;二是行人序列里帧与帧之间的身份一致性很高,真正需要的是"挑出没被遮挡的帧",而不是"建模帧之间的复杂依赖"。Mamba擅长后者,但我们需要的是前者。

2. 锚点重建:把"补全"换成"对齐"

2.1 锚点重建的核心思想

既然时序聚合的增益有限,我就换了个思路:不去纠结怎么融合多帧,而是先定义一个"干净的身份锚点",然后让每一帧都向这个锚点对齐重建。所谓锚点,可以理解成这个行人的"标准照"——一个不受遮挡影响的、稳定的身份表征。重建的目标不是还原像素,而是让被遮挡帧的特征向锚点靠拢,把被遮挡带偏的特征拉回来。

这个思路和传统的图像修复有本质区别。图像修复是补像素,锚点重建是补特征。补像素需要生成模型,容易引入伪影;补特征只需要在特征空间做对齐,稳定得多。而且特征空间的对齐可以直接用度量学习来约束,不需要额外的生成器,训练也简单。

2.2 锚点从哪里来

这是整个方案最关键的问题。锚点不能凭空造,必须有依据。我试过三种来源:

第一种是用同一行人所有帧的特征做加权平均,权重由每帧的可见度估计决定。可见度高的帧权重大,可见度低的帧权重小。这个方案简单,但有个问题:如果整个序列里大部分帧都被遮挡,平均出来的锚点本身就是脏的。

第二种是用一个可学习的全局锚点库,每个身份对应一个锚点向量,训练时更新。这个方案稳定,但锚点库容量有限,身份多了会互相干扰。

第三种是我最终采用的:用CLIP的文本编码器生成身份语义锚点,再用图像特征做残差修正。具体来说,把行人的属性描述(比如"穿红色上衣、黑色裤子、背双肩包")通过CLIP文本编码器得到语义锚点,这个锚点天然不受遮挡影响,因为它来自文本模态。然后用可见度高的帧特征对它做残差修正,得到最终锚点。这样既有语义先验兜底,又能吸收图像细节。

2.3 重建损失怎么设计

锚点有了,接下来是让被遮挡帧向锚点重建。我用的损失由三部分组成:

  • 对齐损失:被遮挡帧特征与锚点的余弦距离,拉近两者。
  • 判别损失:标准的身份分类损失,保证重建后的特征仍然能区分不同身份。
  • 一致性损失:重建后的特征与同一帧在数据增强前后的特征保持一致,防止重建过程引入不稳定。

这三者的权重我调了很久,最终对齐损失权重0.5、判别损失1.0、一致性损失0.3效果最好。对齐损失权重太高会让所有帧特征趋同,丢失个体差异;太低则重建不起作用。

2.4 为什么锚点重建能赢过Mamba

回到那个核心问题:为什么锚点重建比Mamba时序聚合更有效?我的理解是,遮挡行人重识别的核心矛盾是"特征被带偏",而不是"信息不够用"。Mamba解决的是信息融合问题,它假设各帧信息是互补的、可信的,只需要融合。但遮挡帧的信息本身就是被污染的,融合污染信息只会让结果更糟。锚点重建解决的是特征纠偏问题,它先建立一个可信的参照,再把被污染的特征拉回来。方向对了,效果自然好。

打个比方:Mamba像是把几个人的证词拼在一起破案,但如果其中几个人在说谎,拼起来反而误导。锚点重建像是先确定一个可靠的事实基准,再拿每个人的证词去对照修正,说谎的证词会被拉回正轨。

3. 完整实现链路与关键参数

3.1 整体架构

整个模型分四步走:

  1. 骨干特征提取:用CLIP图像编码器提取每帧的行人特征,输出维度512。
  2. 可见度估计:用一个轻量分支预测每帧的可见度分数,范围0到1。
  3. 锚点构建:CLIP文本编码器生成语义锚点,可见度加权残差修正。
  4. 重建与检索:被遮挡帧特征向锚点重建,重建后特征用于最终检索。

这里有个细节:骨干我选CLIP而不是ResNet,是因为CLIP的图像-文本对齐预训练让它的特征本身就带有语义结构,和文本锚点的兼容性更好。实测下来,用CLIP骨干比ResNet50在遮挡协议上高3.2个点,这个差距在换锚点方案后依然存在。

3.2 可见度估计分支的实现

可见度估计是个辅助任务,但很关键,因为锚点修正和重建权重都依赖它。我的实现是一个两层MLP接在骨干特征后面,输出一个标量经过sigmoid。训练标签怎么来?我用的是遮挡掩码的可见像素比例作为监督信号。具体来说,合成遮挡数据时我们知道遮挡区域,直接算可见比例即可;真实遮挡数据没有掩码,我用一个预训练的语义分割模型粗略估计行人区域,再算可见比例。

这里踩过一个坑:一开始我用二分类(可见/不可见)做监督,结果可见度分数分布很极端,要么接近0要么接近1,中间值很少。后来改成回归可见比例,分布就平滑多了,重建效果也稳定了。

3.3 CLIP文本锚点的构建细节

文本锚点的质量直接决定上限。我的做法是给每个身份构造一段属性描述模板,比如"a photo of a person wearing [上衣颜色] [上衣类型], [裤子颜色] [裤子类型], carrying [配件]"。属性从数据集的标注里抽取,没有标注的用CLIP zero-shot预测补全。

这里有个经验:描述不要太长,控制在15个词以内。太长的描述会引入噪声属性,反而拉低锚点质量。我试过用完整句子描述,结果比短模板低了1.5个点。另外,属性顺序也有影响,把最稳定的属性(比如性别、体型)放前面,易变的属性(比如手里拿的东西)放后面,效果更好。

3.4 训练策略与参数配置

训练分两阶段:

第一阶段冻结CLIP骨干,只训练可见度分支和重建模块,学习率1e-3,训练20个epoch。这一步让重建模块先学会对齐,不被骨干的梯度干扰。

第二阶段解冻骨干最后两层,整体微调,学习率降到1e-4,再训练30个epoch。这里学习率一定要降,否则CLIP的预训练知识会被破坏。我试过不降学习率,结果掉了2.3个点。

批量大小设为64,每个身份采样4帧,保证一个batch里有足够的正样本对。优化器用AdamW,权重衰减0.05。整个训练在单张24G显存的卡上跑,大约需要8小时。

4. 实测对比与消融分析

4.1 与基线方法的对比

我在两个标准遮挡评测协议上做了对比,结果如下:

方法协议A mAP协议B mAP平均提升
单帧基线58.255.7-
平均池化时序60.357.8+2.1
Mamba时序聚合60.758.2+2.5
锚点重建(本方案)68.866.3+10.6

这个表格很能说明问题。Mamba相比平均池化只多了0.4个点,说明它的序列建模能力在遮挡场景下几乎没发挥出来。而锚点重建直接拉开8个点以上的差距,证明方向选对了比模块选强了更重要。

4.2 锚点来源的消融

锚点来源不同,效果差异很大:

锚点来源mAP
帧特征加权平均63.1
可学习锚点库64.5
CLIP文本锚点(无修正)66.2
CLIP文本锚点+残差修正68.8

可以看到,纯文本锚点已经比帧平均高3.1个点,说明语义先验确实抗遮挡。加上残差修正再涨2.6个点,说明图像细节的补充也很重要。两者缺一不可。

4.3 可见度估计的影响

去掉可见度估计分支,直接用等权平均构建锚点,mAP掉到65.4,降了3.4个点。这验证了可见度估计的必要性——它让锚点构建能自动压低被遮挡帧的贡献。

4.4 一个反直觉的发现

我原本以为重建模块越深越好,于是堆了一个6层的Transformer做重建。结果mAP反而掉了1.2个点。后来换成2层MLP,效果最好。分析原因是:重建任务本身不复杂,就是把特征往锚点方向拉,太深的网络容易过拟合训练集的遮挡模式,泛化到测试集反而差。这个坑提醒我,重建模块要轻,重了反而坏事。

5. 实操中的坑与经验

5.1 文本模板的坑

前面提到描述要短,这里再补充一个:模板里的属性词要用数据集里高频的词,不要用同义词替换。我试过把"backpack"换成"rucksack",CLIP编码出来的锚点质量明显下降,因为预训练语料里"backpack"更常见。这个细节很小,但影响不小。

5.2 训练不稳定的处理

第一阶段训练时,重建损失偶尔会突然飙升。排查后发现是某些batch里所有帧都被严重遮挡,锚点修正失效,导致对齐损失爆炸。解决办法是给对齐损失加一个可见度门控:当整个batch的平均可见度低于阈值0.3时,降低对齐损失权重。这个改动让训练曲线平滑了很多。

5.3 推理阶段的效率

锚点重建只在训练时需要,推理时锚点已经固化在模型参数里,不需要额外计算。所以推理速度和普通CLIP骨干模型一样,没有增加延迟。这点比Mamba方案好,Mamba推理时要跑序列,延迟明显更高。

5.4 跨数据集泛化的注意点

在一个数据集上训练的文本锚点,直接用到另一个数据集上会掉点,因为属性词分布不同。我的做法是目标数据集上先用CLIP zero-shot重新生成属性描述,再微调10个epoch,就能恢复到接近原数据集的水平。

6. 这套方案适合什么场景

锚点重建这套思路,最适合的是遮挡比例高、遮挡位置随机、且有一定语义标注或可生成语义描述的场景。如果你的数据里遮挡很少,那时序聚合可能更划算,毕竟实现简单。如果你的数据完全没有属性信息,那CLIP文本锚点就用不了,得退回到可学习锚点库方案,效果会打折扣但依然比纯时序聚合好。

另外,这套方案对骨干的依赖没有Mamba那么强。我用ResNet50替换CLIP做骨干,锚点重建依然能涨7.8个点,只是绝对值低一些。这说明锚点重建的增益主要来自重建机制本身,而不是骨干的强弱。这一点对算力有限的团队很友好——你不需要最贵的骨干,也能拿到可观的提升。

我个人在实际操作中的体会是,遮挡行人重识别这个方向,过去两年大家有点被"更强的序列模型"带偏了。Mamba、Transformer这些模块确实强,但它们解决的是信息融合问题,而遮挡的核心矛盾是特征纠偏。把问题定义对了,哪怕用最简单的MLP做重建,效果也比堆复杂模块好。这个10.6点的提升,与其说是某个模块的胜利,不如说是问题定义方式的胜利。后续我打算把锚点重建和轻量时序聚合结合起来试试,看看能不能在纠偏的基础上再吃一点融合的红利,不过那是下一步的事了。