Собесов

Сценарий ML: cosine vs euclidean для эмбеддингов

ML / Data ScienceNLP и эмбеддингиЛёгкаяMiddle

Условие

Когда использовать 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). Идея — большая «амплитуда» эмбеддинга = более популярный объект.

Подводные камни

  1. Cosine на сильно различных по длине эмбеддингах может дать «false near» — два короткихvектора с малым cos близки по cos, но euclidean показывает их «удалённость».
  2. Cosine не метрика (нет triangle inequality для cos_distance = 1 − cos). Это similarity.
  3. Numerical stability: для очень близких векторов ||a−b||² через формулу выше может выдавать малое отрицательное число из-за floating point. Clip к 0.
  4. На non-нормированных embeddings KMeans даёт странные кластера — нормируйте или используйте SphericalKMeans.
  5. ANN индексы FAISS на L2 vs IP — производительность разная. Бенчмарк под свой workload.

Эталонный ответ

Для нормированных векторов cosine и euclidean эквивалентны: ||a−b||² = 2(1−cos). Cosine — для разной «длины» эмбеддингов (sentence-len-dependent). Euclidean — для нормированных или физических расстояний. В векторных БД нормируем заранее и используем IP — быстрее.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти