MLOps 5 — Model Registry & triển khai mô hình
MLOps 5 — Model Registry & triển khai mô hình
Ở bài pipelines ta kết thúc bằng bước Register rồi Deploy mà chưa nói kỹ. Bài này đi vào chính hai mắt xích đó: nơi cất giữ và quản lý phiên bản mô hình (model registry), và cách đưa mô hình ra phục vụ thật (serving) sao cho an toàn, có thể rollback, và không làm sập hệ thống ngân hàng đang chạy.
Một mô hình train xong mà chỉ nằm dưới dạng file .pkl trong thư mục của một data scientist thì chưa có giá trị. Câu hỏi thực chiến luôn là: bản nào đang chạy trên production? ai duyệt cho nó lên? nó được train từ dữ liệu nào? nếu nó hỏng thì quay về bản cũ trong bao lâu? Model registry và các mẫu triển khai chính là để trả lời những câu này.
Model Registry là gì
Model registry là một kho tập trung quản lý vòng đời của các mô hình đã huấn luyện. Nó khác với artifact store (chỉ lưu file model) ở chỗ nó thêm lớp quản trị: mỗi mô hình có tên, nhiều version (phiên bản), mỗi version có một stage (giai đoạn) và một đống metadata đi kèm.
Các thành phần cốt lõi:
- Registered model — một "tên logic", ví dụ
fraud_scoringhaycredit_pd_model. Đây là cái nghiệp vụ nhắc tới, độc lập với version cụ thể. - Version — mỗi lần train ra một mô hình mới đủ tốt để đăng ký thì tạo thêm một version (v1, v2, v3...). Version là bất biến: đã đăng ký thì file không đổi.
- Stage — trạng thái vòng đời của một version. Bộ stage kinh điển của MLflow: None (mới đăng ký, chưa gán), Staging (đang test/UAT), Production (đang phục vụ thật), Archived (đã nghỉ hưu). Việc "promote" một version từ Staging lên Production là hành động có kiểm soát, thường cần phê duyệt.
- Metadata & tags — metric (AUC, KS), khung train, kích thước dữ liệu, người tạo, mô tả, số ticket phê duyệt...
- Lineage — liên kết ngược version này về experiment/run đã sinh ra nó (params, code, git commit) và về dữ liệu/feature đầu vào. Đây là mảnh ghép để trả lời thanh tra: "mô hình đang từ chối khoản vay này được train thế nào?"
Ranh giới stage cũng là ranh giới quyền: data scientist được đăng ký version và đẩy lên Staging, nhưng chỉ role vận hành/quản lý mới được promote lên Production. Điều này gắn chặt với kiểm soát truy cập và là nền cho phần governance ở bài sau.
MLflow Model Registry — ví dụ cụ thể
MLflow là công cụ phổ biến và mã nguồn mở nên hay được dùng làm ví dụ. Luồng điển hình: train xong log model vào một run, rồi đăng ký run đó thành một version, rồi chuyển stage.
import mlflow
from mlflow.tracking import MlflowClient
# 1. Trong lúc train: log model kèm signature + môi trường
with mlflow.start_run() as run:
mlflow.sklearn.log_model(
sk_model=model,
artifact_path="model",
signature=signature, # mô tả schema input/output
input_example=X_valid.head(),
registered_model_name="fraud_scoring", # tự tạo version mới
)
# 2. Sau đó promote version sang Production (thường ở bước riêng, có duyệt)
client = MlflowClient()
client.transition_model_version_stage(
name="fraud_scoring",
version=3,
stage="Production",
archive_existing_versions=True, # bản Production cũ tự chuyển Archived
)
Lưu ý thực chiến: từ MLflow 2.9 trở đi, mô hình stage (None/Staging/Production/Archived) bị coi là deprecated và được thay bằng model alias (ví dụ gán alias @champion, @challenger, @prod cho một version) cùng tags. Alias linh hoạt hơn — bạn tự đặt tên giai đoạn theo quy trình của mình. Ví dụ minh hoạ, tuỳ phiên bản MLflow mà API khác nhau, nên khi triển khai cần bám theo docs đúng version đang dùng.
# Cách mới (MLflow 2.9+): dùng alias thay stage
client.set_registered_model_alias("fraud_scoring", "champion", version=3)
model = mlflow.pyfunc.load_model("models:/fraud_scoring@champion")
Đóng gói mô hình
"Đăng ký" chỉ có ý nghĩa nếu cái được đăng ký chạy lại được ở nơi khác. Vấn đề kinh điển: model train trên máy data scientist với scikit-learn 1.3, đưa sang server serving có scikit-learn 1.1, kết quả lệch hoặc lỗi load. Đóng gói tốt phải kèm ba thứ.
- Trọng số/model artifact — bản thân mô hình. Định dạng lưu:
- Pickle / joblib — mặc định của Python, tiện nhưng gắn chặt phiên bản thư viện và không an toàn khi load file lạ (pickle có thể chạy code tuỳ ý). Chỉ load pickle từ nguồn tin cậy.
- ONNX (Open Neural Network Exchange) — định dạng trung gian, chuẩn hoá, tách model khỏi framework train. Chạy được bằng ONNX Runtime với độ trễ thấp, ngôn ngữ độc lập (C++, Java, .NET) — hợp khi team serving không dùng Python.
- Định dạng riêng của framework —
SavedModel(TensorFlow), TorchScript (PyTorch), Booster (XGBoost/LightGBM).
- Signature — mô tả schema input và output: tên cột, kiểu dữ liệu, shape. Signature giúp phát hiện sớm khi dữ liệu gọi vào sai định dạng, thay vì để mô hình trả kết quả rác.
- Môi trường — danh sách thư viện + version (
conda.yaml/requirements.txtdo MLflow tự sinh khi log model), hoặc gói cả vào Docker image để đóng băng tuyệt đối. Chuẩn MLmodel của MLflow gói cả model + signature + môi trường vào một thư mục, và định nghĩa "flavor" (sklearn, pyfunc, onnx...) để công cụ biết cách load.
Nguyên tắc: mô hình lên Production nên đi kèm môi trường được đóng băng (image cụ thể, digest cố định), không "cài lại theo requirements lỏng" mỗi lần deploy.
Bốn mẫu triển khai (serving)
Không có một cách serving đúng cho mọi bài toán. Chọn mẫu theo yêu cầu độ trễ và cách tiêu thụ kết quả.
| Mẫu | Độ trễ | Cách chạy | Ví dụ ngân hàng |
|---|---|---|---|
| Batch / offline | Phút–giờ | Chạy định kỳ, chấm điểm cả tập, ghi ra bảng/warehouse | Chấm điểm tín dụng (PD) hàng tháng, phân khúc khách hàng |
| Online / real-time | Mili-giây | REST/gRPC endpoint, gọi theo từng request | Chặn giao dịch gian lận ngay khi phát sinh |
| Streaming | Giây | Tiêu thụ event từ Kafka, chấm điểm liên tục | Cảnh báo bất thường theo luồng giao dịch |
| Embedded | Cực thấp | Nhúng model vào ứng dụng/thiết bị | Model nhẹ chạy trong app mobile, edge |
(1) Batch / offline
Phổ biến nhất trong ngân hàng. Không cần server luôn bật: một pipeline (Airflow/Spark) chạy theo lịch, load model từ registry, chấm điểm toàn bộ khách hàng, rồi ghi kết quả vào một bảng để các hệ khác (CRM, báo cáo, quyết định tín dụng) đọc. Ưu điểm: đơn giản, throughput cao, dễ backfill. Nhược: kết quả "cũ" tới chu kỳ chạy tiếp theo.
Kết quả điểm thường được ghi thành một bảng như customer_scores(customer_id, score, model_version, scored_at). Sau khi ghi, việc đọc lại để dùng chỉ là truy vấn thường:
-- ▶ Chạy được
SELECT c.city, COUNT(*) AS so_kh
FROM customers c
JOIN accounts a ON a.customer_id = c.id
GROUP BY c.city
ORDER BY so_kh DESC;
(Truy vấn trên minh hoạ phần đọc lại trên các bảng có sẵn — bảng điểm mô hình customer_scores không nằm trong sandbox nên không đánh dấu chạy được cho câu đụng tới nó.)
(2) Online / real-time
Model được bọc sau một REST/gRPC endpoint. Ứng dụng gọi endpoint, gửi feature, nhận điểm về trong vài mili-giây. Đây là nơi độ trễ là tối quan trọng — chi tiết về thiết kế API độ trễ thấp xem bài triển khai API. Mấu chốt của online serving là online feature store (xem bài feature store): tại thời điểm chấm điểm, ta cần feature tươi (ví dụ "số giao dịch của thẻ này trong 5 phút qua") được tra cứu nhanh, nhất quán với lúc train.
# Minh hoạ endpoint online với FastAPI + model từ registry
from fastapi import FastAPI
import mlflow.pyfunc, pandas as pd
model = mlflow.pyfunc.load_model("models:/fraud_scoring@champion")
app = FastAPI()
@app.post("/score")
def score(txn: dict):
# feat = online_store.get_features(txn["card_id"]) # tra online feature store
feat = pd.DataFrame([txn])
prob = float(model.predict(feat)[0])
return {"fraud_prob": prob, "block": prob > 0.9}
(3) Streaming
Model gắn vào một stream processor (Kafka Streams, Flink, Spark Structured Streaming). Mỗi giao dịch chảy qua topic được chấm điểm ngay, kết quả đẩy sang topic khác hoặc trigger cảnh báo. Khác online ở chỗ: không ai "gọi" model, model chủ động tiêu thụ event. Phù hợp giám sát giao dịch theo luồng, gần với kiến trúc Kafka.
(4) Embedded
Model được nhúng trực tiếp vào ứng dụng (thư viện trong app, hoặc chạy trên thiết bị/edge). Không có network hop nên độ trễ cực thấp, hoạt động cả khi offline. Đổi lại: khó cập nhật model (phải phát hành lại app), giới hạn kích thước — thường dùng model nhẹ đã ONNX/quantize.
Công cụ serving
Không cần tự viết server từ đầu. Vài công cụ hay gặp: BentoML (đóng gói + serve model thành API/Docker, thân thiện Python), KServe (serving trên Kubernetes, autoscale, hỗ trợ canary), Seldon Core (serving + graph inference trên K8s), TensorFlow Serving / TorchServe (chuyên framework), và các cloud endpoint (SageMaker, Vertex AI, Azure ML). Chọn theo hạ tầng sẵn có: có Kubernetes thì KServe/Seldon; muốn nhanh gọn thì BentoML.
Chiến lược roll-out an toàn
Không bao giờ "thay model cũ bằng model mới" đột ngột trên toàn bộ traffic production. Rủi ro là model mới train tốt trên offline metric nhưng hành xử tệ trên dữ liệu thật (feature lệch, edge case, latency). Các chiến lược sau giảm rủi ro đó.
- Shadow deployment — model mới nhận bản sao của traffic thật và tính điểm, nhưng kết quả không được dùng để ra quyết định. Ta chỉ ghi lại và so sánh với model hiện tại. Cực an toàn: người dùng không hề bị ảnh hưởng, nhưng ta biết model mới sẽ hành xử ra sao trên dữ liệu thật, kèm đo latency thực tế.
- Canary — cho model mới nhận một phần nhỏ traffic thật (ví dụ 5%), theo dõi metric nghiệp vụ + kỹ thuật. Ổn thì tăng dần 5%→25%→50%→100%; xấu thì rút về ngay.
- Blue-green — chạy song song hai môi trường đầy đủ: blue (đang phục vụ) và green (bản mới đã sẵn sàng). Chuyển traffic từ blue sang green trong một nhịp; có sự cố thì switch ngược lập tức. Rollback nhanh nhưng tốn gấp đôi tài nguyên trong lúc chuyển.
- A/B testing — chia traffic theo nhóm để đo tác động nghiệp vụ (không chỉ metric offline): model A vs B, xem cái nào giảm gian lận / tăng tỷ lệ duyệt vay tốt hơn, có ý nghĩa thống kê.
- Champion / challenger — mô hình đang chạy là champion; các ứng viên là challenger chạy shadow/canary. Challenger nào bền vững vượt champion trên dữ liệu thật thì được promote thành champion mới. Đây là quy trình liên tục, không phải one-shot.
- Rollback — điều kiện tiên quyết của mọi chiến lược: phải promote lại được version cũ trong vài phút. Vì version trong registry là bất biến, rollback chỉ là "đổi alias
@championvề version trước" rồi reload — không cần train lại.
Tối ưu suy luận
Khi endpoint chịu tải cao, hai kỹ thuật hay dùng:
- Batching — gom nhiều request đến gần nhau trong vài mili-giây rồi chấm điểm một lô. Tăng throughput mạnh (nhất là với model chạy GPU) nhưng thêm một chút latency chờ gom. Đổi lấy đánh đổi latency–throughput.
- Quantization — hạ độ chính xác số của trọng số (float32 → int8) để model nhỏ hơn và suy luận nhanh hơn, đổi lại giảm nhẹ độ chính xác. Kèm ONNX Runtime hoặc TensorRT thường cho tốc độ tốt cho model deep learning nặng. Với model dạng cây (XGBoost/LightGBM) thường không cần — chúng vốn đã rất nhanh.
Use case thực tế
Chi nhánh NCB vận hành song song hai mô hình rất khác nhau về mẫu triển khai:
1. Gian lận thẻ — online, real-time. Model fraud_scoring phục vụ qua REST endpoint (KServe), yêu cầu p99 < 50ms. Mỗi giao dịch thẻ gọi endpoint, tra online feature store lấy feature tươi (số giao dịch/số quốc gia trong 10 phút qua), trả fraud_prob; nếu > 0.9 thì chặn và đẩy alert. Khi có model v4 mới:
- Tuần 1: chạy shadow — v4 chấm song song v3 trên 100% traffic, không chặn giao dịch nào theo v4, chỉ log. Phát hiện v4 gắn cờ nhầm 3× nhiều giao dịch quốc tế hợp lệ → sửa feature, retrain.
- Tuần 2: v4 (đã sửa) chạy canary 5% → precision trên nhóm canary tốt hơn v3, latency ổn → tăng lên 25%, 50%.
- Tuần 3: promote 100%, đổi alias
@championsang v4, v3 chuyển Archived. Rollback nếu cần chỉ là đổi alias về v3, mất < 2 phút.
2. Chấm điểm tín dụng — batch. Model credit_pd_model (xác suất vỡ nợ, xem scorecard) chạy batch hàng tháng: một job Spark load version Production từ registry, chấm điểm toàn bộ ~1,2 triệu khách hàng, ghi vào bảng customer_pd_scores(customer_id, pd, band, model_version, scored_at). Bộ phận tín dụng đọc bảng này khi xét duyệt. Vì là batch nên không cần độ trễ thấp, nhưng vẫn cần lineage: mỗi dòng ghi kèm model_version để khi thanh tra hỏi "điểm tháng 3 của khách X từ đâu ra" thì tra ngược được version → run → dữ liệu train. Việc giám sát drift chạy trên chính bảng kết quả này để phát hiện phân phối điểm lệch dần theo tháng.
Ghi nhớ
- Model registry quản lý vòng đời mô hình: registered model → nhiều version (bất biến) → stage None/Staging/Production/Archived, kèm metadata & lineage ngược về run và dữ liệu.
- Promote lên Production là hành động có kiểm soát và phê duyệt — gắn với phân quyền, là nền cho governance.
- MLflow là ví dụ điển hình; từ 2.9+ khuyến nghị alias + tags thay cho stage cứng. Bám docs đúng version đang dùng.
- Đóng gói phải gồm cả model + signature (schema I/O) + môi trường (đóng băng bằng requirements/conda hoặc Docker). Pickle tiện nhưng gắn version và không an toàn với file lạ; ONNX chuẩn hoá, độc lập ngôn ngữ.
- Bốn mẫu serving: batch (chấm hàng loạt ghi bảng — hợp chấm điểm tín dụng định kỳ), online (REST, độ trễ thấp — hợp gian lận real-time, cần online feature store), streaming, embedded. Chọn theo yêu cầu độ trễ.
- Roll-out an toàn: shadow (chạy song song, không dùng kết quả) → canary (traffic nhỏ, tăng dần) → blue-green / A/B / champion-challenger. Luôn có đường rollback nhanh (đổi alias về version cũ).
- Vì version bất biến, rollback không cần train lại — chỉ trỏ lại bản cũ.
- Tối ưu suy luận: batching (đánh đổi latency lấy throughput) và quantization (float32→int8, nhanh hơn, giảm nhẹ độ chính xác).
Bài viết liên quan
Phân biệt AI/ML/DL, các kiểu học máy, quy trình ML end-to-end và thuật ngữ nền tảng.
Chất lượng dữ liệu, xử lý thiếu/ngoại lai, mã hoá, chuẩn hoá, tạo đặc trưng và tránh data leakage.
Mô hình ngôn ngữ lớn hoạt động ra sao, token, context window, tham số sinh, và kỹ thuật viết prompt.
Retrieval-Augmented Generation, vector database, tool calling, agent và MCP để xây ứng dụng LLM thực tế.