遮挡行人重识别这个方向做过的人都知道它有多磨人。正常行人重识别已经够难了遮挡场景直接把难度拉满——一个人被车挡住半截、被广告牌切掉一条腿、被另一个行人叠在身后模型拿到的往往是一堆残缺不全的碎片。更麻烦的是遮挡位置随机、遮挡比例不定同一张图里可能同时出现几乎完整和只剩一个头两种极端情况。过去两年大家把希望寄托在时序聚合上尤其是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 整体架构整个模型分四步走骨干特征提取用CLIP图像编码器提取每帧的行人特征输出维度512。可见度估计用一个轻量分支预测每帧的可见度分数范围0到1。锚点构建CLIP文本编码器生成语义锚点可见度加权残差修正。重建与检索被遮挡帧特征向锚点重建重建后特征用于最终检索。这里有个细节骨干我选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.82.1Mamba时序聚合60.758.22.5锚点重建本方案68.866.310.6这个表格很能说明问题。Mamba相比平均池化只多了0.4个点说明它的序列建模能力在遮挡场景下几乎没发挥出来。而锚点重建直接拉开8个点以上的差距证明方向选对了比模块选强了更重要。4.2 锚点来源的消融锚点来源不同效果差异很大锚点来源mAP帧特征加权平均63.1可学习锚点库64.5CLIP文本锚点无修正66.2CLIP文本锚点残差修正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换成rucksackCLIP编码出来的锚点质量明显下降因为预训练语料里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点的提升与其说是某个模块的胜利不如说是问题定义方式的胜利。后续我打算把锚点重建和轻量时序聚合结合起来试试看看能不能在纠偏的基础上再吃一点融合的红利不过那是下一步的事了。
阅读完成 · 觉得有帮助?