BERT
BERT - Biểu diễn mã hoá hai chiều
Bạn đọc câu: 'Mẹ tôi vừa ra chợ mua [che] để nấu canh chua'. Làm sao con người (hoặc máy) đoán từ bị che?
Hãy hình dung bạn đang đọc một tờ báo và một vết mực che mất một từ: "Hôm qua tôi đi [●●●] để xem phim mới chiếu." Bạn không cần đoán mò, bộ não tự động kết hợp thông tin trước ("đi") và sau ("xem phim") để suy ra "rạp". Đó chính là cách BERT học ngôn ngữ: đọc hai chiều cùng lúc.
So sánh với GPTgiống như đọc truyện đang diễn ra — bạn chỉ biết quá khứ và hiện tại, phải đoán câu kế tiếp. BERT thì giống nghe một đoạn ghi âm đã hoàn chỉnh rồi bị che vài chữ — bạn có quyền tua tới tua lui để hiểu.
Vì sao điều này quan trọng? Trong tiếng Việt, nghĩa của một từ thường phụ thuộc vào từ đứng sau. "Sông Hương" chỉ rõ là tên sông khi thấy "Huế" phía sau. BERT tận dụng chính xác tín hiệu này để tạo embeddingsphụ thuộc ngữ cảnh — mỗi từ có một vector khác nhau tuỳ câu.
Thực tế ở Việt Nam: các trợ lý như chatbot ngân hàng, công cụ tóm tắt báo chí, hệ thống tìm kiếm nội dung (vd VnExpress, Tiki) đều tận dụng biến thể của BERT (PhoBERT, viBERT) để hiểu truy vấn tiếng Việt. Hiểu BERT đồng nghĩa hiểu nền móng của NLP hiện đại.
Hình minh họa
Đây là tác vụ Masked Language Modeling: BERT được huấn luyện bằng cách che ngẫu nhiên 15% từ rồi đoán lại. Hãy chơi thử với mô hình.
Hà Nội là thủ đô của [MASK]
Hãy chọn từ bạn nghĩ là đúng để xem BERT dự đoán thế nào.
Hình minh họa
BERT là một đứa trẻ đọc hai chiều: khi mất một chữ trong câu, nó biết nhìn cả trước và sau để đoán. Sau khi luyện đọc kiểu này trên hàng tỉ câu, nó mang lại một "bộ não ngôn ngữ" mà mọi tác vụ hiểu văn bản — từ phân loại đến nhận dạng thực thể— đều có thể mượn dùng, chỉ cần gắn thêm một lớp đầu ra nhỏ và tinh chỉnh vài giờ.
Nếu đưa cho BERT câu 'Tôi [MASK] phở sáng nay', BERT sẽ dự đoán từ nào có xác suất cao nhất?
Vì sao BERT-base thường đủ tốt cho đa số tác vụ tiếng Việt khi dữ liệu hạn chế?
Trong pipeline fine-tune BERT cho phân loại cảm xúc, phần nào mới được huấn luyện từ đầu?
Hình minh họa
Mỗi câu đi qua 12 lớp Transformer (BERT-base). Hãy chọn một lớp để xem tầng đó học được gì.
Tham số
110M
BERT-base
Hidden size
768
vector mỗi token
Attention heads
12
mỗi lớp
Hình minh họa
Cùng một BERT pre-trained, chọn tác vụ để xem cách thêm lớp đầu ra.
Phân loại cảm xúc (Sentiment)
Đầu vào: BERT([CLS] Bộ phim này tuyệt vời [SEP])
Lớp head: Linear(768, 2) + Softmax
Đầu ra: → [positive 0.94, negative 0.06]
Dùng vector của [CLS] (kích thước 768 ở BERT-base) làm đầu vào. Một lớp tuyến tính + softmax đủ cho tác vụ 2 nhãn.
Giải thích
BERT (Bidirectional Encoder Representations from Transformers) là mô hình ngôn ngữ tiền huấn luyện do Google công bố năm 2018 (Devlin và cộng sự). Điểm đột phá: dùng Transformer Encoder đọc hai chiều cùng lúc, kết hợp tác vụ Masked Language Modeling để học biểu diễn ngữ nghĩa sâu mà không cần nhãn.
Công thức cốt lõi— self-attention trong một lớp encoder:
là các ma trận query/key/value, là chiều của key. BERT áp dụng attention đầy đủ (không có causal mask), nên mỗi token thấy được mọi token khác trong câu.
Hàm mất mát MLM: dự đoán các token bị che dựa trên phần còn lại :
Các bước của quá trình tiền huấn luyện:
Bước hiện đang được minh hoạ: thay token theo tỉ lệ 80/10/10. Tỉ lệ này giúp mô hình không "lười" chỉ xử lý [MASK]; nó phải luôn sẵn sàng cập nhật biểu diễn cho mọi token.
# Cài: pip install transformers torch
from transformers import AutoTokenizer, AutoModelForMaskedLM
import torch
# Tải mô hình tiếng Việt tiền huấn luyện
name = "vinai/phobert-base"
tokenizer = AutoTokenizer.from_pretrained(name)
model = AutoModelForMaskedLM.from_pretrained(name)
# Che một từ trong câu để BERT đoán lại
text = "Hà Nội là thủ đô của <mask>"
inputs = tokenizer(text, return_tensors="pt")
# Tìm vị trí của token [MASK]
mask_idx = (inputs.input_ids == tokenizer.mask_token_id).nonzero(as_tuple=True)[1]
# Chạy forward pass (không tính gradient)
with torch.no_grad():
logits = model(**inputs).logits
# Lấy top-5 token dự đoán ở vị trí mask
top5 = logits[0, mask_idx].topk(5, dim=-1).indices[0]
for tid in top5:
print(tokenizer.decode([tid]).strip())
# Kỳ vọng: Việt_Nam, Đông_Dương, Đông_Á, ...
from transformers import (
AutoTokenizer,
AutoModelForSequenceClassification,
Trainer,
TrainingArguments,
)
from datasets import load_dataset
# Dữ liệu review phim tiếng Việt (vd uit-vsfc, vlsp)
ds = load_dataset("uit-nlp/vietnamese_students_feedback")
# Khởi tạo tokenizer và mô hình, num_labels=3 (neg/neu/pos)
tok = AutoTokenizer.from_pretrained("vinai/phobert-base")
model = AutoModelForSequenceClassification.from_pretrained(
"vinai/phobert-base", num_labels=3
)
# Hàm tiền xử lý: tokenize + padding
def preprocess(batch):
return tok(batch["sentence"], truncation=True, padding="max_length", max_length=128)
ds = ds.map(preprocess, batched=True)
ds = ds.rename_column("sentiment", "labels")
# Cấu hình huấn luyện (lr nhỏ, ít epoch — đặc trưng fine-tune)
args = TrainingArguments(
output_dir="./out",
num_train_epochs=3,
per_device_train_batch_size=16,
learning_rate=2e-5,
weight_decay=0.01,
evaluation_strategy="epoch",
)
trainer = Trainer(model=model, args=args, train_dataset=ds["train"], eval_dataset=ds["validation"])
trainer.train()
# Sau 3 epoch thường đạt ~88% accuracy trên test set
from transformers import AutoTokenizer, AutoModel
import torch
# Tải mô hình PhoBERT
tok = AutoTokenizer.from_pretrained("vinai/phobert-base")
model = AutoModel.from_pretrained("vinai/phobert-base")
model.eval()
def embed(sentences):
"""Trả về vector 768 chiều cho mỗi câu (mean-pooled)."""
enc = tok(sentences, padding=True, truncation=True, return_tensors="pt", max_length=128)
with torch.no_grad():
out = model(**enc).last_hidden_state # (B, T, 768)
# Mean pooling, bỏ qua padding
mask = enc.attention_mask.unsqueeze(-1) # (B, T, 1)
pooled = (out * mask).sum(1) / mask.sum(1)
return torch.nn.functional.normalize(pooled, dim=-1)
queries = ["sông nào chảy qua Huế?", "thủ đô của Việt Nam"]
docs = ["Sông Hương chảy qua thành phố Huế",
"Hà Nội là thủ đô của Việt Nam",
"Sài Gòn là thành phố lớn nhất"]
qv = embed(queries)
dv = embed(docs)
scores = qv @ dv.T # cosine similarity
print(scores.argmax(dim=1)) # tensor([0, 1]) — khớp đúng!
- Learning rate nhỏ: 1e-5 đến 5e-5.
- Warmup linear 10% tổng số bước, rồi giảm tuyến tính.
- Weight decay 0.01 cho các tham số không phải bias/LayerNorm.
- Chỉ 2–4 epoch là đủ cho dataset cỡ vài chục nghìn mẫu.
Ứng dụng thực tế
- Google Search dùng BERT để hiểu truy vấn tự nhiên từ 2019.
- Chatbot chăm sóc khách hàng: phân loại ý định, trích xuất thực thể.
- Tóm tắt bài báo: BERTSUM, PreSumm.
- Phát hiện tin giả, phân loại bình luận độc hại.
- Y tế: BioBERT, ClinicalBERT xử lý văn bản y khoa.
- Tài chính: FinBERT phân tích tin tức chứng khoán.
Bẫy thường gặp
- Dùng embedding của [CLS] mà không fine-tune sẽ cho kết quả kém.
- Quên truncate: câu quá 512 token bị mất thông tin.
- Huấn luyện tokenizer riêng thay vì dùng tokenizer đi kèm mô hình.
- Không chuẩn hoá văn bản (Unicode NFC, lowercase) trước khi đưa vào.
- Fine-tune trên dữ liệu domain khác xa pre-training → dùng domain-specific BERT.
So sánh với lựa chọn khác
- vs GPT: BERT giỏi hiểu (classification, extraction), GPT giỏi sinh (generation). Dùng BERT khi cần phân loại/trích xuất, GPT khi cần viết.
- vs T5: T5 là encoder-decoder, linh hoạt hơn cho mọi tác vụ (text-to-text) nhưng nặng hơn.
- vs Sentence-BERT: SBERT tinh chỉnh BERT cho embedding câu, cho cosine similarity tốt hơn. Nên dùng SBERT khi cần semantic search.
- vs LLM hiện đại: LLM (Llama, Qwen) có zero-shot mạnh hơn nhưng chi phí cao. BERT fine-tuned vẫn cạnh tranh về tốc độ/chi phí cho task cụ thể.
Năm 2026, khi các LLM hàng trăm tỷ tham số đã trở nên phổ biến, BERT tưởng như đã lỗi thời. Nhưng trên thực tế, BERT và các biến thể encoder-only vẫn được triển khai rộng rãi trong các hệ thống sản phẩm. Lý do then chốt: BERT-base chỉ cần khoảng 400MB bộ nhớ, có thể chạy inference dưới 10ms trên CPU, và khi được fine-tune cho tác vụ cụ thể (phân loại ý định chatbot, phát hiện spam, kiểm duyệt nội dung) nó thường đạt độ chính xác tương đương hoặc cao hơn LLM với chi phí chỉ bằng 1/100. Trong bài toán retrieval (RAG), các encoder nhỏ như BGE, E5, GTE — đều là hậu duệ kiến trúc BERT — là xương sống của pipeline tìm kiếm ngữ nghĩa.
Nếu bạn dùng mBERT (multilingual BERT) cho tiếng Việt, hãy cẩn thận: mBERT học từ 104 ngôn ngữ nên vốn từ vựng tiếng Việt bị chia nhỏ thành nhiều subword, dễ làm mất thông tin hình vị. PhoBERT dùng RDRSegmenter để tách từ trước khi tokenize, giữ được ngữ nghĩa cấp độ từ tiếng Việt (vốn là ngôn ngữ đơn tiết phân tách bằng dấu cách). Hầu hết benchmark tiếng Việt (VLSP, UIT-VSFC) đều cho thấy PhoBERT vượt mBERT 3–7 điểm F1.
- BERT là Transformer Encoder đọc hai chiều, tiền huấn luyện bằng MLM + NSP trên hàng tỉ câu.
- [CLS] tổng hợp biểu diễn câu cho tác vụ phân loại; [SEP] ngăn cách câu A và câu B.
- Fine-tune = giữ trọng số pre-train, thêm lớp đầu ra nhỏ, huấn luyện vài epoch với lr ~2e-5.
- BERT-base (110M, 12 lớp) đủ cho đa số tác vụ; BERT-large mạnh hơn nhưng cần nhiều dữ liệu.
- Với tiếng Việt, PhoBERT/viBERT hiệu quả hơn mBERT đa ngôn ngữ.
- Điểm yếu: giới hạn 512 token, không giỏi sinh văn bản, cần fine-tune thay vì prompt.
Kiểm tra hiểu biết
BERT được tiền huấn luyện bằng hai tác vụ. Tác vụ nào giúp BERT hiểu nghĩa từ trong ngữ cảnh?