Danh sách bài viết

Bài 42: Model Registry — versioning model artifact

Hiểu vấn đề không có Model Registry, 3 yêu cầu cốt lõi (versioning, stage, metadata), và hands-on với MLflow Model Registry 2.x dùng aliases thay vì legacy stages. Bao gồm promotion workflow, load by alias, MLflow serve, Hugging Face Hub, và W&B Model Registry.

27/05/2026
1 lượt xem
1

Mục Tiêu Bài Học

Sau bài này bạn sẽ:

  • ✅ Hiểu tại sao cần Model Registry riêng biệt ngoài experiment tracking
  • ✅ Đăng ký model vào MLflow Model Registry và quản lý version
  • ✅ Dùng aliases (champion, challenger, staging) thay vì legacy stages
  • ✅ Load model từ registry theo alias — không cần thay đổi code khi đổi version
  • ✅ Biết khi nào dùng MLflow Registry, Hugging Face Hub, hay W&B Model Registry
  • ✅ Nắm promotion workflow từ dev đến production và rollback
2

Vấn Đề Không Có Registry

Bài 40 đã giải quyết vấn đề tracking — ghi lại ngữ cảnh mỗi lần train. Nhưng sau khi có hàng chục runs với params và metrics, câu hỏi tiếp theo xuất hiện:

  • "Model đang chạy production tốt nhất hiện tại ở đâu? Trên S3? Ổ cứng local của ai đó? Trong notebook?"
  • "Model A.B.C tốt hơn model X.Y.Z ở điểm nào cụ thể? Train trên data nào?"
  • "Cần rollback về model 2 tuần trước vì có regression — tìm artifact ở đâu?"
  • "Bao nhiêu version đang chạy đồng thời trên staging và production?"
  • "Dev team muốn test model mới mà không ảnh hưởng model production hiện tại."

Experiment tracking (bài 40–41) lưu artifact của mỗi run, nhưng không có khái niệm "đây là model chính thức cho production". Model Registry bổ sung lớp đó: một catalog trung tâm, mỗi entry có version tăng dần, stage rõ ràng, và metadata đủ để tái tạo hoặc rollback.

Hai khái niệm cần phân biệt:

  • Experiment run: một lần chạy train cụ thể, có run_id, params, metrics, artifact thô. Có thể có hàng trăm runs.
  • Registered model version: một artifact đã được chọn, gắn version số, và có lifecycle rõ ràng (dev → staging → prod). Chỉ có vài version active.
3

3 Yêu Cầu Của Model Registry

1. Versioning

Mỗi model có tên (ví dụ iris-classifier) và version tự tăng (v1, v2, v3, ...). Version không bao giờ bị ghi đè — nếu muốn cập nhật, tạo version mới. Điều này đảm bảo audit trail đầy đủ.

2. Stage Management

Model đi qua các giai đoạn rõ ràng: dev → staging → production. Bất kỳ lúc nào cũng biết version nào đang chạy ở đâu. Rollback = gán lại pointer về version cũ — không cần redeploy artifact mới.

3. Metadata và Lineage

Mỗi version lưu:

  • Code commit (git SHA): biết chính xác code nào tạo ra model này.
  • Dataset version: biết train trên data nào.
  • Hyperparameters đầy đủ.
  • Metrics trên test set.
  • Người tạo, timestamp.
  • Approval status (quan trọng trong ngành regulated như tài chính, y tế).

Lineage cho phép trả lời câu hỏi: "Model v3 được fine-tune từ checkpoint nào? Dataset nào? Bởi ai, lúc mấy giờ?"

4

3 Cách Implement Registry

a) Managed Tool

Tích hợp sẵn với tracking platform — ít setup nhất:

  • MLflow Model Registry: tích hợp với MLflow Tracking, open source, self-host hoặc Databricks managed.
  • W&B Model Registry: tích hợp với W&B Artifacts.
  • SageMaker Model Registry: AWS, tích hợp với SageMaker Pipelines.
  • Vertex AI Model Registry: GCP.
  • Hugging Face Hub: phổ biến cho transformer / open-source model.

b) Tự Build Trên Object Storage + Metadata DB

Khi không muốn phụ thuộc tool ngoài hoặc có yêu cầu bảo mật đặc thù:

  • Artifact file → S3/GCS với S3 Versioning bật.
  • Metadata → bảng Postgres riêng: model_name, version, stage, artifact_uri, run_id, git_sha, created_by.
  • Custom CLI hoặc web UI nhỏ để promote/rollback.

Cách này tốn công duy trì nhưng cho phép kiểm soát hoàn toàn.

c) Git LFS / DVC

Track model file trong git qua LFS (Large File Storage), git tag = version model. Phù hợp khi team nhỏ, model không quá lớn, muốn dùng git workflow quen thuộc. DVC mở rộng cách này với remote storage (S3/GCS) và pipeline tracking. Bài 43 sẽ đào sâu DVC.

5

MLflow Model Registry — Đăng Ký Model

MLflow Model Registry yêu cầu backend store là database (SQLite, PostgreSQL) — không hoạt động với file store thuần (./mlruns/). Nếu dùng local, cần khởi động server với SQLite trước:

mlflow server \
  --backend-store-uri sqlite:///mlflow.db \
  --artifacts-destination ./artifacts \
  --host 0.0.0.0 --port 5000
import mlflow
mlflow.set_tracking_uri("http://localhost:5000")

Cách 1: Register Sau Khi Train

import mlflow
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

mlflow.set_tracking_uri("http://localhost:5000")
mlflow.set_experiment("iris-classification")

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

with mlflow.start_run() as run:
    model = LogisticRegression(C=1.0, max_iter=1000)
    model.fit(X_train, y_train)

    acc = accuracy_score(y_test, model.predict(X_test))
    mlflow.log_param("C", 1.0)
    mlflow.log_metric("accuracy", acc)
    mlflow.sklearn.log_model(model, "model")

    run_id = run.info.run_id

# Register model từ run artifact
model_uri = f"runs:/{run_id}/model"
mv = mlflow.register_model(model_uri, "iris-classifier")
# → tạo version v1 nếu chưa có, hoặc v2, v3, ... nếu đã tồn tại

print(f"Registered: {mv.name} version {mv.version}")

Cách 2: Kết Hợp Trong 1 Bước

with mlflow.start_run():
    model = LogisticRegression(C=2.0, max_iter=1000)
    model.fit(X_train, y_train)

    mlflow.sklearn.log_model(
        model,
        artifact_path="model",
        registered_model_name="iris-classifier",  # tự động register
    )
    # version mới được tạo ngay khi run kết thúc

Xem Danh Sách Version

from mlflow.tracking import MlflowClient

client = MlflowClient()

# Tất cả version của model
versions = client.search_model_versions("name='iris-classifier'")
for v in versions:
    print(f"v{v.version}  run_id={v.run_id[:8]}  status={v.status}")

Output:

v1  run_id=a3f2e1d0  status=READY
v2  run_id=b9c4a7f1  status=READY
v3  run_id=c1d5b8e2  status=READY
6

Aliases Và Tags (MLflow 2.9+)

MLflow 2.9 deprecated legacy stages (Staging, Production, Archived) và thay bằng aliases — linh hoạt hơn vì:

  • Đặt tên tự do: champion, challenger, staging, shadow, canary, ...
  • Một version có thể có nhiều aliases.
  • Alias là mutable pointer: đổi alias sang version khác mà không cần redeploy code.

Set Alias

from mlflow.tracking import MlflowClient

client = MlflowClient()

# Gán alias "champion" cho version 3
client.set_registered_model_alias(
    name="iris-classifier",
    alias="champion",
    version="3",
)

# Gán alias "challenger" cho version 5 (đang test)
client.set_registered_model_alias(
    name="iris-classifier",
    alias="challenger",
    version="5",
)

# Gán alias "staging" cho version 5 đồng thời
client.set_registered_model_alias(
    name="iris-classifier",
    alias="staging",
    version="5",
)

Tag Cho Model Version

# Tag trên version — metadata về trạng thái approval
client.set_model_version_tag(
    name="iris-classifier",
    version="3",
    key="validation_status",
    value="approved",
)

client.set_model_version_tag(
    name="iris-classifier",
    version="3",
    key="approved_by",
    value="ml-platform-team",
)

# Tag trên model (không phải version cụ thể)
client.set_registered_model_tag(
    name="iris-classifier",
    key="task",
    value="multiclass-classification",
)

Xóa Alias

# Xóa alias (ví dụ sau khi promote challenger lên champion)
client.delete_registered_model_alias(
    name="iris-classifier",
    alias="challenger",
)

Lưu ý: nếu dùng MLflow Tracking server cũ (trước 2.9), legacy stages vẫn hoạt động nhưng sẽ bị deprecated. Code mới nên dùng aliases.

7

Load Model Từ Registry

URI format để load model từ registry:

import mlflow

mlflow.set_tracking_uri("http://localhost:5000")

# By alias (khuyến nghị cho production code)
model = mlflow.sklearn.load_model("models:/iris-classifier@champion")

# By version (khi cần pin cụ thể — ví dụ trong test)
model = mlflow.sklearn.load_model("models:/iris-classifier/3")

# Pyfunc — load bất kỳ model format nào (sklearn, pytorch, transformers, ...)
model = mlflow.pyfunc.load_model("models:/iris-classifier@champion")
predictions = model.predict(X_test)

Ưu điểm của load by alias: khi team promote version mới lên champion, code production không cần thay đổi gì — lần restart tiếp theo sẽ tự tải version mới.

Lấy Thông Tin Alias Đang Trỏ Tới Version Nào

from mlflow.tracking import MlflowClient

client = MlflowClient()
mv = client.get_model_version_by_alias("iris-classifier", "champion")
print(f"champion → version {mv.version}, run_id={mv.run_id}")
8

Promotion Workflow

Workflow thực tế từ kết quả train đến production:

  1. Register: sau train, register model vào registry → version mới được tạo (không có alias nào lúc đầu).
  2. Validate: chạy evaluation script độc lập trên test set → nếu đạt ngưỡng, set tag validation_status=approved.
  3. Staging: set alias staging → version mới → deploy lên staging environment. Staging environment load model bằng models:/iris-classifier@staging.
  4. Production: sau khi staging pass, review → set alias champion → version mới. Production environment tự tải khi restart.
  5. Rollback: phát hiện vấn đề → set alias champion → version cũ. Không cần redeploy artifact.
from mlflow.tracking import MlflowClient

client = MlflowClient()
MODEL_NAME = "iris-classifier"

def validate_and_promote_to_staging(version: str, threshold: float = 0.92):
    """Validate model và promote lên staging nếu đạt ngưỡng."""
    # Lấy run_id của version này để đọc metrics
    mv = client.get_model_version(MODEL_NAME, version)
    run = client.get_run(mv.run_id)
    accuracy = run.data.metrics.get("accuracy", 0)

    if accuracy >= threshold:
        client.set_model_version_tag(
            MODEL_NAME, version, "validation_status", "approved"
        )
        client.set_model_version_tag(
            MODEL_NAME, version, "test_accuracy", str(accuracy)
        )
        client.set_registered_model_alias(MODEL_NAME, "staging", version)
        print(f"v{version} promoted to staging (accuracy={accuracy:.4f})")
    else:
        client.set_model_version_tag(
            MODEL_NAME, version, "validation_status", "rejected"
        )
        print(f"v{version} rejected (accuracy={accuracy:.4f} < {threshold})")


def promote_to_production(version: str):
    """Promote version đã validate lên production (champion)."""
    mv = client.get_model_version(MODEL_NAME, version)
    tags = {t.key: t.value for t in mv.tags}

    if tags.get("validation_status") != "approved":
        raise ValueError(f"v{version} chưa được approve — không thể promote.")

    client.set_registered_model_alias(MODEL_NAME, "champion", version)
    print(f"v{version} is now champion")


def rollback(target_version: str):
    """Rollback champion về version cũ hơn."""
    client.set_registered_model_alias(MODEL_NAME, "champion", target_version)
    print(f"Rolled back champion → v{target_version}")
9

MLflow Serve — Deploy Nhanh Từ Registry

MLflow có built-in serve command, phù hợp cho dev/staging. Production thường dùng FastAPI, TorchServe, hoặc Triton để có nhiều kiểm soát hơn.

Khởi Động Server

# Serve model theo alias
mlflow models serve \
  -m "models:/iris-classifier@champion" \
  --host 0.0.0.0 \
  -p 5001

# Hoặc theo version cụ thể
mlflow models serve \
  -m "models:/iris-classifier/3" \
  -p 5001

Gọi API

# Format dataframe_split
curl -X POST http://localhost:5001/invocations \
  -H "Content-Type: application/json" \
  -d '{
    "dataframe_split": {
      "columns": ["sepal_length", "sepal_width", "petal_length", "petal_width"],
      "data": [[5.1, 3.5, 1.4, 0.2], [6.7, 3.1, 4.7, 1.5]]
    }
  }'
{"predictions": [0, 1]}

Từ Python

import requests

payload = {
    "dataframe_split": {
        "columns": ["sepal_length", "sepal_width", "petal_length", "petal_width"],
        "data": [[5.1, 3.5, 1.4, 0.2]],
    }
}
resp = requests.post("http://localhost:5001/invocations", json=payload)
print(resp.json())  # {"predictions": [0]}

mlflow models serve đọc MLmodel file trong artifact để biết framework (sklearn, pytorch, transformers) và load đúng cách. Không cần viết serving code thủ công.

10

Hugging Face Hub

Hugging Face Hub là registry phổ biến nhất cho transformer model và LLM. Version được quản lý qua git commit + tag. Phù hợp cho open-source model, public hoặc private repo.

Push Model Lên Hub

from transformers import AutoModelForSequenceClassification, AutoTokenizer

model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=3)
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

# ... fine-tuning ...

# Push lên Hub (cần HF_TOKEN)
model.push_to_hub("username/my-bert-sentiment")
tokenizer.push_to_hub("username/my-bert-sentiment")

Tag Version

# Tạo git tag để đánh version
git tag v1.2 HEAD
git push origin v1.2

Load Theo Revision (Tag Hoặc Commit Hash)

from transformers import AutoModelForSequenceClassification

# Load theo tag version
model = AutoModelForSequenceClassification.from_pretrained(
    "username/my-bert-sentiment",
    revision="v1.2",
)

# Load theo commit hash (pin cứng — khuyến nghị cho production)
model = AutoModelForSequenceClassification.from_pretrained(
    "username/my-bert-sentiment",
    revision="a3f2e1d0c8b7",
)

# Load latest main (không pin — dễ bị ảnh hưởng khi repo update)
model = AutoModelForSequenceClassification.from_pretrained(
    "username/my-bert-sentiment",
)

Dùng revision với commit hash trong production để tránh bị ảnh hưởng khi author push thay đổi lên branch main.

Private Repo

from huggingface_hub import login

login(token="hf_...")  # hoặc set env HF_TOKEN

model = AutoModelForSequenceClassification.from_pretrained(
    "your-org/private-model",
    use_auth_token=True,
)
11

W&B Model Registry

W&B Model Registry (ra mắt W&B 0.15+) xây trên W&B Artifacts. Mỗi model version là một Artifact, được link vào Model Registry và có thể gắn alias.

Log Và Register Model

import wandb

wandb.init(project="sentiment-model", job_type="train")

# ... train model ...

# Tạo artifact
artifact = wandb.Artifact(
    name="bert-finetune",
    type="model",
    description="BERT fine-tuned trên dataset sentiment v2",
    metadata={"accuracy": 0.924, "dataset_version": "v2.1"},
)
artifact.add_file("model.bin")
artifact.add_file("config.json")

# Log artifact
wandb.log_artifact(artifact)

wandb.finish()

Link Vào Model Registry Và Gán Alias

import wandb

run = wandb.init(project="sentiment-model", job_type="registry")

# Lấy artifact đã log
artifact = run.use_artifact("entity/sentiment-model/bert-finetune:v2")

# Link vào Model Registry với alias "staging"
run.link_artifact(
    artifact,
    target_path="entity/model-registry/bert-finetune",
    aliases=["staging", "v2"],
)

wandb.finish()

Promote Lên Production

import wandb

api = wandb.Api()

# Lấy artifact version cụ thể từ registry
artifact = api.artifact("entity/model-registry/bert-finetune:v2")

# Cập nhật aliases — thêm "production"
artifact.aliases = ["staging", "v2", "production"]
artifact.save()

Download Và Load

import wandb
import torch

api = wandb.Api()

# Download artifact theo alias
artifact = api.artifact("entity/model-registry/bert-finetune:production")
artifact_dir = artifact.download()  # trả về path local

# Load model từ path đã download
model = torch.load(f"{artifact_dir}/model.bin")
12

Metadata Cần Lưu

Metadata tối thiểu cần có để model version có thể tái tạo và audit được:

  • Code commit hash (git SHA): biết chính xác code train.
  • Dataset version: DVC tag, S3 object version ID, hoặc dataset hash.
  • Hyperparameters đầy đủ: learning rate, batch size, scheduler, số epochs, ...
  • Metrics trên test set: accuracy, F1, AUC, ... — không phải val set.
  • Training duration và hardware: training time, GPU type (A100, V100, ...), số GPU.
  • Author và timestamp: ai tạo, lúc nào.
  • Approval status: đặc biệt cần thiết trong ngành regulated (tài chính, y tế).
  • Base model (nếu fine-tune): tên và version của pretrained model gốc.

Ví dụ lưu đầy đủ metadata khi register với MLflow:

import subprocess
import mlflow
from mlflow.tracking import MlflowClient

# Lấy git SHA hiện tại
git_sha = subprocess.check_output(
    ["git", "rev-parse", "HEAD"]
).decode().strip()

with mlflow.start_run() as run:
    mlflow.log_params({
        "learning_rate": 2e-5,
        "batch_size": 16,
        "num_epochs": 3,
        "base_model": "bert-base-uncased",
        "dataset_version": "sentiment-v2.1",
    })
    mlflow.set_tags({
        "git_sha": git_sha,
        "author": "nam.nguyen",
        "gpu_type": "A100",
        "training_duration_hours": "2.3",
    })

    # ... train ...

    mlflow.log_metrics({
        "test_accuracy": 0.924,
        "test_f1_macro": 0.911,
    })
    mlflow.transformers.log_model(
        {"model": model, "tokenizer": tokenizer},
        artifact_path="model",
        registered_model_name="bert-sentiment",
    )
13

Model Card

Model card là file documentation đi kèm model, mô tả những gì metadata số không thể hiện. Khái niệm được hệ thống hóa trong paper "Model Cards for Model Reporting" (Mitchell et al., 2019, arXiv:1810.03993).

Trên Hugging Face Hub, model card là file README.md ở root repo. Nội dung cơ bản cần có:

  • Intended use: model được thiết kế cho task nào, ngôn ngữ nào, domain nào.
  • Training data: dataset gì, size, nguồn gốc, có bias không.
  • Evaluation results: metrics trên benchmark/test set, breakdown theo nhóm dân số nếu có.
  • Limitations: model fail ở trường hợp nào, dữ liệu out-of-distribution ra sao.
  • Ethical considerations: potential misuse, fairness issues.
---
language: vi
tags:
  - text-classification
  - sentiment-analysis
license: apache-2.0
---

# bert-sentiment-vi

## Intended Use
Phân loại sentiment (positive/negative/neutral) cho text tiếng Việt
trong domain social media và reviews.

## Training Data
Dataset tự thu thập: 50k reviews từ Shopee/Lazada/Tiki.
Split: 80% train / 10% dev / 10% test. Label bởi 3 annotators,
inter-annotator agreement (Cohen's kappa) = 0.82.

## Evaluation
| Metric     | Value |
|------------|-------|
| Accuracy   | 0.924 |
| F1 Macro   | 0.911 |

## Limitations
- Không hoạt động tốt với câu viết tắt nhiều (SMS style).
- Sarcasm / irony dễ bị classify sai.
- Chưa test trên domain y tế / pháp luật.
14

Tích Hợp Với CI/CD

Model Registry là trung gian giữa pipeline train và pipeline deploy. Luồng điển hình:

  1. PR mở → pipeline train chạy → register model mới vào registry (không có alias).
  2. Merge vào main → auto promote alias staging → version mới → deploy staging env.
  3. Staging pass smoke test và load test → manual approval → promote alias champion.
  4. Production env tải lại model theo alias champion khi restart.

Bài 44 sẽ đi vào chi tiết GitHub Actions pipeline cho các bước trên, bao gồm cách gọi MLflow API từ CI/CD workflow.

Điểm quan trọng: deploy environment chỉ cần biết alias (champion, staging), không cần biết version number cụ thể. Khi promote hoặc rollback chỉ cần đổi alias pointer — không cần update config deploy hay rebuild image.

15

Common Pitfalls

1. Đẩy Model File Vào Git Thường

Model binary (pkl, pt, bin) có thể vài trăm MB đến vài GB. Commit thẳng vào git khiến repo phình to, clone chậm, và không thể xóa được (git giữ lịch sử). Dùng Git LFS, DVC, hoặc MLflow Registry để lưu artifact.

2. Quên Register Model Sau Train

MLflow tracking lưu artifact trong mỗi run, nhưng tracking server có policy cleanup — run cũ có thể bị xóa. Nếu không register, artifact mất khi cleanup chạy. Register ngay sau khi train xong và validate.

3. Registry Không Persist (File Store)

# KHÔNG dùng để lưu registry — sẽ mất khi server restart
mlflow.set_tracking_uri("file:./mlruns")  # file store không hỗ trợ registry

# ĐÚNG — dùng database backend
mlflow.set_tracking_uri("sqlite:///mlflow.db")
# hoặc
mlflow.set_tracking_uri("http://mlflow-server:5000")

4. Promote Không Validate

Promote thẳng từ train sang production mà không chạy evaluation riêng biệt. Nếu training metric tốt nhưng model bị overfit hoặc evaluate trên wrong test set, production nhận model tệ hơn. Luôn có bước validation độc lập trước khi promote.

5. Chỉ Register Model, Không Link Code Commit

Sau 3 tháng, không ai biết model v7 được train từ code nào. Luôn gắn git SHA vào tag/metadata khi register. MLflow 2.x tự gắn mlflow.source.git.commit nếu chạy trong git repo — kiểm tra tag này có giá trị không.

6. Alias Trùng Nhau Trên Nhiều Model

Alias chỉ unique trong phạm vi một registered model name. iris-classifier@championbert-sentiment@champion là hai alias khác nhau — không nhầm lẫn. Nhưng trong cùng một model, đừng đặt 2 alias cùng tên trỏ 2 version khác nhau — MLflow sẽ chỉ giữ lại assignment cuối cùng.

7. Không Có Rollback Plan

Trước khi promote alias champion sang version mới, ghi lại version hiện tại đang là champion. Nếu xảy ra sự cố, rollback bằng cách set alias về version cũ — thao tác này mất vài giây.

16

Bài Tiếp Theo

Bài 43: Data Versioning với DVC — version dataset và pipeline, track thay đổi data giống git track code.