GloVe
GloVe - Biểu diễn vector toàn cục
Nếu đếm tất cả sách & bài báo tiếng Việt, cặp từ nào sẽ xuất hiện CÙNG NHAU nhiều nhất?
Đây là trái tim của GloVe: ma trận đồng xuất hiện với 10 từ tiếng Việt. Mỗi ô là số lần từ i và j xuất hiện gần nhau (cửa sổ ±5). Di chuột qua ô để xem chi tiết, và kéo thanh trượt để xem quá trình phân tích ma trận .
Hình minh họa
| phở | bún | chả | ngon | Hà Nội | xe máy | đường phố | tuyệt | thích | đông | |
|---|---|---|---|---|---|---|---|---|---|---|
| phở | ||||||||||
| bún | ||||||||||
| chả | ||||||||||
| ngon | ||||||||||
| Hà Nội | ||||||||||
| xe máy | ||||||||||
| đường phố | ||||||||||
| tuyệt | ||||||||||
| thích | ||||||||||
| đông |
Di chuột qua ô để xem và — giá trị mà GloVe muốn khớp.
Phân tích ma trận:
Bước 1/5100 giá trị
≈
Khởi tạo ngẫu nhiên W
Loss: 2.10
d=4 chiều (rút gọn)
Mục tiêu: tìm và sao cho khớp với (có trọng số f).
Embedding 2D (phép chiếu mô phỏng) — phở
Top 3 từ gần phở:
Đồng xuất hiện cao
bún + chả = 22
→ → vector rất gần
Đồng xuất hiện thấp
chả + xe máy = 0
→ → bỏ qua (f=0)
GloVe = Global Vectors. Nó xây bảng thống kê "ai đi cùng ai" trên TOÀN BỘ dữ liệu (100 ô cho 10 từ, hàng trăm triệu ô cho từ vựng thật), rồi tìm vector sao cho .
Giống thám tử: Word2Vec theo dõi từng cuộc gặp riêng lẻ (mỗi cửa sổ là một "lần quan sát"), GloVe lập bảng tổng hợp "ai gặp ai bao nhiêu lần trong cả năm" rồi phân tích mối quan hệ một cách tổng thể — nhanh hơn, ổn định hơn, dễ song song hơn.
Trong ma trận 10×10, X(bún, chả) = 22 nhưng X(bún, xe máy) = 1. GloVe sẽ tạo embeddings thế nào?
Một trong những test kinh điển cho word embeddings là analogy query: cho 3 từ A, B, C, tìm D sao cho "A với B như C với D". Biểu diễn vector: . Hãy so sánh GloVe và Word2Vec trên 5 query tiếng Việt:
Hình minh họa
Query
Kỳ vọng: hoàng hậu
GloVe (toàn cục)
hoàng hậu
cosine = 0.78
Word2Vec (cục bộ)
hoàng hậu
cosine = 0.76
Cả hai đều bắt được quan hệ giới tính.
Nếu chỉ optimize , hai vấn đề sẽ xảy ra: (1) cặp từ xuất hiện quá ít (nhiễu) có thể phá vỡ model, (2) cặp quá nhiều (như "của", "là") sẽ chi phối toàn bộ loss. Giải pháp: thêm trọng số .
Hình minh họa
Đường cong f(x) — Weighting function
Cặp trung bình → trọng số tăng dần theo công thức power.
Một corpus có X(của, là) = 2,000,000 (cực phổ biến) và X(phở, ngon) = 80. Hàm f với x_max = 100 xử lý ra sao?
Giải thích
GloVe (Global Vectors for Word Representation, Pennington, Socher & Manning, Stanford 2014) kết hợp hai trường phái lớn: phân tích ma trận toàn cục (LSA, HAL) và học cửa sổ cục bộ (như Word2Vec). Cả hai đều cho ra word embeddings chất lượng cao, nhưng GloVe có điểm tựa toán học rõ ràng hơn: bắt đầu từ ratio của xác suất đồng xuất hiện và dẫn tới một objective có thể chứng minh được.
Công thức hoàn chỉnh mà bạn sẽ thấy trong paper gốc:
Trong đó là số lần từ i, j đồng xuất hiện, là trọng số, và là bias giúp hấp thụ tần suất marginal của từng từ. V là kích thước từ vựng (thường 400K).
- f(0) = 0 — bỏ qua cặp không đồng xuất hiện (tránh log 0).
- Không giảm — cặp thường gặp không bị đánh trọng số nhỏ hơn cặp hiếm.
- Bão hoà — cặp cực phổ biến ("của", "là") không chi phối gradient.
GloVe: Dữ liệu lớn (6B+ tokens), cần embeddings ổn định, có sẵn pre-trained (glove.6B, glove.42B, glove.840B), dễ song song hoá trên cluster. Word2Vec: Dữ liệu nhỏ-vừa, cần huấn luyện tuỳ chỉnh, dùng Skip-gram cho từ hiếm. Thực tế: kết quả hai model rất gần nhau trên các benchmark — chọn cái nào tiện hơn cho pipeline của bạn.
Cả GloVe lẫn Word2Vec đều là static: một từ chỉ có MỘT vector bất kể ngữ cảnh. "Con đá" và "đá bóng" — từ "đá" có nghĩa hoàn toàn khác — nhưng GloVe không phân biệt được. Đây là động lực chính để ngành NLP chuyển sang contextual embeddings: ELMo (2018), BERT (2018), GPT-2 (2019). Mỗi lần gặp "đá" trong ngữ cảnh mới, model tạo một vector mới.
"""
Huấn luyện GloVe với Gensim trên corpus tiếng Việt.
Yêu cầu: pip install glove_python_binary gensim scikit-learn
"""
from glove import Corpus, Glove
from gensim.utils import simple_preprocess
import numpy as np
# ─── 1. Chuẩn bị corpus ───
# Mỗi câu là một list tokens
corpus_text = [
"phở Hà Nội rất ngon và nổi tiếng",
"bún chả là món đặc sản của Hà Nội",
"xe máy chạy khắp đường phố Hà Nội",
"tôi thích phở bò ngon tuyệt",
# ... hàng triệu câu khác
]
sentences = [simple_preprocess(s) for s in corpus_text]
# ─── 2. Xây ma trận đồng xuất hiện ───
corpus = Corpus()
corpus.fit(sentences, window=10) # cửa sổ ±10
print(f"Vocabulary size: {len(corpus.dictionary)}")
print(f"Non-zero entries: {corpus.matrix.nnz}")
# ─── 3. Huấn luyện GloVe ───
glove = Glove(
no_components=100, # vector 100 chiều
learning_rate=0.05,
alpha=0.75, # exponent của f(x)
max_count=100, # x_max
)
glove.fit(
corpus.matrix,
epochs=30,
no_threads=8, # parallel
verbose=True,
)
glove.add_dictionary(corpus.dictionary)
# ─── 4. Truy vấn ───
print(glove.most_similar("phở", number=5))
# → [('bún', 0.82), ('chả', 0.76), ('ngon', 0.71), ...]
# ─── 5. Analogy: vua - đàn_ông + phụ_nữ ≈ ? ───
def analogy(a, b, c, model, topn=3):
va = model.word_vectors[model.dictionary[a]]
vb = model.word_vectors[model.dictionary[b]]
vc = model.word_vectors[model.dictionary[c]]
target = va - vb + vc
# cosine similarity với tất cả từ
norms = np.linalg.norm(model.word_vectors, axis=1)
sims = model.word_vectors @ target / (norms * np.linalg.norm(target) + 1e-8)
# loại 3 từ đầu vào
for w in (a, b, c):
sims[model.dictionary[w]] = -1
top = np.argsort(-sims)[:topn]
inv_dict = {v: k for k, v in model.dictionary.items()}
return [(inv_dict[i], sims[i]) for i in top]
print(analogy("vua", "đàn_ông", "phụ_nữ", glove))
# → [('hoàng_hậu', 0.78), ('nữ_hoàng', 0.71), ...]
# ─── 6. Lưu model ───
glove.save("vi_glove_100d.model")"""
Sử dụng GloVe pre-trained (tải từ nlp.stanford.edu/projects/glove)
"""
import numpy as np
# ─── Tải glove.6B.100d.txt (822 MB, 400K từ tiếng Anh) ───
embeddings = {}
with open("glove.6B.100d.txt", "r", encoding="utf-8") as f:
for line in f:
values = line.split()
word = values[0]
vec = np.array(values[1:], dtype=np.float32)
embeddings[word] = vec
print(f"Loaded {len(embeddings)} word vectors, dim={len(next(iter(embeddings.values())))}")
# ─── Cosine similarity ───
def cosine_sim(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-8)
# ─── So sánh các cặp nổi tiếng ───
print(cosine_sim(embeddings["king"], embeddings["queen"])) # 0.75 — rất gần
print(cosine_sim(embeddings["king"], embeddings["man"])) # 0.53 — gần
print(cosine_sim(embeddings["king"], embeddings["car"])) # 0.15 — xa
# ─── Analogy kinh điển ───
target = embeddings["king"] - embeddings["man"] + embeddings["woman"]
# Tìm từ gần target nhất (trừ 3 từ đầu vào)
best = ("", -1)
for w, v in embeddings.items():
if w in {"king", "man", "woman"}:
continue
s = cosine_sim(target, v)
if s > best[1]:
best = (w, s)
print(best) # ('queen', 0.71)
# ─── Analogy địa danh ───
target = embeddings["paris"] - embeddings["france"] + embeddings["vietnam"]
# → "hanoi" (cosine ≈ 0.67)- GloVe xây ma trận đồng xuất hiện TOÀN CỤC X_ij — đếm số lần mọi cặp từ đi cùng nhau trên toàn corpus (không chỉ window cục bộ).
- Mục tiêu cốt lõi: w_i · ~w_j + b_i + ~b_j ≈ log(X_ij) — tích vô hướng vector xấp xỉ log đồng xuất hiện, có trọng số f(X_ij).
- Hàm f(x) = (x/x_max)^α (α=0.75, x_max=100) bão hoà ở 1 — giảm ảnh hưởng cặp hiếm (nhiễu) và cặp quá phổ biến ('của', 'là').
- Kết hợp ưu điểm LSA (toàn cục) + Word2Vec (cục bộ) → embeddings ổn định, song song hoá dễ, kết quả analogy mạnh.
- Pre-trained GloVe Stanford: glove.6B (400K từ, 50-300d), glove.42B (1.9M từ), glove.840B (2.2M từ) — tải miễn phí.
- Hạn chế: mỗi từ chỉ có 1 vector cố định (không phân biệt nghĩa theo ngữ cảnh) → BERT/GPT giải quyết bằng contextual embeddings.
Kiểm tra hiểu biết
GloVe khác Word2Vec ở điểm cốt lõi nào?