Salta ai contenuti

Norme e distanze: L1, L2, cosine e le loro parenti

Ogni “vicino”, “simile”, “errore” che un sistema AI calcola passa per una scelta di norma. La norma non è un dettaglio implementativo: è una scelta di significato.

Quando un vector database restituisce i top-k documenti più rilevanti per una query, sta calcolando distanze. Quando una loss di training penalizza un modello che sbaglia, sta misurando l’errore con una norma. Quando un sistema di anomaly detection segnala un punto come outlier, sta misurando quanto è “lontano” dal resto. Quando una regolarizzazione vincola i pesi di una rete neurale, sta usando una norma come costo.

In tutti questi casi la scelta della norma cambia la risposta. Due embedding possono essere “vicini” secondo la cosine similarity e “lontani” secondo la L2; un dataset può avere outlier secondo la distanza euclidea e nessuno secondo la Mahalanobis; una regolarizzazione L1 produce modelli sparsi, una L2 produce modelli dolcemente contratti. Trattare la norma come un parametro intercambiabile è uno degli errori più comuni di chi costruisce pipeline AI senza capire cosa misura.

Questo capitolo costruisce la cassetta degli attrezzi. Prima gli assiomi, perché senza di quelli “norma” è una parola vuota. Poi la famiglia Lp, che copre il 90% dei casi con tre parametri (1, 2, ∞). Poi la cosine similarity, regina indiscussa del retrieval testuale, e la sua relazione con il prodotto scalare. Poi le distanze “non-norma” — Hamming, Jaccard, Mahalanobis, Levenshtein, KL — che vivono in spazi diversi e rispondono a domande diverse. Infine il punto più scomodo: in alta dimensione le distanze si comportano in modo controintuitivo, e il dev che ignora questo fatto costruisce sistemi che funzionano in laboratorio e crollano in produzione.

Il capitolo sta nella Parte IV, dopo vettori e spazi. Quel capitolo dà la grammatica; questo dà il vocabolario operativo per misurare. I capitoli successivi della Parte IV (matrici e trasformazioni, prodotto scalare in dettaglio, embedding) costruiscono sopra questo strato.

Il concetto di “lunghezza di un vettore” sembra ovvio: in R^2 e R^3 c’è il teorema di Pitagora, e tutti l’abbiamo visto al liceo. Ma generalizzarlo richiede scelte. Quale lunghezza? Misurata come? Soddisfacendo quali proprietà?

La risposta moderna nasce a cavallo tra fine Ottocento e inizio Novecento, in due luoghi distanti. Hermann Minkowski, matematico tedesco di origine lituana vissuto fra il 1864 e il 1909, professore a Gottinga e maestro di Einstein, pubblica nel 1896 (con II edizione 1910) Geometrie der ZahlenGeometria dei numeri, un libro che usa la geometria di insiemi convessi per studiare problemi di teoria dei numeri. In quel libro compare la disuguaglianza che oggi porta il suo nome e che rende le norme Lp legittime per ogni p ≥ 1. Pafnuty Chebyshev, matematico russo vissuto fra il 1821 e il 1894, lavorando sulla teoria dell’approssimazione, fissa la norma del massimo come strumento naturale per misurare l’errore peggiore, anticipando di mezzo secolo l’L∞ moderna.

La distanza di Mahalanobis arriva da un’altra direzione. Prasanta Chandra Mahalanobis, statistico indiano vissuto fra il 1893 e il 1972, fondatore dell’Indian Statistical Institute, pubblica nel 1936 sui Proceedings of the National Institute of Sciences of India un articolo dal titolo telegrafico — On the generalised distance in statistics — in cui introduce una distanza pesata dall’inversa della matrice di covarianza. Il problema concreto era confrontare crani di popolazioni diverse: lunghezza, larghezza e altezza hanno scale diverse e sono correlate, e una distanza euclidea ingenua dà classifiche prive di senso. Mahalanobis fornisce la correzione, e quella correzione è oggi il fondamento dell’anomaly detection multivariato.

Una terza linea di ricerca è quella della teoria dell’informazione. Solomon Kullback (1907-1994) e Richard Leibler (1914-2003), crittografi americani, pubblicano nel 1951 On information and sufficiency sugli Annals of Mathematical Statistics, dove la divergenza KL viene introdotta come quantità di informazione discriminante tra due ipotesi statistiche. Il dettaglio cruciale, che torna in tutto il deep learning moderno, è che KL non è una distanza nel senso tecnico: non è simmetrica e non rispetta la disuguaglianza triangolare. Il termine corretto è “divergenza”, e il dev che la tratta come distanza commette errori prevedibili.

Nel libro queste idee tornano in molti capitoli successivi. La regolarizzazione L1/L2, il gradient clipping con norma globale, la cosine similarity in retrieval, la KL divergence in RLHF e VAE, la Mahalanobis in detection di out-of-distribution: sono tutte applicazioni dirette del materiale di questo capitolo. Per questo conviene installare bene le idee qui, una volta, e poi rimandare al vocabolario costruito.

flowchart TD
    R[Funzioni di distanza] --> N[Indotte da norma]
    R --> M[Metriche non-norma]
    R --> D[Divergenze<br/>non metriche]
    N --> LP[Famiglia Lp]
    LP --> L1[L1 — Manhattan]
    LP --> L2[L2 — Euclidea]
    LP --> LI[L∞ — Chebyshev]
    N --> COS[Cosine similarity<br/>L2 + dot product]
    N --> MAH[Mahalanobis<br/>L2 pesata]
    M --> HAM[Hamming]
    M --> LEV[Levenshtein]
    M --> JAC[Jaccard]
    D --> KL[KL]
    D --> JS[JS]
    D --> WAS[Wasserstein]

Figura 1 — concept graph: norms and distances family tree

Due angoli prima del formalismo. Tenerli entrambi attivi.

La forma della palla unitaria — l’insieme dei vettori di norma 1 — racconta tutto della norma. È la sua impronta digitale geometrica.

In R^2:

  • la palla L2 unitaria è il cerchio di raggio 1. Tutti i punti a distanza 1 dall’origine in senso pitagorico. È rotondo, isotropo, indistinguibile in qualsiasi rotazione.
  • la palla L1 unitaria è il rombo con vertici sugli assi (±1, 0) e (0, ±1). I quattro spigoli stanno sugli assi. Punto chiave: gli spigoli sono acuti, e gli assi cartesiani li attraversano. Questo è il motivo geometrico per cui L1 produce sparsità: l’ottimo di una funzione vincolata a stare dentro il rombo tende a cadere su un vertice, cioè su un punto con componenti nulle.
  • la palla L∞ unitaria è il quadrato [-1, 1] × [-1, 1]. La componente più grande è sotto controllo, le altre possono variare liberamente sotto quel limite. Geometricamente, è il rombo ruotato di 45° e gonfiato.

Tre forme diverse, tre modi diversi di “tagliare” lo spazio. Una funzione di errore minimizzata con L2 cerca soluzioni dentro un cerchio; con L1 dentro un rombo; con L∞ dentro un quadrato. La forma del vincolo determina dove cadrà l’ottimo.

flowchart TD
    R[Funzioni di distanza] --> N[Indotte da norma]
    R --> M[Metriche non-norma]
    R --> D[Divergenze<br/>non metriche]
    N --> LP[Famiglia Lp]
    LP --> L1[L1 — Manhattan]
    LP --> L2[L2 — Euclidea]
    LP --> LI[L∞ — Chebyshev]
    N --> COS[Cosine similarity<br/>L2 + dot product]
    N --> MAH[Mahalanobis<br/>L2 pesata]
    M --> HAM[Hamming]
    M --> LEV[Levenshtein]
    M --> JAC[Jaccard]
    D --> KL[KL]
    D --> JS[JS]
    D --> WAS[Wasserstein]

Figura 1 — unit balls in 2D for L1, L2, Linf overlaid

In dimensioni più alte le forme diventano impossibili da disegnare ma il principio resta. La palla L2 in R^n è un’ipersfera. La palla L1 in R^n è un cross-polytope con 2n vertici (uno per ogni ±ei± e_i). La palla L∞ in R^n è un ipercubo con 2^n vertici. Si noti l’asimmetria: il cross-polytope ha vertici lineari in n, l’ipercubo ne ha esponenzialmente molti. È un primo segnale che le geometrie in alta dimensione divergono.

Secondo angolo: somme di errori contro picchi di errore

Sezione intitolata “Secondo angolo: somme di errori contro picchi di errore”

Pensiamo a un errore di previsione su n punti. Vogliamo riassumerlo in un numero.

  • L1 dice: somma tutti gli errori. Ogni errore conta per quello che è. Un piccolo errore su mille punti conta uguale a un errore grande su uno.
  • L2 dice: somma i quadrati degli errori. Errori grandi pesano molto più di proporzionalmente. Dieci errori da 1 valgono come uno solo da sqrt(10)sqrt(10) ≈ 3.16, non come uno da 10.
  • L∞ dice: prendi il massimo. Solo l’errore peggiore conta. Mille errori da 0.1 valgono meno di un solo errore da 0.2.

Questo dà una guida operativa immediata. Se vuoi essere robusto agli outlier — un punto rotto non deve dominare — usa L1 (o varianti come Huber). Se vuoi penalizzare con forza errori grossi (es. un errore catastrofico in un sistema critico), usa L2. Se l’unica cosa che conta è che il caso peggiore sia sotto controllo (es. latency budget per un servizio), usa L∞.

Questa è una scelta di significato, non di efficienza. Cambiare norma cambia cosa il sistema sta ottimizzando. Una rete addestrata con MSE (L2 al quadrato) dà importanza diversa agli outlier rispetto alla stessa rete addestrata con MAE (L1).

Una funzione :VR||·|| : V → R è una norma sullo spazio vettoriale V se soddisfa tre proprietà:

  1. Positività e definitezza: v0||v|| ≥ 0 per ogni v, e v=0||v|| = 0 se e solo se v = 0.
  2. Omogeneità assoluta: av=av||a v|| = |a| · ||v|| per ogni scalare a e ogni vettore v.
  3. Disuguaglianza triangolare: u+vu+v||u + v|| ≤ ||u|| + ||v|| per ogni coppia di vettori.

Tre assiomi, e ogni norma deve passarli. Da questi deriva automaticamente che la distanza indotta d(u,v)=uvd(u, v) = ||u - v|| soddisfa gli assiomi di metrica: non-negatività, simmetria, disuguaglianza triangolare. Questa è la macchina principale che useremo: dato un modo di misurare la grandezza, ottieni gratis un modo di misurare la differenza.

Una funzione che non discende da una norma può comunque essere una metrica — la distanza di Hamming, ad esempio, vive su uno spazio non vettoriale. In quel caso si verificano direttamente gli assiomi metrici.

Per p ≥ 1, la norma Lp (o p-norma) di x = (x1, ..., xn) è definita come:

xp=(x1p+x2p+...+xnp)(1/p)||x||_p = ( |x1|^p + |x2|^p + ... + |xn|^p )^(1/p)

Riga per riga: prendi i valori assoluti di ogni componente, elevali alla p, somma, prendi la radice p-esima. Per p = 1 il 1^1 e la (1/1)^(1/1) sono identità e si ottiene la somma dei valori assoluti. Per p = 2 si ottiene la radice della somma dei quadrati, ovvero Pitagora generalizzato. Per p = ∞ si dimostra (limite) che x=maxixi||x||_∞ = max_i |x_i|.

Disuguaglianza di Minkowski (TEOREMA, Minkowski 1910): per p ≥ 1 vale x+ypxp+yp||x + y||_p ≤ ||x||_p + ||y||_p. È esattamente la disuguaglianza triangolare per Lp, e la sua dimostrazione richiede la disuguaglianza di Hölder (parente di Cauchy-Schwarz). Per 0 < p < 1 la disuguaglianza si rovescia e Lp non è più una norma — diventa una quasi-norma, oggetto teoricamente curioso ma fuori dal nostro scope pratico.

Equivalenza topologica delle norme in dimensione finita (TEOREMA): in R^n con n finito, per ogni coppia di norme || · ||_a e || · ||_b esistono costanti positive C1, C2 tali che C1xaxbC2xaC1 ||x||_a ≤ ||x||_b ≤ C2 ||x||_a per ogni x. Geometricamente, ogni palla unitaria è contenuta in una palla unitaria dell’altra norma a meno di scala. Conseguenza: nozioni come convergenza, continuità, limitatezza non dipendono dalla norma scelta. Attenzione: equivalenza topologica non è equivalenza pratica. Le costanti C1 e C2 possono dipendere da n e crescere male; il comportamento di un classificatore o di un sistema di retrieval può cambiare drasticamente a seconda della norma anche se “topologicamente” sono la stessa cosa. Marcatura di classe: questo è un teorema, non un’analogia, e va trattato come tale.

La notazione x0||x||_0 indica il numero di componenti non nulle di x. Non è una norma vera (viola l’omogeneità: ax0=x0||a x||_0 = ||x||_0 per a ≠ 0, non ax0|a| · ||x||_0), ma è un oggetto utile: misura la sparsità di un vettore.

Il problema con L0 è che minimizzarla è NP-hard in generale: combinatorio, non differenziabile. Il workaround pratico è L1, che è la più piccola Lp convessa che incoraggia sparsità — la geometria dei vertici della palla L1 fa il lavoro. Questo è il cuore del lasso (Tibshirani 1996) e di tutta la regolarizzazione sparsa moderna.

Il prodotto scalare (o dot product) tra due vettori in R^n è:

<u,v>=u1v1+u2v2+...+unvn<u, v> = u1 v1 + u2 v2 + ... + un vn

Connessione con L2: <u,u>=u22<u, u> = ||u||_2^2. La norma euclidea è la radice del prodotto scalare di un vettore con se stesso.

Connessione geometrica: <u,v>=u2v2cos(θ)<u, v> = ||u||_2 · ||v||_2 · cos(θ), dove θ è l’angolo tra i due vettori. Questa è una definizione, non un teorema: estende la nozione di angolo da R^2 e R^3 a qualunque dimensione. In R^768 non possiamo “vedere” l’angolo, ma possiamo calcolare il coseno, e il calcolo è coerente.

La cosine similarity è il coseno dell’angolo:

cossim(u,v)=<u,v>/(u2v2)cos_sim(u, v) = <u, v> / ( ||u||_2 · ||v||_2 )

Vive in [-1, 1]: 1 = stessa direzione, 0 = ortogonali, -1 = direzioni opposte. La cosine distance è di solito definita come 1cossim(u,v)1 - cos_sim(u, v), che vive in [0, 2]. Attenzione, qui c’è un trabocchetto pedagogico: la cosine distance così definita non è una metrica — non rispetta la disuguaglianza triangolare. La metrica genuina associata all’angolo è la angular distance arccos(cossim)/πarccos(cos_sim)/π, ma in pratica nessuno la usa: la cosine distance funziona benissimo come similarity score anche se non è metricamente onesta, e questo è uno dei tanti casi in ML in cui la praticità batte la pulizia teorica.

Una proprietà operativa che ricorre: se i vettori sono pre-normalizzati a u2=v2=1||u||_2 = ||v||_2 = 1, allora uv22=22<u,v>=22cossim(u,v)||u - v||_2^2 = 2 - 2 <u, v> = 2 - 2 cos_sim(u, v). In quel caso ordinare per cosine decrescente, per dot product decrescente, o per L2 crescente produce lo stesso ranking. È il motivo per cui i vector database normalizzano gli embedding a monte e usano dot product (più veloce di cosine perché evita due divisioni per riga).

La distanza di Mahalanobis tra due punti, dato un dataset con matrice di covarianza Σ stimata, è:

dM(u,v)=sqrt((uv)TΣ(1)(uv))d_M(u, v) = sqrt( (u - v)^T · Σ^(-1) · (u - v) )

L’idea: la matrice Σ codifica scala e correlazione delle feature. Σ^(-1) le decorrela e standardizza. La distanza che ne risulta tratta come “vicini” punti che la euclidea ingenua tratterebbe come lontani perché differiscono lungo direzioni di alta varianza naturale del dataset.

Casi particolari:

  • Σ = I (identità): dM=uv2d_M = ||u - v||_2, recuperiamo la euclidea.
  • Σ diagonale con varianze sull’asse: euclidea pesata, dM2=Σi(uivi)2/σi2d_M^2 = Σ_i (u_i - v_i)^2 / σ_i^2.
  • Σ piena: incorpora correlazioni tra coppie di feature.

Pseudocodice per il calcolo batch in NumPy:

import numpy as np
def mahalanobis_batch(X, mu, cov):
"""X: (n, d) — punti; mu: (d,) — media; cov: (d, d)."""
delta = X - mu
inv_cov = np.linalg.pinv(cov) # pseudoinversa per robustezza
left = delta @ inv_cov # (n, d)
return np.sqrt(np.sum(left * delta, axis=1)) # (n,)

Quando Σ è singolare (rank deficiency, succede quando le feature sono linearmente dipendenti) si usa la pseudoinversa di Moore-Penrose o si regolarizza Σ aggiungendo εIε · I.

Tra due distribuzioni di probabilità discrete P e Q sullo stesso supporto:

KL(PQ)=ΣxP(x)log(P(x)/Q(x))KL(P || Q) = Σ_x P(x) · log( P(x) / Q(x) )

Riga per riga: per ogni evento x, prendi la probabilità che P gli assegna, moltiplicala per il logaritmo del rapporto P(x)/Q(x), somma su tutti gli x.

Proprietà:

  • KL(PQ)0KL(P||Q) ≥ 0, con uguaglianza se e solo se P = Q (disuguaglianza di Gibbs).
  • Asimmetrica: KL(PQ)KL(QP)KL(P||Q) ≠ KL(Q||P) in generale. Geometricamente, KL “guarda” da P verso Q, non viceversa.
  • Niente disuguaglianza triangolare: KL viola sistematicamente KL(PR)KL(PQ)+KL(QR)KL(P||R) ≤ KL(P||Q) + KL(Q||R).
  • Può essere ++∞ se Q assegna massa 0 a un evento dove P assegna massa positiva.

Per questi tre motivi KL è una divergenza, non una distanza, e questa parola va presa sul serio. Un dev che la usa pensando di avere a disposizione una metrica si sorprende: clustering basato su KL ha proprietà sgradevoli, “vicino reciprocamente” non è ben definito, ranking con KL come distanza dà risultati diversi da ranking con KL inversa.

Esiste una versione simmetrizzata, la Jensen-Shannon divergence, definita come JS(P,Q)=(1/2)KL(PM)+(1/2)KL(QM)JS(P,Q) = (1/2) KL(P || M) + (1/2) KL(Q || M) con M = (P+Q)/2. Ha range limitato (in [0, log 2] se logaritmi naturali) ed è simmetrica; la sua radice è una metrica vera. Costo: due valutazioni di KL invece di una.

Cross-link: il dettaglio su entropia, cross-entropy e KL come perdite di training vive nel capitolo entropia-cross-entropy.

Non tutte le distanze derivano da norme. Tre famiglie comuni:

  • Hamming su stringhe binarie (o di simboli) di stessa lunghezza: numero di posizioni in cui differiscono. dH("10110","11100")=3d_H("10110", "11100") = 3. È una metrica genuina. Coincide con uv0||u - v||_0 se interpretiamo le stringhe come vettori binari. Usata in error-correcting codes, locality-sensitive hashing (SimHash), confronto di hash di documenti.

  • Levenshtein (edit distance) su stringhe di lunghezza diversa: numero minimo di inserimenti, cancellazioni e sostituzioni per trasformare una stringa nell’altra. Si calcola in O(nm)O(n · m) con programmazione dinamica. Metrica genuina. Spazio di base non è uno spazio vettoriale: la “differenza” tra due stringhe non è un’operazione naturale.

  • Jaccard su insiemi: J(A,B)=AB/ABJ(A, B) = |A ∩ B| / |A ∪ B| ∈ [0, 1]. La distanza di Jaccard 1 - J(A, B) è una metrica. Usata per detection di near-duplicates, similarity tra set di token (shingles), recommender systems su co-occurrence di item.

Tutte queste vivono fuori dalla famiglia Lp ma rispondono a domande di “quanto sono simili” che non si lasciano formulare bene con vettori reali.

Prendiamo u = (3, 4) e v = (0, 0).

  • L1: |3| + |4| = 7
  • L2: sqrt(9+16)=sqrt(25)=5sqrt(9 + 16) = sqrt(25) = 5
  • L∞: max(3, 4) = 4

La stessa coppia di punti, tre misure diverse, tre valori diversi. Il rapporto L1/L2 è 7/5 = 1.4 ≈ √2, che è una proprietà generale (in R^n, x2x1sqrt(n)x2||x||_2 ≤ ||x||_1 ≤ sqrt(n) · ||x||_2). L’L∞ è il più piccolo tra L1, L2 e L∞ su questo esempio. Più precisamente, per ogni vettore finito vale xx2x1||x||_∞ ≤ ||x||_2 ≤ ||x||_1; L∞ è il limite delle norme Lp per p → ∞, cioè il massimo valore assoluto delle componenti.

Ora prendiamo u = (1, 0, 0, 0, 0, 0, 0, 0, 0, 1) e v = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) in R^10.

  • L1: 2 (somma di valori assoluti, due 1)
  • L2: sqrt(2) ≈ 1.41
  • L∞: 1
  • L0: 2 (numero di componenti non nulle di u)

L1 vede “due unità di errore”. L2 le aggrega in sqrt(2). L∞ vede solo “il picco è 1”. L0 conta gli elementi attivi. Stesso vettore, quattro letture diverse.

flowchart TD
    R[Funzioni di distanza] --> N[Indotte da norma]
    R --> M[Metriche non-norma]
    R --> D[Divergenze<br/>non metriche]
    N --> LP[Famiglia Lp]
    LP --> L1[L1 — Manhattan]
    LP --> L2[L2 — Euclidea]
    LP --> LI[L∞ — Chebyshev]
    N --> COS[Cosine similarity<br/>L2 + dot product]
    N --> MAH[Mahalanobis<br/>L2 pesata]
    M --> HAM[Hamming]
    M --> LEV[Levenshtein]
    M --> JAC[Jaccard]
    D --> KL[KL]
    D --> JS[JS]
    D --> WAS[Wasserstein]

Figura 1 — vector (3,4) with three distances to origin annotated

Ricerca semantica con cosine vs L2 su tre vettori:

import numpy as np
# embedding inventati di tre frasi
v_query = np.array([0.8, 0.6, 0.0])
v_a = np.array([0.4, 0.3, 0.0]) # stessa direzione, magnitudine 1/2
v_b = np.array([0.6, 0.8, 0.0]) # diversa direzione, stessa magnitudine
v_c = np.array([0.0, 0.0, 1.0]) # ortogonale
def cos_sim(u, v):
return np.dot(u, v) / (np.linalg.norm(u) * np.linalg.norm(v) + 1e-12)
def l2(u, v):
return np.linalg.norm(u - v)
for name, vec in [("a", v_a), ("b", v_b), ("c", v_c)]:
print(f"{name}: cos={cos_sim(v_query, vec):.3f} L2={l2(v_query, vec):.3f}")

Output:

a:cos=1.000L2=0.500b:cos=0.960L2=0.283c:cos=0.000L2=1.414a: cos=1.000 L2=0.500 b: cos=0.960 L2=0.283 c: cos=0.000 L2=1.414

Il punto: con la cosine, a è il più simile (stessa direzione), poi b, poi c. Con L2, b è il più vicino, poi a, poi c. Il vettore a è ranking-1 con cosine ma ranking-2 con L2, perché L2 vede la sua magnitudine ridotta come un allontanamento.

query vector with cosine vs L2 ranking on three candidates Se gli embedding rappresentano direzioni semantiche e la magnitudine è rumore (lunghezza del documento, frequenza dei termini), cosine è la scelta corretta. Se la magnitudine ha significato (es. intensità di un segnale), L2 lo è. Stesso dataset, due risposte diverse.

SimHash riduce un documento a un hash binario di 64 bit costruito in modo che documenti simili producano hash con poca distanza di Hamming. Esempio sintetico:

import numpy as np
def hamming(a, b):
"""Numero di bit diversi tra due interi a 64 bit."""
return bin(a ^ b).count("1")
# tre hash inventati di tre documenti
h_query = 0xAB12CD34EF567890
h_doc1 = 0xAB12CD34EF567891 # un solo bit diverso
h_doc2 = 0xAB12CD34EF567000 # tredici bit diversi
h_doc3 = 0x0000000000000000 # quasi tutti diversi
for name, h in [("doc1", h_doc1), ("doc2", h_doc2), ("doc3", h_doc3)]:
d = hamming(h_query, h)
print(f"{name}: hamming={d}, similarity≈{1 - d/64:.2f}")

Il punto: con 64 bit la distanza Hamming va da 0 (identici) a 64 (opposti). Una soglia tipica per “near-duplicate” in pipeline di deduplicazione web è ≤ 3-5. Doc1 passa la soglia, doc2 no nonostante la grande maggioranza dei bit coincida. Hamming è veloce (XOR + popcount, due istruzioni assembly) e questo è il motivo per cui a scala web miliardi di confronti SimHash al giorno sono routine industriale.

Esempio 4: scenario reale — regolarizzazione L1 vs L2 in regressione

Sezione intitolata “Esempio 4: scenario reale — regolarizzazione L1 vs L2 in regressione”

Un team di data science deve prevedere il prezzo di una casa da 500 feature: età, metratura, zona codificata in 50 dummy, dati socio-demografici, vicinanza a 100 punti di interesse, eccetera. Molte feature sono ridondanti o irrilevanti.

Modello A — regressione lineare con regolarizzazione L2 (ridge):

min_w Σ (y_i - x_i · w)^2 + λ ||w||_2^2

Tutti i pesi vengono contratti dolcemente verso zero. Nessuno è esattamente zero. Il modello usa tutte le 500 feature, ognuna con un peso piccolo. Buono per varianza bassa, scarso per interpretabilità.

Modello B — regressione lineare con regolarizzazione L1 (lasso):

min_w Σ (y_i - x_i · w)^2 + λ ||w||_1

Geometricamente, gli spigoli del rombo della palla L1 forzano molti pesi esattamente a zero. Il modello finale potrebbe usare solo 30 feature su 500. Scopre da solo quali contano. Buono per interpretabilità, può essere instabile se le feature sono molto correlate (sceglie una a caso tra varianti quasi-equivalenti).

L’interpretazione bayesiana è una EQUIVALENZA argomentabile: se interpretiamo la loss come negative log-posterior, L2 corrisponde a un prior gaussiano sui pesi, L1 a un prior Laplace. Questa lettura non è automatica — richiede di accettare l’inquadramento MAP come equivalente alla minimizzazione regolarizzata — ma è coerente e illuminante. Non è un’identità matematica: è un dizionario tra due modi di pensare lo stesso problema.

Cross-link: il dettaglio operativo di lasso, ridge ed elastic net vive nel capitolo regolarizzazione (in preparazione).

Retrieval e RAG. Pipeline tipica: encoder genera embedding di documenti, embedding normalizzati a 2=1||·||_2 = 1, similarità calcolata via dot product (equivalente a cosine sui normalizzati). Database come FAISS, Milvus, Weaviate, pgvector espongono la metrica come parametro: inner_product, cosine, l2. La scelta di default è cosine per testi, L2 per immagini (dipende dall’encoder). Cross-link: rag-base (in preparazione).

Approximate Nearest Neighbor (ANN). HNSW, IVF, ScaNN, DiskANN: tutti algoritmi che pre-organizzano gli embedding per restituire i top-k vicini in tempo sub-lineare. La scelta della metrica determina la struttura dell’indice: HNSW con cosine costruisce un grafo diverso da HNSW con L2. Cambiare metrica significa ricostruire l’indice. Cross-link: ann-intro (in preparazione), ann-hnsw (in preparazione).

Loss di training.

  • MSE (Mean Squared Error): (1/n)Σ(yiy^i)2(1/n) Σ (y_i - ŷ_i)^2, una L2 al quadrato sulla differenza. Sensibile agli outlier perché il quadrato amplifica errori grandi.
  • MAE (Mean Absolute Error): (1/n)Σyiy^i(1/n) Σ |y_i - ŷ_i|, una L1 sulla differenza. Robusta agli outlier ma con derivata discontinua in 0 (sub-gradient).
  • Huber loss: L2 vicino a 0, L1 lontano. Compromesso usato in regressione robusta e in RL (DQN clipping).

Gradient clipping. Per stabilizzare il training, si limita la norma globale del gradiente: se g2>τ||g||_2 > τ, si rescala ggτ/g2g ← g · τ / ||g||_2. Si usa quasi sempre L2; alternative L∞ (clipping per-componente) hanno comportamento diverso e meno smooth.

Anomaly detection. Distanza Mahalanobis dai centroidi delle classi note, soglia per dichiarare un punto out-of-distribution. Funziona bene se le classi sono approssimativamente gaussiane multivariate. Cross-link: calibration-abstention (in preparazione).

Hashing e deduplication. SimHash produce un hash binario di 64 bit per documento; la distanza di Hamming tra hash misura quanto i documenti sono simili. Funziona perché SimHash è una locality-sensitive hash: documenti simili producono hash con poca distanza Hamming. Cross-link: lsh (in preparazione).

Batch normalization. Ogni layer normalizza le sue attivazioni a media 0 e varianza 1 sul batch (una versione di standardizzazione, parente della Mahalanobis con Σ diagonale stimata sul batch). L’idea geometrica è la stessa: rimettere le feature su una scala comparabile prima di farle passare nel layer successivo.

Le norme funzionano benissimo finché non si entra in alta dimensione, finché non si lavora con embedding non-isotropi, finché non si confondono divergenze e metriche, finché non si dimentica la precisione finita dei float. Tutti i problemi che seguono sono prevedibili e ricorrenti.

Risultato di Beyer, Goldstein, Ramakrishnan e Shaft (1999): in un dataset con punti distribuiti in modo “ragionevole” in R^d, al crescere di d il rapporto

( max_i d(query, point_i) ) / ( min_i d(query, point_i) )

tende a 1. In altre parole, tutti i punti tendono a essere ugualmente lontani dalla query. Conseguenza: nearest neighbor diventa un concetto sempre più fragile.

Geometricamente, in R^d con d grande, il volume di una sfera è quasi tutto concentrato vicino alla “buccia”: prendere un punto random dentro una sfera unitaria significa, con altissima probabilità, prenderlo a distanza vicina a 1 dal centro. La distribuzione delle distanze si stringe attorno a un valore tipico, e la differenza tra “più vicino” e “più lontano” si appiattisce.

Aggarwal, Hinneburg e Keim (2001) mostrano che L1 si concentra meno di L2, e norme frazionarie (Lp con p < 1, quasi-norme) ancora meno. Una norma “più affilata” (penalizza meno i picchi) preserva discriminazione in alta dimensione. Questo è il motivo per cui in alcune pipeline di ANN si usa cosine invece di L2 anche quando L2 sarebbe più naturale.

distribution of distances in low vs high dimension

Caveat onesto: l’analisi di concentrazione è asintotica e assume distribuzioni di base “tipiche” (uniformi su un cubo, gaussiane). Gli embedding di buona qualità vivono su manifold a bassa dimensione effettiva immersi in R^d, e la concentrazione è meno severa di quanto i risultati formali suggeriscano. Non è una scusa per ignorare il problema: è una promemoria che la dimensione effettiva conta più della dimensione nominale.

Cross-link: curse-dimensionalita.

Embedding contemporanei (BERT, GPT, e i loro discendenti) tendono a essere anisotropi: invece di occupare R^d in modo uniforme, vivono in un cono ristretto. Conseguenza diretta: la cosine similarity tra due token random non è 0 (come si vorrebbe) ma 0.3-0.5. Le similarità “informative” sono variazioni piccole su un baseline alto.

Effetto pratico: ranking di similarità ancora funziona (l’ordine relativo è informativo), ma i valori assoluti di cosine non vanno presi alla lettera. “Cosine 0.7” non significa “molto simili” in assoluto: significa “sopra la media del baseline anisotropo”.

Mitigazioni: whitening post-hoc, BERT-flow, contrastive training (CLIP, SimCSE). Cross-link: embedding-concetto.

Errore frequente: usare KL come distanza, ad esempio per clustering o per calcolare “il documento più vicino alla query” in termini di distribuzioni. Tre tipi di problemi che ne derivano:

  1. Asimmetria: KL(PQ)KL(QP)KL(P||Q) ≠ KL(Q||P). Decidere “quale direzione” è una scelta semantica, non un dettaglio. Forward KL KL(PQ)KL(P||Q) punisce Q che assegna 0 dove P assegna massa (mode-covering). Reverse KL KL(QP)KL(Q||P) punisce Q che assegna massa dove P assegna 0 (mode-seeking). Sono comportamenti opposti.

forward KL vs reverse KL on two distributions 2. Triangolare violata: clustering basato su KL può produrre cluster non transitivi. 3. Infinità: se Q ha zeri esatti dove P ha massa positiva, KL diverge. In pratica si applica smoothing (Laplace, Lidstone), che però introduce un iperparametro e altera il risultato.

Quando serve una vera distanza tra distribuzioni, JS divergence (simmetrica e bounded) o Wasserstein (sempre metrica, costosa) sono alternative. Cross-link: entropia-cross-entropy.

Cosine è un’ottima scelta quando la magnitudine è rumore. Diventa un problema quando la magnitudine è il segnale.

Esempio: due embedding di documenti tecnici con e senza forti termini chiave. La differenza in magnitudine può codificare la “densità” di contenuti specialistici; cosine la cancella. Risultato: documenti generici e documenti specialistici nello stesso topic vengono trattati come ugualmente simili, e il sistema di retrieval non distingue. Soluzione: usare dot product non normalizzato (sensibile alla magnitudine) o pesi misti.

Altro caso: embedding di immagini in cui la norma codifica la confidence dell’encoder. Normalizzare prima del retrieval butta via informazione utile.

Se la matrice di covarianza Σ è singolare (succede quando alcune feature sono linearmente dipendenti, o quando il numero di sample è inferiore alla dimensione), Σ(1)Σ^(-1) non esiste e la distanza non è calcolabile. Soluzioni:

  • pseudoinversa di Moore-Penrose (gestisce il rank deficiency)
  • regolarizzazione Σreg=Σ+εIΣ_reg = Σ + ε · I con ε piccolo
  • ridurre prima la dimensione (PCA) e calcolare Mahalanobis nello spazio ridotto

Senza queste protezioni, il calcolo esplode silenziosamente o produce numeri arbitrari.

Per vettori molto vicini, uv2||u - v||_2 calcolata come sqrt((uv)(uv))sqrt((u-v) · (u-v)) può perdere cifre significative per cancellation (sottrazione di numeri vicini): u - v ha magnitudine piccola, i quadrati pure, e l’accumulo introduce rumore numerico. Workaround: usare np.linalg.norm(u - v) o, in calcoli batch, scipy.spatial.distance.cdist, che implementano percorsi numericamente più stabili.

Per Lp con p grande e componenti minori di 1, |x|^p può andare a zero (underflow). Tecnica: lavorare in log-space, calcolare (1/p)log(Σexp(plogxi))(1/p) · log(Σ exp(p · log|x_i|)) con il trucco del log-sum-exp.

Per cosine quando una norma è prossima a zero: u0||u|| ≈ 0 implica divisione per quasi-zero, instabilità. Aggiungere epsilon al denominatore (/ (norm + 1e-12)) è la soluzione standard; ignorare il caso porta a NaN che propagano.

Combinare regolarizzazioni (λ1w1+λ2w22λ1 ||w||_1 + λ2 ||w||_2^2 = elastic net) richiede tuning di due iperparametri invece di uno, e l’interazione tra le due penalità non è banale. Senza grid search o cross-validation seria, i risultati sono peggiori della L1 o L2 pura.

Calcolare KL o cross-entropy tra una distribuzione empirica P (con supporto finito sui sample osservati) e una distribuzione teorica Q (smooth) richiede attenzione: se P ha massa su punti dove Q assegna densità minuscola, KL esplode in modo numericamente instabile. Smoothing di P o Q è obbligatorio in pratica.

Trabocchetto classico, banale ma onnipresente. Due feature: età (in anni, range 0-100) e reddito (in euro, range 0-100000). La distanza euclidea tra due individui è dominata dal reddito, perché i suoi numeri sono tre ordini di grandezza più grandi. Risultato: due persone della stessa età ma con reddito diverso vengono classificate come “lontane”, due persone con stesso reddito ma età diversa come “vicine”. Soluzione: standardizzare le feature (sottrarre media, dividere per deviazione standard) prima di calcolare distanze, oppure usare Mahalanobis che fa la cosa giusta automaticamente. Senza standardizzazione, KNN, k-means, e tutto ciò che si appoggia su L2 dà risultati guidati dalle unità di misura, non dalla struttura dei dati.

In retrieval testuale capita che una query molto corta produca un embedding con norma piccola e direzione instabile (poche parole, poco segnale). Cosine non è impressionata dalla magnitudine ma è ipersensibile a piccole variazioni di direzione. Conseguenza: top-1 spesso instabile, due query quasi identiche restituiscono documenti diversi. Soluzioni comuni: query expansion (aggiungere termini sinonimi prima di encodare), reranking con un modello cross-encoder, ensemble di metriche (cosine + BM25). La cosine da sola non basta su query povere.

Il punto generale, riassunto: la norma non è un parametro intercambiabile come la learning rate. Cambiare norma cambia cosa il sistema sta misurando. Un retrieval con cosine e un retrieval con L2 rispondono a domande diverse anche se gli embedding sono identici. Una loss MSE e una loss MAE fanno ottimizzare obiettivi diversi anche se i dati sono identici. Trattare la scelta della norma come un dettaglio è il punto di rottura più pernicioso, perché silenzioso: il sistema funziona, restituisce numeri, fa il suo lavoro — solo che sta rispondendo a una domanda diversa da quella che il dev pensava di stargli porre.

  • vettori e spazi: la grammatica vettoriale su cui si poggia tutto il calcolo di norme. Senza somma e moltiplicazione per scalare, gli assiomi non si possono nemmeno enunciare.
  • prodotto-scalare: il prodotto scalare visto come proiezione e somiglianza, parente stretto della cosine similarity.
  • matrici-trasformazioni: le matrici come trasformazioni preservano o deformano norme; questo è il ponte verso autovalori e analisi di stabilità.
  • entropia-cross-entropy: KL divergence e entropia in dettaglio, e il loro ruolo nelle loss di training (cross-entropy, RLHF, distillation).
  • regolarizzazione (in preparazione): L1, L2, elastic net, dropout — il capitolo dove la teoria di questo si fa pratica di fitting.
  • curse-dimensionalita: la concentrazione delle distanze in alta dimensione e le sue implicazioni per ANN, clustering e generalizzazione.
  • embedding-concetto: spazi di embedding, anisotropia, direzioni semantiche.
  • ann-intro (in preparazione): nearest neighbor approssimato, dove la scelta della metrica determina struttura e prestazioni dell’indice.
  • rag-base (in preparazione): retrieval augmented generation, prima applicazione massiva di cosine similarity in produzione.
  • ponte distribuzionale-embeddings: come la nozione di “vicinanza semantica” formalizzata in questo capitolo realizza l’ipotesi di Firth.
  • Hermann Minkowski, Geometrie der Zahlen, Teubner 1910. Fonte primaria per la disuguaglianza che porta il suo nome. Lettura impegnativa, in tedesco; serve per capire l’origine geometrica della famiglia Lp.
  • Prasanta Chandra Mahalanobis, “On the generalised distance in statistics”, Proc. Nat. Inst. Sci. India 2(1), 1936. Articolo originale, sorprendentemente leggibile. Sei pagine che cambiano la statistica multivariata.
  • Solomon Kullback, Richard Leibler, “On information and sufficiency”, Annals of Mathematical Statistics 22(1), 1951. Per chi vuole vedere KL nascere dal contesto crittografico-statistico originale.
  • Christopher M. Bishop, Pattern Recognition and Machine Learning, Springer 2006. Capitoli 1.6 (information theory) e 3 (regolarizzazione e interpretazione bayesiana). Trattazione moderna e pulita.
  • Kevin Beyer et al., “When Is ‘Nearest Neighbor’ Meaningful?”, ICDT 1999. Il paper sulla concentrazione delle distanze. Lettura corta, conseguenze profonde per chi progetta sistemi di retrieval.