पाठ 3 / 28

Similarity मापदंड: Dot, Cosine और Euclidean

तीन आम मापदंडों से vectors की तुलना करें और जानें कब वे सहमत होते हैं।

दिशा, आकार, या दोनों

तीन मापदंड हावी हैं। Dot product संगत घटकों को गुणा करके जोड़ता है: यह vectors के बीच के कोण और उनकी लंबाइयों दोनों के साथ बढ़ता है। Cosine similarity dot product को दोनों लंबाइयों से भाग देती है, इसलिए सिर्फ़ दिशा मापती है (1 = समान दिशा, 0 = असंबंधित, -1 = विपरीत)। Euclidean (L2) दूरी सीधी रेखा की दूरी है (कम = पास)। इकाई-लंबाई (normalised) vectors के लिए तीनों क्रम पर सहमत हैं: cosine = dot, और L2² = 2 - 2·cosine। कई embedding models normalised vectors देते हैं, या cosine के साथ उपयोग के लिए बने हैं; मॉडल का दस्तावेज़ मानें, और अनिश्चित हों तो ख़ुद normalise करें ताकि तेज़ dot product cosine क्रम दे।

छोटे vectors पर तीन मापदंड, चलाकर

मैंने यह Python virtual environment में numpy 2.5.3, scikit-learn 1.9.1 और faiss-cpu 1.15.1 के साथ चलाया, निश्चित random seeds के साथ ताकि संख्याएँ दोहराई जाएँ। Vector b, a की दोगुनी लंबी प्रति है, और c, a पर लंबवत है। Dot product a·b के लिए 50 पर a·c के लिए 0 देता है; cosine कहती है कि a और b एक ही ओर इशारा करते हैं (1.0) जबकि a और c असंबंधित हैं (0.0); L2 कहता है b 5 दूर और c 7.07 दूर है। Normalise करने के बाद dot, cosine के बराबर है।

import numpy as np

a = np.array([3.0, 4.0]); b = np.array([6.0, 8.0]); c = np.array([4.0, -3.0])
def dot(x, y): return float(x @ y)
def cos(x, y): return float(x @ y / (np.linalg.norm(x) * np.linalg.norm(y)))
def l2(x, y): return float(np.linalg.norm(x - y))

print("dot   a.b, a.c :", dot(a, b), dot(a, c))
print("cosine a,b / a,c:", round(cos(a, b), 3), round(cos(a, c), 3))
print("L2    a,b / a,c :", round(l2(a, b), 3), round(l2(a, c), 3))

an, bn = a / np.linalg.norm(a), b / np.linalg.norm(b)
print("after normalising, dot == cosine:", round(dot(an, bn), 3), "==", round(cos(a, b), 3))

Output:

dot   a.b, a.c : 50.0 0.0
cosine a,b / a,c: 1.0 0.0
L2    a,b / a,c : 5.0 7.071
after normalising, dot == cosine: 1.0 == 1.0

रैंकिंग कब सहमत होती हैं, चलाकर

मैंने यह Python virtual environment में numpy 2.5.3, scikit-learn 1.9.1 और faiss-cpu 1.15.1 के साथ चलाया, निश्चित random seeds के साथ ताकि संख्याएँ दोहराई जाएँ। बहुत अलग लंबाई वाले 1,000 random vectors पर कच्चा dot product और कच्चा L2, cosine से अलग पड़ोसी चुनते हैं क्योंकि लंबाई उन्हें बिगाड़ती है। इकाई लंबाई पर normalise करने के बाद L2 ठीक cosine क्रम देता है।

import numpy as np
rng = np.random.default_rng(0)
docs = rng.normal(size=(1000, 32)) * rng.uniform(0.5, 5.0, size=(1000, 1))     # vectors with very different lengths
q = rng.normal(size=32)

by_dot = np.argsort(-(docs @ q))[:5]
by_l2 = np.argsort(np.linalg.norm(docs - q, axis=1))[:5]
dn = docs / np.linalg.norm(docs, axis=1, keepdims=True); qn = q / np.linalg.norm(q)
by_cos = np.argsort(-(dn @ qn))[:5]
dn_l2 = np.argsort(np.linalg.norm(dn - qn, axis=1))[:5]
print("dot (raw)      :", by_dot.tolist())
print("L2 (raw)       :", by_l2.tolist())
print("cosine         :", by_cos.tolist())
print("L2 on unit vecs:", dn_l2.tolist(), "| same as cosine:", dn_l2.tolist() == by_cos.tolist())

Output:

dot (raw)      : [353, 868, 15, 456, 130]
L2 (raw)       : [25, 226, 20, 590, 550]
cosine         : [859, 36, 25, 226, 20]
L2 on unit vecs: [859, 36, 25, 226, 20] | same as cosine: True

Metric को मॉडल से मिलाएँ

जिस similarity के लिए मॉडल प्रशिक्षित है वही उपयोग करें (आम तौर पर cosine)। Vector store में index बनाते समय वही metric configure करें।

त्वरित जाँच: इकाई-लंबाई vectors के लिए क्या सही है?

  • L2 उलटा क्रम देता है
  • Cosine हमेशा शून्य है
  • Dot product अर्थहीन है
  • Dot product, cosine similarity के बराबर है, और L2 वही क्रम देता है
Answer

Dot product, cosine similarity के बराबर है, और L2 वही क्रम देता है — Normalise करना लंबाई हटाकर सिर्फ़ दिशा छोड़ता है।