Khi nói đến xử lý ngôn ngữ tự nhiên (NLP) và truy xuất thông tin, khả năng truy xuất thông tin liên quan một cách hiệu quả và chính xác là điều tối quan trọng. Khi lĩnh vực này tiếp tục phát triển, các kỹ thuật và phương pháp luận mới đang được phát triển để nâng cao hiệu suất của các hệ thống truy xuất, đặc biệt trong bối cảnh Truy xuất thế hệ tăng cường (GIẺ). Một kỹ thuật như vậy, được gọi là truy xuất hai giai đoạn với công cụ sắp xếp lại, đã nổi lên như một giải pháp mạnh mẽ để giải quyết những hạn chế cố hữu của các phương pháp truy xuất truyền thống.
Trong bài viết này, chúng tôi thảo luận về sự phức tạp của việc truy xuất và sắp xếp lại hai giai đoạn, khám phá các nguyên tắc cơ bản, chiến lược triển khai và lợi ích mà chúng mang lại trong việc nâng cao tính chính xác và hiệu quả của hệ thống RAG. Chúng tôi cũng sẽ cung cấp các ví dụ thực tế và đoạn mã để minh họa các khái niệm và giúp bạn hiểu sâu hơn về kỹ thuật tiên tiến này.
Tìm hiểu về thế hệ tăng cường truy xuất (RAG)
Trước khi đi sâu vào chi tiết cụ thể về truy xuất và sắp xếp lại hai giai đoạn, chúng ta hãy xem lại ngắn gọn khái niệm về Thế hệ tăng cường truy xuất (RAG). RAG là một kỹ thuật mở rộng kiến thức và khả năng của các mô hình ngôn ngữ lớn (LLM) bằng cách cung cấp cho chúng quyền truy cập vào các nguồn thông tin bên ngoài, chẳng hạn như cơ sở dữ liệu hoặc bộ sưu tập tài liệu. Tham khảo thêm từ bài viết “Đi sâu vào thế hệ tăng cường truy xuất trong LLM".
Quy trình RAG điển hình bao gồm các bước sau:
- Query: Người dùng đặt câu hỏi hoặc đưa ra hướng dẫn cho hệ thống.
- Truy xuất: Hệ thống truy vấn cơ sở dữ liệu vectơ hoặc tập hợp tài liệu để tìm thông tin liên quan đến truy vấn của người dùng.
- Mở rộng: Thông tin được truy xuất được kết hợp với truy vấn hoặc hướng dẫn ban đầu của người dùng.
- Thế hệ: Mô hình ngôn ngữ xử lý đầu vào tăng cường và tạo ra phản hồi, tận dụng thông tin bên ngoài để nâng cao độ chính xác và tính toàn diện của đầu ra.
Mặc dù RAG đã được chứng minh là một kỹ thuật mạnh mẽ nhưng nó không phải là không có thách thức. Một trong những vấn đề chính nằm ở giai đoạn truy xuất, trong đó các phương pháp truy xuất truyền thống có thể không xác định được các tài liệu phù hợp nhất, dẫn đến phản hồi dưới mức tối ưu hoặc không chính xác từ mô hình ngôn ngữ.
Sự cần thiết của việc truy xuất và sắp xếp lại hai giai đoạn
Các phương pháp truy xuất truyền thống, chẳng hạn như các phương pháp dựa trên kết hợp từ khóa hoặc mô hình không gian vectơ, thường gặp khó khăn trong việc nắm bắt các mối quan hệ ngữ nghĩa mang tính sắc thái giữa các truy vấn và tài liệu. Hạn chế này có thể dẫn đến việc truy xuất các tài liệu chỉ có liên quan bề ngoài hoặc bỏ lỡ thông tin quan trọng có thể cải thiện đáng kể chất lượng của phản hồi được tạo ra.
Để giải quyết thách thức này, các nhà nghiên cứu và thực hành đã chuyển sang truy xuất hai giai đoạn bằng công cụ sắp xếp lại. Cách tiếp cận này bao gồm một quá trình gồm hai bước:
- Truy xuất ban đầu: Trong giai đoạn đầu tiên, một tập hợp tương đối lớn các tài liệu có khả năng liên quan được truy xuất bằng phương pháp truy xuất nhanh và hiệu quả, chẳng hạn như mô hình không gian vectơ hoặc tìm kiếm dựa trên từ khóa.
- Sắp xếp lại: Trong giai đoạn thứ hai, một mô hình sắp xếp lại phức tạp hơn được sử dụng để sắp xếp lại các tài liệu được truy xuất ban đầu dựa trên mức độ liên quan của chúng với truy vấn, đưa các tài liệu phù hợp nhất lên đầu danh sách một cách hiệu quả.
Mô hình sắp xếp lại, thường là mạng thần kinh hoặc kiến trúc dựa trên máy biến áp, được đào tạo cụ thể để đánh giá mức độ liên quan của tài liệu với một truy vấn nhất định. Bằng cách tận dụng khả năng hiểu ngôn ngữ tự nhiên nâng cao, người xếp hạng lại có thể nắm bắt được các sắc thái ngữ nghĩa và mối quan hệ theo ngữ cảnh giữa truy vấn và tài liệu, dẫn đến xếp hạng chính xác và phù hợp hơn.
Lợi ích của việc truy xuất và sắp xếp lại hai giai đoạn
Việc áp dụng truy xuất hai giai đoạn với trình sắp xếp lại mang lại một số lợi ích đáng kể trong bối cảnh hệ thống RAG:
- Cải thiện độ chính xác: Bằng cách sắp xếp lại các tài liệu được truy xuất ban đầu và đưa những tài liệu phù hợp nhất lên đầu, hệ thống có thể cung cấp thông tin chính xác và chính xác hơn cho mô hình ngôn ngữ, dẫn đến phản hồi được tạo ra có chất lượng cao hơn.
- Các vấn đề ngoài miền được giảm nhẹ: Các mô hình nhúng được sử dụng để truy xuất truyền thống thường được đào tạo về kho văn bản có mục đích chung, có thể không nắm bắt đầy đủ ngôn ngữ và ngữ nghĩa của miền cụ thể. Mặt khác, các mô hình sắp xếp lại có thể được đào tạo về dữ liệu theo miền cụ thể, giảm thiểu vấn đề “ngoài miền” và cải thiện mức độ liên quan của tài liệu được truy xuất trong các miền chuyên biệt.
- khả năng mở rộng: Cách tiếp cận hai giai đoạn cho phép mở rộng quy mô hiệu quả bằng cách tận dụng các phương pháp truy xuất nhanh và nhẹ trong giai đoạn đầu, đồng thời bảo lưu quy trình sắp xếp lại có cường độ tính toán cao hơn cho một tập hợp con tài liệu nhỏ hơn.
- Linh hoạt: Các mô hình sắp xếp lại có thể được hoán đổi hoặc cập nhật độc lập với phương pháp truy xuất ban đầu, mang lại sự linh hoạt và khả năng thích ứng với nhu cầu ngày càng phát triển của hệ thống.
ColBERT: Tương tác muộn hiệu quả và hiệu quả
Một trong những mô hình nổi bật trong lĩnh vực sắp xếp lại là ColBERT (Tương tác muộn theo ngữ cảnh qua BERT). ColBERT là mô hình sắp xếp lại tài liệu tận dụng khả năng hiểu ngôn ngữ sâu của BERT đồng thời giới thiệu một cơ chế tương tác mới được gọi là “tương tác muộn”.
ColBERT: Tìm kiếm đoạn văn hiệu quả và hiệu quả thông qua tương tác muộn theo ngữ cảnh trên BERT
Cơ chế tương tác muộn trong ColBERT cho phép truy xuất hiệu quả và chính xác bằng cách xử lý các truy vấn và tài liệu riêng biệt cho đến giai đoạn cuối của quá trình truy xuất. Cụ thể, ColBERT mã hóa độc lập truy vấn và tài liệu bằng BERT, sau đó sử dụng bước tương tác nhẹ nhưng mạnh mẽ để mô hình hóa sự tương đồng chi tiết của chúng. Bằng cách trì hoãn nhưng vẫn duy trì sự tương tác chi tiết này, ColBERT có thể tận dụng khả năng diễn đạt của các mô hình ngôn ngữ sâu đồng thời đạt được khả năng tính toán trước các cách trình bày tài liệu ngoại tuyến, tăng tốc đáng kể quá trình xử lý truy vấn.
Kiến trúc tương tác muộn của ColBERT mang lại một số lợi ích, bao gồm hiệu quả tính toán được cải thiện, khả năng mở rộng với kích thước bộ sưu tập tài liệu và khả năng ứng dụng thực tế cho các tình huống trong thế giới thực. Ngoài ra, ColBERT đã được cải tiến hơn nữa với các kỹ thuật như giám sát khử nhiễu và nén dư (trong ColBERTv2), giúp tinh chỉnh quy trình đào tạo và giảm dấu chân không gian của mô hình trong khi vẫn duy trì hiệu quả truy xuất cao.
Đoạn mã này trình bày cách định cấu hình và sử dụng mô hình jina-colbert-v1-en để lập chỉ mục một bộ sưu tập tài liệu, tận dụng khả năng xử lý các ngữ cảnh dài một cách hiệu quả.
Triển khai truy xuất hai giai đoạn với Reranker
Bây giờ chúng ta đã hiểu về các nguyên tắc đằng sau việc truy xuất và sắp xếp lại hai giai đoạn, hãy cùng khám phá cách triển khai thực tế của chúng trong bối cảnh hệ thống RAG. Chúng tôi sẽ tận dụng các thư viện và khung phổ biến để chứng minh sự tích hợp của các kỹ thuật này.
Thiết lập Môi trường
Trước khi đi sâu vào mã, hãy thiết lập môi trường phát triển của chúng ta. Chúng tôi sẽ sử dụng Python và một số thư viện NLP phổ biến, bao gồm Hugging Face Transformers, Sentence Transformers và LanceDB.
# Install required libraries
!pip install datasets huggingface_hub sentence_transformers lancedb
Chuẩn bị dữ liệu
Với mục đích trình diễn, chúng tôi sẽ sử dụng bộ dữ liệu “ai-arxiv-chunked” từ Bộ dữ liệu ôm khuôn mặt, chứa hơn 400 bài viết ArXiv về học máy, xử lý ngôn ngữ tự nhiên và mô hình ngôn ngữ lớn.
from datasets import load_dataset
dataset = load_dataset("jamescalam/ai-arxiv-chunked", split="train")
<pre>
Tiếp theo, chúng tôi sẽ xử lý trước dữ liệu và chia dữ liệu thành các phần nhỏ hơn để tạo điều kiện truy xuất và xử lý hiệu quả.
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
def chunk_text(text, chunk_size=512, overlap=64):
tokens = tokenizer.encode(text, return_tensors="pt", truncation=True)
chunks = tokens.split(chunk_size - overlap)
texts = [tokenizer.decode(chunk) for chunk in chunks]
return texts
chunked_data = []
for doc in dataset:
text = doc["chunk"]
chunked_texts = chunk_text(text)
chunked_data.extend(chunked_texts)
Đối với giai đoạn truy xuất ban đầu, chúng tôi sẽ sử dụng mô hình Biến đổi câu để mã hóa tài liệu và truy vấn của chúng tôi thành các biểu diễn vectơ dày đặc, sau đó thực hiện tìm kiếm lân cận gần nhất gần đúng bằng cơ sở dữ liệu vectơ như LanceDB.
from sentence_transformers import SentenceTransformer
from lancedb import lancedb
# Load Sentence Transformer model
model = SentenceTransformer('all-MiniLM-L6-v2')
# Create LanceDB vector store
db = lancedb.lancedb('/path/to/store')
db.create_collection('docs', vector_dimension=model.get_sentence_embedding_dimension())
# Index documents
for text in chunked_data:
vector = model.encode(text).tolist()
db.insert_document('docs', vector, text)
from sentence_transformers import SentenceTransformer
from lancedb import lancedb
# Load Sentence Transformer model
model = SentenceTransformer('all-MiniLM-L6-v2')
# Create LanceDB vector store
db = lancedb.lancedb('/path/to/store')
db.create_collection('docs', vector_dimension=model.get_sentence_embedding_dimension())
# Index documents
for text in chunked_data:
vector = model.encode(text).tolist()
db.insert_document('docs', vector, text)
Với các tài liệu của chúng tôi được lập chỉ mục, chúng tôi có thể thực hiện truy xuất ban đầu bằng cách tìm các lân cận gần nhất với một vectơ truy vấn nhất định.
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
def chunk_text(text, chunk_size=512, overlap=64):
tokens = tokenizer.encode(text, return_tensors="pt", truncation=True)
chunks = tokens.split(chunk_size - overlap)
texts = [tokenizer.decode(chunk) for chunk in chunks]
return texts
chunked_data = []
for doc in dataset:
text = doc["chunk"]
chunked_texts = chunk_text(text)
chunked_data.extend(chunked_texts)
Sắp xếp lại
Sau lần truy xuất đầu tiên, chúng tôi sẽ sử dụng mô hình sắp xếp lại để sắp xếp lại các tài liệu được truy xuất dựa trên mức độ liên quan của chúng với truy vấn. Trong ví dụ này, chúng tôi sẽ sử dụng trình sắp xếp lại ColBERT, một mô hình dựa trên máy biến áp nhanh và chính xác được thiết kế đặc biệt để xếp hạng tài liệu.
from lancedb.rerankers import ColbertReranker
reranker = ColbertReranker()
# Rerank initial documents
reranked_docs = reranker.rerank(query, initial_docs)
Sản phẩm reranked_docs
danh sách hiện chứa các tài liệu được sắp xếp lại dựa trên mức độ liên quan của chúng với truy vấn, được xác định bởi trình sắp xếp lại ColBERT.
Tăng cường và thế hệ
Với các tài liệu được sắp xếp lại và có liên quan trong tay, chúng tôi có thể tiến hành các giai đoạn mở rộng và tạo của quy trình RAG. Chúng tôi sẽ sử dụng mô hình ngôn ngữ từ thư viện Hugging Face Transformers để tạo phản hồi cuối cùng.
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
tokenizer = AutoTokenizer.from_pretrained("t5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
# Augment query with reranked documents
augmented_query = query + " " + " ".join(reranked_docs[:3])
# Generate response from language model
input_ids = tokenizer.encode(augmented_query, return_tensors="pt")
output_ids = model.generate(input_ids, max_length=500)
response = tokenizer.decode(output_ids[0], skip_special_tokens=True)
print(response)