- WordLlama là một bộ công cụ NLP nhanh và gọn nhẹ, tái sử dụng token embedding của LLM để thực hiện fuzzy deduplication, tính toán độ tương đồng, xếp hạng, phân cụm và semantic text splitting
- Suy luận chủ yếu hoạt động dựa trên tra cứu token và average pooling, nhấn mạnh pipeline nhẹ có thể chạy chỉ với NumPy và tối ưu cho CPU
- Mô hình mặc định có kích thước 256 chiều, 16MB, có thể giảm số chiều bằng biểu diễn Matryoshka, còn binary embedding hỗ trợ tính toán nhanh hơn bằng độ tương đồng Hamming
- Trong bảng MTEB, WL64~WL1024 đạt điểm cao hơn GloVe 300d và Komninos ở nhiều chỉ số, nhưng nhìn chung thấp hơn
all-MiniLM-L6-v2
- Có thể dùng sau khi
pip install wordllama và WordLlama.load(), còn .key(query) trả về một hàm callable có thể đưa vào các hàm thư viện chuẩn như sorted, min, max
WordLlama làm gì
- WordLlama là bộ công cụ gọn nhẹ cho các tác vụ tiện ích NLP như fuzzy deduplication, tính toán độ tương đồng, xếp hạng, phân cụm và semantic text splitting
- Nó trích xuất codebook token embedding từ các LLM hiện đại như LLaMA 2, LLaMA 3 70B để tạo ra compact word representation tương tự GloVe, Word2Vec và FastText
- Khi suy luận, nó có ít phụ thuộc và được tối ưu cho phần cứng CPU, nên phù hợp để triển khai trong môi trường hạn chế tài nguyên
- Nhờ tốc độ nhanh và kích thước nhỏ, nó có thể dùng cho các mục đích tiện ích như phân tích khám phá, bộ đánh giá đầu ra LLM, hoặc bước chuẩn bị cho multi-hop hay agentic workflow
Cài đặt và cách dùng cơ bản
pip install wordllama
- Mô hình 256 chiều mặc định được nạp bằng
WordLlama.load()
from wordllama import WordLlama
wl = WordLlama.load()
.key(query) trả về Callable[[str], float], cho phép sắp xếp các chuỗi ứng viên theo độ tương đồng với truy vấn hoặc chọn giá trị lớn nhất
query = "Machine learning methods"
candidates = [
"Foundations of neural science",
"Introduction to neural networks",
"Cooking delicious pasta at home",
"Introduction to philosophy: logic",
]
sim_key = wl.key(query)
sorted_candidates = sorted(candidates, key=sim_key, reverse=True)
best_candidate = max(candidates, key=sim_key)
- Trong kết quả ví dụ,
"Introduction to neural networks" là ứng viên có điểm cao nhất với số điểm 0.3414
Tính năng chính
- Tạo embedding: tạo text embedding nhanh bằng tra cứu token đơn giản và average pooling
- Tính độ tương đồng: tính cosine similarity giữa hai văn bản
- Xếp hạng tài liệu: xếp thứ hạng dựa trên độ tương đồng giữa truy vấn và tài liệu ứng viên
- Fuzzy deduplication: loại bỏ văn bản trùng lặp theo ngưỡng độ tương đồng
- Phân cụm: nhóm tài liệu bằng KMeans
- Lọc: chỉ giữ lại các tài liệu có độ tương đồng với truy vấn từ mức ngưỡng trở lên
- Tìm kiếm Top-K: trả về K tài liệu giống truy vấn nhất
- Semantic text splitting: chia văn bản thành các chunk gắn kết về mặt ngữ nghĩa
- Binary embedding: hỗ trợ tính toán nhanh hơn bằng độ tương đồng Hamming
- Biểu diễn Matryoshka: cắt số chiều embedding theo nhu cầu để điều chỉnh kích thước mô hình và hiệu năng
Kiến trúc mô hình và hiệu năng
- WordLlama huấn luyện mô hình nhỏ không ngữ cảnh trong một framework embedding tổng quát
- Mô hình mặc định có kích thước 256 chiều, 16MB
- Bảng MTEB trong README so sánh WL64, WL128, WL256, WL512, WL1024 với GloVe 300d, Komninos và
all-MiniLM-L6-v2
- WL256 ghi nhận Clustering
33.25, Reranking 52.03, Classification 58.21, Pair Classification 78.22, STS 67.91, CQA DupStack 24.12, SummEval 30.99
- GloVe 300d lần lượt ghi nhận
27.73, 43.29, 57.29, 70.92, 61.85, 15.47, 28.87
all-MiniLM-L6-v2 ghi nhận Clustering 42.35, Reranking 58.04, Classification 63.05, Pair Classification 82.37, STS 78.90, CQA DupStack 41.32, SummEval 30.81
- l2_supercat là mô hình vocabulary LLaMA 2
- Mô hình này được huấn luyện bằng cách nối các codebook từ nhiều mô hình như LLaMA 2 70B và phi 3 medium sau khi loại bỏ các special token bổ sung
- Có thể huấn luyện bằng cách nối chung codebook của nhiều mô hình dùng tokenizer LLaMA 2
- Nó cho hiệu năng tương tự huấn luyện trên codebook LLaMA 3 70B nhưng vocabulary nhỏ hơn 4 lần,
32k so với 128k
- Mô hình dựa trên LLaMA 3 là l3_supercat
- Kết quả bổ sung có trong Results
Semantic text splitting
.split() chia văn bản dài thành các chunk ngữ nghĩa
long_text = "Your very long text goes here... " * 100
chunks = wl.split(long_text, target_size=1536)
print(list(map(len, chunks)))
# Output: [1055, 1055, 1187]
target_size vừa là kích thước mục tiêu vừa là kích thước tối đa
- Quá trình chia cố gắng giữ nguyên thứ tự văn bản, cấu trúc câu và nếu có thể thì cả cấu trúc đoạn văn
- Nó dùng embedding của WordLlama để tìm chỉ số cắt tự nhiên hơn
- Kích thước chunk đầu ra có thể thay đổi trong phạm vi không vượt quá
target_size
- Kích thước mục tiêu khuyến nghị là 512~2048 ký tự, mặc định là
1536
- Nếu cần chunk lớn hơn, nên chia trước rồi gom nhiều semantic chunk lại theo lô
- Xem thêm trong technical overview
Model2Vec và suy luận trực tiếp
- Bản cập nhật 2025-01-04 bổ sung hỗ trợ Model2Vec static embeddings
- Có thể nạp mô hình Model2Vec bằng
WordLlama.load_m2v()
wl = WordLlama.list_configs()
wl = WordLlama.load_m2v("potion_base_8m") # 256-dim model
wl = WordLlama.load_m2v("m2v_multilingual") # multilingual model
- Model2Vec là một cách khác để tạo static embedding bằng PCA
- Phía Model2Vec đã tạo mô hình đa ngôn ngữ và mô hình dựa trên glove, đồng thời cho biết đạt điểm tốt ở bài toán word similarity
- Có thể xem trên minishlab của Hugging Face
WordLlamaInference cho phép dùng trực tiếp một mảng static embedding dạng (n_vocab, dim) cùng tokenizer thay vì dùng loader
from wordllama import WordLlamaInference
from tokenizers import Tokenizer
tokenizer = Tokenizer.from_pretrained(...)
wl = WordLlamaInference(np_embeddings_ar, tokenizer)
Huấn luyện và trích xuất embedding
- Mô hình binary embedding cho thấy mức cải thiện rõ hơn ở số chiều cao, và với binary embedding thì 512 hoặc 1024 chiều được khuyến nghị
- Mô hình L2 Supercat được huấn luyện trong 12 giờ trên một GPU A100 duy nhất với batch size
512
- Để trích xuất token embedding từ mô hình LLaMA, cần đồng ý với thỏa thuận người dùng và đăng nhập Hugging Face CLI
from wordllama.extract.extract_safetensors import extract_safetensors
extract_safetensors("llama3_70B", "path/to/saved/model-0001-of-00XX.safetensors")
- Embedding thường nằm trong file
safetensors đầu tiên, nhưng không phải lúc nào cũng vậy
- Có thể có manifest
- Có thể phải tự kiểm tra và tìm trực tiếp
- Việc huấn luyện dùng các script trong kho mã nguồn, và cần thêm configuration file bằng cách sao chép hoặc chỉnh sửa cấu hình sẵn có
pip install wordllama[train]
python train.py train --config your_new_config
python train.py save --config your_new_config --checkpoint ... --outdir /path/to/weights/
- Bước lưu sẽ lưu từng mô hình theo từng chiều Matryoshka
Cập nhật, lộ trình, giấy phép
- Bản cập nhật 2025-02-01 bổ sung hỗ trợ callable có thể dùng với các hàm thư viện chuẩn như
sorted, min, max
- Bản cập nhật 2024-10-04 bổ sung semantic splitting inference algorithm
- Lộ trình có kế hoạch bổ sung notebook ví dụ cho DSPy evaluator và Retrieval-Augmented Generation, tức pipeline RAG
- Có các dự án cộng đồng như Gradio Demo HF Space và CPU-ish RAG
- Giấy phép của dự án là MIT License
1 bình luận
Ý kiến trên Hacker News
Mình rất thích kích thước nhỏ của nó. Nó đã có lợi thế so với mô hình nhỏ nhất của SBERT
Tuy nhiên, về mặt kỹ thuật thì có vẻ là một cách tiếp cận khá cũ, và mình hiểu đây là sự đánh đổi với hiệu năng. Dù vậy, mình tò mò liệu nó có thể cung cấp khả năng chuyển đổi các loại độ tương đồng như độ tương đồng ngữ nghĩa, suy luận ngôn ngữ tự nhiên (NLI), hay trừu tượng hóa danh từ hay không
Ví dụ, khi nhóm các bài báo vào những danh mục như “sự kiện môi trường cực đoan”, ta muốn “Freezing” và “Burning” được coi là rất giống nhau. Đây là trường hợp hoạt động giống MTEB/Sentence-Similarity hoặc Word2Vec/GloVe cổ điển. Nhưng nếu là bài viết về hóa học thì hai từ này nên gần như đối lập, và đôi khi ta cũng muốn dùng embedding suy luận ngôn ngữ tự nhiên để xem quan hệ nhân quả giữa hai sự vật
Mình nghĩ hai loại embedding sau là các cách tương đối gần đây sau năm 2019 nên còn nhiều cơ hội kỹ thuật hơn. Dòng MTEB/độ tương đồng ngữ nghĩa cũ đã đủ tốt cho nhiều mục đích từ năm 2014, và được cải thiện đáng kể vào năm 2019 với mini-lm-v2, v.v.
Ba loại embedding trên cũng có thể làm bằng SBERT, nhưng số chiều lớn và mô hình cũng lớn, nên nếu tải nhiều mô hình theo từng loại thì gánh nặng tài nguyên khá cao. Các mô hình embedding sinh, E5, hay mô hình suy luận ngôn ngữ tự nhiên thường lớn và đôi khi cần khoảng 6GB
Mình muốn xem hiệu năng ra sao khi huấn luyện với một loại độ tương đồng duy nhất. Mình không chắc có cách nào khác để xử lý việc này mà không tính ngữ cảnh hay không. Có thể phải chuyển đổi mô hình, nhưng bản thân điều đó không phải vấn đề lớn
Không có ý chê bai, chỉ là cần hiểu những việc như thế này trong đúng bối cảnh. Ở đây, bối cảnh là khi tìm hiểu sâu về LLM, người ta phát hiện ra rằng LLM cũng có embedding; từ góc nhìn đó, việc thử nghịch các embedding ấy và tiến thêm một bước tự nhiên hơn là rà soát lại toàn bộ hiện trạng của lĩnh vực embedding
Nghĩ rằng các từ trái nghĩa sẽ có embedding trái ngược là một nhầm lẫn phổ biến. Thực tế, các từ trái nghĩa cũng có rất nhiều điểm chung. “burning” và “freezing” đều liên quan đến nhiệt độ và vật lý, đều là từ tiếng Anh, đều có thể dùng như động từ, danh từ, tính từ, và đều viết đúng chính tả. Tất cả những đặc điểm này đều đi vào embedding
Embedding chứa nhiều thông tin ngữ nghĩa tùy theo dữ liệu huấn luyện và hàm mục tiêu, và có thể được dùng độc lập cho nhiều tác vụ hữu ích
Trước đây mình từng dùng embedding từ bộ mã hóa văn bản của mô hình CLIP để tăng cường prompt sao cho khớp tốt hơn với ảnh tương ứng. Ví dụ, nếu prompt có “building”, mình tìm các láng giềng gần nhất trong ma trận embedding như “concrete”, “underground” rồi thay thế hoặc thêm chúng sau từ đó. Trong các thử nghiệm hạn chế, recall tăng ở hầu hết truy vấn
https://www.marqo.ai/blog/generalized-contrastive-learning-f...
Nhìn vào độ lớn của token embedding trong wordllama, có lẽ nó cũng có thể giúp xác định các token quan trọng cần tăng cường. Tuy nhiên, nếu huấn luyện bằng dữ liệu được chọn lọc riêng cho tác vụ này thì có thể hoạt động tốt hơn nhiều
Mình tò mò có kế hoạch cho các ngôn ngữ ngoài tiếng Anh không. Có vẻ đây sẽ là công cụ hoàn hảo cho tiếng Pháp
Mình từng huấn luyện thử một chút với các mô hình họ Mistral, nên với corpus tiếng Pháp có lẽ mình sẽ thử hướng đó trước
Nếu bạn mở issue, mình sẽ làm thử khi có thời gian
Với corpus lớn, ví dụ hơn 10.000 câu và xem mỗi câu như một tài liệu, việc phân cụm bằng k-means trên vector ma trận thưa TF-IDF cũng có thể cho kết quả tương tự
Tuy nhiên công cụ này có vẻ có khá nhiều tiện ích để làm phần k-means nhanh hơn, chẳng hạn như nhị phân hóa. Mình định benchmark trong vài tuần tới
Vài năm trước mình từng tạo một bộ trò chơi ngôn ngữ dùng các hàm tương tự: https://github.com/Hellisotherpeople/Language-games
https://github.com/plasticityai/magnitude
Mình tò mò không biết đã ai nghĩ đến việc dùng embedding để giải Little Alchemy chưa. #sample-use
Trông hay đấy. Mình tò mò nó có ưu điểm gì so với mô hình mini-lm không. Trong hầu hết tác vụ MTEB, mini-lm có vẻ tốt hơn, nên mình muốn biết liệu nó có điểm nào tốt hơn như tốc độ suy luận chẳng hạn không
Nó cũng không nhắm tới hiệu năng tối tân nhất. Đây là mô hình đặt ra các ràng buộc khá nghiêm ngặt để giảm dependency, kích thước, yêu cầu phần cứng và tăng tốc độ
Ngay cả khi xem như mô hình word embedding thì nó cũng khá nhẹ. Thường các mô hình kiểu đó có từ vựng lớn hơn nhiều và kích thước ở mức vài GB
Trông rất hữu ích cho phát triển game
Nó cho thấy rõ trong bản thân token có bao nhiêu nội dung ngữ nghĩa
Có thể làm thành extension PostgreSQL không?