Published on

Day 16: Mini-project - Fine-tune PhoBERT/BERT Classifier

Authors

Mục tiêu

Sau bài này, bạn cần làm được các việc sau:

  • Frame bài toán sentiment classification tiếng Việt theo hướng production.
  • Xây baseline TF-IDF + Logistic Regression để có mốc so sánh rẻ, nhanh và dễ debug.
  • Fine-tune PhoBERT hoặc BERT multilingual bằng HuggingFace Trainer.
  • Evaluate model bằng accuracy, macro F1, per-class precision/recall/F1, confusion matrix và error analysis.
  • Export artifact đầy đủ: model, tokenizer, label mapping, metric, manifest và model card nội bộ.
  • Serve model bằng FastAPI với request validation, health endpoint, inference latency, confidence và schema ổn định.
  • Ra quyết định production dựa trên chất lượng, latency, cost, drift, rollback và operational risk.

TL;DR

Day 16 là mini-project tổng hợp Phase 2: Deep Learning, NLP và Transformer. Cách làm đúng không phải nhảy thẳng vào PhoBERT, mà là bắt đầu bằng baseline đơn giản, đo metric, hiểu lỗi, rồi mới fine-tune Transformer trên cùng split dữ liệu.

Nếu PhoBERT/BERT chỉ tốt hơn baseline rất ít nhưng latency, memory và vận hành đắt hơn nhiều, baseline có thể là production v1 tốt hơn. Nếu domain có nhiều câu dài, slang, sắc thái tiếng Việt và baseline fail ở negative/neutral class, Transformer đáng để dùng hơn.

1. Day 16 Nằm Ở Đâu Trong Lộ Trình

Trong Phase 2, bạn đã đi qua:

Day 9-11: Neural Network, PyTorch, training loop
Day 12: NLP và tokenizer
Day 13-14: Attention và Transformer
Day 15: Hugging Face ecosystem
Day 16: Mini-project classifier có thể deploy

Day 16 chuyển từ "biết API" sang "ship được một AI service nhỏ có kiểm soát". Với background Senior Software Engineer, output quan trọng không chỉ là notebook train model, mà là một pipeline có data contract, evaluation, artifact, API, monitoring plan và rollback path.

2. Problem Framing

Bài toán:

Input: review hoặc customer message tiếng Việt
Output: sentiment label = negative | neutral | positive

Output production nên là JSON ổn định, không chỉ một string:

{
  "label": "positive",
  "confidence": 0.94,
  "probabilities": {
    "negative": 0.02,
    "neutral": 0.04,
    "positive": 0.94
  },
  "model_version": "sentiment-phobert-v1",
  "input_tokens": 12,
  "latency_ms": 42.7
}

Trước khi train, cần chốt các câu hỏi sau:

Câu hỏiVì sao quan trọng
Có mấy class?Binary dễ hơn, 3-class hữu ích hơn nhưng neutral thường mơ hồ
neutral nghĩa là gì?Nếu guideline không rõ, annotator label không nhất quán
Input tối đa bao nhiêu ký tự/token?Ảnh hưởng truncation, latency và memory
Text có PII không?Quyết định logging, retention và masking
Prediction dùng để làm gì?Route ticket, dashboard, alert hay auto-reply có risk khác nhau
Class nào quan trọng nhất?Negative review thường cần recall cao hơn

Map về Senior SE: label schema giống API contract. Nếu contract mơ hồ, downstream system vẫn chạy nhưng business behavior sai.

3. Dataset Và Label Design

Schema tối thiểu:

text,label
"sản phẩm tốt, giao hàng nhanh",positive
"đóng gói kém, hàng bị lỗi",negative
"tạm được, chưa có gì đặc biệt",neutral

Nguồn dữ liệu có thể dùng:

  • Dataset nội bộ từ customer support, review, survey hoặc ticket.
  • Public Vietnamese sentiment dataset như VLSP/AIVIVN/Shopee review nếu license phù hợp.
  • Synthetic fallback chỉ để kiểm tra pipeline, không dùng làm bằng chứng chất lượng production.

Label guideline nên đủ cụ thể:

LabelKhi dùngVí dụ
negativeNgười dùng phàn nàn, thất vọng, yêu cầu đổi trả, lỗi sản phẩm/dịch vụ"hàng lỗi, shop không hỗ trợ"
neutralNhận xét mô tả, chưa đánh giá, vừa có điểm tốt vừa có điểm xấu nhẹ"mới nhận hàng, chưa dùng"
positiveNgười dùng hài lòng, khen chất lượng, dịch vụ, tốc độ"sản phẩm tốt, giao nhanh"

Các lỗi data thường gặp:

  • Duplicate gần giống nhau nằm cả train và test, làm metric ảo.
  • Text rỗng, quá ngắn hoặc chỉ có emoji.
  • Label bị lệch class, ví dụ 85% positive.
  • Label neutral bị dùng như "không biết label gì".
  • Review chứa PII, số điện thoại, địa chỉ hoặc mã đơn hàng.
  • Dữ liệu test không cùng distribution với production traffic.

4. Vì Sao Phải Có Baseline

Baseline TF-IDF + Logistic Regression là bắt buộc, không phải bước phụ.

Baseline giúp:

  • Train nhanh trên CPU.
  • Dễ phát hiện label noise và data leakage.
  • Có latency thấp, thường đủ cho API traffic nhỏ/vừa.
  • Dễ giải thích token/ngram nào đang ảnh hưởng prediction.
  • Là regression guardrail khi Transformer được fine-tune sai.

Pipeline baseline:

raw text
  -> normalize text
  -> TF-IDF word/char n-gram
  -> Logistic Regression
  -> label probabilities

Với tiếng Việt, baseline nên thử cả word n-gram và char n-gram. Char n-gram thường robust hơn với teencode, typo, thiếu dấu hoặc tokenization không chuẩn.

Ví dụ cấu hình hợp lý:

Pipeline(
    steps=[
        ("features", FeatureUnion([
            ("word_tfidf", TfidfVectorizer(ngram_range=(1, 2), min_df=2, max_features=50000)),
            ("char_tfidf", TfidfVectorizer(analyzer="char_wb", ngram_range=(3, 5), min_df=2, max_features=50000)),
        ])),
        ("clf", LogisticRegression(max_iter=1000, class_weight="balanced")),
    ]
)

Trade-off: baseline không hiểu semantic sâu như Transformer. Câu "giao hàng nhanh nhưng hàng hỏng" có thể bị kéo về positive nếu token positive quá mạnh. Nhưng nếu business chỉ cần dashboard aggregate và dữ liệu đơn giản, baseline có thể đủ.

5. Fine-tune PhoBERT/BERT

Transformer classifier flow:

text
  -> tokenizer
  -> input_ids + attention_mask
  -> BERT/PhoBERT encoder
  -> classification head
  -> logits
  -> softmax
  -> label + confidence

Model candidates:

ModelNên dùng khiTrade-off
vinai/phobert-baseTask tiếng Việt, cần quality tốt, có kiểm soát preprocessingCó thể cần chú ý word segmentation/preprocessing nhất quán
bert-base-multilingual-casedCần baseline Transformer multilingual, không muốn phụ thuộc model riêng tiếng ViệtQuality tiếng Việt có thể kém PhoBERT
distilbert-base-multilingual-casedCPU hoặc demo nhanh, latency thấp hơn BERT baseQuality thường thấp hơn model lớn

Hyperparameters v1:

HyperparameterGiá trị khởi đầuGhi chú
max_length128Review/ticket ngắn thường đủ; benchmark trước khi tăng
learning_rate2e-5Default an toàn cho full fine-tune BERT-like
epochs2-4Dataset nhỏ dễ overfit
batch_size8-16Tùy VRAM/CPU RAM
weight_decay0.01Regularization nhẹ
metric_for_best_modelf1_macroTốt hơn accuracy khi class imbalance

Điểm cần nghiêm túc: preprocessing train và serving phải giống nhau. Nếu train dùng text đã word-segmented nhưng serve nhận raw text, model có thể giảm chất lượng mà API vẫn trả response hợp lệ.

6. Evaluation

Không chỉ report accuracy. Cần tối thiểu:

  • Accuracy.
  • Macro F1.
  • Per-class precision/recall/F1.
  • Confusion matrix.
  • Error samples: false negative cho negative, false positive cho negative, lỗi neutral.
  • Metric theo input length, source/channel hoặc product category nếu có metadata.

Vì sao macro F1 quan trọng:

Dataset: 80% positive, 10% neutral, 10% negative
Model luôn đoán positive -> accuracy 80%
Nhưng model vô dụng cho use case bắt lỗi negative review.

Macro F1 tính trung bình F1 của từng class, nên phạt model bỏ quên class nhỏ.

Confusion matrix cần đọc như sau:

LỗiÝ nghĩa business
negative -> positiveRủi ro cao, bỏ sót khách hàng bất mãn
positive -> negativeTạo false alarm cho support
neutral -> positive/negativeCó thể chấp nhận nếu action downstream không quá nhạy

7. Export Artifact

Artifact không chỉ là weights. Một bundle tốt nên có:

artifacts/sentiment_classifier/
  baseline.joblib
  baseline_metrics.json
  best_model/
    config.json
    model.safetensors
    tokenizer.json hoặc vocab files
  transformer_metrics.json
  comparison.json
  labels.json
  manifest.json
  model_card.md
  errors.csv

manifest.json nên ghi:

  • model_id và revision nếu dùng model từ Hub.
  • labels, label2id, id2label.
  • max_length, seed, split ratio.
  • Package/runtime version chính.
  • Metric trên validation/test.
  • Training timestamp.
  • Git commit nếu project có Git.

Production bug phổ biến: model artifact mới nhưng label mapping cũ. Ví dụ model output index 0negative, API lại map 0 thành positive. Vì vậy label mapping phải đi cùng artifact.

8. FastAPI Inference

Serving flow:

FastAPI startup
  -> load model/tokenizer một lần
  -> warmup inference
request
  -> validate text length
  -> normalize text giống training
  -> tokenize with truncation
  -> model inference under torch.inference_mode()
  -> softmax
  -> response JSON
  -> log latency/model_version/input_tokens/confidence

Không load model ở mỗi request. Model loading có thể mất vài giây và tốn RAM/VRAM. Theo pattern hiện đại của FastAPI, tài nguyên lớn như ML model nên được load qua lifespan khi app startup, rồi dùng lại cho các request.

API tối thiểu:

  • GET /health: process sống và model đã load.
  • GET /ready: model/tokenizer sẵn sàng inference.
  • POST /predict: nhận một text.
  • POST /predict-batch: nhận nhiều text nếu traffic cần throughput.

Response nên có model_version, latency_ms, input_tokensprobabilities. Không nên log raw text mặc định nếu có khả năng chứa PII.

9. Trade-offs

Lựa chọnNên dùng khiKhông nên dùng khiProduction note
TF-IDF + Logistic RegressionCần baseline nhanh, CPU, latency thấp, explainableCâu nhiều ngữ cảnh, sarcasm, semantic phức tạpCó thể là v1 nếu đạt business metric
PhoBERTTask tiếng Việt domain-specific, cần quality caoKhông kiểm soát được preprocessing/latencyBenchmark p95/p99 và memory
BERT multilingualMulti-language hoặc setup đơn giảnChỉ tiếng Việt và cần quality cao nhấtDễ vận hành hơn nhưng có thể kém PhoBERT
DistilBERT multilingualCPU, demo, latency nhạyMetric không đạtCó thể là middle ground
3-class sentimentNeutral có ý nghĩa businessAnnotator không phân biệt được neutralCần guideline tốt
Binary sentimentChỉ cần good/bad routingNeutral quan trọng cho dashboardĐơn giản hơn, metric dễ hơn
Full fine-tuneDataset đủ lớn, GPU có sẵnData ít, overfit mạnhCần early stopping/eval
Freeze encoderData ít, train nhanhCần quality tối đaÍt update weights hơn
ONNX/quantizationCPU latency/cost quan trọngChưa đo quality regressionLà bước tối ưu sau baseline correctness

10. Performance Considerations

Các con số cần benchmark trên hardware thật:

  • Baseline TF-IDF thường sub-ms đến vài ms/request trên CPU.
  • BERT/PhoBERT base trên CPU có thể 50-300 ms/request tùy CPU, max_length và batch size.
  • GPU giảm latency khi batch/throughput đủ cao, nhưng cold start và cost tăng.
  • max_length=128 thường đủ cho review ngắn; 512 làm attention cost tăng mạnh.
  • Batch inference tăng throughput nhưng thêm queueing latency cho realtime API.
  • Quantization, ONNX Runtime hoặc Torch compile có thể giảm CPU latency, nhưng cần đo lại metric.

Benchmark nên report:

MetricVì sao cần
p50/p95/p99 latencySLA không dựa vào average
throughput request/sCapacity planning
memory/RAM/VRAMSizing container
cold start timeDeploy/scale behavior
max input acceptedBảo vệ service khỏi request quá dài

11. Production Concerns

Checklist production:

  • Data/license: dataset và base model được phép dùng cho mục đích của bạn.
  • Reproducibility: seed, split, model revision và package version được lưu.
  • Train-serving skew: preprocessing/tokenizer/label mapping giống nhau.
  • Observability: latency, error rate, confidence distribution, label distribution.
  • Drift: slang, campaign, sản phẩm mới hoặc channel mới làm distribution đổi.
  • Privacy: không log raw text nếu chứa PII; có retention policy.
  • Security: validate input length, rate limit, timeout, không bật trust_remote_code=True nếu chưa audit.
  • Rollback: giữ baseline artifact và previous Transformer artifact.
  • Human review: với action high impact, prediction chỉ nên hỗ trợ quyết định.
  • Re-training loop: thu thập feedback, review error samples, version dataset.

12. Dùng Được Trong Production Không?

Có, sentiment classifier kiểu này dùng được trong production nếu thỏa các điều kiện sau:

  1. Dataset đại diện domain thật, đủ size và có label guideline rõ.
  2. Có baseline và Transformer được so sánh trên cùng train/validation/test split.
  3. Test set không bị leakage và có metric theo từng class, đặc biệt là negative.
  4. Artifact lưu đầy đủ model, tokenizer, label mapping, preprocessing config, metric và manifest.
  5. API load model một lần, validate input, có timeout, health/readiness và logging không lộ PII.
  6. Đã benchmark p95/p99 latency, memory và throughput trên hardware deploy thật.
  7. Có monitoring drift, confidence, label distribution, error rate và rollback plan.
  8. License của model/dataset phù hợp với môi trường sử dụng.

Không nên đưa vào production nếu chỉ train bằng synthetic fallback, chỉ có accuracy, không có confusion matrix, không kiểm soát label mapping, chưa benchmark latency hoặc chưa rõ data privacy.

13. Best Solution Theo Context

ContextGợi ý
Cần ship dashboard sentiment nội bộ trong 1 tuầnBaseline TF-IDF + Logistic Regression, monitor lỗi, giữ API schema mở để thay model
Cần route negative ticket realtime với SLA thấpBaseline hoặc DistilBERT, threshold cẩn thận, human-in-the-loop
Cần quality tiếng Việt cao cho review đa dạngFine-tune PhoBERT, benchmark latency, cân nhắc GPU/ONNX
Data ít hơn vài nghìn sampleBaseline trước, active learning, freeze encoder hoặc dùng pretrained multilingual nhỏ
Có nhiều ngôn ngữBERT/DistilBERT multilingual hoặc model multilingual chuyên dụng
Có compliance nghiêm ngặtSelf-host, không log raw text, model/dataset license review, audit artifact

14. Kết Quả Cần Nộp

Sau khi hoàn thành bài này, mini-project nên có:

  • train_sentiment.py chạy được từ CSV hoặc synthetic fallback.
  • serve_sentiment.py expose FastAPI inference.
  • artifacts/sentiment_classifier/comparison.json.
  • artifacts/sentiment_classifier/labels.json.
  • artifacts/sentiment_classifier/model_card.md.
  • Một đoạn kết luận: chọn baseline hay Transformer cho production v1, vì sao, còn thiếu điều kiện gì.

15. Tự Kiểm Tra

  1. Vì sao baseline là bắt buộc trước Transformer?
  2. Khi nào macro F1 quan trọng hơn accuracy?
  3. Train-serving skew trong tokenizer/preprocessing gây lỗi gì?
  4. Vì sao label mapping phải nằm trong artifact?
  5. Khi nào PhoBERT đáng dùng hơn BERT multilingual?
  6. API production cần log những metric nào?
  7. Dùng model này trong production được không? Điều kiện còn thiếu là gì?

Tài liệu

1. Project Structure Đề Xuất

sentiment-classifier/
  data/
    reviews.csv
  src/
    train_sentiment.py
    serve_sentiment.py
  artifacts/
    sentiment_classifier/
      baseline.joblib
      baseline_metrics.json
      best_model/
      transformer_metrics.json
      comparison.json
      labels.json
      manifest.json
      model_card.md
      errors.csv
  tests/
    test_preprocessing.py
    test_api_contract.py

Trong repo học này, script mẫu nằm trực tiếp trong folder Day 16 để bạn chạy nhanh.

2. Data Contract

CSV input tối thiểu:

text,label
"sản phẩm tốt, giao hàng nhanh",positive
"đóng gói kém, hàng bị lỗi",negative
"tạm được, chưa có gì đặc biệt",neutral

Yêu cầu:

  • Cột text là string, không rỗng sau khi trim.
  • Cột label chỉ thuộc negative, neutral, positive.
  • Không chứa duplicate exact hoặc near-duplicate giữa train/validation/test.
  • Nếu text có PII, cần masking hoặc policy không log raw text.
  • Nếu có metadata như channel/product/date, nên giữ để error analysis.

3. Label Guideline Template

LabelĐịnh nghĩaNên labelKhông nên label
negativeNgười dùng thể hiện bất mãn hoặc vấn đề cần xử lýLỗi, chậm, hỏng, thất vọng, yêu cầu hoàn tiềnGóp ý nhẹ không có cảm xúc xấu rõ
neutralNhận xét mô tả, chưa đánh giá hoặc cảm xúc cân bằng"mới nhận chưa dùng", "bình thường"Review vừa có lỗi nghiêm trọng vừa có lời khen
positiveNgười dùng hài lòng hoặc khen rõTốt, nhanh, đáng tiền, sẽ mua lạiKhen mỉa mai hoặc khen một phần nhưng phàn nàn chính

Quy tắc thực tế: nếu action downstream ưu tiên cứu negative review, hãy label câu có lỗi nghiêm trọng là negative dù có khen một phần.

4. Split Strategy

Mặc định:

  • Train: 60%.
  • Validation: 20%.
  • Test: 20%.
  • Stratify theo label.
  • Seed cố định, ví dụ 42.

Với production data có thời gian:

  • Dùng time-based split để mô phỏng tương lai.
  • Ví dụ train trên tháng 1-3, validation tháng 4, test tháng 5.
  • Tránh random split nếu duplicate/campaign làm leakage.

5. Metrics Template

{
  "model_name": "phobert-base-sentiment-v1",
  "dataset_version": "reviews-2026-05-10",
  "split": "test",
  "accuracy": 0.91,
  "f1_macro": 0.88,
  "per_class": {
    "negative": {"precision": 0.86, "recall": 0.82, "f1": 0.84},
    "neutral": {"precision": 0.80, "recall": 0.76, "f1": 0.78},
    "positive": {"precision": 0.95, "recall": 0.97, "f1": 0.96}
  },
  "confusion_matrix_labels": ["negative", "neutral", "positive"],
  "confusion_matrix": [[82, 12, 6], [10, 76, 14], [3, 6, 191]]
}

Metric acceptance nên gắn với business:

Use caseMetric ưu tiên
Alert negative reviewRecall/F1 của negative, false negative rate
Dashboard aggregateMacro F1 và calibration tương đối
Auto-route supportPrecision và recall theo class route
Auto action high impactKhông nên fully automated nếu chưa có human review

6. Error Analysis Checklist

Lấy ít nhất 20-50 lỗi từ test set và phân loại:

  • Label noise: ground truth có thể sai.
  • Ambiguous neutral: câu không rõ positive/negative.
  • Sarcasm: "giao nhanh ghê, chờ có 2 tuần".
  • Mixed sentiment: khen giao hàng nhưng chê sản phẩm.
  • Domain slang/teencode: "ổn áp", "xịn xò", "toang".
  • Missing context: "như lần trước" cần conversation history.
  • Long text bị truncation.
  • PII/order code làm nhiễu token.

Sau error analysis, quyết định:

  • Sửa guideline label.
  • Thêm data cho class yếu.
  • Thêm preprocessing.
  • Điều chỉnh threshold.
  • Đổi model hoặc tăng max_length.

7. Baseline Checklist

  • Dùng Pipeline của scikit-learn để tránh train-serving skew.
  • Thử word n-gram và char n-gram.
  • Bật class_weight="balanced" nếu class imbalance.
  • Save bằng joblib.
  • Export classification_report, confusion_matrix, errors.csv.
  • Không tune trên test set.

Baseline production được nếu:

  • Đạt business metric.
  • Có latency tốt hơn Transformer rõ rệt.
  • Dataset/domain không đòi hỏi semantic quá phức tạp.
  • Có monitoring và rollback như model khác.

8. Transformer Checklist

  • Pin MODEL_ID và nếu dùng Hub production thì pin revision/commit SHA.
  • Lưu tokenizer cùng model.
  • Lưu label2id/id2label trong config và labels.json.
  • Dùng DataCollatorWithPadding để padding động theo batch.
  • Dùng f1_macro để chọn best checkpoint nếu class imbalance.
  • Dùng validation để chọn model, test chỉ để final report.
  • Benchmark max_length=64/128/256 trước khi chọn.
  • Kiểm tra preprocessing PhoBERT nhất quán giữa train và serve.

Theo Context7/HuggingFace docs, tokenizer nên dùng truncation=True, max_length rõ ràng, return_tensors="pt" khi inference PyTorch. Với FastAPI, pattern lifespan phù hợp để load ML model một lần trước khi nhận request.

9. Artifact Manifest Template

{
  "artifact_name": "vietnamese-sentiment-classifier",
  "version": "sentiment-v1",
  "created_at": "2026-05-10T00:00:00Z",
  "task": "text-classification",
  "labels": ["negative", "neutral", "positive"],
  "model_id": "vinai/phobert-base",
  "max_length": 128,
  "seed": 42,
  "data": {
    "source": "internal_reviews",
    "dataset_version": "reviews-2026-05-10",
    "train_size": 6000,
    "validation_size": 2000,
    "test_size": 2000
  },
  "metrics": {
    "baseline_f1_macro": 0.82,
    "transformer_f1_macro": 0.88
  },
  "runtime": {
    "python": "3.12",
    "torch": "pinned",
    "transformers": "pinned",
    "scikit_learn": "pinned"
  }
}

10. FastAPI API Contract

Request:

{
  "text": "sản phẩm tốt, giao hàng nhanh"
}

Response:

{
  "label": "positive",
  "confidence": 0.94,
  "probabilities": {
    "negative": 0.02,
    "neutral": 0.04,
    "positive": 0.94
  },
  "input_tokens": 12,
  "latency_ms": 42.7,
  "model_version": "sentiment-v1"
}

Validation:

  • text min length: 1.
  • text max length: ví dụ 2000 ký tự.
  • Batch size max: ví dụ 32.
  • Timeout inference: theo SLA.

11. Monitoring Dashboard

Tối thiểu cần:

MetricAlert gợi ý
Request rateTraffic bất thường
Error rate5xx tăng
p95/p99 latencyVượt SLA
Input length distributionRequest quá dài tăng
Predicted label distributionDrift hoặc bug label mapping
Confidence distributionModel không chắc chắn hơn bình thường
Negative rate theo channel/productVấn đề business thật hoặc data drift
Model versionĐảm bảo deploy đúng artifact

Không log raw text mặc định. Nếu cần debug, dùng sampling có masking và retention ngắn.

12. Production Decision Template

# Production Decision

## Candidate
- Baseline:
- Transformer:

## Metrics
- Baseline macro F1:
- Transformer macro F1:
- Negative recall:
- p95 latency:
- Memory:

## Decision
- Chọn:
- Lý do:

## Conditions before production
- License checked:
- Dataset representative:
- PII policy:
- Monitoring:
- Rollback:
- Human review:

## Risks
- Drift:
- Label ambiguity:
- Latency/cost:
- Bias:

13. Dùng Được Trong Production Không?

Có, nhưng chỉ khi model được xem như một service có lifecycle đầy đủ:

  • Data có nguồn rõ và đại diện.
  • Evaluation đủ sâu, không chỉ notebook accuracy.
  • Artifact versioned và reproducible.
  • API có contract ổn định.
  • Monitoring/rollback có sẵn.
  • Privacy/license được xử lý.

Nếu thiếu các điều kiện này, chỉ nên gọi là prototype hoặc internal demo.

14. Context7 Docs Đã Tham Chiếu Khi Viết Bài

  • /websites/huggingface_co_transformers_main: tokenizer parameters, AutoModelForSequenceClassification, Trainer, TrainingArguments, dynamic padding và model save/load pattern.
  • /fastapi/fastapi: lifespan để load ML model một lần, Pydantic request validation, endpoint pattern.

Bài tập

Mục tiêu thực hành

Bạn sẽ build một classifier sentiment tiếng Việt end-to-end:

  1. Chuẩn bị dataset CSV.
  2. Train baseline TF-IDF + Logistic Regression.
  3. Fine-tune Transformer bằng HuggingFace Trainer.
  4. So sánh metric và phân tích lỗi.
  5. Export artifact.
  6. Serve model bằng FastAPI.
  7. Viết production decision: dùng được production chưa, còn thiếu gì.

Yêu cầu môi trường

Khuyến nghị dùng virtual environment riêng.

pip install -U pandas numpy scikit-learn joblib datasets transformers accelerate torch fastapi uvicorn pydantic

Nếu không có GPU, hãy dùng model nhỏ:

export MODEL_ID=distilbert-base-multilingual-cased
export EPOCHS=1
export BATCH_SIZE=4

Nếu có GPU/Colab và muốn thử PhoBERT:

export MODEL_ID=vinai/phobert-base
export EPOCHS=3
export BATCH_SIZE=8

Exercise 1: Tạo Dataset

Tạo file data/reviews.csv:

text,label
"sản phẩm rất tốt, giao hàng nhanh",positive
"đóng gói cẩn thận, hàng đúng mô tả",positive
"chất lượng tốt, sẽ mua lại",positive
"shop hỗ trợ nhanh và lịch sự",positive
"hàng bị lỗi, không đúng mô tả",negative
"đóng gói tệ, sản phẩm bị vỡ",negative
"giao hàng quá chậm",negative
"chất lượng kém, rất thất vọng",negative
"sản phẩm tạm được",neutral
"bình thường, không có gì đặc biệt",neutral
"giao hàng đúng hẹn",neutral
"mới dùng nên chưa đánh giá",neutral

Trong thực tế, dataset nên có ít nhất vài nghìn sample và được review label guideline. File nhỏ này chỉ để kiểm tra pipeline.

Exercise 2: Chạy Training Script

Từ folder Day 16:

cd lessions/day-16-fine-tune-phobert-bert-classifier
DATA_PATH=data/reviews.csv OUT_DIR=artifacts/sentiment_classifier python train_sentiment.py

Nếu chưa có data/reviews.csv, script sẽ dùng synthetic fallback có dấu để bạn vẫn chạy được.

Kết quả mong đợi:

artifacts/sentiment_classifier/
  baseline.joblib
  baseline_metrics.json
  best_model/
  transformer_metrics.json
  comparison.json
  labels.json
  manifest.json
  model_card.md
  errors.csv

Ghi lại:

MetricBaselineTransformer
Accuracy
Macro F1
Negative recall
p95 latencychưa đochưa đo

Exercise 3: Đọc Confusion Matrix

Mở comparison.json và trả lời:

  • Model nào có macro F1 tốt hơn?
  • Model nào bỏ sót nhiều negative hơn?
  • Nếu dùng để route ticket khẩn cấp, lỗi nào nguy hiểm nhất?
  • Nếu Transformer tốt hơn 1-2 điểm F1 nhưng latency cao hơn 50 lần, bạn chọn gì cho v1?

Exercise 4: Error Analysis

Mở errors.csv, chọn ít nhất 10 lỗi và phân loại:

TextTruePredNhóm lỗiCách sửa
label noise / ambiguous / slang / truncation / mixed sentiment

Kết luận cần có:

  • Có cần sửa label guideline không?
  • Có cần thêm data cho class nào không?
  • Có cần tăng max_length không?
  • Có cần chuyển từ baseline sang Transformer không?

Exercise 5: Serve FastAPI

Sau khi train xong:

MODEL_DIR=artifacts/sentiment_classifier/best_model \
LABEL_PATH=artifacts/sentiment_classifier/labels.json \
MODEL_VERSION=sentiment-v1 \
uvicorn serve_sentiment:app --host 0.0.0.0 --port 8000

Health check:

curl http://localhost:8000/health
curl http://localhost:8000/ready

Predict:

curl -X POST http://localhost:8000/predict \
  -H "Content-Type: application/json" \
  -d '{"text":"sản phẩm tốt, giao hàng nhanh"}'

Batch predict:

curl -X POST http://localhost:8000/predict-batch \
  -H "Content-Type: application/json" \
  -d '{"texts":["sản phẩm tốt","giao hàng quá chậm","mới dùng nên chưa đánh giá"]}'

Ghi lại:

  • latency_ms.
  • input_tokens.
  • confidence.
  • Output schema có đủ cho downstream service chưa?

Exercise 6: Benchmark Cấu Hình

Chạy lại với các cấu hình:

RunMODEL_IDMAX_LENGTHBATCH_SIZEMacro F1Ghi chú latency
1distilbert-base-multilingual-cased644
2distilbert-base-multilingual-cased1284
3bert-base-multilingual-cased1288
4vinai/phobert-base1288

Kết luận:

  • max_length tăng có cải thiện metric không?
  • Model lớn có đáng với latency/cost không?
  • Với hardware của bạn, model nào phù hợp production v1?

Exercise 7: Production Decision

Viết file ngắn production_decision.md theo template:

# Production Decision

## Use case

## Dataset

## Metrics
- Baseline:
- Transformer:

## Latency and cost

## Decision
Chọn baseline hoặc Transformer.

## Dùng được trong production không?
Có/không.

## Điều kiện bắt buộc trước production
- Dataset:
- License:
- Monitoring:
- PII:
- Rollback:
- Human review:

Yêu cầu câu trả lời không được chung chung. Ví dụ chưa đạt:

Có thể dùng production nếu cải thiện thêm.

Ví dụ đạt:

Chưa dùng production. Dataset hiện chỉ là synthetic fallback 36 dòng, không đại diện traffic thật. Có thể dùng làm demo nội bộ. Để production cần ít nhất 3.000 review đã label theo guideline, test set không leakage, negative recall >= 0.85, p95 latency < 100 ms trên CPU target, không log raw PII và có rollback sang baseline artifact.

Checklist Hoàn Thành

  • Dataset có schema text,label.
  • Baseline đã train và lưu artifact.
  • Transformer đã fine-tune và lưu artifact.
  • comparison.json.
  • Có confusion matrix và error samples.
  • FastAPI chạy được /health, /ready, /predict.
  • Có production decision rõ ràng.
  • Trả lời được: dùng production được không, cần điều kiện gì.