Sau khi train xong một mô hình ML, câu hỏi tiếp theo luôn là: làm sao đưa nó ra production? Mình đã trải qua không ít lần phải tự viết Flask API để wrap model, rồi gặp đủ thứ vấn đề: thiếu versioning, khó scale, log lộn xộn. Đến khi team thử BentoML, cách nhìn về ML serving thay đổi hoàn toàn.
Bức tranh tổng quan: Các cách deploy model ML
Thực tế có nhiều cách để expose model ML thành API. Mình chia thành 4 nhóm chính:
- Tự viết API (Flask/FastAPI) — linh hoạt nhất, nhưng phải tự xử lý mọi thứ từ đầu
- BentoML — framework chuyên biệt cho ML serving, tích hợp sẵn nhiều tính năng production
- TorchServe — dành riêng cho PyTorch, tốt nếu bạn all-in PyTorch
- Triton Inference Server (NVIDIA) — hiệu năng cực cao, nhưng phức tạp và cần GPU cluster
So sánh chi tiết từng approach
Flask/FastAPI tự viết
Đây là cách phổ biến nhất vì ai cũng biết Flask/FastAPI. Bạn load model, viết endpoint, xong. Nhưng vấn đề nằm ở chỗ khác:
- Không có cơ chế versioning model — khi update model phải deploy lại toàn bộ service
- Batching phải tự implement — ảnh hưởng lớn đến throughput khi load cao
- Health check, monitoring phải tự viết thêm
- Không có chuẩn nào cho cách đóng gói model cùng dependencies
Mình từng maintain một service Flask như vậy suốt 6 tháng. Mỗi lần data scientist update model là cả team phải coordinate thủ công — copy file, restart service, check log. Rất mất thời gian và dễ xảy ra sự cố.
TorchServe
Nếu team chỉ dùng PyTorch và muốn giải pháp official từ Meta, TorchServe là lựa chọn. Nhưng nó khá opinionated — chỉ dành cho PyTorch, cấu hình XML-based (khá cổ), và tài liệu còn thiếu nhiều edge case thực tế.
Triton Inference Server
Khi cần vắt kiệt hiệu năng GPU — dynamic batching, multiple backends (TensorRT, ONNX, TF, PyTorch) — Triton mới xứng đáng bỏ công setup. Vấn đề là learning curve dốc, cấu hình phức tạp, và nếu không có GPU cluster thì rõ ràng là over-engineering.
BentoML
BentoML đứng ở điểm ngọt ngào giữa “tự viết Flask” và “Triton phức tạp”. Framework-agnostic (hỗ trợ sklearn, PyTorch, TF, XGBoost, ONNX…), có versioning tích hợp, adaptive batching, và export Docker tự động. Phù hợp với 80% use case production mà không cần setup phức tạp.
Tại sao chọn BentoML cho production
Sau khi so sánh, team DevOps của mình chốt BentoML vì 3 lý do cụ thể:
- Model registry tích hợp sẵn — save/load model có versioning, không cần DVC hay MLflow riêng cho bước này
- Bento = artifact đóng gói hoàn chỉnh — model + code + dependencies gói thành một artifact, deploy ở đâu cũng được
- Docker image generation tự động — một lệnh ra ngay Docker image production-ready, không cần viết Dockerfile phức tạp
Lợi ích ít được nhắc đến nhất lại quan trọng nhất với team mình: không còn cuộc gọi “model mới để ở đâu, Python version mấy, dependencies cần gì”. Data scientist save model với tag, DevOps lấy tag đó build Docker. Cái quy trình chuẩn hóa này tiết kiệm cho team mình khoảng 2 tiếng mỗi lần release model mới.
Hướng dẫn triển khai BentoML trên Linux
1. Cài đặt
pip install bentoml
# Kiểm tra
bentoml --version
2. Save model vào BentoML model store
Bước đầu tiên là đưa model đã train vào BentoML registry. Ví dụ với scikit-learn:
import bentoml
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
# Train model (thực tế bạn đã có model rồi)
iris = load_iris()
clf = RandomForestClassifier(n_estimators=100)
clf.fit(iris.data, iris.target)
# Save vào BentoML model store
saved_model = bentoml.sklearn.save_model(
"iris_classifier",
clf,
signatures={"predict": {"batchable": True}},
metadata={"accuracy": 0.97, "dataset": "iris"}
)
print(f"Model saved: {saved_model.tag}")
# Output: iris_classifier:3mxqpfzbs6tpjuqj
Model được lưu tại ~/bentoml/models/, có versioning tự động qua tag hash — muốn rollback chỉ cần đổi tag.
3. Tạo BentoML Service
Phần cốt lõi — định nghĩa API endpoint và logic xử lý:
# service.py
import bentoml
import numpy as np
from bentoml.io import NumpyNdarray, JSON
# Load model từ registry
iris_runner = bentoml.sklearn.get("iris_classifier:latest").to_runner()
svc = bentoml.Service("iris_classifier_service", runners=[iris_runner])
IRIS_CLASSES = ["setosa", "versicolor", "virginica"]
@svc.api(input=NumpyNdarray(shape=(-1, 4), dtype=np.float32), output=JSON())
async def predict(input_data: np.ndarray):
batch_pred = await iris_runner.predict.async_run(input_data)
result = [IRIS_CLASSES[i] for i in batch_pred]
return {"predictions": result}
4. Test local
# Chạy development server
bentoml serve service:svc --reload
# Test bằng curl (terminal khác)
curl -X POST http://localhost:3000/predict \
-H "Content-Type: application/json" \
-d '[[5.1, 3.5, 1.4, 0.2]]'
# Response:
# {"predictions": ["setosa"]}
5. Build Bento artifact
Tạo file bentofile.yaml mô tả toàn bộ dependencies:
service: "service:svc"
labels:
owner: devops-team
project: iris-api
include:
- "service.py"
python:
packages:
- scikit-learn
- numpy
bentoml build
# Output:
# Successfully built Bento(tag="iris_classifier_service:7a3bk2...")
# Bento size: 15.2 MB
6. Deploy lên production với Docker
# Containerize Bento thành Docker image
bentoml containerize iris_classifier_service:latest
# Tag và push lên registry
docker tag iris_classifier_service:latest your-registry.com/iris-api:v1
docker push your-registry.com/iris-api:v1
# Chạy container
docker run -p 3000:3000 iris_classifier_service:latest serve
7. Deploy trực tiếp trên Linux với systemd
Nếu không dùng Docker, tạo systemd service để quản lý process:
# /etc/systemd/system/iris-api.service
[Unit]
Description=BentoML Iris Classifier API
After=network.target
[Service]
User=www-data
WorkingDirectory=/opt/iris-api
ExecStart=/opt/iris-api/venv/bin/bentoml serve iris_classifier_service:latest \
--host 0.0.0.0 \
--port 3000 \
--workers 4
Restart=always
RestartSec=5
Environment=BENTOML_HOME=/opt/iris-api/bentoml
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable iris-api
systemctl start iris-api
systemctl status iris-api
Những điểm cần lưu ý khi chạy production
Adaptive batching
BentoML có cơ chế adaptive batching — tự gom nhiều request nhỏ thành batch để tăng throughput. Cấu hình trong bentofile.yaml:
runners:
- name: iris_runner
max_batch_size: 100
max_latency_ms: 15
Monitoring với Prometheus
BentoML expose sẵn metrics Prometheus tại /metrics. Thêm vào Prometheus config là dùng được ngay:
scrape_configs:
- job_name: 'bentoml'
static_configs:
- targets: ['your-server:3000']
Health check endpoint
Built-in tại /healthz và /readyz — dùng được ngay với Kubernetes liveness/readiness probe mà không cần viết thêm gì.
Kết
Mình đã migrate 3 service ML từ Flask tự viết sang BentoML. Thời gian để đưa một model mới lên production — từ lúc data scientist bàn giao đến khi API chạy được — giảm từ khoảng 3 tiếng xuống còn 20–30 phút, chủ yếu là thời gian build Docker image. Model registry cũng giúp rollback dễ dàng khi model mới có vấn đề.
BentoML không phải silver bullet. Cần tối đa hiệu năng GPU với TensorRT thì Triton vẫn là lựa chọn tốt hơn. Nhưng với phần lớn team ML/DevOps, BentoML là điểm cân bằng thực tế giữa tốc độ triển khai và độ ổn định production. Thử ngay với pip install bentoml scikit-learn và chạy theo các bước trên.

