度量学习对比损失:Siamese 与对比损失原理

FreeGuideOnline 最新 2026-06-21

度量学习与对比损失:从孪生网络到特征空间塑造

度量学习(Metric Learning)的目标是学习一个映射函数,将原始数据(如图像、文本)嵌入到一个低维特征空间中,使得在该空间里,相似样本的距离近,不相似样本的距离远。这种学习方式不依赖固定的类别标签,而是直接优化样本对或三元组之间的相对距离,因此特别适用于人脸验证、图像检索、签名鉴定等需要度量相似度的任务。

在最经典的范式下,度量学习通过对比损失(Contrastive Loss) 来训练孪生网络(Siamese Network)。本文将深入解析这一组合的原理、数学定义、训练技巧以及直观理解,帮助初学者从零构建起对度量学习核心机制的认识。


孪生网络:共享权重的双流架构

什么是孪生网络?

孪生网络不是一种全新的网络结构,而是一种权重共享的训练框架。它由两个完全相同的子网络(通常是卷积神经网络)组成,这两个子网络接受两个不同的输入,并输出它们在特征空间中的表示。因为两份输入的流程共享同一组参数,就像一对“孪生体”,故而得名。

输入1 → 子网络 ← 共享权重 → 子网络 ← 输入2
        |                       |
       输出向量1              输出向量2
              \               /
               距离度量(如欧氏距离)
                      |
                 对比损失

为什么需要权重共享?

  • 对称性:如果交换两个输入的顺序,输出的距离应保持不变。共享权重天然保证了这种对称性。
  • 参数效率:两个输入使用同一套规则编码,避免了学习两套不同映射函数可能带来的不一致。
  • 可比性:只有将输入映射到同一个空间,距离比较才有意义。

子网络的结构可以灵活选择:CNN用于图像,LSTM用于序列,Transformer用于更通用的模态。训练时,输入以成对的形式组织:正样本对(两张属于同一类或同一人的图片)和负样本对(两张不同类/不同人的图片)。


对比损失:一个直接且优雅的优化目标

对比损失(Contrastive Loss)最早由Yann LeCun等人提出,用于降维和孪生网络训练。其核心思想是:如果两个样本相似,就让它们的编码向量在特征空间里靠近;如果不相似,就推远一定距离,当距离超过某个边界时就不再施加额外的推力。

数学上,给定一对样本 ((X_a, X_b)),其二进制标签 (Y) 为:

  • (Y = 1):二者相似(正例)
  • (Y = 0):二者不相似(负例)

设 (D) 为两个样本特征向量之间的欧氏距离: [ D = | f(X_a) - f(X_b) |_2 ] 其中 (f(\cdot)) 表示孪生网络的嵌入函数。

对比损失定义为: [ L(X_a, X_b, Y) = Y \cdot D^2 + (1 - Y) \cdot \max(0, m - D)^2 ] 或者更紧凑地写成: [ L = Y \cdot D^2 + (1 - Y) \cdot [\max(0, m - D)]^2 ]

参数 (m > 0) 称为边界(Margin),是一个超参数。

损失函数的直观拆解

  • 当 (Y = 1)(相似对):损失退化为 (L = D^2)。优化器会尽可能将 (D) 推向 0,使两个正样本在特征空间中重合。
  • 当 (Y = 0)(不相似对):损失只在 (D < m) 时非零,此时 (L = (m - D)^2),惩罚两个负样本靠得太近。一旦 (D \ge m),损失降为 0,模型不再继续将它们推远。这种“边际”设计避免了模型过度关注已经分离得很好的负对,让训练精力集中在难分的负对和需要拉近的正对上。

为什么采用平方形式?

  • 平方项使得梯度与距离线性相关(对于正例)或与 ((D - m)) 线性相关(对于负例),训练稳定。
  • 与均方误差形式一致,易于实现和优化。

对比损失的梯度与优化行为

从梯度角度理解对比损失能更清楚地看到它如何塑造特征空间。

相似对(正例)的梯度

对于 (L = D^2),距离 (D) 的梯度为: [ \frac{\partial L}{\partial D} = 2D ] 梯度大小与距离成正比,距离越大,拉近的力度越强;当样本已经非常接近时,梯度很小,不会过度调整。

不相似对(负例)的梯度

当 (D < m) 时,(L = (m - D)^2),梯度为: [ \frac{\partial L}{\partial D} = -2(m - D) ] 梯度为负值,意味着朝着增加 (D) 的方向更新(推远)。梯度绝对值随 (D) 靠近 (m) 而减小;当 (D = m) 时,梯度刚好为 0;若 (D > m),梯度归零,停止更新。

这种难例聚焦机制使得训练更高效:优化器主动忽略那些已经轻松分离的负对,反向传播的能量集中在那些仍然“纠缠”在一起的负对和需要进一步靠拢的正对上。


超参数边界 (m) 的选择策略

边界 (m) 设定了“足够远”的基准。其取值对模型泛化能力影响巨大:

  • (m) 太小:负对极易满足 (D \ge m),模型几乎没有机会学习有分辨力的特征,导致正负样本混淆。
  • (m) 太大:所有负对都远未达到边界,模型一直被惩罚,训练会陷入不稳定,甚至导致所有样本被压缩到一个极小的球面中以保持正样本近,而过大的 (m) 使得负样本需要极大的推远力,可能破坏整体结构。

经验法则:观察特征空间的初始平均距离(通常接近某种范数的期望),然后设置 (m) 为该值的 2~5 倍。还可以在验证集上通过网格搜索结合最近邻分类准确率来选择。在一些人脸识别任务中,(m) 可设于 0.5~2.0 之间(依赖于特征是否归一化)。


与三元组损失的对比(简要)

常有人将对比损失与三元组损失(Triplet Loss)混淆。两者目标相同,但输入形式不同:

  • 对比损失:成对输入+相似性标签,适合“是/否”验证场景。
  • 三元组损失:锚点、正例、负例三元组输入,直接优化关系:(D_{anchor,pos} + \alpha < D_{anchor,neg})。

对比损失的优势在于训练简单,不用精心构建三元组,但可能面临正负样本不平衡时正对损失被淹没的问题。实际应用中,常将对比损失作为基础模块,或结合难例挖掘策略使用。


实现要点与稳定训练技巧

1. 距离度量的选择

欧氏距离是最常用的,但也可以使用余弦距离(需配合特征归一化)。当使用余弦距离时,建议将特征向量约束到单位超球面上,此时 (D) 变为角度距离,对比损失依然有效。

2. 特征归一化

将嵌入向量的 L2 范数固定为 1(如 (f(X) = \frac{g(X)}{|g(X)|_2}))可以:

  • 防止特征维度过大,避免 (D) 的无界增长。
  • 让边界 (m) 的设计更稳定(此时最大归一化欧氏距离为 2,余弦距离在 [0,2] 之间)。
  • 结合温度参数进一步调节分布。

3. 难例挖掘

简单的随机配对会导致大量已经满足条件的负对((D > m))贡献零梯度,模型学习缓慢。需要在线难负样本挖掘:在每个批次内,只选择那些 (D < m) 的负对计算损失,或从这些难负对中挑选最具挑战性的部分。

对于正对,通常所有相似对都参与计算,但也可对正对中距离异常大的样本对给予更高权重。

4. 配对策略与数据增强

  • 同类配对:从同一类别随机选择两个不同样本。
  • 异类配对:随机从不同类别选择两样本,但需借助难例挖掘提高效率。
  • 利用数据增强生成正对(同一图片两次不同增强),这是自监督对比学习的基础思路,此时所有变换后的图像都视为正例。

一个简化的PyTorch实现示例

为了将理论落地,以下给出对比损失的核心代码框架(基于PyTorch),供理解与快速实验。

import torch
import torch.nn as nn
import torch.nn.functional as F

class ContrastiveLoss(nn.Module):
    def __init__(self, margin=1.0):
        super(ContrastiveLoss, self).__init__()
        self.margin = margin

    def forward(self, output1, output2, label):
        """
        output1, output2: 形状 (batch_size, 特征维度) 的嵌入向量
        label: 0 表示不相似,1 表示相似,形状 (batch_size,)
        """
        # 计算欧氏距离
        euclidean_distance = F.pairwise_distance(output1, output2)
        # 相似对的损失: D^2
        loss_pos = label * torch.pow(euclidean_distance, 2)
        # 不相似对的损失: max(0, m - D)^2
        loss_neg = (1 - label) * torch.pow(
            torch.clamp(self.margin - euclidean_distance, min=0.0), 2
        )
        # 总损失取平均
        loss = torch.mean(loss_pos + loss_neg)
        return loss

训练循环中,需保证 output1output2 通过同一个模型(或共享参数)得到,label 根据样本对的关系设定。


应用场景与局限

典型应用

  • 人脸验证 / 签名验证:比对两张图像是否来自同一人。
  • 图像检索:用对比损失训练编码器,使得查询图与相关图距离近,与不相关图距离远。
  • 商品匹配:判断两个商品是否属于同一款式。
  • 自监督对比学习(如SimCLR)的基础形式,使用增强样本作为正对。

局限与注意事项

  • 对负样本采样敏感:随机采样可能导致大量平凡负对,模型学不到强判别力,必须配合难例挖掘。
  • 类别极度不平衡时,正对数量远小于负对,损失被负对主导,可引入正对损失权重或降低负对贡献。
  • 边界 (m) 需要根据任务和特征尺度精心调整,且不具有自适应能力。

总结

对比损失与孪生网络的结合,以一种简洁而强大的方式实现了“相似靠近,不似远离”的度量学习范式。通过共享权重架构保证编码空间的统一,再利用Margin机制实现对难负例的自适应聚焦,使得模型能快速学习出具有判别力的嵌入表示。对于想要深入理解度量学习和现代对比学习(如对比预测编码、MoCo等)的读者,掌握对比损失是必不可少的一步。

建议初学者尝试在MNIST或CIFAR-10上搭建简单的孪生网络,并观察不同边界 (m) 下嵌入空间t-SNE可视化后的分布变化,从而获得直观感受。