余弦距离学习
📐 1. 定义
给定两个非零向量 a 和 b ∈ ℝⁿ,余弦相似度定义为它们夹角的余弦值:
cosine_similarity(a,b)=a⋅b∥a∥2 ∥b∥2=∑i=1naibi∑ai2⋅∑bi2 \text{cosine\_similarity}(\mathbf{a}, \mathbf{b}) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\|_2 \, \|\mathbf{b}\|_2} = \frac{\sum_{i=1}^n a_i b_i}{\sqrt{\sum a_i^2} \cdot \sqrt{\sum b_i^2}} cosine_similarity(a,b)=∥a∥2∥b∥2a⋅b=∑ai2⋅∑bi2∑i=1naibi
- 取值范围:[-1, 1]
1:完全同向(最相似)0:正交(无关)-1:完全反向(最不相似)
🔔 实际中,若向量为非负(如图像特征、词频),则范围退化为 [0, 1]。
↔️ 2. 余弦距离(Cosine Distance)
为适配“距离越小越相似”的惯例,常将其转换为余弦距离:
cosine_distance(a,b)=1−cosine_similarity(a,b) \text{cosine\_distance}(\mathbf{a}, \mathbf{b}) = 1 - \text{cosine\_similarity}(\mathbf{a}, \mathbf{b}) cosine_distance(a,b)=1−cosine_similarity(a,b)
- 取值范围:[0, 2](非负向量时为 [0, 1])
- 满足非负性、对称性,但 不满足三角不等式 → 不是严格度量(non-metric),不能用于某些要求度量公理的算法(如某些层次聚类)。
🧭 3. 几何意义(关键!)
✅ 余弦相似度只关注方向,忽略幅值(模长)。
| 向量对 | 欧氏距离 | 余弦相似度 | 说明 |
|---|---|---|---|
| (1, 0), (100, 0) | 99 | 1.0 | 幅值差大,但同方向 → 余弦认为完全相似 |
| (1, 0), (0, 1) | √2 ≈ 1.41 | 0.0 | 正交 → 不相关 |
| (1, 1), (-1, -1) | 2√2 ≈ 2.83 | -1.0 | 完全反向 |
👉 这一特性使其天然适配归一化特征(如 L2 归一化的深度学习特征)。
🧪 4. 何时使用余弦相似度?✅(结合你的背景)
| 场景 | 为什么适合余弦? |
|---|---|
| 深度学习视觉特征 (如 DINOv2, CLIP, NetVLAD) | 特征通常 L2 归一化,此时: cosine_sim=a⊤b,L2_dist2=2(1−cosine_sim)\text{cosine\_sim} = \mathbf{a}^\top \mathbf{b},\quad \text{L2\_dist}^2 = 2(1 - \text{cosine\_sim})cosine_sim=a⊤b,L2_dist2=2(1−cosine_sim) → 余弦与 L2 等价,但计算更快(无需开方) |
| Place Recognition / VPR (视觉定位、回环检测) | 环境光照/曝光变化导致特征幅值不稳定,方向更鲁棒 |
| 文本/词袋模型(TF-IDF) | 文档长度差异大,余弦消除长度影响,专注词分布方向 |
| SLAM 中的全局描述子匹配 | 如使用 SuperPoint + SuperGlue,其 descriptor 常归一化,余弦匹配更稳定 |
✅ 在 FAISS、Annoy 等近似最近邻库中,
IndexFlatIP(内积)常配合 L2 归一化实现高效余弦搜索。
⚠️ 5. 何时避免使用?
| 场景 | 问题 |
|---|---|
| 原始像素/未归一化特征 | 幅值含重要信息(如亮度),忽略它会丢失判别性 |
| 需要严格度量的空间 | 如构建度量树(Ball Tree)、某些聚类算法要求三角不等式 |
| 二进制描述子(ORB/BRIEF) | 汉明距离更合理;余弦对二进制向量退化为相关性,效果差且慢 |
🛠️ 6. 代码示例(Python)
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# 手动计算
cos_sim = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
cos_dist = 1 - cos_sim
print(f"余弦相似度: {cos_sim:.4f}") # → 0.9746
print(f"余弦距离: {cos_dist:.4f}") # → 0.0254
# sklearn(支持批量)
sim_matrix = cosine_similarity([a, b])
🔍 加速技巧:若所有向量已 L2 归一化(
x /= np.linalg.norm(x)),则cosine_similarity = a @ b.T(纯矩阵乘),可用 BLAS/GPU 加速。
📊 7. 与其他距离对比(归一化后)
| 距离 | 公式(a,b L2 归一化) | 计算量 | 适用性 |
|---|---|---|---|
| L2 距离 | 2(1−cosθ)\sqrt{2(1 - \cos\theta)}2(1−cosθ) | 高(开方) | 通用 |
| 余弦距离 | 1−cosθ1 - \cos\theta1−cosθ | 低(仅内积) | ✅ 归一化特征首选 |
| 汉明距离 | ∣a−b∣1|a - b|_1∣a−b∣1(二进制) | 极低 | 二进制描述子 |
✅ 总结一句话:
余弦相似度衡量“方向一致性”,是处理归一化高维特征(尤其是深度学习特征)的黄金标准——快、鲁棒、与人类直觉一致。
更多推荐

所有评论(0)