1. 度量学习基础与核心动机
在机器学习实践中,我们常常需要处理高维数据。想象你是一名数据分析师,手头有一份包含100个特征的客户数据集。直接在这些特征上运行分类算法,不仅计算成本高昂,还可能遭遇"维度灾难"——随着维度增加,数据变得稀疏,算法性能反而下降。这就是降维技术存在的意义。
但降维不仅仅是简单地把数据压缩到低维空间。关键在于:我们要找到一个能更好保留数据内在结构的低维表示。这就引出了度量学习(Metric Learning)的核心思想——通过学习一个合适的距离度量,来定义数据点之间的相似性。
传统欧氏距离假设所有维度同等重要且相互独立,这在实际中往往不成立。比如在客户分析中,"年收入"和"消费金额"这两个特征明显相关,而"登录频率"可能比其他行为特征更重要。度量学习就是要自动发现这些关系。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 马氏距离与度量矩阵
2.1 从加权欧氏距离到马氏距离
让我们从基础的欧氏距离开始:
code复制dist_ed²(xi, xj) = Σ|xi_d - xj_d|²
这个公式暗含了两个假设:
- 所有维度同等重要
- 维度之间相互独立
第一个问题可以通过引入权重解决:
code复制dist_wed²(xi, xj) = Σ w_d·|xi_d - xj_d|² = (xi-xj)ᵀW(xi-xj)
其中W是对角矩阵,W_dd = w_d。
但现实中的数据维度往往存在相关性。比如在电商数据中,"浏览时长"和"购买次数"通常是正相关的。这时就需要马氏距离:
code复制dist_mah²(xi, xj) = (xi-xj)ᵀM(xi-xj)
其中M是半正定对称矩阵,称为度量矩阵。
关键理解:当M是单位矩阵时,马氏距离退化为欧氏距离;当M是对角矩阵时,就是加权欧氏距离;完整的M可以捕捉维度间的交互关系。
2.2 度量矩阵的性质与几何解释
M必须满足半正定对称,这保证了:
- 距离非负:dist_mah(xi,xj) ≥ 0
- 对称性:dist_mah(xi,xj) = dist_mah(xj,xi)
- 三角不等式成立
从几何角度看,M定义了一个新的内积空间。通过Cholesky分解M=PPᵀ,我们可以将马氏距离理解为:
- 先用Pᵀ对数据进行线性变换
- 然后在变换后的空间中计算欧氏距离
这就将度量学习与降维联系起来了——如果M的秩k小于原维度d,P就是一个降维矩阵。
3. 近邻成分分析(NCA)算法详解
3.1 NCA的概率框架
NCA的核心思想是:定义样本xj对xi分类影响的概率:
code复制p_ij = exp(-dist_mah²(xi,xj)) / Σ_k exp(-dist_mah²(xi,xk))
这个softmax形式的概率表示:
- 距离越近的样本对分类影响越大
- 所有样本的影响概率之和为1
3.2 优化目标构建
NCA以留一法(LOO)正确率为优化目标:
code复制正确率 = Σ_i Σ_{j∈Ω_i} p_ij
其中Ω_i是与xi同类的样本集合。
我们的目标是最大化这个正确率,等价于最小化:
code复制损失 = 1 - 正确率
3.3 梯度推导与实现
要实现随机梯度下降,需要计算损失函数对P的梯度。经过推导可得:
code复制∂loss/∂P = -Σ_{j∈Ω_i} [ (xi-xj)(xi-xj)ᵀP · exp(-d_ij)/Σ_k exp(-d_ik) ]
Python实现关键步骤:
- 距离计算:
python复制def compute_distances(P, xi):
X_trans = X @ P.T # 所有样本投影
xi_trans = xi @ P.T # 当前样本投影
dists = np.sum(X_trans**2, axis=1) - 2*(xi_trans @ X_trans.T) + np.sum(xi_trans**2)
return dists
- 损失和梯度计算:
python复制def nca_loss_and_grad(P, X, y, i):
xi = X[i]
dists = compute_distances(P, xi)
# 同类样本掩码(排除自己)
mask = (y == y[i]) & (np.arange(len(y)) != i)
n_i = np.sum(np.exp(-dists[mask])) # 同类项分子
d_i = np.sum(np.exp(-dists)) # 所有样本分母
loss = 1 - (n_i / d_i)
# 梯度计算
grad = np.zeros_like(P)
for j in np.where(mask)[0]:
xj = X[j]
diff = xi - xj
grad += np.outer(diff, diff) @ P * (np.exp(-dists[j]) / d_i)
return loss, grad
- 随机梯度下降:
python复制for epoch in range(iterations):
for i in range(m):
loss, grad = nca_loss_and_grad(P, X, y, i)
P -= learning_rate * grad
4. 实践技巧与常见问题
4.1 参数初始化策略
P的初始化影响优化效果:
- 随机初始化:使用高斯分布随机数,注意尺度要与数据匹配
- 身份初始化:从单位矩阵开始,适合特征尺度相近时
- PCA初始化:先用PCA获取初始投影,适合线性可分数据
4.2 学习率选择与调整
由于NCA的损失函数非凸,学习率很关键:
- 初始学习率通常在0.001-0.1之间
- 使用学习率衰减:如每epoch乘以0.95
- 监控损失曲线:如果震荡剧烈应减小学习率
4.3 正则化与数值稳定
为避免过拟合和数值问题:
- 加入Frobenius范数正则项:λ||P||_F²
- 计算softmax时减去最大值防止溢出:
python复制logits = -dists
logits -= np.max(logits)
exps = np.exp(logits)
probs = exps / np.sum(exps)
4.4 常见问题排查
- 损失不下降:
- 检查梯度计算是否正确
- 尝试更小的学习率
- 检查数据是否已经线性可分
- 结果不稳定:
- 增加batch size
- 使用动量优化器
- 多次运行取平均
- 降维效果差:
- 检查M的秩是否合适
- 尝试非线性扩展(如核方法)
- 考虑其他度量学习方法
5. 扩展与应用场景
5.1 与其他降维方法对比
| 方法 | 监督信息 | 距离度量 | 计算复杂度 |
|---|---|---|---|
| PCA | 无 | 欧氏 | O(d³) |
| LDA | 有 | 欧氏 | O(d³) |
| NCA | 有 | 可学习 | O(m²d²) |
| t-SNE | 无 | 概率 | O(m²d) |
NCA的优势在于可以利用监督信息学习任务相关的距离度量。
5.2 实际应用案例
- 人脸识别:
- 学习区分不同人脸的度量
- 在LFW数据集上可提升5-10%准确率
- 推荐系统:
- 学习用户/物品的相似性度量
- 比余弦相似性更适合稀疏数据
- 医学图像分析:
- 学习病理特征的判别性距离
- 有助于微小病变的检测
5.3 进阶方向
- 深度度量学习:
- 用神经网络学习非线性投影
- 如Siamese网络、Triplet网络
- 多度量学习:
- 不同类别/区域使用不同度量
- 更适合复杂数据分布
- 在线度量学习:
- 适应数据流变化
- 适用于动态环境
