Word Embeddings
Word Embeddings - Biểu diễn từ dạng vector
Trong "bản đồ từ ngữ", từ nào sẽ nằm GẦN "phở" nhất?
Liên tưởng 1 — Cách bạn sắp xếp kệ sách: Khi bạn sắp kệ sách ở nhà, bạn đặt sách cùng chủ đề gần nhau: tiểu thuyết gần tiểu thuyết, sách kỹ thuật gần sách kỹ thuật. Bạn không cần ai bảo — bạn "cảm" được từ nội dung. Word embedding là bản đồ tự sắp xếp như vậy cho từ ngữ: "phở" gần "bún chả", không phải vì ai dán nhãn, mà vì chúng cùng xuất hiện trong các ngữ cảnh về ẩm thực.
Liên tưởng 2 — Map định vị Sài Gòn: Trên bản đồ Sài Gòn, Bến Thành gần phố Tây (Phạm Ngũ Lão), xa quận 9. Bạn đo khoảng cách bằng km. Trong word embedding, mỗi từ là một toạ độ trong không gian 300 chiều. Bạn đo "độ giống nghĩa" bằng cosine similarity giữa hai vector.
Liên tưởng 3 — "Vua - đàn ông + phụ nữ = hoàng hậu": Đây là đẳng thức kinh điển thể hiện word embedding không chỉ là "gần/xa" — nó còn biểu diễn được các mối quan hệ trừu tượng như "giới tính", "số ít/số nhiều", "thủ đô-quốc gia", "nguyên thể-quá khứ". Việc này gần như phép thuật khi công bố (Mikolov, 2013).
Liên tưởng 4 — Tìm kiếm ngữ nghĩa trên Shopee: Khi bạn gõ "quần jean", Shopee cũng hiện "quần bò", "quần tây" — dù bạn không gõ. Đằng sau hậu trường là embedding: các từ này có vector gần nhau. Đây là một trong những ứng dụng công nghiệp sớm nhất của word embedding.
Bản đồ bên dưới cho thấy các từ trong không gian 2D. Di chuột qua từng từ để xem — bạn sẽ thấy "phở" nằm gần "bún chả", và "xe máy" nằm gần "Grab"!
Hình minh họa
Phép tính vector nổi tiếng
vua - đàn ông + phụ nữ = hoàng hậu
Tại sao việc đo "gần" trong embedding khác với khoảng cách Euclid thông thường? Trong word embedding, độ dài vector phụ thuộc vào tần suất từ xuất hiện. Nếu dùng Euclid, từ hiếm sẽ "xa" tất cả vì norm nhỏ. Cosine similarity bỏ qua độ dài, chỉ đo hướng — phù hợp hơn cho đo độ tương đồng ngữ nghĩa.
Bảng ví dụ cosine similarity thực tế (embedding tiếng Việt):
| Cặp từ | Cosine | Diễn giải |
|---|---|---|
| phở — bún chả | 0.86 | Cùng chủ đề ẩm thực |
| Hà Nội — Sài Gòn | 0.79 | Đều là thành phố lớn |
| vui — hạnh phúc | 0.72 | Cảm xúc tích cực |
| phở — máy tính | 0.11 | Khác chủ đề hoàn toàn |
| vui — buồn | 0.42 | Trái nghĩa nhưng cùng domain cảm xúc ⇒ cosine vừa |
Word Embeddings biến mỗi từ thành tọa độ trong không gian nhiều chiều. Từ có nghĩa gần thì nằm gần nhau, và phép tính vector thể hiện quan hệ ngữ nghĩa!
Giống bản đồ Việt Nam: Hà Nội gần Hải Phòng (cùng miền Bắc), xa Sài Gòn (miền Nam). Khoảng cách trên bản đồ phản ánh mối quan hệ thực tế!
Nếu vector('Hà Nội') - vector('phở') + vector('cơm tấm'), kết quả sẽ gần vector nào nhất?
Từ "đá" có thể là động từ ("đá bóng") hoặc danh từ ("hòn đá"). Word2Vec gán MỘT vector duy nhất cho "đá". Điều gì xảy ra?
Bạn xây hệ thống tìm kiếm bán hàng tiếng Việt. User gõ 'áo khoác ấm'. Hệ thống truyền thống (BoW) không tìm được sản phẩm 'jacket mùa đông'. Dùng word embedding giải quyết thế nào?
Giải thích
Word Embeddings biểu diễn từ dưới dạng vector số thực trong không gian liên tục (thường 100-300 chiều). Các mô hình kinh điển như Word2Vec và GloVe đã mở đường, và ngày nay các embedding model hiện đại học được ngữ nghĩa theo ngữ cảnh.
Dựa trên giả thuyết phân phối (distributional hypothesis):
Từ xuất hiện trong ngữ cảnh giống nhau → vector gần nhau. "Phở" và "bún chả" đều hay đi cùng "ngon", "Việt Nam", "ăn" → nằm gần nhau.
Cosine similarity đo góc giữa 2 vector (từ -1 đến 1):
cosine("phở", "bún chả") = 0.85 (rất gần). cosine("phở", "xe máy") = 0.12 (rất xa).
import gensim.downloader as api
# Tải word embeddings pre-trained
model = api.load("word2vec-google-news-300")
# Tìm từ gần nhất
similar = model.most_similar("Vietnam")
print(similar[:3])
# [('Viet_Nam', 0.72), ('Cambodia', 0.68), ('Laos', 0.65)]
# Phép tính vector nổi tiếng
result = model.most_similar(
positive=["king", "woman"],
negative=["man"]
)
print(result[0]) # ('queen', 0.71)
# Đo cosine similarity
print(model.similarity("pho", "noodle")) # 0.45
print(model.similarity("pho", "car")) # 0.08PhoBERT (VinAI) cung cấp embeddings chất lượng cao cho tiếng Việt. fastText cũng có pre-trained vectors cho tiếng Việt. Các mô hình này hiểu "phở" gần "bún chả" tốt hơn mô hình tiếng Anh.
import gensim
from gensim.models import Word2Vec
from pyvi import ViTokenizer
# 1. Chuẩn bị corpus — list câu, mỗi câu là list từ (đã tokenize)
raw_sentences = [
"Tôi ăn phở mỗi sáng ở Hà Nội",
"Bún chả là đặc sản Hà Nội nổi tiếng",
"Cơm tấm thơm ngon đậm chất Sài Gòn",
"Grab là ứng dụng xe ôm phổ biến tại Việt Nam",
# ... cần vài triệu câu để có embedding tốt
]
# Tách từ tiếng Việt (ViTokenizer nối 'Hà_Nội' thành 1 token)
sentences = [ViTokenizer.tokenize(s).split() for s in raw_sentences]
# 2. Huấn luyện Word2Vec (skip-gram)
model = Word2Vec(
sentences=sentences,
vector_size=100, # Số chiều embedding
window=5, # Cửa sổ ngữ cảnh
min_count=2, # Bỏ qua từ xuất hiện < 2 lần
sg=1, # 1 = skip-gram, 0 = CBOW
workers=4,
epochs=10,
)
# 3. Khám phá không gian vector
print(model.wv.most_similar("phở", topn=3))
# [('bún_chả', 0.85), ('cơm_tấm', 0.79), ('bánh_mì', 0.72)]
# 4. Phép toán vector — king-queen trên tiếng Việt
result = model.wv.most_similar(
positive=["Sài_Gòn", "phở"],
negative=["Hà_Nội"],
)
print(result[0]) # Gần 'cơm_tấm' — đặc sản Sài Gònvector("lập trình viên") − vector("đàn ông") + vector("phụ nữ") có thể cho ra "nội trợ"thay vì "lập trình viên" — vì corpus chứa thiên kiến giới. Khi triển khai cho hệ thống tuyển dụng, tín dụng, tư pháp, bạn BẮT BUỘC phải kiểm tra và giảm thiểu bias (debias techniques).from sentence_transformers import SentenceTransformer, util
import torch
# Load model tiếng Việt
model = SentenceTransformer(
"bkai-foundation-models/vietnamese-bi-encoder"
)
# Cơ sở dữ liệu sản phẩm của shop thời trang
products = [
"Áo khoác dạ nam ấm mùa đông",
"Giày sneaker thể thao chạy bộ",
"Quần jean slim nam basic",
"Áo thun polo cổ trụ nam",
"Jacket nỉ trơn đi chơi lạnh",
]
prod_emb = model.encode(products, convert_to_tensor=True)
# User gõ truy vấn
query = "áo ấm cho mùa lạnh"
q_emb = model.encode(query, convert_to_tensor=True)
# Tìm top-3 sản phẩm gần nghĩa nhất
scores = util.cos_sim(q_emb, prod_emb)[0]
top3 = torch.topk(scores, 3)
for score, idx in zip(top3.values, top3.indices):
print(f"{score:.3f} - {products[idx]}")
# 0.872 - Jacket nỉ trơn đi chơi lạnh
# 0.845 - Áo khoác dạ nam ấm mùa đông
# 0.412 - Áo thun polo cổ trụ namSo sánh các thuật toán embedding kinh điển:
- Word2Vec (Mikolov, 2013): predict context từ center word (skip-gram) hoặc ngược lại (CBOW). Đơn giản, nhanh, nhưng không tận dụng được thống kê toàn cục.
- GloVe (Pennington, 2014): kết hợp matrix factorization với local context. Thường cho kết quả tương đương Word2Vec nhưng hội tụ nhanh hơn trên corpus lớn.
- fastText (Bojanowski, 2017): dùng n-gram ký tự — xử lý được từ hiếm và OOV. Hoạt động tốt với các ngôn ngữ có hình thái phong phú (morphology-rich languages).
- ELMo (Peters, 2018): lần đầu cung cấp contextual embedding bằng bi-LSTM. Đã giải quyết một phần vấn đề polysemy.
- BERT (Devlin, 2018): contextual embedding dùng Transformer — chuẩn vàng cho NLP hiện đại.
Quy trình chuẩn cho semantic search tiếng Việt:
- Preprocessing: làm sạch văn bản (bỏ HTML, emoji dư thừa, normalize dấu), chia câu dài thành đoạn 200-300 token để tôn trọng giới hạn context của embedding model.
- Chọn model: cho tiếng Việt, cân nhắc PhoBERT-based bi-encoder (chạy local, free) hay OpenAI API (chất lượng cao, trả phí). Với dataset 1M+ chunk, cân bằng tốt nhất là model open source chạy trên GPU của bạn.
- Encode & index: chạy batch encode, lưu vector vào vector database (Qdrant, Milvus, pgvector Supabase). Cần approximate nearest neighbor (HNSW) để scale.
- Retrieval + rerank: bi-encoder lấy top-50, sau đó cross-encoder rerank xuống top-5. Cross-encoder (như BKAI vietnamese-rerank) cho độ chính xác cao hơn.
- Monitor drift: theo dõi phân phối truy vấn theo thời gian. Nếu user bắt đầu hỏi về chủ đề mới (ví dụ COVID xuất hiện 2020), bạn có thể cần retrain/fine-tune embedding trên dữ liệu mới.
Câu chuyện thực tế: knowledge base CSKH Viettel
Giả sử đội CSKH có 50.000 câu hỏi thường gặp về gói cước, dịch vụ, khuyến mãi. Cách cũ (BoW + TF-IDF) bắt keyword chính xác nhưng hỏng khi user dùng synonym ("5G" vs "mạng nhanh", "gói cước" vs "data"). Sau khi chuyển sang bi-encoder tiếng Việt, recall@5 tăng từ 62% lên 89%, user resolution rate tăng 20%. Đầu tư: 1 tuần kỹ sư và GPU T4 giá rẻ.
Hãy so sánh 3 cách biểu diễn từ mà bạn đã học:
BoW / TF-IDF
Số chiều: Rất lớn (~100K)
Ngữ nghĩa: Không
Dạng: Thưa (sparse)
Word2Vec / GloVe
Số chiều: Nhỏ (100-300)
Ngữ nghĩa: Có
Dạng: Dày (dense)
BERT / GPT
Số chiều: Lớn (768-1024)
Ngữ nghĩa: Có + ngữ cảnh
Dạng: Dày (dense)
- Embeddings biến từ thành vector dense (100-300 chiều) — nắm bắt ngữ nghĩa.
- Từ tương tự nằm gần nhau: 'phở' gần 'bún chả', xa 'xe máy'.
- Phép tính vector có ý nghĩa: vua - đàn ông + phụ nữ ≈ hoàng hậu.
- Cosine similarity đo mức tương đồng giữa hai từ (từ -1 đến 1).
- Nền tảng cho mọi mô hình NLP hiện đại: Word2Vec → GloVe → BERT → GPT.
- Hạn chế: không xử lý đa nghĩa (polysemy) và thừa kế bias từ corpus — cần debias khi triển khai.
Kiểm tra hiểu biết
Tại sao 'phở' và 'bún chả' nằm gần nhau trong không gian vector?