Hugging Face: Blog
85

Sản phẩm

Sentence Transformers v6.0 ra mắt MultiVectorEncoder: Hỗ trợ mô hình ColBERT mạnh mẽ

(giờ Việt Nam)

Tóm tắt AI

Phiên bản Sentence Transformers v6.0 bổ sung MultiVectorEncoder, cho phép tích hợp trực tiếp các mô hình ColBERT và ColPali để tối ưu hóa khả năng truy xuất thông tin (RAG) với cơ chế tương tác muộn.

Bản dịch AI

Multi-Vector (Late Interaction) Embedding Models with Sentence Transformers

Quay lại các bài viết

Sentence Transformers là một thư viện Python dùng để sử dụng và huấn luyện các mô hình embedding và reranker cho các ứng dụng như truy xuất tăng cường thế hệ (retrieval augmented generation), tìm kiếm ngữ nghĩa, và nhiều ứng dụng khác. Với bản cập nhật v6.0, thư viện này có thêm loại mô hình thứ tư: MultiVectorEncoder, dành cho truy xuất tương tác muộn (late interaction) theo phong cách ColBERT. Bất kỳ checkpoint PyLate nào và bất kỳ checkpoint ColBERT nào từ Stanford-NLP đều có thể được tải trực tiếp vào mô hình này, và các mô hình colpali-engine cho truy xuất tài liệu hình ảnh cũng có thể được sử dụng thông qua cùng một API quen thuộc mà bạn vẫn dùng cho các mô hình dense, sparse và reranker.

Trong khi một mô hình embedding thông thường nén toàn bộ văn bản thành một vector duy nhất, một mô hình đa vector (multi-vector) giữ lại một vector cho mỗi token và tính điểm truy vấn dựa trên tài liệu bằng toán tử MaxSim. Điều này bảo toàn thông tin khớp ở cấp độ token mà một vector đơn lẻ buộc phải làm mờ đi thông qua tính trung bình, điều này thường mang lại khả năng truy xuất mạnh mẽ hơn với cái giá là chỉ mục (index) lớn hơn. Đây cũng là công nghệ tiên tiến nhất (state of the art) cho truy xuất tài liệu hình ảnh, nơi truy vấn văn bản được khớp trực tiếp với hình ảnh trang mà không cần bước OCR ở giữa.

Trong bài viết này, chúng tôi sẽ hướng dẫn bạn cách sử dụng các mô hình này: tải các định dạng checkpoint khác nhau, mã hóa và tính điểm, tích hợp chúng vào ngăn xếp tìm kiếm (search stack), chạy chúng trên hình ảnh trang và giữ cho chỉ mục ở mức chi phí hợp lý. Mọi thứ dưới đây đều chạy trên lệnh pip install -U sentence-transformers cơ bản.

Mục lục

Mô hình đa vector (Multi-Vector Models) là gì?

Một mô hình dense embedding đọc văn bản và trả về một vector có kích thước cố định duy nhất. Mọi thứ mà mô hình nhận thấy đều phải gói gọn trong 384, 768 hoặc 1024 con số đó, và độ tương đồng là một tích vô hướng giữa hai bản tóm tắt như vậy. Cách này hoạt động rất hiệu quả, nhưng việc nén dữ liệu bị mất mát theo một cách cụ thể: một thực thể hiếm gặp, một định danh chính xác hoặc một mệnh đề quan trọng trong một đoạn văn dài đều phải cạnh tranh không gian trong cùng một vector. Một truy vấn với nhiều yêu cầu cùng lúc cũng gặp phải rào cản tương tự. Đối với "ghế sofa màu xanh lá cây với chân gỗ và đệm tròn", một vector đơn lẻ phải hòa trộn cả bốn đặc điểm vào một điểm, vì vậy một chiếc ghế sofa màu xanh lá cây nhưng sai kiểu chân cuối cùng lại nằm gần với chiếc ghế bạn thực sự yêu cầu.

Một mô hình đa vector (còn gọi là mô hình tương tác muộn hoặc mô hình kiểu ColBERT, theo bài báo về ColBERT) bỏ qua quá trình nén đó. Nó chạy cùng một transformer, nhưng thay vì gộp (pooling) các embedding của token thành một vector, nó chiếu mỗi embedding của token xuống một chiều nhỏ hơn (thường là 128) và giữ lại tất cả chúng. Một tài liệu gồm 9 token sẽ trở thành một ma trận 9x128, thay vì một vector 1x128.

Sự tương tác giữa truy vấn và tài liệu sau đó được hoãn lại cho đến thời điểm tính điểm, đó là lý do tại sao nó có tên là "tương tác muộn". Một cross-encoder tương tác sớm: cả hai văn bản cùng đi qua mô hình, điều này chính xác nhưng không để lại gì để tính toán trước, vì mỗi tài liệu phải được mã hóa lại cho mỗi truy vấn mới. Một bi-encoder, chính là mô hình dense embedding ở trên, hầu như không tương tác (chỉ là một tích vô hướng giữa hai bản tóm tắt đã hoàn thiện), và đó chính xác là điều cho phép bạn mã hóa một tập hợp dữ liệu một lần và truy vấn nó nhanh chóng. Tương tác muộn nằm ở giữa: các tài liệu vẫn được mã hóa độc lập và có thể được lập chỉ mục ngoại tuyến (offline), nhưng việc tính điểm so sánh từng token truy vấn với từng token tài liệu, điều này để lại nhiều không gian hơn cho cả hai tương tác với nhau.

Dense embedding versus multi-vector late interaction: a dense model encodes each text into one vector and scores with cosine similarity, while a multi-vector model keeps one vector per token and score

Toán tử MaxSim

Việc tính điểm sử dụng MaxSim: đối với mỗi token truy vấn, lấy độ tương đồng cao nhất của nó với bất kỳ token tài liệu nào, sau đó cộng các giá trị cực đại đó trên toàn bộ truy vấn.

MaxSim(Q,D)=∑Qi∈Qmax⁡Dj∈DQi⋅Dj\text{MaxSim}(Q, D) = \sum_{Q_i \in Q} \max_{D_j \in D} Q_i \cdot D_j

Vì các embedding của token được chuẩn hóa L2, mỗi tích vô hướng đó là một độ tương đồng cosine trong khoảng [-1, 1], vì vậy tổng toàn bộ nằm trong khoảng [-num_query_tokens, num_query_tokens].

Bạn có thể hiểu toán tử này như một sự căn chỉnh mềm (soft alignment): mỗi token truy vấn trỏ đến một token tài liệu giải thích tốt nhất cho nó, và điểm số chính là mức độ tài liệu đó hỗ trợ truy vấn tổng thể.

Sự căn chỉnh không nhất thiết phải là từ vựng (lexical), vì các embedding của token đã được đặt trong ngữ cảnh. Hãy mã hóa "Where do penguins live?" so với "Penguins inhabit Antarctica." bằng lightonai/mLateOn, token truy vấn "live" tìm thấy khớp tốt nhất của nó với "inhabit" ở mức 0.94, một từ không có ký tự nào chung với nó! Đó là điều mà truy xuất từ vựng không thể làm được, BM25 và các thuật toán liên quan cần chính thuật ngữ đó, vì vậy các từ đồng nghĩa và cách diễn đạt khác sẽ bị bỏ qua. Tất nhiên, các mô hình dense embedding cũng thu hẹp khoảng cách đó. Điều mà tương tác muộn bổ sung là nó thực hiện điều đó mà không từ bỏ hướng ngược lại: khi một kết quả khớp chính xác là điều quan trọng (mã sản phẩm, họ tên, tên hàm), MaxSim vẫn giữ token đó ở đó một mình, trong khi mô hình vector đơn lẻ phải lấy trung bình nó với mọi thứ khác. Nó cũng không phải là một-một, vì nhiều token truy vấn thường xuyên cùng trỏ vào một token tài liệu.

Bạn đạt được gì và phải trả giá những gì?

Bạn đạt được chất lượng truy xuất, đặc biệt là đối với các truy vấn mà một phần cụ thể của tài liệu làm cho nó trở nên liên quan, đối với các truy vấn nhiều yêu cầu như chiếc ghế sofa ở trên nơi mỗi yêu cầu có thể tìm thấy bằng chứng riêng của nó, và trên dữ liệu ngoài miền (out-of-domain) nơi quá trình nén của mô hình dense được tinh chỉnh cho một phân phối khác. Quá trình nén đó được học từ các truy vấn huấn luyện, vì vậy mô hình học cách giữ lại những gì chúng cần và loại bỏ mọi thứ khác, điều này có thể bao gồm chính xác những gì các truy vấn thực tế của bạn hỏi đến. Hiệu ứng này tăng lên theo độ dài tài liệu, vì nhiều văn bản hơn phải vừa với cùng một vector cố định.

Cái giá phải trả là kích thước chỉ mục. Một vector cho mỗi token thay vì một vector cho mỗi tài liệu là số lượng vector lớn hơn nhiều, chỉ được bù đắp một phần bởi kích thước chiều nhỏ hơn. Việc mã hóa 4.874 đoạn văn Natural Questions với lightonai/LateOn tạo ra 608.414 vector token, trung bình 124,8 vector mỗi đoạn:

Đó là khoảng 42 lần dung lượng lưu trữ của chỉ mục MiniLM, hoặc 62 KiB mỗi đoạn. Tuy nhiên, các chỉ mục thường được nén, ví dụ: 608.414 vector đó chiếm 92 MB dưới dạng chỉ mục fast-plaid, vì PLAID lưu trữ một id tâm (centroid id) cộng với phần dư được lượng tử hóa (quantized residual) cho mỗi vector thay vì chính vector đó. Để so sánh quy mô, một mô hình dense 4096 chiều như Qwen3-Embedding-8B sẽ cần khoảng 80 MB cho cùng 4.874 đoạn văn này, vì vậy một chỉ mục đa vector nén nằm trong cùng phạm vi với các chỉ mục dense mà mọi người đang sử dụng. Token Pooling cắt giảm số lượng vector trước khi thực hiện bất kỳ điều đó, và Retrieve and Rerank tránh việc phải xây dựng chỉ mục hoàn toàn.

PyLate xuất hiện xuyên suốt bài viết này, vì vậy tóm tắt ngắn gọn: Sentence Transformers xử lý các mô hình dense và sparse nhưng không phải tương tác muộn, vì vậy LightOn đã xây dựng PyLate trên nền tảng của nó để lấp đầy khoảng trống đó, bổ sung các phần huấn luyện, suy luận và truy xuất mà các mô hình này cần. Phần lớn những gì bạn sẽ tải dưới đây được huấn luyện với nó, và LightOn cũng xây dựng một hệ sinh thái xung quanh nó, bao gồm fast-plaid, chỉ mục tương tác muộn xuất hiện trong phần Indexing. Với v6.0, các khả năng đó đã nằm ngay trong chính Sentence Transformers.

Với sự đánh đổi đó trong tâm trí, hãy bắt đầu chạy một mô hình.

Cài đặt

Các mô hình đa vector hoạt động với lệnh cài đặt cơ bản:

Đối với truy xuất tài liệu hình ảnh kiểu ColPali, bạn cũng cần các phụ thuộc hình ảnh (xem Installation để biết tất cả các phần mở rộng, và Multimodal Embedding & Reranker Models để biết hỗ trợ đa phương thức nói chung):

Sentence Transformers v6.0 yêu cầu transformers v5.x, torch 2.2+ và huggingface-hub v1.x. Nếu bạn ghim bất kỳ phiên bản nào thấp hơn, hãy lên kế hoạch nâng cấp trước. Xem Migration Guide để biết danh sách đầy đủ các thay đổi gây lỗi (breaking changes).

Tải một mô hình

Việc tải một mô hình đa vector trông giống hệt như tải bất kỳ mô hình Sentence Transformers nào khác:

Để tìm các mô hình hoạt động, hãy tìm các thẻ multi-vector và sentence-transformers trên Hub. Bất kỳ mô hình nào có các thẻ đó đều tải được với dòng lệnh trên, cho dù nó bắt đầu là một checkpoint PyLate, một checkpoint ColBERT của Stanford-NLP, hay một mô hình thuộc dòng ColPali cho truy xuất tài liệu hình ảnh. Chúng tôi đang làm việc trên toàn bộ hệ sinh thái để gắn thẻ đó lên mọi mô hình hoạt động, vì vậy danh sách này vẫn đang tiếp tục tăng lên.

Bên dưới, MultiVectorEncoder đọc từng định dạng mà các checkpoint này đã được công bố qua nhiều năm, vì vậy các checkpoint PyLate và Stanford-NLP tải trực tiếp ngay cả khi thẻ chưa được thêm vào:

Các mô hình truy xuất tài liệu hình ảnh là một ngoại lệ. Các checkpoint thuộc dòng ColPali được phát hành theo định dạng riêng của colpali-engine, không chứa thông tin mà Sentence Transformers có thể sử dụng, vì vậy mỗi mô hình cần một cấu hình nhỏ được thêm vào kho lưu trữ của nó trước khi nó tải được. Hầu hết công việc đó đã hoàn thành và đang chờ được hợp nhất. Xem Supported Models để biết trạng thái hiện tại và cách tải chúng ngay hôm nay.

Kiểm tra cấu hình của một Checkpoint

Các mô hình đa vector mang theo một số nút điều chỉnh (recipe knobs) khác nhau tùy theo checkpoint: tiền tố đánh dấu cho truy vấn và tài liệu, giới hạn độ dài, liệu các truy vấn có được đệm bằng token [MASK] hay không, và những token nào bị bỏ qua khi tính điểm tài liệu. Tất cả chúng đều nằm trong cấu hình mô-đun, vì vậy print(model) cho bạn thấy chính xác những gì bạn đã tải. Đây là checkpoint ColBERTv2 gốc, đệm mọi truy vấn thành chính xác 32 token và cắt ngắn tài liệu ở mức 180:

Đó là quy trình ColBERT cổ điển: một Transformer tạo ra các embedding token theo ngữ cảnh, một lớp Dense cấp token chiếu từng token đó xuống 128 chiều, một MultiVectorMask quyết định token nào được tính trong khi tính điểm, và một lớp Normalize cấp token. Các checkpoint khác điền các giá trị khác nhau. lightonai/GTE-ModernColBERT-v1 sử dụng bốn mô-đun tương tự với các prompt [Q] và [D], không mở rộng truy vấn, và giới hạn ở mức 48 và 300.

Bạn hiếm khi cần can thiệp vào bất kỳ điều nào trong số này, vì mọi checkpoint được phát hành đều tự cấu hình. Nó quan trọng khi bạn xây dựng một mô hình từ một backbone cơ bản, điều này được đề cập trong phần Creating Custom Models.

Tuy nhiên, có một giá trị đáng để kiểm tra với dữ liệu của riêng bạn. document_length thực hiện cắt ngắn, vì vậy bất kỳ thứ gì vượt quá nó sẽ không bao giờ đến được chỉ mục. Ví dụ, một đoạn văn 662 token qua giới hạn 300 của LateOn sẽ trả về 273 vector, với phần còn lại của đoạn văn đơn giản là biến mất. Hầu hết các checkpoint này được huấn luyện trên các đoạn văn ngắn, vì vậy nếu các đoạn (chunks) của bạn dài hơn giới hạn, bạn có thể nâng nó lên cho một lệnh gọi duy nhất với encode_document(..., processing_kwargs={"text": {"max_length": 512}}), lưu ý rằng bạn sẽ chạy mô hình vượt quá độ dài mà nó được huấn luyện và chỉ mục sẽ tăng lên gần như tương ứng. Các mô hình đa vector có xu hướng chịu đựng điều đó khá tốt. Trên MLDR, một tiêu chuẩn truy xuất tài liệu dài, các phiên bản đa ngôn ngữ của cặp mô hình trên cho thấy khoảng cách rõ ràng: mLateOn đạt 77,92 so với 51,59 của mDenseOn.

Mã hóa Truy vấn và Tài liệu

Các mô hình đa vector là bất đối xứng: truy vấn và tài liệu đi qua các tiền tố khác nhau, giới hạn độ dài khác nhau và các mặt nạ tính điểm (scoring masks) khác nhau. Không giống như nhiều mô hình dense, nơi hai loại này có thể thay thế cho nhau, encode_query và encode_document là bắt buộc để có được các embedding chính xác:

Lưu ý những gì bạn nhận lại: một danh sách các tensor 2D, mỗi đầu vào một tensor, mỗi tensor có hình dạng (num_tokens, embedding_dim). Không giống như dense embedding, bạn không thể xếp chồng chúng thành một tensor hình chữ nhật, vì mỗi đầu vào có số lượng token riêng. Tài liệu thứ hai dài hơn tài liệu thứ nhất, vì vậy nó trả về một ma trận cao hơn.

AIEmbeddingRAGSentenceTransformersNLP
Đọc bài gốc

Bài viết được AI dịch và tổng hợp tự động từ Hugging Face: Blog. Liên kết bài gốc ở phía trên. Dữ liệu đồng bộ qua API công khai được ghi nguồn tại AI HOT (canonical) ↗. AIHOT.vn luôn dẫn nguồn đầy đủ — nếu bạn thấy điểm cần chỉnh sửa, hãy gửi ý kiến tại trang phản hồi.