
1. 跨模态行人重识别的问题本质与方案定位跨模态行人重识别Cross-Modality Person Re-identification业内常简称为跨模态 ReID要解决的核心问题很具体同一名行人在可见光摄像头下被拍到一次又在红外摄像头下被拍到一次系统需要判断这两张图是不是同一个人。这个任务在学术上通常写作 VI-ReIDVisible-Infrared ReID是智能安防、夜间监控、多摄像头轨迹串联等场景里绕不开的一环。为什么它比普通 ReID 难普通 ReID 是可见光对可见光图像的颜色、纹理、光照分布基本一致模型主要解决姿态、视角、遮挡带来的差异。而跨模态 ReID 面对的是两种物理成像机制完全不同的图像可见光图有 RGB 三通道携带丰富的颜色和纹理信息红外图通常是单通道灰度图靠热辐射成像没有颜色纹理也弱得多。同一个人的可见光图和红外图在像素层面几乎找不到直接对应关系。模型如果只学看起来像不像很容易被模态差异带偏——它可能把两张红外图判为同一人因为都是灰的而把同一人的可见光和红外图判为不同人。这篇工作AAAI 2020 的Attend to the Difference: Cross-Modality Person Re-identification via Contrastive的切入点很有意思它不去强行消除模态差异而是主动去关注差异用对比学习的思路把模态间的差异信息变成有用的监督信号。这个思路在当年是比较新颖的因为主流做法要么是共享权重强行对齐要么是生成式方法把一种模态转成另一种模态。我先把这篇工作的整体定位讲清楚方便你判断它值不值得复现、适不适合迁移到自己的项目里。1.1 跨模态 ReID 的三大核心痛点在展开方案之前得先把痛点摆明白否则后面讲为什么这么设计就没有落脚点。痛点一模态鸿沟Modality Gap。可见光和红外是两种成像物理过程前者依赖反射光后者依赖热辐射。这导致同一目标在两种模态下的特征分布差异极大。用生活化的类比这就像同一个人一张是彩色照片一张是热成像仪拍的黑白图你要判断这俩是不是同一个人靠肉眼都得费点劲更别说让模型自动学了。痛点二类内差异Intra-class Variation。同一个人在不同摄像头、不同姿态、不同时间下的外观本来就有差异跨模态又叠加了一层模态差异导致同一人的跨模态样本之间的距离可能比不同人的同模态样本还大。这是 ReID 的经典难题跨模态场景下被放大。痛点三标注数据稀缺。跨模态 ReID 的数据集规模远小于普通 ReID。常用的 SYSU-MM01、RegDB 这类数据集身份数和图像数都有限模型很容易过拟合。这就要求算法在有限数据下尽可能高效地利用监督信号。这篇工作的价值就在于它用一个对比学习框架同时缓解了前两个痛点而且没有引入额外的生成网络训练成本相对可控。1.2 为什么选对比学习 注意力这条路线当年跨模态 ReID 的主流路线大致有三类路线代表思路优点局限共享权重对齐两种模态共用主干靠损失函数拉近结构简单强行共享会损失模态特有信息生成式转换把红外转可见光或反之直观生成质量难保证训练不稳定对比学习拉近正样本、推远负样本监督信号强需要精心设计正负样本这篇工作选的是第三条路并且做了一个关键改造不是简单地拉近跨模态正样本而是显式地建模差异。它的核心洞察是——如果模型只学把正样本拉近那它学到的可能是忽略模态信息而不是理解模态对应关系。而如果让模型去attend to the difference即关注那些真正区分身份的特征、忽略模态本身带来的干扰效果会更好。这个思路和后来大火的对比学习框架比如 SimCLR、MoCo 那一脉在精神上是相通的但这篇工作更早地把对比学习用在了跨模态 ReID 上并且结合了注意力机制。这也是它被 AAAI 收录的原因之一。1.3 适合谁来参考这篇内容如果你是以下几类人这篇内容对你会有直接帮助正在做跨模态检索、跨模态 ReID 相关课题的研究生或工程师需要理解对比学习在跨模态场景下的落地方式想复现 AAAI 2020 这篇工作但被论文里的公式和模块绕晕需要一份人话版拆解做智能安防、夜间监控系统需要把可见光和红外摄像头的数据打通做行人轨迹串联对对比学习感兴趣想看看它在视觉检索任务里除了自监督还能怎么用。需要说明的是下面涉及的具体实现细节论文里有明确给出的我会标注论文没细说但工程上必须补的我会基于常见实践给出合理方案并明确说明这是补充。2. 核心思路拆解对比学习如何关注差异这一节是全文的重点。我尽量把论文的核心机制讲透同时补上论文里一笔带过、但复现时一定会卡住的细节。2.1 整体框架双流主干 对比头这篇工作的整体结构可以概括为双流主干 对比学习头 注意力差异建模。具体来说双流主干可见光图像和红外图像分别送入主干网络。论文里用的是 ResNet-50 这类经典骨干两种模态可以共享部分底层权重也可以完全独立。共享底层是常见做法因为底层提取的是边缘、纹理这类通用特征模态差异主要体现在高层语义。特征嵌入主干输出经过全局池化得到特征向量再经过一个嵌入头embedding head映射到对比学习用的特征空间。对比学习头这是核心。它不只做正样本拉近、负样本推远而是引入了差异注意力机制让模型显式地去区分哪些差异是身份差异哪些差异是模态差异。这里有个关键设计点值得展开为什么要有独立的嵌入头因为对比学习对特征空间的度量很敏感如果直接在分类特征上做对比分类损失和对比损失会互相干扰。加一个专门的投影头projection head让对比学习在另一个子空间里进行是后来被广泛验证有效的做法。论文里虽然没有用projection head这个后来流行的叫法但结构上是类似的。2.2 Attend to the Difference到底在关注什么标题里的 Attend to the Difference 是整个方法的名字来源也是最容易被误解的地方。很多人第一反应是注意力机制关注差异区域但实际含义更微妙。我的理解是它让模型在对比学习的过程中主动去识别并利用模态间的差异而不是被动地消除差异。具体怎么实现论文的思路大致是对同一身份的可见光图和红外图分别提取特征计算两者之间的差异表示difference representation用注意力机制对这个差异表示加权突出那些对身份判别有用的差异维度抑制那些纯粹由模态造成的差异维度把这个加权后的差异表示纳入对比学习的监督中。打个比方你要判断两张照片是不是同一个人一张彩色一张黑白。如果你盯着颜色这个维度看那肯定判不出来因为一个是彩的一个是黑白的。但如果你把注意力放在脸型、身高比例、体型轮廓这些跨模态稳定的维度上就能判出来。Attend to the Difference 做的就是这件事——它让模型学会在差异中挑出有用的部分。注意这里的差异不是指两张图逐像素相减而是在特征空间里的差异。逐像素相减对跨模态毫无意义因为两种模态的像素根本不在一个语义空间里。2.3 对比学习的正负样本怎么构造对比学习的效果很大程度上取决于正负样本怎么选。在跨模态 ReID 里正负样本的构造比自监督对比学习更直接因为有身份标签。常见的构造方式正样本对同一身份、不同模态的样本可见光 vs 红外这是跨模态对比的核心负样本对不同身份的样本可以是同模态也可以是跨模态难负样本和锚点身份不同但特征很接近的样本这类样本对训练最有价值。论文里应该也用了类似难样本挖掘hard mining的策略因为跨模态 ReID 的数据集里随机采样的负样本往往太容易模型学不到东西。这一点在复现时非常关键——如果你不做难样本挖掘对比学习的收益会大打折扣。我实测下来的经验是跨模态场景下跨模态负样本可见光 vs 红外不同身份比同模态负样本更有价值因为它们直接逼迫模型去区分模态差异和身份差异。如果只用同模态负样本模型可能学到的还是模态内判别跨模态泛化能力上不去。2.4 损失函数的设计逻辑对比学习常用的损失是 InfoNCE 那一类核心思想是对于一个锚点正样本的相似度要尽可能高负样本的相似度要尽可能低用 softmax 归一化后取负对数。在跨模态 ReID 里损失函数通常是对比损失 身份分类损失的组合。为什么还要加分类损失因为对比学习只约束了样本间的相对距离没有直接约束这个特征能不能分类。加上 ID loss交叉熵能让特征在身份维度上更可分两者互补。论文里可能还引入了模态对齐损失或者差异正则项用来约束差异表示不要退化成噪声。这部分如果论文没细说复现时可以先用对比损失 ID 损失的基线再逐步加模块观察每一步的增益。3. 实操复现从数据准备到训练调参这一节我按实际复现的顺序来讲尽量给出可以直接抄的参数和步骤。需要提前说明论文里的具体超参我无法逐一对齐下面给出的是基于跨模态 ReID 常见实践的一套可跑通配置你可以在此基础上微调。3.1 数据集准备与预处理跨模态 ReID 最常用的两个公开数据集是 SYSU-MM01 和 RegDB。它们都包含可见光和红外两种模态的图像且标注了身份 ID。SYSU-MM01的规模更大包含 6 个摄像头4 个可见光、2 个红外训练集有 395 个身份测试集有 96 个身份。它的评估协议分 All-Search 和 Indoor-Search 两种前者用全部可见光图做 gallery后者只用室内的。RegDB规模小一些包含 412 个身份每个身份有 10 张可见光 10 张红外图。它的评估通常做多次随机划分取平均。预处理方面常规做法是图像统一 resize 到 288×144 或 256×128ReID 常用的长宽比是 2:1因为行人通常是竖长的随机水平翻转、随机裁剪做数据增强归一化用 ImageNet 的均值和方差即使红外是单通道也复制成三通道以适配预训练主干。提示红外图复制成三通道是个常见 trick。因为主干通常是在 ImageNet 上预训练的输入要求三通道。直接复制比改成单通道输入更省事实测效果也不差。3.2 主干网络与嵌入头配置主干用 ResNet-50 是最稳的选择预训练权重用 ImageNet 的。去掉最后的全连接层保留到 global average pooling 那一层输出 2048 维特征。嵌入头我建议这样设计import torch.nn as nn class EmbeddingHead(nn.Module): def __init__(self, in_dim2048, feat_dim512, num_classes395): super().__init__() self.fc nn.Linear(in_dim, feat_dim) self.bn nn.BatchNorm1d(feat_dim) self.classifier nn.Linear(feat_dim, num_classes) def forward(self, x): feat self.bn(self.fc(x)) logits self.classifier(feat) return feat, logits这里 feat_dim 设 512 是常见选择太小会损失信息太大对比学习不好收敛。BatchNorm 放在嵌入后很关键它能让特征分布更稳定对比学习对分布很敏感。3.3 对比损失的具体实现对比损失的核心是构造相似度矩阵。假设一个 batch 里有 B 个可见光样本和 B 个红外样本共 2B 个样本我们计算 2B×2B 的相似度矩阵然后对每个锚点把同身份跨模态的样本作为正样本其余作为负样本。import torch import torch.nn.functional as F def contrastive_loss(feats, labels, temperature0.07): # feats: [2B, D], labels: [2B] feats F.normalize(feats, dim1) sim feats feats.t() / temperature # 构造正样本掩码同身份且不同样本 mask (labels.unsqueeze(0) labels.unsqueeze(1)).float() mask.fill_diagonal_(0) # 数值稳定处理 sim sim - sim.max(dim1, keepdimTrue)[0].detach() exp_sim torch.exp(sim) log_prob sim - torch.log(exp_sim.sum(dim1, keepdimTrue)) # 只对正样本求平均 pos_count mask.sum(dim1).clamp(min1) loss -(mask * log_prob).sum(dim1) / pos_count return loss.mean()温度系数 temperature 设 0.07 是 SimCLR 那一脉的经验值跨模态场景下可以试 0.05 到 0.1。温度越低模型对难负样本越敏感但太低会导致训练不稳定。3.4 训练参数与调参经验下面这套参数是我在类似任务上跑通过的配置供参考参数建议值说明优化器Adam对比学习用 Adam 比 SGD 稳初始学习率3.5e-4主干和嵌入头可以设不同 lr权重衰减5e-4防止过拟合Batch size6432 可见光 32 红外太小对比学习负样本不够训练轮数60-120看数据集规模学习率调度余弦退火或 warmup stepwarmup 对对比学习很重要温度系数0.07可微调调参上有几个坑我踩过坑一batch size 太小。对比学习依赖足够多的负样本如果 batch 只有 16负样本太少模型学不到判别性特征。建议至少 64显存不够就用梯度累积。坑二学习率太大导致崩溃。对比学习初期如果学习率太大特征空间会剧烈震荡损失直接 NaN。用 warmup 前几个 epoch 慢慢升上去能显著提升稳定性。坑三忽略模态平衡采样。如果每个 batch 里可见光和红外数量不均衡对比学习的正样本对会偏少。建议每个 batch 严格保证两种模态各占一半。4. 常见问题排查与避坑实录复现这类工作最耗时间的往往不是写模型而是排查各种训练不收敛指标上不去的问题。这一节我把常见问题和排查思路整理成速查表再补充几个独家经验。4.1 训练不收敛的排查顺序遇到 loss 不降或者震荡按这个顺序查先看数据确认可见光和红外的标签对齐是否正确。跨模态数据集里同一身份的两种模态图像必须共享同一个 ID如果标签错位模型永远学不对。再看学习率把 lr 调小 10 倍试试如果 loss 开始降说明是 lr 太大。然后看归一化对比学习前必须对特征做 L2 归一化否则相似度会被特征模长主导。最后看温度系数温度太低会导致梯度爆炸先调到 0.1 试试。4.2 指标上不去的典型原因现象可能原因解决方向mAP 低但 Rank-1 还行特征区分度不够加强难样本挖掘Rank-1 和 mAP 都低跨模态对齐没学好检查对比损失的正样本构造训练集指标高、测试集低过拟合加数据增强、加权重衰减红外模态指标明显差模态不平衡调整采样比例给红外更多权重4.3 几个容易被忽略的实操细节细节一评估协议要对齐。SYSU-MM01 的 All-Search 和 Indoor-Search 结果差异很大论文里报的是哪个协议你复现时就要用哪个否则没法对比。很多人复现指标对不上就是因为评估协议搞错了。细节二随机种子的影响。跨模态 ReID 数据集不大随机种子对结果影响可能有 1-2 个点。建议跑 3 次取平均别拿单次结果下结论。细节三预训练权重的选择。主干用 ImageNet 预训练权重是标配但如果你能在更大规模的 ReID 数据上预训练效果会更好。不过要注意预训练数据的模态要和目标任务匹配纯可见光预训练对红外分支的帮助有限。细节四注意力的可视化验证。Attend to the Difference 这个模块到底有没有在关注有用的差异最好可视化验证一下。如果注意力图集中在背景或者模态伪影上说明模块没学到东西需要调整监督信号。提示复现论文时先跑通一个去掉核心模块的基线再逐步加模块观察每一步的增益。这样既能验证模块有效性也能在指标异常时快速定位问题。直接上完整模型出问题很难排查。5. 这套思路的延展与迁移价值这篇工作的价值不局限于跨模态 ReID 本身。它提出的关注差异而非消除差异的思路在很多跨域任务里都能迁移。比如跨域检索、跨模态图文匹配、多传感器融合感知本质上都面临不同来源的数据分布不一致的问题。传统做法是强行对齐但这篇工作提示我们差异本身可能携带判别信息关键是学会区分有用的差异和干扰的差异。从工程角度看这套框架的训练成本可控不需要生成网络也不需要复杂的对抗训练落地门槛相对低。如果你手头有可见光和红外的监控数据想做一个行人轨迹串联的原型系统这篇工作的思路是可以直接借鉴的。我个人在实际操作中的体会是跨模态任务里最难的从来不是模型结构而是数据质量和评估协议。模型再花哨如果数据标签有噪声、评估协议不统一结果都是空中楼阁。所以复现这类工作时我建议先把数据管线打磨扎实再动模型。另外对比学习虽然香但它对 batch size 和训练稳定性的要求比普通分类高得多显存和时间预算要提前算好别做到一半发现跑不动。最后分享一个小技巧如果你显存有限跑不了大 batch可以用动量编码器 队列的思路类似 MoCo 那一套来扩大负样本池这样即使 batch 只有 32也能有几千个负样本参与对比。这个改动不大但在跨模态场景下往往能带来明显提升。