Módulo 5: Distance Metrics Deep Dive
Performance Benchmarks
Benchmark Setup
import numpy as np
import time
# Generate random embeddings
n = 10000
dim = 1536
embeddings = np.random.randn(n, dim)
query = np.random.randn(dim)
# Normalize (for fair comparison)
embeddings_norm = embeddings / np.linalg.norm(embeddings, axis=1, keepdims=True)
query_norm = query / np.linalg.norm(query)
Speed Comparison
# Cosine similarity
start = time.time()
cos_sims = np.dot(embeddings, query) / (np.linalg.norm(embeddings, axis=1) * np.linalg.norm(query))
time_cosine = time.time() - start
# Dot product (normalized embeddings)
start = time.time()
dot_sims = np.dot(embeddings_norm, query_norm)
time_dot = time.time() - start
# Euclidean
start = time.time()
euc_dists = np.linalg.norm(embeddings - query, axis=1)
time_euclidean = time.time() - start
print(f"Cosine: {time_cosine:.4f}s")
print(f"Dot Product: {time_dot:.4f}s")
print(f"Euclidean: {time_euclidean:.4f}s")
print(f"\nSpeedup (Dot vs Cosine): {time_cosine/time_dot:.1f}x")
Output típico:
Cosine: 0.0234s
Dot Product: 0.0078s
Euclidean: 0.0156s
Speedup (Dot vs Cosine): 3.0x
Key Insights
- Dot product 3x más rápido que cosine
- Euclidean 2x más rápido que cosine
- Pre-normalizar embeddings → usar dot product
Production Pattern
class FastVectorSearch:
"""Optimized search con dot product"""
def __init__(self, embeddings):
# Normalizar una vez (upfront cost)
self.embeddings = embeddings / np.linalg.norm(embeddings, axis=1, keepdims=True)
def search(self, query, k=5):
# Normalizar query
query_norm = query / np.linalg.norm(query)
# Dot product (rápido!)
scores = np.dot(self.embeddings, query_norm)
# Top-K
top_k = np.argsort(scores)[::-1][:k]
return top_k, scores[top_k]
Resumen
- ✅ Dot product: 3x más rápido
- ✅ Pre-normalize: Upfront cost, runtime savings
- ✅ Production: Siempre usar dot product si puedes
Módulo 5 - Cápsula 05