Bạn thêm một công cụ tìm kiếm vào ứng dụng tài liệu. Một người dùng muốn tìm trang có van nằm phía trên bơm. Tìm kiếm toàn văn của bạn tìm được từ "pump" trong nhiều sổ tay. Nhưng chỉ từ từ đó, nó không biết sơ đồ nào có bố cục đang được tìm kiếm.
Sổ tay hư cấu Lumen Equipment sẽ là môi trường thực hành của chúng ta. Nó có một đường cong, một sơ đồ mạch và một bảng kê, tức danh sách linh kiện. Câu hỏi của chúng ta là: "Which page shows the bypass valve above the pump?", nghĩa là: "Trang nào cho thấy van bypass ở phía trên bơm?" Bản dịch giúp hiểu ví dụ; các truy vấn trong bài vẫn bằng tiếng Anh.
Chúng ta sẽ xây dựng một công cụ lập chỉ mục hình ảnh của các trang, chứ không chỉ các từ của chúng. ColQwen2 biến các hình ảnh và câu hỏi này thành biểu diễn số; sau đó mã của chúng ta tính mức tương đồng bằng phương pháp gọi là MaxSim. Chúng ta sẽ so sánh phương pháp này với BM25, một phương pháp tìm kiếm văn bản, và với biểu diễn thu được bằng cách lấy trung bình các vector.
Mục tiêu rất cụ thể: trả về các trang để xem xét, không tạo ra câu trả lời về cách máy hoạt động. Mô hình đã được huấn luyện và không thay đổi trong hướng dẫn này. Chúng ta sẽ học cách làm chủ việc lập chỉ mục, xếp hạng và đánh giá chúng.
Vấn đề cụ thể
Bộ sưu tập của chúng ta, còn gọi là corpus, gồm 24 sổ tay, mỗi sổ bốn trang, tức 96 trang. Chương trình nhận hình ảnh của chúng và các câu hỏi. Nó phải sắp thứ tự các trang từ gần truy vấn nhất đến xa nhất, rồi cho phép quay lại tài liệu gốc.
Một chú thích về mức độ liên quan, hay label, chỉ ra trang nào được kỳ vọng cho một câu hỏi. Nó dùng để đo xếp hạng, không phải để tạo ra xếp hạng: dịch vụ inference truy cập hình ảnh và truy vấn, còn các label nằm ngoài Docker mount của nó.
Embedding thực sự là gì?
Ở đây, vector là một danh sách số. Embedding là biểu diễn do mô hình tính ra, được thiết kế để cho phép so sánh hữu ích giữa các đầu vào. Thay vì so sánh trực tiếp ký tự trong câu hỏi với pixel của sơ đồ, chúng ta so sánh các biểu diễn số của chúng.
Chương trình tạo các biểu diễn này gọi là bộ mã hóa. Trong trường hợp của chúng ta, nó có thể nhận văn bản cho một truy vấn và hình ảnh cho một trang. Trang chính thức của ColQwen2 trình bày phương pháp tìm kiếm tài liệu kết hợp văn bản và hình ảnh này, với các biểu diễn nhiều vector.
Tại sao lại nhiều vector? Một trang có thể chứa tiêu đề, chú thích, đường cong và một sơ đồ nhỏ. Chúng ta không nhất thiết muốn tóm tất cả trong một vector duy nhất. ColQwen2 giữ lại một chuỗi vector, mà chúng ta gọi là đa vector. Truy vấn cũng có chuỗi riêng.
Để hình dung, hãy nghĩ đến nhiều manh mối số thay vì một phiếu tóm tắt duy nhất. Nhưng đừng hiểu hình ảnh này quá sát: không có cột nào tên là "bơm", cột khác là "van" và cột thứ ba là "phía trên". Các biểu diễn được học và phụ thuộc ngữ cảnh. Những tên chúng ta đặt trong ví dụ để giải thích phép tính, không phải để tự động dịch các chiều của chúng.
Vì sao gọi là tương tác muộn?
Tương tác muộn nghĩa là trang và truy vấn trước hết được mã hóa riêng. Chúng chỉ được so sánh khi tìm kiếm. Đây là nguyên lý được trình bày bởi dự án ColBERT, nguồn cảm hứng cho chiến lược tìm kiếm đa vector này.
Với một lập trình viên web, sự tách biệt này rất quen thuộc. Khi nhập tài liệu, bạn chuẩn bị dữ liệu có thể tái sử dụng: chỉ mục. Khi có tìm kiếm mới, bạn mã hóa câu hỏi rồi tra chỉ mục đó. Vẫn còn các so sánh cần tính, nhưng không cần đưa lại mọi hình ảnh qua mô hình cho mỗi truy vấn.
Lập chỉ mục không phải là huấn luyện. Ở đây, tham số của mô hình, còn gọi là trọng số, được đóng băng: chúng ta không điều chỉnh chúng theo các sổ tay Lumen. Chúng ta dùng một mô hình đã huấn luyện trước để tính các biểu diễn mới. Nội dung chỉ mục thay đổi khi thêm trang; trọng số mô hình thì không thay đổi trong bài này.
Mạch chính: giải thích một kết quả, không chỉ nhìn thấy nó
Hãy trở lại ví dụ khái niệm: một trang có bơm, mũi tên và van. Câu hỏi có nhiều manh mối, đặc biệt bypass valve, above và pump. Công cụ phải tìm trang tương thích với các manh mối này, rồi để chúng ta mở nó ra kiểm tra bố cục.
Chuỗi xử lý là: PDF → ảnh trang → đa vector → so sánh với truy vấn → xếp hạng → kiểm tra trang. Kết xuất PDF thành ảnh nghĩa là tạo các pixel của trang như trình đọc PDF hiển thị. Chỉ mục lưu trang, mã định danh sổ tay, vector và mặt nạ chỉ ra vector nào cần dùng.
Đầu ra gồm thứ hạng và các đóng góp vào điểm số. Thứ hạng trả lời "công cụ đặt trang này ở đâu?". Các đóng góp giúp xem xét những liên hệ số đã tham gia vào điểm số.
Không đầu ra nào trong số này cho phép khẳng định "van đang mở". Thông tin đó không được hỏi cũng không được xác lập bằng xếp hạng. Một câu trả lời được soạn trong ứng dụng của bạn sẽ là bước bổ sung, cần liên kết với nguồn và đánh giá riêng. Công cụ tìm kiếm chỉ cho chúng ta biết cần xem ở đâu; nó không thay thế việc đọc nội dung đã tìm được.
Vì sao trung bình làm mất chi tiết hữu ích
Trung bình vector gộp nhiều biểu diễn thành một bằng cách lấy trung bình các thành phần của chúng. Sự đơn giản hóa này giữ lại thông tin tổng quát, nhưng không giữ hết khác biệt giữa các biểu diễn gốc.
Để trực giác, hãy tưởng tượng một vector truy vấn tìm manh mối liên quan đến bơm và vector khác tìm cách bố trí của nó. Mỗi vector có thể tìm được tương đồng mạnh với một phần khác nhau của trang. Khi trộn các biểu diễn của sơ đồ, văn bản và nền, trung bình có thể làm yếu đi một chi tiết hiếm.
MaxSim đưa ra lựa chọn khác: với mỗi vector truy vấn, giữ lại mức tương đồng tốt nhất với trang. Sau đó cộng các kết quả tốt nhất này. Những manh mối khác nhau không cần tìm láng giềng tốt nhất ở cùng một vị trí.
Lựa chọn này không bảo đảm tính liên quan. Một giá trị cực đại cũng có thể giữ lại tương đồng ngẫu nhiên, và nhiều vector truy vấn có thể chọn cùng một vector trang. Bản thân phép toán này không bắt buộc kiểm chứng hình học quan hệ "phía trên". Mô hình cung cấp biểu diễn; MaxSim so sánh chúng. Chúng ta vẫn phải đo xem tổ hợp này có tìm được đúng trang không.
Hiểu MaxSim trước khi viết mã
Từ bảng số đến điểm số
Trong mã, query chứa các vector của truy vấn và document chứa vector của một trang. Với các thao tác đang xét, tensor đơn giản là một mảng số. Mỗi hàng của hai mảng là một vector.
Lq là số vị trí của truy vấn, Ld là số vị trí của trang và D là số thành phần của vector. Vì vậy đầu vào có dạng [Lq, D] và [Ld, D]. Chúng phải có cùng chiều D để vector của chúng có thể được so sánh.
Bạn cũng sẽ gặp từ token. Với văn bản, đó là đơn vị mô hình xử lý, không nhất thiết tương ứng với một từ trọn vẹn. Với ảnh, quá trình xử lý dùng các biểu diễn thị giác. Trong các hàm dưới đây, phép tính chủ yếu thao tác các vị trí trong chuỗi và vector của chúng: không cần gán tên tiếng Pháp cho chúng.
Mức tương đồng được tính bằng tích vô hướng: nhân các thành phần tương ứng của hai vector rồi cộng lại. Ví dụ thuần số học: vector [1, 0] và [0.6, 0.8], viết theo ký hiệu thập phân của Python, cho 1 × 0,6 + 0 × 0,8 = 0,6. Ta nhân hai thành phần đầu với nhau, rồi hai thành phần sau, và cộng kết quả.
Hợp đồng mã cho biết bộ mã hóa cung cấp các vector đã chuẩn hóa. Khi chuẩn của chúng bằng 1, tích vô hướng này tương ứng với độ tương đồng cosine, so sánh hướng của chúng. Việc chuẩn hóa thuộc bước chuẩn bị đầu vào: hàm check() không tự tính hoặc kiểm tra nó.
MaxSim có thể tính bằng tay
Hãy lấy một ví dụ sư phạm hư cấu, với hai vector truy vấn và ba vector trang. Dưới đây là các tích vô hướng thu được; đây không phải số đo của corpus Lumen.
| Vector truy vấn | Trang: vector 0 | Trang: vector 1 | Trang: vector 2 |
|---|---|---|---|
| Truy vấn: vector 0 | 0,8 | 0,1 | 0,2 |
| Truy vấn: vector 1 | 0,1 | 0,9 | 0,2 |
Ở hàng đầu, cực đại là 0,8, tìm thấy tại vector 0 của trang. Ở hàng thứ hai, nó là 0,9, tại vector 1. Vì vậy điểm MaxSim là 0,8 + 0,9 = 1,7.
Chúng ta không lấy cực đại duy nhất của bảng, vốn là 0,9, cũng không lấy tổng mọi ô. Quy tắc là: tìm một cực đại cho mỗi hàng truy vấn, rồi cộng các cực đại đó. Chỉ những vị trí được khai báo hợp lệ mới góp vào kết quả.
Điểm 1,7 này không phải xác suất. Nó có thể lớn hơn 1 vì cộng nhiều đóng góp. Số vector truy vấn cũng ảnh hưởng tổng này: đừng biến một ngưỡng chọn cho một câu hỏi thành cam kết liên quan phổ quát cho mọi câu hỏi khác.
Padding: vị trí được thêm vào, không phải nội dung
Để xử lý cùng lúc nhiều chuỗi có độ dài khác nhau, ta có thể thêm các vị trí nhân tạo vào chuỗi ngắn hơn: đó là padding, hay phần đệm. Mặt nạ là danh sách boolean có cùng độ dài với chuỗi. True nghĩa là "dùng vị trí này" và False là "loại trừ".
Vì sao không chỉ để số không? Hãy lấy ví dụ số khác: hai vector thực của một trang cho độ tương đồng −0,6 và −0,8 với một vector truy vấn. Vector rỗng thêm vào để đệm cho 0. Không có mặt nạ, không sẽ thắng cực đại dù không tương ứng với thông tin thực nào.
Do đó chương trình thay độ tương đồng ở các vị trí tài liệu không hợp lệ bằng âm vô cực, viết là -torch.inf. Cực đại trở thành −0,6, kết quả tốt nhất trong hai kết quả được phép. Sau đó mặt nạ truy vấn loại khỏi tổng các vị trí nhân tạo của chính nó.
Phần cài đặt của dự án
Khối sau chứa phần kiểm tra đầu vào, ba cách tính cùng một điểm số và một hàm kiểm tra. Chúng ta giữ nguyên mã của bài r001.
"""Exact masked MaxSim; inputs are normalized by the pretrained encoder."""
import torch
def check(query, document, query_mask, document_mask):
if query.ndim != 2 or document.ndim != 2 or query.shape[1] != document.shape[1]:
raise ValueError("Expected [Lq,D] and [Ld,D] with the same D")
if query_mask.shape != query.shape[:1] or document_mask.shape != document.shape[:1]:
raise ValueError("Mask length does not match embeddings")
if query_mask.dtype != torch.bool or document_mask.dtype != torch.bool:
raise ValueError("Masks must be boolean")
if not query_mask.any() or not document_mask.any():
raise ValueError("Empty valid query or document sequence")
if not torch.isfinite(query).all() or not torch.isfinite(document).all():
raise ValueError("Non-finite embeddings")
def maxsim_dense(query, document, query_mask, document_mask):
check(query, document, query_mask, document_mask)
similarities = query.float() @ document.float().T
similarities = similarities.masked_fill(~document_mask[None, :], -torch.inf)
best = similarities.max(dim=1).values
return best[query_mask].sum()
def maxsim_scalar(query, document, query_mask, document_mask):
check(query, document, query_mask, document_mask)
return sum(
max(
float(torch.dot(query[i].float(), document[j].float()))
for j in range(len(document))
if document_mask[j]
)
for i in range(len(query))
if query_mask[i]
)
def maxsim_blocked(query, document, query_mask, document_mask, block_size=128):
check(query, document, query_mask, document_mask)
if not isinstance(block_size, int) or block_size <= 0:
raise ValueError("Positive integer vector block size required")
best = torch.full((len(query),), -torch.inf, device=query.device)
for start in range(0, len(document), block_size):
scores = query.float() @ document[start : start + block_size].float().T
scores = scores.masked_fill(
~document_mask[None, start : start + block_size], -torch.inf
)
best = torch.maximum(best, scores.max(dim=1).values)
return best[query_mask].sum()
def contributions(query, document, query_mask, document_mask):
check(query, document, query_mask, document_mask)
matrix = query.float() @ document.float().T
values, positions = matrix.masked_fill(~document_mask[None, :], -torch.inf).max(
dim=1
)
return [
{
"query_vector": i,
"document_vector": int(positions[i]),
"similarity": float(values[i]),
}
for i in range(len(query))
if query_mask[i]
]
Đọc từng hàm từng bước
check() kiểm tra hợp đồng đầu vào. Các mảng phải có hai chiều và vector cùng kích thước. Mỗi mặt nạ phải khớp độ dài chuỗi tương ứng và có kiểu boolean. Cần có ít nhất một vị trí hợp lệ ở mỗi bên. Cuối cùng, mảng không được chứa NaN, biểu thị giá trị số không xác định, cũng không chứa vô cực. Kiểm tra cuối áp dụng cho mọi giá trị, kể cả vị trí bị che.
Các từ chối này tránh trả về điểm có vẻ dùng được dù đầu vào không nhất quán. Tuy nhiên, chúng không kiểm tra xem biểu diễn có nắm được đúng thông tin hình ảnh hay không.
maxsim_dense() xây dựng mọi mức tương đồng cùng lúc. .float() chuyển mảng thành số thực 32 bit. .T chuyển vị mảng trang: các hàng thành cột. Toán tử @ sau đó thực hiện phép nhân ma trận, được mô tả trong tài liệu PyTorch. Kết quả có Lq hàng và Ld cột, như bảng ví dụ nhỏ của chúng ta.
document_mask[None, :] tạo cho mặt nạ một hàng, áp dụng được cho mọi hàng của bảng. Dấu ~ đảo boolean: vị trí không hợp lệ trở thành vị trí cần thay bằng âm vô cực. max(dim=1) tìm cực đại trên các cột của từng hàng. Cuối cùng, best[query_mask].sum() giữ những hàng truy vấn được phép và cộng điểm tốt nhất của chúng.
maxsim_scalar() triển khai cùng quy tắc bằng vòng lặp. Với mỗi vị trí truy vấn hợp lệ, nó tính tích vô hướng với các vị trí tài liệu hợp lệ, lấy cực đại rồi cộng lại. Đây là tham chiếu dễ đọc để hiểu phép tính, không phải chiến lược nhằm khai thác hiệu quả tính song song của GPU. Phiên bản này trả về số Python, trong khi các phiên bản vector hóa trả về tensor vô hướng.
maxsim_blocked() tránh tạo cả bảng một lúc. Nó duyệt vector trang theo từng khối, mặc định 128 vị trí. Mảng best giữ một điểm tốt nhất cho mỗi vị trí truy vấn. Ở mỗi khối, torch.maximum so sánh điểm tốt nhất này với các cực đại mới và giữ giá trị lớn hơn, theo từng vị trí. Chỉ sau khi duyệt mọi khối mới tính tổng.
Điểm cần nhớ là: ta giữ cực đại toàn cục của từng vector truy vấn, không phải một điểm độc lập để cộng cho từng khối. Nếu không, kết quả sẽ đổi chỉ vì trang được chia khối theo cách khác.
Các khối thực sự tiết kiệm gì
Phiên bản dày đặc hiện thực hóa Lq × Ld độ tương đồng. Với khối kích thước B, bảng tạm chỉ chứa khoảng Lq × B tại một thời điểm, cùng các cực đại được giữ lại. Số phép so sánh vẫn cùng bậc: chúng ta tính cùng một điểm theo cách khác, không bỏ qua phần nào của trang.
Hãy lấy kích thước minh họa, không liên quan đến phép đo bộ nhớ của bài: 32 vector truy vấn và 1 024 vector trang cho 32 768 độ tương đồng. Ở 32 bit, bảng của chúng chiếm 128 KiB. Với khối 128, bảng tương đồng của một khối có 4 096 giá trị, tức 16 KiB.
Mức giảm này áp dụng cho bảng điểm tạm. Nó không nén chỉ mục đã lưu, không xóa vector đầu vào và không giảm trọng số mô hình. Chuyển đổi số và các phép tính khác cũng dùng bộ nhớ. Chỉ mục quá lớn trên đĩa và phép tính tạm quá lớn trên GPU là hai vấn đề khác nhau.
Phiên bản dày đặc và theo khối tính cùng MaxSim về mặt toán học; các kiểm thử dự án xác nhận sự tương đương này. Ngoài ra, tài liệu PyTorch về độ chính xác số nhắc rằng tương đương toán học không bảo đảm giống hệt từng bit sau mỗi thay đổi về phần cứng hoặc phép tính số thực. Hãy giữ các kiểm tra của dự án khi điều chỉnh phần cài đặt.
Đọc một đóng góp cụ thể
contributions() dùng lại ma trận tương đồng nhưng giữ vị trí thắng, ngoài giá trị của nó. Trong ví dụ sư phạm, vector truy vấn 0 chọn vector trang 0 với 0,8; vector truy vấn 1 chọn vector trang 1 với 0,9.
Trong các đối tượng trả về, query_vector là chỉ số trong truy vấn, document_vector là chỉ số trong chuỗi của trang và similarity là giá trị được giữ. Cộng chúng lại sẽ thu được điểm trong ví dụ. Vì vậy các đối tượng này liên kết tổng điểm với các đóng góp của nó.
Tuy vậy, một chỉ số không phải từ đã dịch, cũng không phải hộp phát hiện. Để hiển thị nó trên ảnh, cần giữ tương ứng với quá trình chuẩn bị ảnh đó. Ngay cả khi trực quan hóa cho thấy vùng gần bơm, điều đó không chứng minh mô hình đã hiểu đúng toàn bộ quan hệ không gian.
Nếu một kết quả bất ngờ có vẻ phụ thuộc nền trang, hãy kiểm tra bản kết xuất, mặt nạ và câu hỏi. Đừng sửa dữ liệu hoặc ngưỡng ngay từ đầu để làm xếp hạng có vẻ thuyết phục hơn. Vai trò của đóng góp là làm phép tính có thể kiểm tra, không phải khoác cho mọi kết quả một lời giải thích nhất thiết đúng.
Điều kiện tiên quyết và môi trường
Bạn cần có thể đọc Python, thao tác danh sách và mảng, và dùng Docker từ terminal. Không cần biết cách huấn luyện mạng để theo bài này: chúng ta dùng bộ mã hóa đã huấn luyện trước mà không sửa trọng số của nó.
Cấu hình tham chiếu dùng Linux, Docker Engine, Compose, trình điều khiển NVIDIA và NVIDIA Container Toolkit, với RTX 3090 24 GiB. Không có cấu hình CPU nào được xác nhận. 32 GiB RAM và 40 GiB ổ đĩa được nêu là ước lượng để chuẩn bị, không phải mức tối thiểu đã đo cho mọi máy. RAM là bộ nhớ của máy tính; 24 GiB của card là bộ nhớ video, hay VRAM.
NVIDIA Container Toolkit kết nối Docker với thiết bị và thư viện trình điều khiển NVIDIA của máy chủ. Vì vậy GPU thấy được dưới Linux chưa chắc dùng được bởi chương trình trong container. Hãy xem tài liệu cài đặt để tích hợp phù hợp hệ thống của bạn. Kiểm tra dự án sau đó chạy mô hình trong Docker; nvidia-smi trên máy chủ không thay thế được kiểm tra này.
Giải nén ZIP và vào thư mục gốc của nó. Mọi lệnh sau đều chạy từ thư mục này. Dịch vụ tải xuống là dịch vụ duy nhất trong bài có mạng; nó kiểm tra revision, kích thước và dấu vân tay SHA-256 của trọng số. Dấu vân tay cho phép kiểm tra danh tính nội dung đã tải. Hãy giữ các phụ thuộc và tệp đã khóa trong ZIP thay vì thay bằng một bản cài đặt từ ví dụ mới hơn.
Bước 1 — kiểm tra runtime
Ở đây, runtime là môi trường chương trình chạy trong đó. Hãy chuẩn bị thư mục, xác nhận Compose, xây dựng dịch vụ, rồi tải mô hình và chạy các kiểm tra.
sh scripts/preflight.sh
sh scripts/setup.sh
docker compose config --quiet
docker compose build acquisition tutorial inference
docker compose run --rm acquisition python scripts/acquire.py --config configs/minimum.yaml
docker compose run --rm tutorial python scripts/check_environment.py
docker compose run --rm tutorial python -m pytest -q
Mỗi lệnh phải kết thúc với mã trả về bằng không, nghĩa là chạy thành công. Kiểm thử bao phủ mặt nạ, MaxSim, tương thích chỉ mục và tọa độ PDF. Chúng kiểm tra chương trình hoạt động; chúng không có nghĩa mọi xếp hạng đều liên quan.
Bước 2 — chuẩn bị và lập chỉ mục
Bây giờ chúng ta có thể tạo các trang Lumen và biểu diễn của chúng, kiểm tra một điểm số, rồi tính mốc tham chiếu văn bản.
docker compose run --rm tutorial python -m pdfmaxsim.cli prepare --config configs/minimum.yaml
docker compose run --rm inference python -m pdfmaxsim.cli index --config configs/minimum.yaml
docker compose run --rm inference python -m pdfmaxsim.cli explain-score --config configs/minimum.yaml
docker compose run --rm inference python -m pdfmaxsim.cli baseline --config configs/minimum.yaml
prepare kết xuất các trang. Bạn phải tìm lại 96 ảnh của catalogue. Hãy kiểm tra trực quan văn bản và sơ đồ: ảnh bị cắt hoặc không đọc được đã là đầu vào kém trước mọi phép tính embedding.
index lưu các đa vector và mặt nạ của chúng. Nhờ vậy ảnh được biến thành dữ liệu tái sử dụng khi tìm kiếm. Liên kết với trang và sổ tay phải còn sẵn: tìm lại một vector mà không mở được nguồn của nó thì chưa đủ.
explain-score hiển thị các đóng góp. Hãy tìm truy vấn mạch chính và đối chiếu điểm với các láng giềng tốt nhất của nó. Đừng thay việc kiểm tra này bằng trực giác "trang đầu trông có vẻ đúng".
baseline tính mốc BM25. Một baseline là phương pháp so sánh. BM25 xếp hạng văn bản dựa trên các thuật ngữ hiện diện, tần suất của chúng, độ hiếm của chúng trong bộ sưu tập và độ dài tài liệu. Chương về BM25 trong giáo trình Stanford trình bày chi tiết các cơ chế này.
Ở đây, BM25 dùng văn bản sẵn có: nó không nhận pixel của sơ đồ để diễn giải bố cục. Dù vậy, nhờ nhãn của chúng nó vẫn có thể tìm đúng trang. Đó chính là ích lợi của so sánh: kiểm tra tìm kiếm thị giác bổ sung gì ngoài các manh mối văn bản, mà không giả định nó sẽ thắng ở mọi nơi.
Bước 3 — đo lường và thử nghiệm
Khi đó, đánh giá có thể so sánh xếp hạng với các trang kỳ vọng, trong một dịch vụ tách biệt với dịch vụ tạo biểu diễn và tìm kiếm.
docker compose run --rm tutorial python -m pdfmaxsim.cli evaluate --config configs/minimum.yaml
Chúng ta sẽ đọc các phép đo của nó ở phần sau. Đừng thay đổi cài đặt sau khi xem kết quả kiểm thử để chỉ giữ biến thể tốt nhất.
Mỗi đầu ra cho phép kiểm tra điều gì
Sau index, hãy kiểm tra kích thước, mặt nạ và dấu vân tay bộ mã hóa trong các tệp đầu ra. Sau explain-score, quay lại trang của mạch chính và các đóng góp của nó. Kiểm tra tính tương đương phải tìm được cùng phép tính với bản dày đặc và bản theo khối.
Catalogue 96 trang là chung; các truy vấn mới được tách riêng. Bài có 48 truy vấn phát triển và 144 truy vấn kiểm thử. Nó không huấn luyện mô hình trên một nhóm trang đầu rồi kiểm tra trên nhóm khác.
Tập phát triển dùng để đưa ra quyết định thiết kế. Tập kiểm thử dùng để đo quyết định khi nó đã cố định. Ngay cả không huấn luyện, chọn một cài đặt vì nó thành công hơn trên test sẽ làm test mất vai trò đo cuối cùng, độc lập với lựa chọn.
Hai ngân sách độ phân giải được cố định trước: 200704 và 401408. Chúng ảnh hưởng kích thước biểu diễn và chi phí tìm kiếm. Hãy dùng cấu hình đã cung cấp để tái lập. Ngân sách thứ hai gấp đôi ngân sách đầu; điều đó không cho phép suy ra kích thước thực của chỉ mục hoặc thời gian chạy sẽ chính xác gấp đôi. Các tác động này được đo trong đầu ra của bài.
So sánh với trung bình vector nhằm xem việc giữ nhiều biểu diễn thay đổi điều gì. Đầu ra của nó phải được xem cùng các ngân sách: đừng suy ra kết quả định lượng chỉ từ trực giác rằng trung bình làm mất chi tiết.
Đọc các chỉ số trước khi xem số liệu
Chỉ số là phép đo được chọn để đánh giá một hành vi. Với công cụ của chúng ta, câu hỏi không phải "điểm MaxSim có lớn không?", mà là "các trang kỳ vọng có được đặt đúng vị trí không?". Chúng ta sẽ phân biệt số lượng trang liên quan tìm được và vị trí của trang đầu tiên.
Recall@k: ta tìm lại được bao nhiêu trang tốt?
Recall@k, hay recall trong k vị trí đầu, đo với mỗi truy vấn tỷ lệ trang liên quan xuất hiện trong các vị trí đó. Sau đó lấy trung bình các tỷ lệ trên những truy vấn được đánh giá.
Hãy lấy một xếp hạng hư cấu. Ba trang liên quan mang tên A, B và C. Công cụ trả về A, X, B, C, Y, trong đó X và Y không liên quan.
Ở hạng 1, ta tìm được A, tức một trang liên quan trên ba: Recall@1 = 1/3. Trong ba kết quả đầu, có A và B: Recall@3 = 2/3. Trong năm kết quả đầu, A, B và C đều có mặt: Recall@5 = 1.
Tuy vậy trang đầu đã đúng ngay từ đầu! Vì thế Recall@1 ở đây không phải tỷ lệ truy vấn có kết quả đầu tiên liên quan. Một câu hỏi có thể có nhiều trang tốt; chỉ hiển thị một trang không thể tìm lại tất cả.
MRR: trang liên quan đầu tiên xuất hiện ở đâu?
MRR, viết tắt của Mean Reciprocal Rank, lấy trung bình nghịch đảo thứ hạng của trang liên quan đầu tiên. Ở hạng 1, đóng góp là 1/1 = 1; ở hạng 2 là 1/2 = 0,5; ở hạng 4 là 1/4 = 0,25.
Trong xếp hạng hư cấu A, X, B, C, Y, đóng góp này là 1. Với X, A, B, C, Y, nó là 0,5. Nếu các xếp hạng này ứng với hai truy vấn, MRR của chúng là (1 + 0,5) / 2 = 0,75.
MRR không cho biết có bao nhiêu trang tốt khác theo sau trang đầu. Recall và MRR vì vậy xem hai thuộc tính khác nhau: tìm lại các trang kỳ vọng và làm cho trang liên quan đầu tiên xuất hiện nhanh. Cả hai đều không kiểm tra nội dung của câu trả lời được soạn nếu có.
Kết quả quan sát trên Lumen
Các phép đo sau liên quan đến 144 truy vấn kiểm thử, trên catalogue tổng hợp tiếng Anh gồm 96 trang. Chúng lấy lại các giá trị của bài r001.
| Chỉ số | MaxSim độ phân giải cao | BM25 |
|---|---|---|
| MRR | 0,9549 | 0,9410 |
| Recall@1 | 0,5903 | 0,5972 |
| Recall@5 | 1,0000 | Không nêu ở đây |
| Recall@10 | 1,0000 | Không nêu ở đây |
"Không nêu ở đây" nghĩa là giá trị này không được cung cấp trong các kết quả số được lấy lại trong bài; điều đó không có nghĩa bằng không hay phương pháp thất bại.
MRR của MaxSim tốt hơn, nhưng Recall@1 thì không. Vì vậy xếp hạng thuận lợi hơn theo trung bình nghịch đảo thứ hạng, nhưng không cải thiện tỷ lệ trung bình trang liên quan tìm được ở vị trí đầu. Chúng ta không thể suy ra ưu thế cho từng truy vấn.
BM25 vẫn là đối thủ đáng gờm trên corpus này: một số nhãn văn bản có thể đã đủ để tìm trang. Recall@5 và Recall@10 của MaxSim được báo là 1,0000, nhưng chúng không chứng minh sự hiểu hoàn hảo sơ đồ, cũng không chứng minh chất lượng tương tự trên PDF thật, ngôn ngữ khác hoặc bộ sưu tập lớn hơn nhiều.
Khi không có trang nào liên quan
Bài cũng có 12 truy vấn ngoài corpus. Với chúng, không trang nào trong bộ sưu tập là câu trả lời liên quan. Chúng bị loại khỏi các chỉ số liên quan nêu trên và cần được xem xét riêng.
Công cụ vẫn tạo xếp hạng: nó tìm trang gần nhất trong các trang mình có. Điều đó không có nghĩa nó đã tìm được trang tốt. Ứng viên tốt nhất trong một danh sách tồi vẫn là ứng viên tồi.
Không có chính sách từ chối đã hiệu chỉnh trong bài này. Nói cách khác, dự án không cung cấp quy tắc đã xác thực để quyết định "không trang nào đáp ứng yêu cầu này". Điểm MaxSim không được đọc như xác suất câu trả lời đúng. Để thêm từ chối tự động, cần thiết kế rồi đo hành vi này với yêu cầu có và không có kết quả liên quan.
Những điều chúng ta đã học
Chúng ta đã giữ nhiều biểu diễn cho mỗi trang, thay vì thu mọi thứ về một vector. Tương tác muộn tách việc chuẩn bị chỉ mục khỏi việc mã hóa câu hỏi mới. MaxSim tìm láng giềng tốt nhất trong trang cho mỗi vector truy vấn hợp lệ, rồi cộng các đóng góp này.
Mặt nạ là một phần của phép tính: chúng ngăn phần đệm tham gia xếp hạng. Xử lý theo khối giữ cùng các cực đại toàn cục trong khi giới hạn kích thước bảng tạm; nó không nén chỉ mục.
Cuối cùng, một xếp hạng liên quan không phải câu trả lời, cũng không phải bằng chứng định vị trung thực. Các đóng góp giúp kiểm tra điểm. Recall và MRR đánh giá xếp hạng. Các yêu cầu ngoài corpus đặt ra một vấn đề khác mà bài này không giải quyết bằng ngưỡng từ chối.
Bài tập — giữ đúng các cực đại
Trước khi chạy lệnh, hãy lấy một ví dụ số bổ sung, được chọn để tính tay. Một vector truy vấn duy nhất so sánh độ tương đồng với hai khối trang. Trong khối đầu, các giá trị là −0,8 và −0,6. Trong khối thứ hai, chúng là −0,4 và −0,2. Mọi vị trí đều hợp lệ.
Cuối cùng điểm nào phải được giữ? Điều gì xảy ra nếu cộng kết quả tốt nhất của mỗi khối? Và nếu best bắt đầu bằng không thay vì âm vô cực? Hãy viết ba câu trả lời trước khi tiếp tục.
Cũng hãy đưa ra giả thuyết khi so sánh ngân sách độ phân giải: kích thước chỉ mục, thời gian tìm kiếm và recall có thể thay đổi thế nào khi ngân sách tăng? Recall có nhất thiết cải thiện ở từng câu hỏi không? Hãy phân biệt kỳ vọng hợp lý với kết quả đã được đo.
Sau đó chạy bài tập được cung cấp. Nó giữ nguyên thuật toán của dự án; nó cho bạn so sánh dự đoán với đầu ra thay vì âm thầm sửa phép tính.
docker compose run --rm inference python -m pdfmaxsim.cli exercise-index --config configs/exercise.yaml
docker compose run --rm inference python -m pdfmaxsim.cli exercise-search --config configs/exercise.yaml
docker compose run --rm tutorial python -m pdfmaxsim.cli exercise --config configs/exercise.yaml
docker compose run --rm tutorial python lesson/figures/plot.py
docker compose run --rm tutorial python scripts/check_checkpoints.py
Lời giải phép tính nhỏ. Khối đầu cho −0,6; khối thứ hai cho −0,2. Cực đại toàn cục là −0,2. Cộng các cực đại cục bộ sẽ cho −0,8, tức đếm hai đóng góp cho một vector truy vấn. Khởi tạo bằng không sẽ cho 0, giá trị không do so sánh thực nào tạo ra.
Các số này minh họa cơ chế; chúng không được công bố là đầu ra của tệp dự án. Quy tắc cần tìm trong maxsim_blocked() là: so sánh các cực đại, rồi chỉ cộng một lần ở cuối.
Đối với thử nghiệm độ phân giải, hãy xem viewer.html, các PNG và các đóng góp. So sánh số đo về kích thước, thời gian và recall với giả thuyết của bạn. Độ phân giải cao hơn có thể giữ nhiều chi tiết hơn, nhưng không chứng minh mô hình sẽ dùng chúng tốt hơn cho mọi câu hỏi. Đừng gán một cải thiện cho thị giác chỉ dựa trên hình thu nhỏ sắc nét hơn.
Khắc phục sự cố mà không làm sai lệch thử nghiệm
Tải xuống thất bại? Hãy đọc lại revision mong đợi, kích thước tệp và SHA-256 trước khi chạy lại. Đừng chép vào assets/ các trọng số tìm thấy ở nơi khác: mô hình được tải khi đó không nhất thiết còn là mô hình của bài.
CUDA thất bại trong Docker? Hãy kiểm tra runtime, trình điều khiển và NVIDIA Container Toolkit. Chẩn đoán trước hết liên quan quyền truy cập GPU thực tế; thay đổi chỉ số hoặc mặt nạ không sửa được vấn đề môi trường này.
Chỉ mục không tương thích? Hãy xây lại nó bằng cùng bộ mã hóa, cùng cấu hình độ phân giải và cùng quy ước mặt nạ đã dùng để tìm kiếm. Các vector cùng chiều không nhất thiết so sánh được nếu đến từ hai phiên bản khác nhau. Hãy giữ biểu diễn cùng cấu hình làm nó có ý nghĩa.
Phép tính thiếu bộ nhớ? Tìm kiếm theo khối có thể giảm bảng tương đồng tạm. Ngược lại, nếu vấn đề là kích thước chính chỉ mục, chia phép tính không làm nó nhỏ hơn. Giảm ngân sách biểu diễn đòi hỏi xây lại dữ liệu liên quan, rồi đo lại kích thước, độ trễ và recall. Hãy giữ các thử nghiệm này tách khỏi kết quả tham chiếu.
Xếp hạng có vẻ vô lý? Hãy bắt đầu bằng mở trang đã kết xuất, rồi kiểm tra mặt nạ, đóng góp và cách viết truy vấn. Đừng bao giờ thay quan sát bằng label kỳ vọng để đầu ra có vẻ thỏa đáng hơn.
Vận hành và dọn dẹp
Hướng dẫn xử lý một bộ sưu tập nhỏ có kiểm soát. Để biến nó thành dịch vụ tài liệu, vẫn cần quản lý quyền truy cập, cập nhật, xóa dữ liệu đã lập chỉ mục, chất lượng kết xuất, ngôn ngữ, độ trễ và truy vấn không có đáp án. Đây là các công việc tích hợp cần chuẩn bị, không phải tính năng được chứng minh bởi điểm Lumen.
Giữ lại nguồn gốc và phiên bản. Mỗi kết quả phải tiếp tục liên kết với PDF, trang và bộ mã hóa đã dùng. Các đóng góp và tham số lập chỉ mục cho phép lần từ xếp hạng về phép tính. Hãy phiên bản hóa chỉ mục thay vì âm thầm trộn các biểu diễn không tương thích.
Áp dụng quyền cho kết quả như cho phần xem trước của chúng. Một trang bị cấm không được trở nên xem được qua hình thu nhỏ, cache hay đầu ra chẩn đoán. Xóa tài liệu cũng phải tính đến vector, phần xem trước và cache của nó.
Đánh giá các yêu cầu đại diện cho người dùng. Corpus tổng hợp tiếng Anh không xác thực độ vững trước lỗi chính tả, ngôn ngữ khác hay sự đa dạng của tài liệu thực. 12 truy vấn ngoài corpus cho thấy xếp hạng bị ép buộc; chúng không xác thực cơ chế từ chối. Hãy lập các trường hợp có và không có trang liên quan, rồi xem lỗi từng truy vấn một, ngoài các giá trị trung bình.
Việc sinh câu trả lời nếu có phải tham khảo và trích dẫn các nguồn thực sự được tìm thấy. Nó không được tạo văn bản từ chỉ thứ hạng của một trang. Chương trình của chúng ta dừng ở một kết quả tìm kiếm có thể kiểm tra.
Chỉ dọn đầu ra dự kiến
Hãy giữ các chỉ mục, phần xem trước, hình và phép đo bạn muốn nghiên cứu trước khi dọn. Các lệnh sau dừng dự án, chạy dọn dẹp có mục tiêu, rồi lại dừng dự án.
docker compose down
docker compose run --rm tutorial python scripts/clean.py --outputs-only
docker compose down
Script chỉ xóa outputs/. Nó giữ assets/ và data/generated/. Đừng nhầm việc dọn kết quả này với xóa mọi tệp của mô hình và corpus.
Tài liệu tham khảo để tìm hiểu thêm
Tài liệu chính thức của ColQwen mô tả mô hình và các biểu diễn của nó. Kho ColBERT giải thích tương tác muộn; chương BM25 trong giáo trình Stanford đi sâu vào mốc văn bản.
Để đọc lại các phép toán mã, hãy xem phép nhân ma trận, điền bằng mặt nạ và giới hạn độ chính xác số trong PyTorch. Tài liệu NVIDIA Container Toolkit nói về truy cập GPU từ Docker.
Các tài liệu này bổ sung cho lời giải thích; chúng không thay thế phiên bản, cấu hình và lệnh của ZIP r001. Các phép tính nhỏ trong bài là ví dụ sư phạm, tách biệt với phép đo thu được trên Lumen.