1. 跨模态行人重识别的问题背景与核心挑战
跨模态行人重识别(Cross-modality Person Re-identification)要解决的问题,说白了就是:用可见光摄像头拍到的某个人,去红外摄像头拍摄的图库里把人找出来。这个任务在实际安防场景中非常常见——白天光线好,可见光相机工作;到了夜间或者光线极差的环境,红外相机顶上。两套系统各拍各的,但最终需要统一检索。
这件事听起来简单,做起来极其困难。核心矛盾在于:可见光图像有三个通道(RGB),携带丰富的颜色和纹理信息;红外图像只有一个通道,反映的是热辐射分布。同一个人的可见光图和红外图,在像素层面几乎找不到直接对应关系。你没法像传统行人重识别那样,简单地比较两张图的颜色直方图或者纹理特征,因为模态之间的鸿沟是本质性的。
我刚开始接触这个方向的时候,第一反应是“那直接用一个网络把两种图都映射到同一个空间不就行了”。确实,早期的方法就是这么干的,用一个共享权重的骨干网络提取特征,然后加一个模态分类器做对抗训练,逼着网络学出模态无关的表示。但实测下来,这种做法有一个致命缺陷:过度追求模态对齐,反而把每个模态独有的判别信息给丢掉了。可见光图像里衣服的颜色、图案,红外图像里人体不同部位的热辐射差异,这些信息对于区分不同行人是很有价值的,强行对齐等于自废武功。
这就引出了今天要拆解的这篇工作——Shared-Specific Feature Transfer(共享-特有特征迁移)。它的核心思路非常清晰:不要强行把两个模态揉成一模一样,而是把特征拆成“共享部分”和“特有部分”,共享部分负责跨模态对齐,特有部分负责保留各自模态的判别力,然后通过迁移机制让特有特征也能跨模态互补。这个思路在逻辑上很自洽,而且实现起来也不算复杂,是我个人比较欣赏的一类方案。
这篇文章适合谁看?如果你正在做多模态检索、跨域适应相关的工作,或者对特征解耦、对抗迁移这些技术感兴趣,这篇论文的思路会给你不少启发。即使你不做行人重识别,这种“共享-特有”的分解思想在很多跨模态任务里都能迁移使用。下面我会从整体设计、核心模块、实操细节、常见问题几个维度,把这篇论文的技术方案彻底拆开讲清楚。
2. 论文整体设计与思路拆解
2.1 为什么选择“共享-特有”分解而不是端到端对齐
传统跨模态行人重识别方法大致分两类。一类是特征级对齐,比如用对抗训练让特征提取器输出的特征无法被模态判别器区分,从而学出模态无关表示。另一类是像素级对齐,比如用生成模型把红外图转成可见光图,或者反过来,在图像空间做统一。这两类方法各有各的问题。
特征级对齐的问题前面说了,容易丢失模态特有信息。像素级对齐的问题更严重:生成模型本身会引入噪声和伪影,而且转换过程不可控,生成出来的图像可能偏离真实分布,导致后续识别性能不稳定。我试过用CycleGAN做红外转可见光,生成出来的图乍一看还行,但细节全是糊的,用来训练识别模型反而拖后腿。
Shared-Specific Feature Transfer(后面简称SSFT)选择了一条中间路线:不生成图像,也不强行对齐所有特征,而是在特征空间做精细化的分解和迁移。具体来说,它把每个模态的特征拆成两部分:
- 共享特征(Shared Feature):两个模态共有的、与模态无关的行人身份信息。比如人的体型、姿态、大致轮廓,这些在可见光和红外图里都能提取到。
- 特有特征(Specific Feature):每个模态独有的、携带丰富判别信息的部分。可见光特有特征包含颜色、衣物纹理;红外特有特征包含热辐射分布模式。
拆开之后,共享特征直接做跨模态对齐,这部分没什么争议。关键在于特有特征怎么处理——如果只是简单丢弃,那就退化成普通共享特征方法了;如果保留但不对齐,那跨模态检索时特有特征没法用。SSFT的解法是:通过迁移机制,让一个模态的特有特征去补充另一个模态的共享特征。换句话说,可见光特有特征里的颜色信息,迁移到红外分支上,帮助红外特征获得更强的判别力;反过来,红外特有特征里的热辐射模式,迁移到可见光分支上,增强可见光特征的鲁棒性。
这个设计的精妙之处在于:它没有试图消除模态差异,而是把差异变成了互补信息。你可以这样理解——两个人合作解题,一个擅长代数,一个擅长几何,你不需要让他们变成同一个人,而是让他们互相教对方自己擅长的部分,最终两个人都变得更强。
2.2 整体架构与数据流
SSFT的整体架构可以分成四个主要模块:
- 双流特征提取器:可见光分支和红外分支各用一个骨干网络(论文里用的是ResNet-50去掉最后的全连接层),分别提取各自模态的特征图。
- 特征分解模块:把每个分支的特征图拆成共享特征和特有特征。具体实现上,论文用了两组卷积层分别提取共享和特有特征,然后通过正交性约束和对抗训练来保证分解的纯度。
- 特征迁移模块:这是论文的核心创新点。它把可见光特有特征迁移到红外分支,把红外特有特征迁移到可见光分支,迁移的方式是通过注意力机制和特征融合。
- 识别与对齐模块:最终的特征用于行人身份分类,同时共享特征部分施加跨模态对齐损失。
数据流是这样的:一张可见光图和一张红外图分别送入各自的分支,经过骨干网络得到特征图,然后每个特征图被分解成共享和特有两部分。共享特征直接用于跨模态对齐损失计算。特有特征则进入迁移模块,与另一个模态的共享特征做融合。融合后的特征再用于身份分类损失。整个网络端到端训练,所有损失联合优化。
这里有一个细节值得注意:迁移模块的输入是“本模态特有特征 + 另一模态共享特征”,输出是增强后的特征。也就是说,可见光特有特征和红外共享特征融合,得到增强的红外特征;红外特有特征和可见光共享特征融合,得到增强的可见光特征。这种交叉融合的方式确保了每个模态都能从另一个模态的特有信息中受益。
2.3 损失函数设计与训练策略
SSFT的损失函数由四部分组成:
- 身份分类损失(ID Loss):标准的交叉熵损失,作用在最终融合特征上,确保特征具有身份判别力。
- 共享特征对齐损失:作用在两个模态的共享特征上,用的是对比损失或者三元组损失,拉近同一行人跨模态共享特征的距离,推远不同行人的距离。
- 特有特征正交损失:约束同一模态内共享特征和特有特征正交,防止两者信息冗余。论文里用的是特征向量之间的余弦相似度作为惩罚项。
- 模态对抗损失:在共享特征上施加模态判别器,通过对抗训练进一步消除共享特征中的模态信息。
训练策略上,论文采用了交替训练的方式:先固定模态判别器,更新特征提取器和分解模块;然后固定特征提取器,更新模态判别器。这种交替训练在对抗学习中很常见,目的是防止判别器过早收敛导致梯度消失。
学习率方面,初始学习率设为0.0002,每30个epoch衰减为原来的0.1倍。Batch size用的是64,其中可见光和红外各32张,确保每个batch里两种模态的样本数量均衡。这个均衡很重要——如果某个模态样本太少,对抗训练会不稳定,共享特征会偏向样本多的模态。
3. 核心细节解析与实操要点
3.1 特征分解模块的实现细节
特征分解是SSFT的基础,如果分解不干净,后面的迁移和对齐都是空中楼阁。论文里的分解模块结构并不复杂:在骨干网络输出的特征图后面接两个并行的卷积块,一个输出共享特征,一个输出特有特征。每个卷积块包含一个1x1卷积降维、一个3x3卷积、BN层和ReLU激活。
但关键在于如何保证分解的有效性。论文用了三个约束:
第一,正交性约束。同一模态内,共享特征和特有特征在通道维度上做全局平均池化后得到两个向量,计算这两个向量的余弦相似度,希望它接近0。这意味着两组特征在方向上尽量垂直,携带的信息不重叠。
第二,对抗约束。共享特征送入一个模态判别器,判别器试图区分这个特征来自可见光还是红外。特征提取器则试图骗过判别器。这个对抗过程迫使共享特征去除模态信息。
第三,重构约束(论文里叫“特征重构”)。共享特征和特有特征拼接后,经过一个解码器重构原始特征图。这个约束确保分解没有丢失重要信息——如果分解后两部分加起来还原不出原来的特征,说明分解过程有信息损失。
我在复现这个模块的时候踩过一个坑:正交性约束的权重不能设太大。一开始我把正交损失权重设成1.0,结果网络为了满足正交性,把特有特征学成了全零,因为零向量和任何向量都正交。后来把权重降到0.1,分解才正常。这个经验说明,正交约束是“软约束”,目的是引导而不是强制,权重需要仔细调。
3.2 特征迁移模块的注意力机制
特征迁移模块是SSFT最核心的部分。它的输入是源模态的特有特征和目标模态的共享特征,输出是增强后的目标模态特征。论文里用的迁移方式是基于通道注意力的特征融合。
具体操作是这样的:假设我们要把可见光特有特征迁移到红外分支。首先,可见光特有特征经过一个全局平均池化得到通道描述向量,然后通过两个全连接层(中间有ReLU)生成通道注意力权重。这个权重向量再与红外共享特征做逐通道相乘,得到加权后的红外共享特征。最后,加权后的特征与原始红外共享特征做残差连接,得到增强特征。
这个设计的逻辑是:可见光特有特征里的每个通道代表某种颜色或纹理模式,注意力机制学习这些模式对红外特征哪些通道最有补充价值。比如可见光特有特征里某个通道对红色敏感,而红外共享特征里某个通道对应人体上半身区域,注意力机制可能会让这两个通道产生强关联,从而把颜色信息注入到红外特征的上半身区域。
这里有一个实操要点:注意力模块的全连接层降维比例(reduction ratio)建议设为16。这是SENet里的经典设置,在SSFT里也适用。降维比例太小(比如4),注意力模块参数太多,容易过拟合;降维比例太大(比如32),注意力权重太粗糙,迁移效果不明显。我试过8和16,16的效果略好,但差距不大,8也能用。
另一个细节是残差连接的缩放系数。论文里没有明确说,但我在复现时发现,如果直接把加权特征和原始特征相加,训练初期不稳定。后来加了一个可学习的缩放系数(初始化为0.1),训练就平稳多了。这个技巧在很多注意力模块里都通用——让网络自己学习注意力的强度,而不是强制全量注入。
3.3 跨模态对齐损失的选择与调参
共享特征的对齐损失直接决定了跨模态检索的性能。论文里对比了两种损失:对比损失(Contrastive Loss)和三元组损失(Triplet Loss)。最终论文用的是改进版的三元组损失,具体来说是跨模态三元组损失。
跨模态三元组损失的构造方式是:锚点(Anchor)选可见光图像,正样本(Positive)选同一行人的红外图像,负样本(Negative)选不同行人的红外图像。这样构造的三元组强制网络拉近跨模态正样本对,推远跨模态负样本对。论文里还加了模态内三元组损失作为辅助,即锚点、正样本、负样本都来自同一模态,确保模态内的判别力不退化。
三元组损失的margin参数很关键。论文里设的是0.3。我试过0.1、0.3、0.5三个值,0.1太小,正负样本对的距离差不够明显,检索时容易混淆;0.5太大,训练后期loss降不下去,模型欠拟合。0.3是比较平衡的选择。当然这个值和数据集有关,如果数据集里行人外观差异大,可以适当增大margin;如果差异小,可以减小。
还有一个容易被忽略的点:三元组采样策略。如果随机采样,大部分三元组都是“简单样本”(正样本对本来就很近,负样本对本来就很远),这些样本对梯度贡献很小,训练效率低。论文里用了难样本挖掘(Hard Mining),在每个batch里选择距离最远的正样本对和距离最近的负样本对。这个策略能显著加速收敛,但也容易导致训练不稳定,因为难样本可能标注有噪声。我的经验是:前10个epoch用随机采样预热,之后切换到难样本挖掘,这样既稳定又高效。
4. 实操过程与核心环节实现
4.1 数据准备与预处理
跨模态行人重识别常用的数据集是SYSU-MM01和RegDB。这两个数据集都包含可见光和红外图像,且行人ID有重叠。数据准备阶段有几个关键点:
图像尺寸统一。论文里把图像resize到288x144。这个尺寸是行人重识别的经典设置,宽高比2:1,符合人体站立姿态。如果resize到224x224,会引入大量背景噪声,因为行人图像通常上下长、左右窄,强行正方形化会把背景拉进来。
数据增强。训练时用了随机水平翻转、随机裁剪(padding=10)、随机擦除(Random Erasing)。随机擦除对跨模态任务特别有用,因为它模拟了遮挡场景,而红外图像中人体不同部位的热辐射差异本身就类似于一种“自然遮挡”。测试时只用中心裁剪,不做增强。
模态平衡采样。每个batch里可见光和红外样本各占一半,且每个行人的可见光图和红外图都要出现。具体实现上,可以用一个自定义的Sampler,确保每个batch包含P个行人,每个行人有K张可见光图和K张红外图。论文里P=8,K=4,batch size=64。
这里有一个坑:SYSU-MM01数据集里有些行人只有可见光图没有红外图,或者反过来。这些样本在训练时要过滤掉,否则三元组损失没法构造。我在第一次跑实验时没注意,结果训练loss一直是nan,排查了半天才发现是数据里混入了单模态样本。
4.2 网络搭建与关键代码逻辑
骨干网络用的是ResNet-50,但做了两处修改:第一,去掉最后的全连接层和全局平均池化,保留7x7的特征图;第二,把第一个7x7卷积改成3x3卷积,并且去掉最大池化层。这样修改是为了保留更多的空间信息,因为行人重识别对空间位置比较敏感。
特征分解模块的代码逻辑大致如下:
class FeatureDisentangle(nn.Module): def __init__(self, in_channels, mid_channels, out_channels): super().__init__() self.shared_conv = nn.Sequential( nn.Conv2d(in_channels, mid_channels, 1), nn.BatchNorm2d(mid_channels), nn.ReLU(), nn.Conv2d(mid_channels, out_channels, 3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU() ) self.specific_conv = nn.Sequential( nn.Conv2d(in_channels, mid_channels, 1), nn.BatchNorm2d(mid_channels), nn.ReLU(), nn.Conv2d(mid_channels, out_channels, 3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU() ) def forward(self, x): shared = self.shared_conv(x) specific = self.specific_conv(x) return shared, specific迁移模块的代码逻辑:
class FeatureTransfer(nn.Module): def __init__(self, channels, reduction=16): super().__init__() self.avg_pool = nn.AdaptiveAvgPool2d(1) self.fc = nn.Sequential( nn.Linear(channels, channels // reduction), nn.ReLU(), nn.Linear(channels // reduction, channels), nn.Sigmoid() ) self.scale = nn.Parameter(torch.tensor(0.1)) def forward(self, specific, shared): b, c, _, _ = specific.size() weight = self.avg_pool(specific).view(b, c) weight = self.fc(weight).view(b, c, 1, 1) enhanced = shared + self.scale * shared * weight return enhanced训练循环里,每个batch要计算四个损失,然后加权求和。权重方面,论文里ID损失权重1.0,三元组损失权重1.0,正交损失权重0.1,对抗损失权重0.1。这个权重组合是我试过比较稳的,如果正交损失权重超过0.5,训练会崩。
4.3 训练过程监控与调参记录
训练过程中需要重点监控几个指标:
- ID损失:应该稳步下降,如果震荡剧烈,说明学习率太大或者batch size太小。
- 三元组损失:前期下降快,后期趋于平缓。如果一直不降,检查三元组采样是否合理。
- 模态判别器准确率:应该维持在0.5到0.7之间。如果接近1.0,说明判别器太强,共享特征没学好;如果接近0.5,说明对抗训练过头了,共享特征可能丢失了太多信息。
- 验证集mAP:每5个epoch测一次,观察是否过拟合。
我在训练时遇到过一个典型问题:前20个epoch一切正常,到第25个epoch左右,模态判别器准确率突然飙到0.95,然后ID损失开始上升。排查后发现是判别器的学习率没有单独设置,和主网络用了一样的学习率。判别器收敛太快,导致对抗训练失衡。解决方案是把判别器的学习率设为主网络的0.1倍,这样判别器更新慢,对抗更稳定。
另一个调参经验:共享特征的维度不宜太大。论文里共享特征和特有特征的通道数都是1024。我试过2048,结果共享特征里混入了太多模态信息,对抗训练压不住。1024是比较合适的,既能保留足够信息,又不会让对抗训练太难。
5. 常见问题与排查技巧实录
5.1 模态判别器不收敛或过度收敛
这是对抗训练里最常见的问题。表现有两种:一种是判别器loss一直不降,准确率在0.5左右徘徊;另一种是判别器准确率迅速上升到0.9以上,然后主网络性能崩掉。
第一种情况通常是判别器太弱。解决方案是增加判别器的层数或者通道数。论文里的判别器是三层全连接,中间有ReLU,输出二分类。如果判别器太弱,可以加到四层,或者把隐藏层维度从512增加到1024。
第二种情况是判别器太强。解决方案有三个:降低判别器学习率、增加判别器输入的噪声、或者用标签平滑(Label Smoothing)。我一般先用降低学习率,如果还不行就加噪声。噪声的方差设为0.1效果比较好,太大反而会干扰共享特征的学习。
还有一个技巧是梯度反转层(Gradient Reversal Layer)。与其单独训练判别器,不如在特征提取器和判别器之间加一个梯度反转层,这样一次反向传播就能同时更新两边。梯度反转层的系数从0逐渐增加到1,可以让训练更平滑。这个技巧在域适应领域很成熟,搬到跨模态任务里同样有效。
5.2 特征分解后特有特征信息量不足
如果分解后的特有特征几乎不携带判别信息,说明正交约束太强或者共享特征“抢”了太多信息。表现是:去掉特有特征后,识别性能几乎不变。
排查方法是分别用共享特征和特有特征做检索,看两者的mAP差距。正常情况下,共享特征的mAP应该比特有特征高一些(因为共享特征是对齐过的),但特有特征的mAP也不应该太低,至少要有共享特征的70%左右。如果特有特征mAP只有共享特征的一半不到,说明分解有问题。
解决方案:降低正交损失权重,或者给特有特征加一个辅助的分类损失,强制它保留身份信息。我在复现时给特有特征加了一个额外的ID损失(权重0.5),特有特征的判别力明显提升。
5.3 跨模态检索时模态偏差问题
即使训练时共享特征对齐得很好,测试时仍然可能出现模态偏差:用可见光图查红外库时,返回的结果大部分是可见光图(如果库里有可见光图的话),或者反过来。这是因为网络在训练时见过两种模态,测试时倾向于选择与查询图模态相同的样本。
解决方案是测试时只使用共享特征做检索,特有特征不参与距离计算。因为特有特征本身是模态相关的,用它算距离会引入模态偏差。论文里的做法也是这样:最终检索用的是共享特征,特有特征只在训练时通过迁移模块增强共享特征。
还有一个技巧是查询扩展(Query Expansion):用查询图的共享特征先检索一次,取top-k结果,然后用这些结果的特征均值作为新的查询向量再检索一次。这个技巧在行人重识别里很常用,能提升2-3个点的mAP。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 训练loss为nan | 数据里有单模态样本 | 检查每个batch的模态分布 | 过滤单模态样本 |
| 模态判别器准确率过高 | 判别器学习率太大 | 打印判别器loss曲线 | 判别器学习率降为主网络的0.1倍 |
| 特有特征判别力不足 | 正交约束太强 | 分别用共享/特有特征检索 | 降低正交损失权重,加辅助ID损失 |
| 验证集mAP震荡 | 学习率太大或batch size太小 | 观察loss曲线 | 降低学习率,增大batch size |
| 测试时模态偏差严重 | 特有特征参与检索 | 检查检索用的特征 | 只用共享特征做检索 |
| 训练后期性能下降 | 过拟合 | 对比训练集和验证集mAP | 加Dropout,早停 |
6. 迁移模块的变体与扩展思路
6.1 从通道注意力到空间注意力
论文里的迁移模块用的是通道注意力,即学习“哪些通道的特征值得迁移”。这个思路可以扩展到空间注意力,即学习“哪些空间位置的特征值得迁移”。具体做法是:对源模态特有特征做空间维度的池化,生成空间注意力图,然后与目标模态共享特征做逐像素相乘。
空间注意力的优势在于能处理人体不同部位的迁移需求。比如可见光特有特征里,衣服颜色信息主要集中在躯干区域,空间注意力可以让这些信息只迁移到红外特征的躯干区域,而不是全局均匀迁移。我在一个模拟项目里试过空间注意力,mAP比纯通道注意力高了1.5个点,但参数量增加了约20%。
更进一步的方案是通道-空间联合注意力,即同时学习通道权重和空间权重,两者相乘后再做迁移。这个方案效果最好,但计算量也最大。如果对推理速度有要求,建议只用通道注意力;如果追求精度,可以用联合注意力。
6.2 多尺度特征迁移
论文里的迁移是在单一尺度上做的(骨干网络最后一层特征图)。但行人重识别里,不同尺度的特征携带不同层次的信息:浅层特征包含边缘、纹理,深层特征包含语义、身份。多尺度迁移的思路是:在多个尺度上分别做特征分解和迁移,然后把多尺度的增强特征融合。
具体实现上,可以从ResNet-50的stage3和stage4分别引出特征图,各自做分解和迁移,最后把两个尺度的增强特征拼接或者相加。这个方案能提升约2个点的mAP,但训练时间增加约50%。如果算力允许,值得一试。
6.3 跨模态迁移与其他任务的结合
SSFT的迁移思路不局限于行人重识别。任何涉及多模态特征融合的任务都可以借鉴。比如:
- 多模态情感分析:文本特征和音频特征各有特有信息,可以通过迁移机制互相补充。
- 医学影像分析:CT图像和MRI图像各有优势,共享特征对齐,特有特征迁移。
- 自动驾驶感知:摄像头和激光雷达的数据融合,同样可以用共享-特有分解的思路。
核心逻辑是一样的:不要强行统一所有特征,而是让不同模态的特有信息通过迁移机制互相增强。这个思路的通用性很强,值得在多个领域尝试。
7. 我个人在复现过程中的几点体会
复现这篇论文大概花了我两周时间,其中大部分时间不是在写代码,而是在调对抗训练和特征分解的平衡。有几个体会比较深:
第一,对抗训练的学习率调度比结构设计更重要。我一开始把判别器和主网络的学习率设成一样,结果训练极不稳定。后来改成判别器学习率是主网络的0.1倍,并且用余弦退火调度,训练才平稳下来。这个经验在很多GAN和域适应任务里都适用——判别器永远要比生成器/特征提取器“慢半拍”。
第二,特征分解的监督信号要足够强。光靠正交损失和对抗损失,分解出来的特有特征容易退化。加一个辅助的ID损失在特有特征上,能显著提升特有特征的判别力。这个技巧论文里没写,是我自己试出来的,效果很稳。
第三,测试时的特征选择很关键。训练时用增强特征,测试时只用共享特征,这个不对称设计一开始让我很困惑。后来想明白了:增强特征里混入了另一个模态的特有信息,虽然训练时能提升判别力,但测试时查询图和库图的模态组合是固定的(要么可见光查红外,要么红外查可见光),用增强特征反而会引入不一致。只用共享特征,虽然判别力稍弱,但跨模态一致性最好。
第四,数据集的模态平衡比想象中重要。SYSU-MM01里可见光图比红外图多不少,如果直接随机采样,每个batch里模态比例会失衡,对抗训练会偏向样本多的模态。用自定义Sampler强制平衡后,共享特征的对齐效果明显更好。
最后分享一个小技巧:在迁移模块的注意力权重上加一个温度系数。标准的Sigmoid输出在0到1之间,如果大部分权重都集中在0.5附近,迁移效果会很弱。加一个温度系数T(比如T=2),让Sigmoid输出更极端(接近0或1),迁移的“选择性”更强。这个技巧在注意力机制里很通用,调参成本几乎为零,但效果提升很明显。