基于距离度量学习的马氏距离(Mahalanobis Distance)优化与算法实现
字数 4435 2025-12-09 20:07:48

基于距离度量学习的马氏距离(Mahalanobis Distance)优化与算法实现

我将为你详细讲解机器学习中距离度量学习的核心——马氏距离的优化与学习算法。这个主题旨在学习一个更适应数据分布的、可通用的距离度量,从而提升KNN、聚类等依赖距离的算法的性能。

题目描述
在机器学习中,很多算法(如K近邻、K均值、SVM等)的性能高度依赖于数据点之间“距离”的计算。最常用的欧氏距离假设所有特征维度是独立且同等重要的,这在很多真实数据中并不成立。例如,一个维度是身高(单位:米,数值范围1.5~2.0),另一个维度是收入(单位:万元,数值范围5~50),欧氏距离会过度放大收入维度的差异,并且忽略特征间的相关性。

马氏距离 可以解决这两个问题。给定一个数据集 \(\{x_i\}_{i=1}^N\),其中 \(x_i \in \mathbb{R}^d\),其马氏距离定义为:

\[D_M(x_i, x_j) = \sqrt{(x_i - x_j)^T M (x_i - x_j)} \]

其中 \(M\) 是一个 \(d \times d\) 的半正定矩阵(记为 \(M \succeq 0\))。当 \(M\) 取数据的逆协方差矩阵 \(\Sigma^{-1}\) 时,就是经典的马氏距离,它能自动校正不同特征尺度的差异性,并考虑特征间的线性相关性。

度量学习的核心目标是从数据中自动学出一个最优的 \(M\),使得在学得的距离度量下,满足“同类样本距离近,异类样本距离远”的先验。这被称为马氏度量学习


解题过程详解

第一步:问题形式化与目标设定

假设我们有一个带标签的数据集 \(\{(x_i, y_i)\}_{i=1}^N\)。我们定义两个样本对之间的关系:

  • 相似对(同类样本对)集合 \(S\):如果 \((x_i, x_j) \in S\),则 \(y_i = y_j\)
  • 不相似对(异类样本对)集合 \(D\):如果 \((x_i, x_j) \in D\),则 \(y_i \neq y_j\)

我们的目标是学习一个矩阵 \(M\),使得:

  1. 同类吸引:对于所有相似对,其马氏距离 \(D_M^2(x_i, x_j)\) 尽可能小。
  2. 异类排斥:对于所有不相似对,其马氏距离 \(D_M^2(x_i, x_j)\) 尽可能大(至少大于一个边界值)。

这是一个自然的成对约束优化问题。最经典的算法之一是大边界最近邻(Large Margin Nearest Neighbor, LMNN) 提出的目标函数。下面我们以LMNN的思路为例,分步拆解。

第二步:定义具体的优化目标(损失函数)

LMNN的核心思想是:学到的度量应该使得对于每个样本 \(x_i\)(我们称之为“目标样本”):

  • 它的 \(k\) 个最近邻(根据学到的距离)都属于同类(“同类近邻”,用 \(j \rightsquigarrow i\) 表示)。
  • 任何不同类的样本(“入侵者”,用 \(l\) 表示)与它的距离,应该比它与任何同类近邻的距离至少大出一个边界(Margin)。

为此,LMNN设计了包含两项的损失函数:

  1. 拉近项(Pull Term):拉近目标样本与其同类 \(k\) 近邻的距离。

\[ \epsilon_{pull}(M) = \sum_{i, j \rightsquigarrow i} D_M^2(x_i, x_j) \]

对所有样本 $ i $ 和它的每个同类 $ k $ 近邻 $ j $ 求和。
  1. 推远项(Push Term):推开不同类的“入侵者”。对目标样本 \(i\),它的同类近邻 \(j\),以及任意一个不同类的入侵者 \(l\)(即 \(y_l \neq y_i\)),我们希望:

\[ D_M^2(x_i, l) \ge D_M^2(x_i, j) + 1 \]

这里的“1”是设定的边界(Margin)。如果这个不等式不满足,我们就需要施加一个惩罚。这可以用**合页损失(Hinge Loss)** 来实现:

\[ \xi_{ijl} = \max(0, 1 + D_M^2(x_i, x_j) - D_M^2(x_i, x_l)) \]

只有当入侵者 $ l $ 的距离比同类近邻 $ j $ 的距离至少小于1个单位时,损失 $ \xi_{ijl} > 0 $。

完整的LMNN损失函数 是这两项的加权和:

\[\mathcal{L}(M) = (1 - \mu) \sum_{i, j \rightsquigarrow i} D_M^2(x_i, x_j) + \mu \sum_{i, j \rightsquigarrow i} \sum_{l: y_l \neq y_i} \xi_{ijl} \]

其中 \(\mu \in [0, 1]\) 是一个超参数,用于平衡“拉近”和“推远”两项的重要性。

第三步:优化求解

我们的优化问题是:

\[\min_{M \succeq 0} \mathcal{L}(M) \]

约束 \(M \succeq 0\) 保证了学到的距离满足非负性和三角不等式,是一个合法的度量。

为了求解,我们可以将距离公式代入:

\[D_M^2(x_i, x_j) = (x_i - x_j)^T M (x_i - x_j) = \text{tr}(M (x_i - x_j)(x_i - x_j)^T) \]

这里利用了矩阵迹的循环性质 \(\text{tr}(AB) = \text{tr}(BA)\)。定义差异向量外积 \(C_{ij} = (x_i - x_j)(x_i - x_j)^T\),则 \(D_M^2(x_i, x_j) = \text{tr}(M C_{ij})\)

将此代入损失函数,并将松弛变量 \(\xi_{ijl}\) 显式写出,我们得到一个可求解的半定规划(Semidefinite Programming, SDP)问题:

\[\begin{aligned} \min_{M, \xi} &\quad (1 - \mu) \sum_{i, j \rightsquigarrow i} \text{tr}(M C_{ij}) + \mu \sum_{i, j \rightsquigarrow i} \sum_{l: y_l \neq y_i} \xi_{ijl} \\ \text{s.t.} &\quad \text{tr}(M C_{il}) - \text{tr}(M C_{ij}) \ge 1 - \xi_{ijl} \quad \forall i, j \rightsquigarrow i, l: y_l \neq y_i \\ &\quad \xi_{ijl} \ge 0 \\ &\quad M \succeq 0 \end{aligned} \]

第四步:算法实现与迭代优化

直接求解上述SDP问题对大规模数据比较慢。LMNN论文提出了一种高效的基于子梯度下降的迭代优化方法

  1. 初始化:通常设置 \(M\) 为单位矩阵 \(I\)(即退化为欧氏距离),或者使用基于全局协方差矩阵的逆 \(\Sigma^{-1}\) 作为初始值。初始化同类 \(k\) 近邻关系(基于初始距离)。

  2. 迭代更新

    • 计算当前度量 \(M^{(t)}\) 下的所有距离。
    • 识别活跃的“入侵者”:对每个三元组 \((i, j, l)\),检查是否有 \(1 + D_{M^{(t)}}^2(x_i, x_j) - D_{M^{(t)}}^2(x_i, x_l) > 0\)。只有满足这个条件的三元组,其对应的约束才是“活跃的”,才会对梯度有贡献。
    • 计算损失函数关于 \(M\) 的梯度
      • 拉近项的梯度: \(\nabla_M \epsilon_{pull} = (1-\mu) \sum_{i, j \rightsquigarrow i} C_{ij}\)
      • 推远项的梯度:只对活跃的三元组求和, \(\nabla_M \epsilon_{push} = \mu \sum_{\text{active } (i,j,l)} (C_{ij} - C_{il})\)
      • 总梯度: \(G^{(t)} = \nabla_M \mathcal{L} = \nabla_M \epsilon_{pull} + \nabla_M \epsilon_{push}\)
    • 更新矩阵 \(M\)\(M^{(t+1)} = M^{(t)} - \alpha G^{(t)}\),其中 \(\alpha\) 是学习率。
    • 投影到半正定锥:为了使更新后的 \(M^{(t+1)}\) 满足 \(M \succeq 0\) 的约束,需要对 \(M^{(t+1)}\) 进行投影。常用的方法是进行特征值分解 \(M = U \Lambda U^T\),然后将所有负特征值置零: \(M_{\text{psd}} = U \max(\Lambda, 0) U^T\)
    • (可选)更新近邻关系:在迭代一定轮数后,可以根据更新后的 \(M\) 重新计算每个样本的 \(k\) 个同类近邻。
  3. 收敛:当损失函数的变化或矩阵 \(M\) 的变化小于某个阈值,或达到最大迭代次数时停止。

第五步:应用学到的度量

学习完成后,我们得到最优的矩阵 \(M^*\)。对于任何需要计算距离的任务(如KNN分类、K-means聚类),我们都使用学到的马氏距离:

\[\text{dist}(x_i, x_j) = \sqrt{(x_i - x_j)^T M^* (x_i - x_j)} \]

这个距离度量融入了数据的全局结构和类别信息,通常能显著提升下游任务的性能。

总结:马氏距离度量学习通过优化一个半正定矩阵 \(M\),将原始数据空间线性映射到一个新的特征空间,在该空间中,类内样本更紧凑,类间样本更分离。LMNN算法是其中的一个经典代表,它通过定义明确的目标函数(拉近同类、推远异类)和利用高效的凸优化技术,从成对约束中自动学习到一个有判别力的距离度量。

基于距离度量学习的马氏距离(Mahalanobis Distance)优化与算法实现 我将为你详细讲解机器学习中 距离度量学习 的核心—— 马氏距离的优化与学习算法 。这个主题旨在学习一个更适应数据分布的、可通用的距离度量,从而提升KNN、聚类等依赖距离的算法的性能。 题目描述 在机器学习中,很多算法(如K近邻、K均值、SVM等)的性能高度依赖于数据点之间“距离”的计算。最常用的欧氏距离假设所有特征维度是独立且同等重要的,这在很多真实数据中并不成立。例如,一个维度是身高(单位:米,数值范围1.5~2.0),另一个维度是收入(单位:万元,数值范围5~50),欧氏距离会过度放大收入维度的差异,并且忽略特征间的相关性。 马氏距离 可以解决这两个问题。给定一个数据集 \( \{x_ i\}_ {i=1}^N \),其中 \( x_ i \in \mathbb{R}^d \),其马氏距离定义为: \[ D_ M(x_ i, x_ j) = \sqrt{(x_ i - x_ j)^T M (x_ i - x_ j)} \] 其中 \( M \) 是一个 \( d \times d \) 的半正定矩阵(记为 \( M \succeq 0 \))。当 \( M \) 取数据的 逆协方差矩阵 \( \Sigma^{-1} \) 时,就是经典的马氏距离,它能自动校正不同特征尺度的差异性,并考虑特征间的线性相关性。 度量学习 的核心目标是从数据中自动学出一个最优的 \( M \),使得在学得的距离度量下,满足“同类样本距离近,异类样本距离远”的先验。这被称为 马氏度量学习 。 解题过程详解 第一步:问题形式化与目标设定 假设我们有一个带标签的数据集 \( \{(x_ i, y_ i)\}_ {i=1}^N \)。我们定义两个样本对之间的关系: 相似对(同类样本对)集合 \( S \):如果 \( (x_ i, x_ j) \in S \),则 \( y_ i = y_ j \)。 不相似对(异类样本对)集合 \( D \):如果 \( (x_ i, x_ j) \in D \),则 \( y_ i \neq y_ j \)。 我们的目标是学习一个矩阵 \( M \),使得: 同类吸引 :对于所有相似对,其马氏距离 \( D_ M^2(x_ i, x_ j) \) 尽可能小。 异类排斥 :对于所有不相似对,其马氏距离 \( D_ M^2(x_ i, x_ j) \) 尽可能大(至少大于一个边界值)。 这是一个自然的 成对约束 优化问题。最经典的算法之一是 大边界最近邻(Large Margin Nearest Neighbor, LMNN) 提出的目标函数。下面我们以LMNN的思路为例,分步拆解。 第二步:定义具体的优化目标(损失函数) LMNN的核心思想是:学到的度量应该使得对于每个样本 \( x_ i \)(我们称之为“目标样本”): 它的 \( k \) 个最近邻(根据学到的距离)都属于同类(“同类近邻”,用 \( j \rightsquigarrow i \) 表示)。 任何不同类的样本(“入侵者”,用 \( l \) 表示)与它的距离,应该比它与任何同类近邻的距离至少大出一个边界(Margin)。 为此,LMNN设计了包含两项的损失函数: 拉近项(Pull Term) :拉近目标样本与其同类 \( k \) 近邻的距离。 \[ \epsilon_ {pull}(M) = \sum_ {i, j \rightsquigarrow i} D_ M^2(x_ i, x_ j) \] 对所有样本 \( i \) 和它的每个同类 \( k \) 近邻 \( j \) 求和。 推远项(Push Term) :推开不同类的“入侵者”。对目标样本 \( i \),它的同类近邻 \( j \),以及任意一个不同类的入侵者 \( l \)(即 \( y_ l \neq y_ i \)),我们希望: \[ D_ M^2(x_ i, l) \ge D_ M^2(x_ i, j) + 1 \] 这里的“1”是设定的边界(Margin)。如果这个不等式不满足,我们就需要施加一个惩罚。这可以用 合页损失(Hinge Loss) 来实现: \[ \xi_ {ijl} = \max(0, 1 + D_ M^2(x_ i, x_ j) - D_ M^2(x_ i, x_ l)) \] 只有当入侵者 \( l \) 的距离比同类近邻 \( j \) 的距离至少小于1个单位时,损失 \( \xi_ {ijl} > 0 \)。 完整的LMNN损失函数 是这两项的加权和: \[ \mathcal{L}(M) = (1 - \mu) \sum_ {i, j \rightsquigarrow i} D_ M^2(x_ i, x_ j) + \mu \sum_ {i, j \rightsquigarrow i} \sum_ {l: y_ l \neq y_ i} \xi_ {ijl} \] 其中 \( \mu \in [ 0, 1 ] \) 是一个超参数,用于平衡“拉近”和“推远”两项的重要性。 第三步:优化求解 我们的优化问题是: \[ \min_ {M \succeq 0} \mathcal{L}(M) \] 约束 \( M \succeq 0 \) 保证了学到的距离满足非负性和三角不等式,是一个合法的度量。 为了求解,我们可以将距离公式代入: \[ D_ M^2(x_ i, x_ j) = (x_ i - x_ j)^T M (x_ i - x_ j) = \text{tr}(M (x_ i - x_ j)(x_ i - x_ j)^T) \] 这里利用了矩阵迹的循环性质 \( \text{tr}(AB) = \text{tr}(BA) \)。定义差异向量外积 \( C_ {ij} = (x_ i - x_ j)(x_ i - x_ j)^T \),则 \( D_ M^2(x_ i, x_ j) = \text{tr}(M C_ {ij}) \)。 将此代入损失函数,并将松弛变量 \( \xi_ {ijl} \) 显式写出,我们得到一个可求解的半定规划(Semidefinite Programming, SDP)问题: \[ \begin{aligned} \min_ {M, \xi} &\quad (1 - \mu) \sum_ {i, j \rightsquigarrow i} \text{tr}(M C_ {ij}) + \mu \sum_ {i, j \rightsquigarrow i} \sum_ {l: y_ l \neq y_ i} \xi_ {ijl} \\ \text{s.t.} &\quad \text{tr}(M C_ {il}) - \text{tr}(M C_ {ij}) \ge 1 - \xi_ {ijl} \quad \forall i, j \rightsquigarrow i, l: y_ l \neq y_ i \\ &\quad \xi_ {ijl} \ge 0 \\ &\quad M \succeq 0 \end{aligned} \] 第四步:算法实现与迭代优化 直接求解上述SDP问题对大规模数据比较慢。LMNN论文提出了一种高效的 基于子梯度下降的迭代优化方法 。 初始化 :通常设置 \( M \) 为单位矩阵 \( I \)(即退化为欧氏距离),或者使用基于全局协方差矩阵的逆 \( \Sigma^{-1} \) 作为初始值。初始化同类 \( k \) 近邻关系(基于初始距离)。 迭代更新 : 计算当前度量 \( M^{(t)} \) 下的所有距离。 识别活跃的“入侵者” :对每个三元组 \( (i, j, l) \),检查是否有 \( 1 + D_ {M^{(t)}}^2(x_ i, x_ j) - D_ {M^{(t)}}^2(x_ i, x_ l) > 0 \)。只有满足这个条件的三元组,其对应的约束才是“活跃的”,才会对梯度有贡献。 计算损失函数关于 \( M \) 的梯度 : 拉近项的梯度: \( \nabla_ M \epsilon_ {pull} = (1-\mu) \sum_ {i, j \rightsquigarrow i} C_ {ij} \)。 推远项的梯度:只对活跃的三元组求和, \( \nabla_ M \epsilon_ {push} = \mu \sum_ {\text{active } (i,j,l)} (C_ {ij} - C_ {il}) \)。 总梯度: \( G^{(t)} = \nabla_ M \mathcal{L} = \nabla_ M \epsilon_ {pull} + \nabla_ M \epsilon_ {push} \)。 更新矩阵 \( M \) : \( M^{(t+1)} = M^{(t)} - \alpha G^{(t)} \),其中 \( \alpha \) 是学习率。 投影到半正定锥 :为了使更新后的 \( M^{(t+1)} \) 满足 \( M \succeq 0 \) 的约束,需要对 \( M^{(t+1)} \) 进行投影。常用的方法是进行特征值分解 \( M = U \Lambda U^T \),然后将所有负特征值置零: \( M_ {\text{psd}} = U \max(\Lambda, 0) U^T \)。 (可选)更新近邻关系 :在迭代一定轮数后,可以根据更新后的 \( M \) 重新计算每个样本的 \( k \) 个同类近邻。 收敛 :当损失函数的变化或矩阵 \( M \) 的变化小于某个阈值,或达到最大迭代次数时停止。 第五步:应用学到的度量 学习完成后,我们得到最优的矩阵 \( M^* \)。对于任何需要计算距离的任务(如KNN分类、K-means聚类),我们都使用学到的马氏距离: \[ \text{dist}(x_ i, x_ j) = \sqrt{(x_ i - x_ j)^T M^* (x_ i - x_ j)} \] 这个距离度量融入了数据的全局结构和类别信息,通常能显著提升下游任务的性能。 总结 :马氏距离度量学习通过优化一个半正定矩阵 \( M \),将原始数据空间线性映射到一个新的特征空间,在该空间中,类内样本更紧凑,类间样本更分离。LMNN算法是其中的一个经典代表,它通过定义明确的目标函数(拉近同类、推远异类)和利用高效的凸优化技术,从成对约束中自动学习到一个有判别力的距离度量。