Chỉ mục hàng xóm gần đúng

Đồ thị nhiều tầng bớt số phép đo, mã ngắn bớt chi phí mỗi phép đo; đổi lại, có thể sót hàng xóm thật.

Giải thuật nền tảng của Khoa học dữ liệu

Học kỳ 1 · Năm học 2026–2027

Trường Đại học Công nghệ · Đại học Quốc gia Hà Nội

Tiên quyết và quy ước

Nhắc lại: băm nhạy cảm theo tính cục bộ (LSH) chỉ xác minh ứng viên cùng thùng với $q$ (Bài 06).

Nhắc lại: $\|x-y\|_2^2=\sum_{i=1}^{D}(x_i-y_i)^2$ cộng được theo nhóm tọa độ.

Ký hiệu: kho $Y=\{y_1,\ldots,y_N\}\subset\mathbb R^D$; truy vấn $q\in\mathbb R^D$; số hàng xóm $K$, $1\le K\le N$.

Quy ước: 1 TB là $10^{12}$ byte; tọa độ viết $(1{,}7;\ 0{,}4)$.

Mục tiêu học tập

  1. Đặc tả bài toán $K$ hàng xóm gần đúng và tính độ thu hồi tại $K$.
  2. Chạy tay tìm kiếm trên đồ thị; mã hóa và tính khoảng cách bằng lượng tử hóa tích (PQ).
  3. Tính bộ nhớ, chi phí truy vấn và chọn chỉ mục theo ràng buộc cho trước.

Nội dung

  1. Bài toán hàng xóm gần đúng
  2. Tìm kiếm trên đồ thị lân cận
  3. Đồ thị thế giới nhỏ phân tầng (HNSW)
  4. Lượng tử hóa tích (PQ)
  1. Tệp đảo kết hợp PQ (IVF-PQ)
  2. Tổng kết và tự kiểm tra
  3. Bài tập thực hành

Đọc trước: Malkov và Yashunin, mục 3–4; Jégou, Douze và Schmid, mục II–IV; Princeton COS 597A, lớp 8–9.

Vấn đề trung tâm

Nhu cầu: tìm $K$ véc-tơ gần $q$ trong kho $10^{10}$ véc-tơ, dưới 10 ms, 6 TB (giả định).

  • Tìm kiếm chùm: đo ít đỉnh; đúng trên đỉnh đã thấy.
  • Đồ thị nhiều tầng: rút ngắn đường đi, vẫn giữ véc-tơ gốc.
  • PQ: mã ngắn, tra bảng; vẫn chấm mọi mã.
  • IVF-PQ: chỉ chấm mã trong vài danh sách gần $q$.

Ví dụ: truy hồi ngữ nghĩa trên mười tỷ véc-tơ

$N=10^{10}$ đoạn văn bản; véc-tơ $D=3072$ chiều; số thực 4 byte.

Mười tỷ đoạn văn bản và câu truy vấn đi qua cùng một mô hình nhúng thành véc-tơ 3072 chiều; kết quả là K đoạn có véc-tơ gần véc-tơ truy vấn q nhất

Lưu kho: $10^{10}\cdot3072\cdot4$ byte $=122{,}88$ TB

Quét một truy vấn: $10^{10}\cdot3072\approx3{,}07\cdot10^{13}$ lượt tọa độ

Câu hỏi: Với $10^{12}$ lượt tọa độ mỗi giây, quét toàn kho gấp bao nhiêu lần 10 ms?

Bài toán $K$ hàng xóm gần nhất

Nhu cầu: một tập đúng để so mọi chỉ mục; quét đủ tạo nó bằng $3{,}07\cdot10^{13}$ lượt tọa độ.

Đầu vào: kho $Y$, $|Y|=N$; truy vấn $q$; khoảng cách $d$; số nguyên $1\le K\le N$.

Đầu ra: $N_K(q)$, gồm $K$ điểm có $d(q,y)$ nhỏ nhất; hòa thì chỉ số $i$ nhỏ đứng trước.

Tìm hàng xóm gần đúng

Định nghĩa. Bài toán tìm gần đúng (approximate nearest neighbor) có cùng đầu vào, đầu ra là tối đa $K$ điểm $\widehat N_K(q)\subseteq Y$.

Chỉ mục chỉ đo một phần kho, hoặc đo bằng khoảng cách xấp xỉ.

Lưu ý: $\widehat N_K(q)$ có thể thiếu điểm của $N_K(q)$; mức thiếu đo bằng độ thu hồi.

Độ thu hồi tại $K$

Tập đúng gồm a, b, c, d, e; tập chỉ mục trả về gồm c, d, e, f, g; phần giao gồm c, d, e

Định nghĩa. Độ thu hồi (recall) tại $K$ là tỷ lệ hàng xóm thật mà chỉ mục tìm lại được:

$\operatorname{recall@K}(q)=\dfrac{|\widehat N_K(q)\cap N_K(q)|}{K}$

Ví dụ. $K=5$: giao có 3 phần tử, $\operatorname{recall@5}=3/5$.

Câu hỏi: Với cùng tập đúng, chỉ mục trả $\{a,c,f,g,h\}$. Tính $\operatorname{recall@5}$.

Bốn trục đánh giá chỉ mục

Câu hỏi: A đạt $\operatorname{recall@10}=0{,}9$ trong 5 ms; B đạt $0{,}7$ trong 2 ms. Nêu điều kiện để chọn B.
TrụcĐại lượng đo
Chất lượng$\operatorname{recall@K}$ trung bình
Truy vấnđộ trễ, số khoảng cách
Xây dựngthời gian, dữ liệu huấn luyện
Bộ nhớbyte mỗi véc-tơ, kể cả chỉ mục

Hai cách giảm chi phí truy vấn

Mô hình: chi phí truy vấn $\approx$ số véc-tơ được đo $\times$ chi phí một phép đo.

Cấu trúcThừa số giảmLưu véc-tơ gốc
LSHsố véc-tơcó
Đồ thị lân cậnsố véc-tơcó
PQchi phí một phép đokhông
IVF-PQcả haikhông

2.Tìm kiếm trên đồ thị lân cận

Muốn đo ít véc-tơ mà vẫn tới điểm gần $q$, phải đi trên đồ thị lân cận và giữ nhiều hướng.

Đồ thị lân cận · Tìm kiếm tham lam · Tìm kiếm chùm · SEARCH‑LAYER · Bất biến

Đồ thị lân cận

Nhu cầu: quét đủ đo cả $N=10^{10}$ véc-tơ; cần đo ít véc-tơ mà vẫn tới điểm gần $q$.

Đồ thị bảy đỉnh e, a, b, s, t, u, z có khoảng cách tới q lần lượt 9, 7, 5, 8, 4, 2, 1; cạnh e–a, a–b, e–s, s–t, t–u, u–z; điểm vào là e

Đồ thị lân cận là đồ thị có đỉnh là véc-tơ, cạnh nối mỗi đỉnh với vài đỉnh gần nó.

Chỉ mục lưu véc-tơ, danh sách lân cận của mỗi đỉnh và một điểm vào.

Tìm kiếm tham lam

Tại đỉnh hiện tại, đo mọi lân cận; sang lân cận gần $q$ nhất nếu nó gần hơn, ngược lại dừng.

Ký hiệu: $e{:}9$ nghĩa là $d(e,q)=9$.

Tìm kiếm tham lam đi từ e qua a tới b có khoảng cách 5 rồi dừng; z có khoảng cách 1 nằm trên nhánh e, s, t, u
ĐỉnhLân cậnQuyết định
$e:9$$a:7,\ s:8$sang $a$
$a:7$$e:9,\ b:5$sang $b$
$b:5$$a:7$dừng

Kết luận: $b$ là cực tiểu cục bộ (không lân cận nào gần $q$ hơn), nhưng $d(z,q)=1<5$.

Tìm kiếm chùm

Muốn tới $z{:}1$ khi tham lam dừng ở $b{:}5$, phải giữ nhánh $s$ chưa đi.

Đồ thị bảy đỉnh e, a, b, s, t, u, z có khoảng cách tới q lần lượt 9, 7, 5, 8, 4, 2, 1; cạnh e–a, a–b, e–s, s–t, t–u, u–z; điểm vào là e
  • Tìm kiếm chùm (beam search) tương tự tham lam, nhưng giữ nhiều đỉnh trong $W$.
  • $W$ gồm tối đa $ef$ (bề rộng chùm) đỉnh đã thấy gần $q$ nhất.
  • $C$ chứa các đỉnh từng vào $W$ nhưng chưa mở (chưa đo lân cận); mỗi bước mở đỉnh gần $q$ nhất của $C$.

Ví dụ: tìm kiếm chùm trên đồ thị bảy đỉnh

Điểm vào $e$, $ef=3$. Lập $C$ và $W$ sau mỗi lần mở.

Tìm kiếm chùm với ef bằng 3 giữ s trong hàng đợi; khi b không còn lân cận mới, thuật toán mở s rồi đi qua t, u tới z có khoảng cách 1
Mở$C$ sau bước$W$ sau bước, $ef=3$
$e$$a{:}7,\ s{:}8$$a{:}7,\ s{:}8,\ e{:}9$
$a$$b{:}5,\ s{:}8$$b{:}5,\ a{:}7,\ s{:}8$
$b$$s{:}8$$b{:}5,\ a{:}7,\ s{:}8$
$s$$t{:}4$$t{:}4,\ b{:}5,\ a{:}7$
$t,u,z$rỗng$z{:}1,\ u{:}2,\ t{:}4$
Câu hỏi: chạy lại với $ef=2$; thuật toán dừng ở bước nào, trả $W$ nào? Gợi ý: dừng khi đỉnh sắp mở xa $q$ hơn đỉnh xa nhất của $W$, hoặc $C$ rỗng.

Thuật toán: SEARCH-LAYER

Trạng thái sau khi mở b với ef bằng 3: V gồm e, a, b, s; C gồm s; W gồm b, a, s; C và W là tập con của V

Trạng thái của ví dụ sau khi mở $b$, $ef=3$.

Đầu vào: truy vấn $q$; bề rộng $ef\ge1$; tập điểm vào $ep$ với $1\le|ep|\le ef$; tầng $\ell_c$ (một đồ thị: $\ell_c=0$).

Đầu ra: $W$, tối đa $ef$ đỉnh gần $q$ nhất trong các đỉnh đã thấy.

Ký hiệu: $V$ là tập đỉnh đã thấy; $C,W\subseteq V$.

Thuật toán: SEARCH-LAYER


V ← ep;  C ← ep;  W ← ep
while C khác rỗng:
    c ← lấy ra đỉnh gần q nhất trong C
    f ← đỉnh xa q nhất trong W
    if d(c,q) > d(f,q): break
    for y in lân cận của c ở tầng ℓc:
        if y ∉ V:
            thêm y vào V
            f ← đỉnh xa q nhất trong W
            if |W| < ef or d(y,q) < d(f,q):
                thêm y vào C và W
                if |W| > ef: bỏ đỉnh xa q nhất khỏi W
return W

Ví dụ. $ef=3$, mở $s$ khi $W=\{b,a,s\}$: $f=s{:}8$; thêm $t{:}4$, bỏ $s$; ngưỡng mới $f=a{:}7$.

Tính đúng: SEARCH-LAYER

Bất biến: $W$ là một tập gồm $\min(ef,|V|)$ đỉnh của $V$ gần $q$ nhất.

Với ef bằng 2 và điểm vào e, thuật toán dừng khi đã thấy e, a, s, b; W gồm b và a; t, u, z chưa được thấy
Khởi tạo$V=W=ep$, $|ep|\le ef$.
Duy trìĐỉnh mới $y$ vào $V$; vào $W$ nếu $|W|<ef$, hoặc thay đỉnh xa nhất nếu gần $q$ hơn.
Khi dừng$W$ đúng trên $V$; đỉnh ngoài $V$ không được xét.

Ví dụ. $ef=2$: $W=\{b{:}5,a{:}7\}$ đúng trên $V=\{e,a,s,b\}$, nhưng $z{:}1\notin V$.

3.Đồ thị thế giới nhỏ phân tầng (HNSW)

Muốn tới vùng gần $q$ sau ít bước, phải đặt các tầng thưa có cạnh dài phía trên đồ thị chứa mọi điểm.

Cạnh dài · Truy vấn nhiều tầng · Phân phối tầng · Chèn điểm · Tham số và chi phí

Ví dụ: cạnh dài trên mười hai điểm thẳng hàng

SEARCH-LAYER đúng trên đỉnh đã thấy; với cạnh ngắn, số bước tăng theo khoảng cách từ điểm vào tới $q$.

Nhu cầu: ít bước khi $q$ xa điểm vào.

$s$ ở 0, $p1,\ldots,p11$ ở $1,\ldots,11$, $q$ ở $6{,}4$; đếm số bước tham lam từ $s$.

Mười hai điểm s, p1 đến p11 trên một đường thẳng, q nằm giữa p6 và p7 gần p6 hơn; chỉ có cạnh ngắn thì tham lam từ s cần 6 bước, thêm cạnh dài s–p4, p4–p8, p8–p11 thì cần 3 bước

Kết luận: thêm cạnh $s$–$p4$, $p4$–$p8$, $p8$–$p11$ giảm từ 6 xuống 3 bước.

Đồ thị nhiều tầng

Tầng 0 chứa mười hai điểm s, p1 đến p11; tầng 1 chứa s, p2, p4, p6, p8, p10; tầng 2 chứa s, p4, p8. Truy vấn ở tầng 2 đi s, p4, p8; xuống tầng 1 đi từ p8 sang p6; xuống tầng 0 tìm quanh p6
  • Đồ thị thế giới nhỏ phân tầng (Hierarchical Navigable Small World, HNSW) gồm nhiều tầng lồng nhau.
  • Tầng 0 chứa mọi điểm; tầng trên thưa hơn, cạnh dài hơn.
  • Tầng trên tìm với $ef=1$; điểm dừng là điểm vào của tầng dưới.
  • Tầng 0 tìm với chùm rộng $efSearch$.

Thuật toán: truy vấn HNSW

Đầu vào: $q$, $K$, bề rộng $efSearch\ge K$.

Đầu ra: tối đa $K$ đỉnh gần $q$ nhất trong các đỉnh đã thấy ở tầng 0.


ep ← {điểm vào};  L ← tầng của điểm vào
for ℓc = L, L−1, …, 1:
    W ← SEARCH-LAYER(q, ep, 1, ℓc)
    ep ← W
W ← SEARCH-LAYER(q, ep, efSearch, 0)
return K đỉnh gần q nhất trong W
Ba tầng trên mười hai điểm; tầng 2 đi s, p4, p8; tầng 1 đi từ p8 sang p6; tầng 0 bắt đầu từ p6, gần q

Ví dụ. $ep$ lần lượt là $\{p8\}$, $\{p6\}$; tầng 0 tìm quanh $p6$.

Phân phối tầng của điểm mới

Nhu cầu: khi chèn, mỗi điểm cần một tầng tối đa sao cho các tầng trên thưa dần.

Đặt $\ell=\lfloor-\ln(U)\,m_L\rfloor$, với $U\sim\operatorname{Uniform}(0,1]$ và $m_L>0$.

Mệnh đề. Với số nguyên $k\ge0$: $\Pr[\ell\ge k]=\rho^{k}$, trong đó $\rho=e^{-1/m_L}$.

Chứng minh. $\ell\ge k$ khi và chỉ khi $U\le e^{-k/m_L}$, và $U$ đều trên $(0,1]$.

Ý nghĩa: mỗi tầng giữ khoảng tỷ lệ $\rho$ số điểm của tầng ngay dưới.

Ví dụ. $m_L=1/\ln16$: $\rho=1/16$; với $N=10^{10}$, tầng cao nhất khoảng 8.

Ví dụ: chèn một điểm vào đồ thị ba tầng

Tầng $>\ell$: tìm $x$ với $ef=1$, không thêm cạnh.

Tầng $\le\ell$: tìm với bề rộng chùm $efConstruction$, rồi nối $x$ với $M$ đỉnh gần nó.

Điểm mới $x=2{,}6$, $\ell=1$, $efConstruction=3$, $M=2$. Xác định lân cận ở tầng 1, 0.

Điểm mới x ở tọa độ 2,6 có tầng 1, M bằng 2; pha 1 ở tầng 2 đi từ s tới p4; pha 2 nối x với p2 và p4 ở tầng 1, với p3 và p2 ở tầng 0
TầngTìm từKết quả
2$s$, $ef=1$$ep=\{p4\}$
1$p4$, $ef=3$$\{p2,p4,s\}$; nối $p2,p4$
0$p2,p4,s$, $ef=3$$\{p3,p2,p4\}$; nối $p3,p2$

Kết luận: $x$ nối với $p2,p4$ ở tầng 1 và với $p3,p2$ ở tầng 0.

Thuật toán: chèn HNSW

Đầu vào: $x$; chỉ mục; $M$; $efConstruction\ge M$; bậc tối đa $M_{max}$, $M_{max,0}$; $m_L$.

Đầu ra: chỉ mục có $x$ ở các tầng $0,\ldots,\ell$.


ℓ ← ⌊−ln(U)·mL⌋;  ep ← {điểm vào};  L ← tầng của điểm vào
for ℓc = L, L−1, …, ℓ+1:                      // pha 1
    ep ← {đỉnh gần x nhất trong SEARCH-LAYER(x, ep, 1, ℓc)}
for ℓc = min(L,ℓ), …, 0:                      // pha 2
    W ← SEARCH-LAYER(x, ep, efConstruction, ℓc)
    R ← chọn M lân cận cho x từ W
    nối x với mỗi đỉnh của R theo hai chiều ở tầng ℓc
    với mỗi y ∈ R có bậc vượt Mmax(ℓc): cắt lân cận của y
    ep ← W
if ℓ > L: đặt x làm điểm vào

Ba tham số của HNSW

Tham sốDùng khiTăng tham số thì
$M$chènbộ nhớ và số phép đo mỗi bước tăng
$efConstruction$chènxây chậm hơn; lân cận tốt hơn
$efSearch$truy vấnđộ trễ tăng; độ thu hồi thường tăng
Câu hỏi: Giảm độ trễ mà không xây lại chỉ mục: chỉnh tham số nào, theo chiều nào, mất gì?

Chi phí: truy vấn HNSW

Mô hình: số phép đo $\approx$ số bước $\times$ bậc.

Giả thiết: đồ thị mỗi tầng là Delaunay chính xác (nối điểm có ô Voronoi kề nhau); bậc bị chặn.

Mệnh đề. Với giả thiết trên, số phép đo trung bình là $O(\log N)$.

Lưu ý: đồ thị thực tế chỉ xấp xỉ; trường hợp xấu thăm cả tầng.

Chi phí: bộ nhớ HNSW

Mô hình: mỗi điểm lưu véc-tơ $D$ số thực 4 byte và danh sách lân cận ở mỗi tầng của nó.

Giả thiết: $N=10^{10}$, $D=3072$, $M=16$, $M_{max,0}=32$, $M_{max}=16$, $\rho=1/16$; mã định danh 8 byte.

Thành phầnMỗi điểmToàn kho
Véc-tơ gốc$4D=12\,288$ byte$122{,}88$ TB
Cạnh, kỳ vọng tối đa$\big(M_{max,0}+M_{max}\tfrac{\rho}{1-\rho}\big)\cdot8\approx265$ byte$\approx2{,}65$ TB

Kết luận: véc-tơ gốc chiếm khoảng 98% bộ nhớ.

4.Lượng tử hóa tích (PQ)

Muốn giảm bộ nhớ và chi phí mỗi phép đo, phải thay véc-tơ bằng mã ngắn và tính khoảng cách qua bảng tra.

Lượng tử hóa véc-tơ · Bộ mã con · Mã PQ · Khoảng cách bất đối xứng · Bảng tra

Lượng tử hóa véc-tơ

Nhu cầu: lưu mỗi véc-tơ bằng ít byte hơn; véc-tơ gốc chiếm khoảng 98% bộ nhớ HNSW.

Lượng tử hóa véc-tơ (vector quantization, VQ) là phép thay véc-tơ bằng chỉ số tâm gần nhất trong bộ mã $C=\{c_0,\ldots,c_{k-1}\}$.

Ba tâm c0 tại (0, 0), c1 tại (2, 0), c2 tại (0, 2) chia mặt phẳng thành ba ô; điểm x tại (1,7; 0,4) nằm trong ô của c1

Tâm: $c_0=(0;\ 0)$, $c_1=(2;\ 0)$, $c_2=(0;\ 2)$.

Ví dụ. $x=(1{,}7;\ 0{,}4)$; $\|x-c_i\|^2$: $3{,}05$; $0{,}25$; $5{,}45$.

Mã $i(x)=1$, dài $\lceil\log_2 3\rceil=2$ bit; $\widehat x=c_1=(2;\ 0)$, sai số $0{,}25$.

Câu hỏi: Tính mã và sai số của $y=(0{,}6;\ 1{,}5)$.

Thuật toán: mã hóa VQ

Đầu vào: $x\in\mathbb R^D$; bộ mã $C=\{c_0,\ldots,c_{k-1}\}\subset\mathbb R^D$ học trước bằng k-means.

Đầu ra: mã $i(x)$ dài $\lceil\log_2 k\rceil$ bit; không tâm nào gần $x$ hơn $c_{i(x)}$; hòa thì chọn chỉ số nhỏ hơn.

$i(x)\in\arg\min_{0\le i<k}\|x-c_i\|_2^2,\qquad \widehat x=c_{i(x)}$

Mã hóa tốn $k$ khoảng cách, tức $\Theta(kD)$; lưu bộ mã tốn $kD$ số.

Chi phí: một bộ mã lớn

Nhu cầu: sai số tái dựng nhỏ cần nhiều tâm, tức mã dài.

Mô hình: $k$ tâm trong $\mathbb R^D$, số thực 4 byte.

ViệcChi phíVới $k=2^{64}$, $D=128$
Lưu bộ mã$kD$ số thực 4 byte$\approx9{,}4\cdot10^{21}$ byte
Mã hóa một véc-tơ$\Theta(kD)$$\approx2{,}4\cdot10^{21}$ phép toán
Học bằng k-meansnhiều hơn $k$ điểm huấn luyệnhơn $1{,}8\cdot10^{19}$ điểm

Kết luận: với $D=128$, mã 64 bit không lấy được từ một bộ mã duy nhất.

Mã PQ và tái dựng

Nhu cầu: tạo mã dài từ các bộ mã nhỏ.

Véc-tơ tám chiều chia thành bốn đoạn hai chiều; mỗi đoạn được mã hóa bằng bộ mã con 256 tâm thành một chỉ số 8 bit; mã PQ là bộ bốn chỉ số, dài 32 bit

Định nghĩa. Lượng tử hóa tích (PQ) là VQ riêng trên từng đoạn $x^{(1)},\ldots,x^{(m)}$ của $x\in\mathbb R^D$, mỗi đoạn $D/m$ chiều.

  • Mỗi đoạn $j$ có bộ mã con riêng $k^*$ tâm; mã PQ là $(i_1,\ldots,i_m)$, dài $m\log_2 k^*$ bit.
  • Tái dựng: ghép các tâm con, $\widehat x=\big(c^{(1)}_{i_1},\ldots,c^{(m)}_{i_m}\big)$.

Ví dụ: mã hóa PQ hai đoạn

$D=4$, $m=2$, $k^*=2$; $x=(0{,}2;\ 1{,}8\mid 2{,}7;\ 0{,}1)$. Tìm tâm gần nhất của từng đoạn.

Tâm con: đoạn 1 $(0;\ 2)$, $(2;\ 0)$; đoạn 2 $(0;\ 0)$, $(3;\ 0)$.

Đoạn 1 có tâm 0 tại (0; 2) và tâm 1 tại (2; 0), x gần tâm 0; đoạn 2 có tâm 0 tại (0; 0) và tâm 1 tại (3; 0), x gần tâm 1; mã của x là (0, 1)
Đoạn$\|x^{(j)}-c\|^2$, tâm 0tâm 1chỉ số
1$0{,}08$$6{,}48$$0$
2$7{,}30$$0{,}10$$1$

Mã $(0,1)$, 2 bit. Tái dựng $\widehat x=(0;\ 2\mid 3;\ 0)$, sai số $0{,}08+0{,}10=0{,}18$.

Chi phí: kích thước mã và bộ mã PQ

Mã PQ dài $mb$ bit với $k^*=2^b$; bộ mã gồm $m$ bộ con, tổng $k^*D$ số. Cùng mã 64 bit, $D=128$:

VQ, $k=2^{64}$PQ, $m=8$, $k^*=256$
Số mã khác nhau$2^{64}$$256^8=2^{64}$
Bộ mã$2^{64}\cdot128$ số$256\cdot128=32\,768$ số
Mã hóa một véc-tơ$\Theta(2^{64}\cdot128)$$\Theta(32\,768)$

Kết luận: cùng $2^{64}$ mã, bộ mã PQ nhỏ hơn bộ mã VQ $2^{56}$ lần.

Ví dụ: khoảng cách bất đối xứng của mã $(0,1)$

Nhu cầu: kho chỉ còn mã; cần ước lượng $d(q,x)$ mà không dùng $x$.

Mã của $x$ là $(0,1)$; $q=(0{,}1;\ 1{,}9\mid 2{,}5;\ 0{,}2)$. Tính $\|q-\widehat x\|^2$ thay cho $d(q,x)^2$.

Hai mặt phẳng con của ví dụ PQ: x gần tâm 0 ở đoạn 1 và tâm 1 ở đoạn 2; truy vấn q ở (0,1; 1,9) và (2,5; 0,2)
ĐoạnTâm theo mã$\|q^{(j)}-c\|^2$
1$(0;\ 2)$$0{,}02$
2$(3;\ 0)$$0{,}29$

Ước lượng $0{,}02+0{,}29=0{,}31$; giá trị đúng $\|q-x\|^2=0{,}07$.

Khoảng cách bất đối xứng (ADC)

Định nghĩa. Khoảng cách bất đối xứng (asymmetric distance computation, ADC) giữa $q$ và mã của $y$ là

$\widetilde d(q,y)^2=\|q-\widehat y\|_2^2=\displaystyle\sum_{j=1}^{m}\big\|q^{(j)}-c^{(j)}_{i_j(y)}\big\|_2^2$

Số hạng đoạn $j$ chỉ phụ thuộc $q^{(j)}$ và chỉ số $i_j(y)\in\{0,\ldots,k^*-1\}$.

Kết luận: với một truy vấn, mỗi đoạn chỉ có $k^*$ giá trị số hạng khác nhau, tính trước được.

Bảng tra khoảng cách

Với một truy vấn, lập $T[j,i]=\|q^{(j)}-c^{(j)}_i\|^2$ gồm $m\times k^*$ ô; chấm mã $(i_1,\ldots,i_m)$ bằng $\sum_j T[j,i_j]$.

Ví dụ. $q=(0{,}1;\ 1{,}9\mid 2{,}5;\ 0{,}2)$; đoạn 1: $(0;2)$, $(2;0)$; đoạn 2: $(0;0)$, $(3;0)$.

$T$tâm 0tâm 1
đoạn 1$0{,}02$$7{,}22$
đoạn 2$6{,}29$$0{,}29$

Mã $(0,1)$: $0{,}02+0{,}29=0{,}31$; mã $(1,0)$: $7{,}22+6{,}29=13{,}51$.

Chi phí: bảng tra và chấm mã

Mô hình: chấm một mã là phép đo xấp xỉ qua bảng tra; $n_c$ là số véc-tơ được chấm.

BướcSố lầnChi phí mỗi lầnĐóng góp
Lập bảng$1$$k^*D$$k^*D$; lưu $mk^*$ số
Chấm mã bằng bảng$n_c$$m$ lần tra$mn_c$
Tính trực tiếp$n_c$$D$ tọa độ$Dn_c$

Kết luận: với $D=3072$, $m=512$, mỗi mã cần 512 lần tra thay vì 3072 lượt tọa độ.

Chi phí: PQ quét đầy đủ

Mô hình: đếm byte đọc và lượt tọa độ hoặc lần tra; $N=10^{10}$, $D=3072$, mã PQ $m=512$ đoạn 6 chiều, $b=8$.

Một truy vấnQuét véc-tơ gốcQuét mã PQ
Dữ liệu đọc$122{,}88$ TB$5{,}12$ TB
Phép toán$ND\approx3{,}07\cdot10^{13}$ lượt tọa độ$Nm=5{,}12\cdot10^{12}$ lần tra
Số véc-tơ được chấm, $n_c=N$$10^{10}$$10^{10}$

Kết luận: PQ giảm chi phí mỗi phép đo, không giảm số véc-tơ được chấm.

5.Tệp đảo kết hợp PQ (IVF-PQ)

Muốn chỉ chấm một phần kho bằng mã ngắn, phải chia kho thành danh sách đảo và mã hóa phần dư.

Lượng tử hóa thô · Danh sách cần mở · Phần dư · Truy vấn IVF-PQ · Chi phí

Tệp đảo (IVF)

Nhu cầu: chấm ít hơn $10^{10}$ mã mỗi truy vấn; PQ quét đủ chấm mọi mã.

Tệp đảo (inverted file, IVF) là $k_c$ danh sách; $L_i$ chứa các véc-tơ gần tâm thô $\mu_i$ nhất.

Truy vấn chỉ mở $nprobe$ danh sách có tâm gần $q$ nhất.

Bốn tâm thô μ0 đến μ3 chia mặt phẳng thành bốn ô ứng với bốn danh sách đảo; truy vấn q gần μ1 nhất rồi đến μ0; với nprobe bằng 2 chỉ L1 và L0 được mở

Ví dụ. 16 điểm, bốn danh sách; $nprobe=2$: mở $L_1$, $L_0$, chấm 8 điểm.

Chọn danh sách cần mở

Gán mỗi $y$ cho tâm thô gần nhất; mở $nprobe$ danh sách có $\|q-\mu_i\|$ nhỏ nhất.

$a(y)\in\arg\min_{0\le i<k_c}\|y-\mu_i\|^2,\qquad L_i=\{y: a(y)=i\}$

Bốn tâm thô μ0 đến μ3 chia mặt phẳng thành bốn ô; truy vấn q gần μ1 nhất rồi đến μ0; điểm y3 nằm trong ô của μ0, sát ranh giới với ô của μ1
Tâm$\|q-\mu_i\|^2$Thứ tự
$\mu_1=(8;2)$$6{,}25$1
$\mu_0=(2;2)$$18{,}25$2
$\mu_3=(8;8)$$24{,}25$3
$\mu_2=(2;8)$$36{,}25$4
Câu hỏi: Với $nprobe=3$, danh sách nào được mở, danh sách nào không?

Mã hóa phần dư

Nhu cầu: mã PQ chính xác hơn với cùng số bit.

$r(y)=y-\mu_{a(y)},\qquad \|q-y\|=\big\|(q-\mu_i)-r(y)\big\|$ với $y\in L_i$

Hai ô dưới của ví dụ tệp đảo: mũi tên xanh từ μ1 tới y8 là phần dư r(y8); hai đoạn nét đứt từ μ1 và μ0 tới q là truy vấn dư dùng khi quét L1 và L0
  • Trung bình $\|r(y)\|^2$ nhỏ hơn trung bình $\|y\|^2$ (tâm thô là trọng tâm ô); $L_i$ lưu $\operatorname{id}(y)$ và mã PQ của $r(y)$.
  • Quét $L_i$: ADC với truy vấn dư $\widetilde q_i=q-\mu_i$; mỗi danh sách mở một bảng tra.

Ví dụ. $y_8=(6{,}5;\ 2{,}5)$, $r(y_8)=(-1{,}5;\ 0{,}5)$; $\widetilde q_1=(-2;\ 1{,}5)$, $\widetilde q_0=(4;\ 1{,}5)$.

Thuật toán: truy vấn IVF-PQ

Đầu vào: $q$; $K$; $nprobe$; tâm thô, danh sách đảo, bộ mã PQ của phần dư.

Đầu ra: tối đa $K$ mã định danh có khoảng cách ước lượng nhỏ nhất trong các danh sách mở.


P ← nprobe tâm thô gần q nhất
H ← rỗng      // giữ K cặp (d, id) nhỏ nhất
for i in P:
    T ← bảng tra của q − μi
    for (id, mã) in Li:
        d ← Σj T[j, mãj]
        cập nhật H bằng (d, id)
return id trong H theo d tăng dần

Ví dụ: truy vấn IVF-PQ

Bốn danh sách của ví dụ, $q=(6;3{,}5)$, $nprobe=2$, $K=3$; giả sử ADC không sai số; tập đúng $N_3(q)=\{y_8,y_3,y_7\}$.

Mở$\|q-y\|^2$
$L_1$$y_8$ 1,25; $y_7$ 6,5; $y_5$ 7,25; $y_6$ 13
$L_0$$y_3$ 2,34; $y_2$ 18,5; $y_4$ 20,34; $y_1$ 29

Kết luận: $nprobe=2$, $K=3$ trả $y_8$, $y_3$, $y_7$.

Câu hỏi: Với $nprobe=1$, kết quả và $\operatorname{recall@3}$ là gì?

Chi phí: truy vấn IVF-PQ

Mô hình: một lần tra tính bằng một lượt tọa độ; mỗi phần tử của $L_i$ chiếm $8+512$ byte.

Giả thiết: $N=10^{10}$, $D=3072$, $m=512$, $k^*=256$; $k_c=10^5$, $nprobe=64$; danh sách cân bằng.

BướcSố lầnChi phí mỗi lầnĐóng góp
Chọn tâm thô$k_c$ khoảng cách$D$$3{,}07\cdot10^{8}$
Lập bảng tra$nprobe$ bảng$k^*D$$5{,}03\cdot10^{7}$
Chấm mã$n_c\approx nprobe\,N/k_c$ mã$m$$3{,}28\cdot10^{9}$
Tổng$\approx3{,}63\cdot10^{9}$

Kết luận: ít hơn quét đủ mã PQ khoảng 1400 lần.

6.Tổng kết và tự kiểm tra

Muốn chọn chỉ mục cho kho mở đầu, phải đối chiếu giả thiết, bảo đảm, bộ nhớ và chi phí truy vấn.

Giả thiết · Bảo đảm và chi phí · Vấn đề trung tâm · Câu hỏi tự kiểm tra · Tài liệu đọc

Kết quả và giả thiết không được bỏ

Kết quảGiả thiết không được bỏCông thức hoặc thuật toán
Độ thu hồiphá hòa theo chỉ số; cùng truy vấn, cùng $K$$|\widehat N_K(q)\cap N_K(q)|/K$
Bất biến SEARCH-LAYERchỉ xét đỉnh đã thấy $V$$W$: $\min(ef,|V|)$ đỉnh gần $q$ nhất của $V$
Truy vấn HNSWmỗi tầng là đồ thị Delaunay chính xác, bậc bị chặnsố phép đo trung bình $O(\log N)$
ADCbình phương Euclid; các đoạn rời nhau$\sum_j T[j,i_j]$
Phần dư IVF$y\in L_i$; dùng $\widetilde q_i=q-\mu_i$$\|q-y\|=\|\widetilde q_i-r(y)\|$
Số mã IVF-PQ được chấmdanh sách cân bằng$nprobe\,N/k_c$

Thuật toán, bảo đảm và chi phí

Kho $10^{10}$ véc-tơ, $D=3072$; $M=16$; $m=512$, mã PQ 512 byte; $k_c=10^5$, $nprobe=64$.

Thuật toánĐầu vàoBảo đảmChi phí
LSH (Bài 06)bảng băm, véc-tơ gốc$d(q,y)\le d_1$ được xác minh với xác suất $\ge1-(1-p_1^r)^b$số ứng viên $\times D$; $12\,288+8b$ byte mỗi véc-tơ ($b$ dải)
HNSWđồ thị, $M$, $efSearch\ge K$đúng trên đỉnh đã thấysố bước × bậc × $D$; $\approx12\,553$ byte mỗi véc-tơ
PQ quét đủmã, bảng traxếp theo khoảng cách tới $\widehat y$$5{,}12\cdot10^{12}$ lần tra; 512 byte mỗi véc-tơ
IVF-PQ$k_c$, $nprobe$, mã PQchỉ xét danh sách mở, khoảng cách ADC$\approx3{,}63\cdot10^{9}$ thao tác; $512+8$ byte mỗi véc-tơ

Câu trả lời cho vấn đề trung tâm

Kho $10^{10}$ véc-tơ $D=3072$; giả định $10^{12}$ thao tác mỗi giây.

  • HNSW, $M=16$: giữ véc-tơ gốc, khoảng $125{,}5$ TB, vượt 6 TB.
  • PQ quét đủ: $5{,}12$ TB vừa bộ nhớ, nhưng mất khoảng $5{,}12$ giây mỗi truy vấn.
  • IVF-PQ, $k_c=10^5$, $nprobe=64$, danh sách cân bằng: $5{,}2$ TB, khoảng $3{,}6$ ms.
  • Với 6 TB và 10 ms (giả định), IVF-PQ khả thi; $nprobe$ chọn theo độ thu hồi đo được.

Câu hỏi tự kiểm tra

Câu hỏi: trả lời và nêu kết quả đã dùng.

  1. Cạnh $u{:}8$–$v{:}6$, $u$–$w{:}9$, $w$–$z{:}2$; điểm vào $u$. Chạy tìm kiếm chùm với $ef=2$ và $ef=3$; lần chạy nào tới $z$?
  2. Tính bộ nhớ HNSW cho $10^8$ véc-tơ $D=128$, cạnh 265 byte mỗi véc-tơ; so với 64 GB.
  3. IVF-PQ, $N=10^9$, $k_c=32\,000$, $nprobe=16$, $m=8$, danh sách cân bằng: tính số mã được chấm và số lần tra.

Nguồn và tài liệu đọc

Nguồn: Malkov, Yashunin (2018), bài báo HNSW, arXiv 1603.09320, mục 3–4, tr.1–8.

Nguồn: Jégou, Douze, Schmid (2011), Product quantization for nearest neighbor search, IEEE TPAMI 33(1), mục II–IV, tr.2–7.

Nguồn: Leskovec, Rajaraman, Ullman, Mining of Massive Datasets, ấn bản 3 (2020), Chương 3 (LSH, Bài 06).

Nguồn: Princeton COS 597A (2023), lớp 8 và sổ thực hành, lớp 9; Stanford BIODS 271 (2025), bài 12.

Ghi chú bài giảng

7.Bài tập thực hành

Muốn kiểm các công thức PQ và IVF-PQ bằng số đo, phải chạy sổ thực hành trên dữ liệu tổng hợp.

Mã và tái dựng PQ · Ngân sách 6 byte · Chỉ mục IVF-PQ · Độ thu hồi theo số danh sách mở

Sổ thực hành và dữ liệu

Thực hành

Sổ class-08-runbook-for-students.ipynb (Princeton COS 597A, lớp 8); chuẩn bị bằng các ô 0–4, 17, 21–24.

MảngKích thướcVai trò
xt$10^6\times64$huấn luyện bộ mã
xb$10^4\times64$kho, $N=10^4$
xq$100\times64$truy vấn
gt$100\times10$10 hàng xóm đúng
Nhiệm vụÔ
1. Mã và tái dựng PQ82–97
2. Cùng ngân sách 6 byte98–99
3. Chỉ mục IVF-PQ148–155

Bài tập: mã và tái dựng PQ (a)

Thực hành

Câu hỏi: chạy ô 83–95; điền bảng và giải thích từng chiều của hai mảng.

Ô 83: pq = faiss.ProductQuantizer(d, 4, 8), tức $D=64$, $m=4$, $b=8$.

Đại lượngDự đoán từ $D,m,b$Giá trị kiểm bằng mã
pq.code_size (byte)
pq_centroids.shape
xb_codes.shape

Nguồn: sổ thực hành Princeton COS 597A lớp 8, ô 82–95.

Bài tập: mã và tái dựng PQ (b)

Thực hành

Câu hỏi: hoàn thiện ô 96 mà không gọi decode; ô 97 phải in True.

Nhắc lại: $\widehat x=\big(c^{(1)}_{i_1},\ldots,c^{(m)}_{i_m}\big)$, với tâm con nằm trong pq_centroids và chỉ số trong xb_codes.


# ô 96: reconstruct vector no 123 -- TODO implement the re-construction!
xb123_recons = ________________________________

# ô 97
np.all(pq_reconstruction[123] == xb123_recons)

Nguồn: sổ thực hành Princeton COS 597A lớp 8, ô 96–97.

Bài tập: cùng ngân sách 6 byte (a)

Thực hành

Câu hỏi: dự đoán $D/m$, $k^*$; chạy rồi ghi sai số bình phương trung bình (MSE) và thời gian.

Ô 99: với $m\in\{4,8,16\}$ (Faiss M), $b=48/m$ (nbits); huấn luyện, mã hóa rồi giải mã xb.

$m$$b$$D/m$ (dsub)$k^*$ (ksub)MSEmã hóa–giải mã (ms)
412
86
163

Nguồn: sổ thực hành Princeton COS 597A lớp 8, ô 98–99.

Bài tập: cùng ngân sách 6 byte (b)

Thực hành

Câu hỏi: từ số đo MSE và thời gian đã ghi, trả lời ba ý sau.

  1. Xác nhận ba cấu hình có cùng code_size.
  2. Xếp hạng MSE; so với nhận định của nguồn: $k^*$ lớn hơn, $m$ nhỏ hơn thì chính xác hơn.
  3. So sánh thời gian; giải thích bằng chi phí mã hóa $k^*D$ lần lượt là $4096\cdot64$; $64\cdot64$; $8\cdot64$.

Nguồn: sổ thực hành Princeton COS 597A lớp 8, ô 98–99.

Bài tập: chỉ mục IVF-PQ (a)

Thực hành

Câu hỏi: chạy ô 149–151; đọc chuỗi cấu hình để điền bảng; nêu ô 150, 151 học hoặc lưu gì.


index = faiss.index_factory(d, "IVF200,PQ16x8np")   # ô 149
index.train(xt)                                     # ô 150
index.add(xb)                                       # ô 151
$k_c$$m$$b$byte mã mỗi véc-tơ$|L_i|$ trung bình

Nguồn: sổ thực hành Princeton COS 597A lớp 8, ô 148–151.

Bài tập: chỉ mục IVF-PQ (b)

Thực hành

Câu hỏi: chạy ô 152–155 của sổ thực hành lớp 8; ghi kết quả vào phiếu báo cáo.


for nprobe in 2, 5, 10, 20, 50:                     # ô 155
    index.nprobe = nprobe
    t0 = time.time()
    for _ in range(50):
        D, I = index.search(xq, 10)
    t1 = time.time()
    nok = (I[:, 0] == gt[:, 0]).sum()
    print(f"{nprobe=:} {nok=:} {(t1 - t0)*1000:.3f} ms")
Đại lượngÝ nghĩa
$nok/100$$\operatorname{recall@1}$ trung bình trên 100 truy vấn
$(t_1-t_0)\cdot1000$tổng ms của $50\times100$ lượt truy vấn

Bài tập: chỉ mục IVF-PQ (c)

Thực hành

Câu hỏi: vẽ $\operatorname{recall@1}$ theo thời gian trung bình; giải thích xu hướng bằng số mã được chấm.

$nprobe$$\operatorname{recall@1}$tổng msms trung bình mỗi truy vấn trong lôsố mã được chấm
2
5
10
20
50

Nguồn: sổ thực hành Princeton COS 597A lớp 8, ô 149–155.