Условие
Когда использовать cosine similarity, а когда euclidean distance для эмбеддингов?
Решение
Подход
Связь между ними:
||a − b||² = ||a||² + ||b||² − 2·a·b
Для нормированных векторов (||a|| = ||b|| = 1):
||a − b||² = 2·(1 − cos(a,b))
→ cosine и euclidean эквивалентны на единичной сфере.
Когда cosine
- Эмбеддинги имеют разную длину (например, sentence embeddings от длины текста зависит).
- Семантическая близость, не «амплитуда».
- Sparse vectors (TF-IDF): длина зависит от длины документа.
- Word embeddings (Word2Vec, GloVe) обычно сравниваются по cosine.
Когда euclidean
- Эмбеддинги уже нормированы (большинство современных).
- Geographic / физические векторы: расстояние интерпретируемо.
- KMeans использует euclidean.
- При обучении triplet loss с margin — обычно L2.
Реализация
import numpy as np
def cosine(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
def cosine_matrix(A, B):
A_n = A / np.linalg.norm(A, axis=1, keepdims=True)
B_n = B / np.linalg.norm(B, axis=1, keepdims=True)
return A_n @ B_n.T
def euclidean_matrix(A, B):
# ||a-b||² = ||a||² + ||b||² - 2·a·b
sq_A = (A**2).sum(1)[:, None]
sq_B = (B**2).sum(1)[None, :]
return np.sqrt(sq_A + sq_B - 2 * A @ B.T)В векторных БД
FAISS, Qdrant, Milvus поддерживают:
IP(inner product): для cosine с пре-нормированными векторами быстрее.L2: euclidean.Cosine: с lazy нормированием.
Для cosine лучше нормировать заранее + использовать IP — быстрее в indexing/search.
Dot product (без нормирования)
Используется в recommender systems с factorized embeddings (Matrix Factorization, ALS). Идея — большая «амплитуда» эмбеддинга = более популярный объект.
Подводные камни
- Cosine на сильно различных по длине эмбеддингах может дать «false near» — два короткихvектора с малым cos близки по cos, но euclidean показывает их «удалённость».
- Cosine не метрика (нет triangle inequality для cos_distance = 1 − cos). Это similarity.
- Numerical stability: для очень близких векторов
||a−b||²через формулу выше может выдавать малое отрицательное число из-за floating point. Clip к 0. - На non-нормированных embeddings KMeans даёт странные кластера — нормируйте или используйте SphericalKMeans.
- ANN индексы FAISS на L2 vs IP — производительность разная. Бенчмарк под свой workload.
Эталонный ответ
Для нормированных векторов cosine и euclidean эквивалентны: ||a−b||² = 2(1−cos). Cosine — для разной «длины» эмбеддингов (sentence-len-dependent). Euclidean — для нормированных или физических расстояний. В векторных БД нормируем заранее и используем IP — быстрее.