Mở đầu — vì sao bài này quan trọng
Bạn đã dành hơn ba mươi bài để xây dựng pipeline CI/CD cho ứng dụng phần mềm thông thường: commit code, build, test, đóng gói artifact, rồi deploy. Nhưng khi bước sang thế giới Machine Learning (ML), nhiều kỹ sư DevOps giỏi bỗng nhiên "vấp". Lý do rất đơn giản: một hệ thống ML không chỉ có code, mà còn có model đã huấn luyện (model weights) và dữ liệu dùng để huấn luyện. Ba thứ này thay đổi theo những nhịp khác nhau, và bất kỳ thứ nào thay đổi cũng có thể làm sản phẩm cuối cùng cho ra kết quả khác đi.
Đây chính là lý do MLOps ra đời. MLOps (Machine Learning Operations) là việc áp dụng tư duy DevOps — tự động hóa, versioning, testing, deploy liên tục — vào vòng đời của model ML. Với một fintech ở Việt Nam đang chấm điểm tín dụng bằng model, hay một sàn thương mại điện tử gợi ý sản phẩm bằng thuật toán, thì việc đưa một model tốt hơn lên production nhanh chóng và an toàn có thể là khác biệt giữa lãi và lỗ.
Trong bài này, chúng ta không học lại CI/CD từ đầu. Chúng ta sẽ tập trung vào điều gì làm CD cho ML khác với CD cho app thông thường, và bạn — với nền tảng CI/CD đã có — cần bổ sung tư duy gì để không "ngã" khi làm việc với đội Data Science.
Khái niệm cốt lõi
Artifact của ML = Code + Model + Data
Trong pipeline app thông thường (những bài trước bạn đã học), artifact đầu ra là một file jar, một Docker image, hay một bundle JavaScript. Chỉ cần cùng một commit code là bạn tái tạo được y hệt artifact đó.
Với ML thì không. Một "phiên bản model" được xác định bởi ba thành phần độc lập:
- Code: script tiền xử lý dữ liệu, kiến trúc model, logic huấn luyện (training), logic phục vụ (serving).
- Model weights: file chứa các tham số đã học được sau khi huấn luyện — có thể là
model.pkl,model.onnx,model.safetensorsnặng từ vài MB đến hàng chục GB. - Data: tập dữ liệu dùng để huấn luyện. Cùng một code, nhưng huấn luyện trên dữ liệu tháng 1 và dữ liệu tháng 6 sẽ cho hai model hoàn toàn khác nhau.
- DVC (Data Version Control) hoặc Git LFS: version dữ liệu và model, nhưng file thật lưu ở S3/GCS/MinIO, còn Git chỉ giữ một con trỏ (pointer) nhỏ.
- Model Registry: nơi lưu và đánh version cho model đã huấn luyện, kèm metadata. Phổ biến nhất là MLflow Model Registry, hoặc registry của SageMaker, Vertex AI.
Reproducibility — tái tạo được là luật vàng
Trong app thông thường, "tái tạo được" nghĩa là cùng commit thì build ra cùng artifact. Trong ML, để tái tạo được cùng một model, bạn cần khóa chặt bốn thứ:
- Code (commit hash cụ thể).
- Data (phiên bản dataset cụ thể — hash của dữ liệu).
- Hyperparameter (learning rate, số epoch, batch size...).
- Random seed (hạt giống ngẫu nhiên — vì quá trình huấn luyện có nhiều bước ngẫu nhiên: khởi tạo trọng số, xáo trộn dữ liệu, dropout...).
Drift — kẻ thù thầm lặng chỉ ML mới có
Đây là điểm khác biệt lớn nhất và cũng nguy hiểm nhất. Một ứng dụng phần mềm thông thường, nếu bạn không đụng vào code, nó sẽ chạy đúng mãi mãi. Một model ML thì tự xuống cấp theo thời gian dù bạn không đổi gì cả. Hiện tượng đó gọi là drift.
Có hai loại drift chính bạn cần nhớ:
- Data drift: phân bố của dữ liệu đầu vào thực tế thay đổi so với lúc huấn luyện. Ví dụ: model gợi ý sản phẩm được huấn luyện trước Tết, hành vi mua sắm sau Tết đổi hẳn.
- Concept drift: mối quan hệ giữa đầu vào và đầu ra thay đổi. Ví dụ: model chống gian lận học được "giao dịch 2 giờ sáng là đáng ngờ", nhưng rồi thói quen người dùng đổi và giả định đó không còn đúng.
CT — chữ cái thứ ba của MLOps
Với app: CI/CD. Với ML: CI/CD/CT.
- CI: không chỉ test code, mà còn test data (schema, chất lượng) và test model (độ chính xác tối thiểu).
- CD: deploy model như một dịch vụ (thường là REST API dự đoán) hoặc như một batch job.
- CT: tự động huấn luyện lại model khi có dữ liệu mới hoặc khi phát hiện drift, rồi đưa trở lại pipeline.
Tình huống thực tế
Ví dụ 1 — Fintech Việt cho vay và chuyện "model tốt trên laptop"
Một công ty fintech cho vay tiêu dùng ở TP.HCM (giả định tên là VayNhanh) có một đội Data Science 4 người xây model chấm điểm tín dụng. Ban đầu quy trình rất thủ công: Data Scientist huấn luyện model trên laptop, xuất ra file credit_model.pkl, gửi qua Slack cho đội backend, backend copy vào server production.
Vấn đề bùng nổ sau ba tháng. Một model mới được deploy khiến tỷ lệ duyệt vay tăng vọt bất thường, và một tháng sau nợ xấu tăng theo. Khi truy vết, không ai biết model đó được huấn luyện trên dữ liệu nào, hyperparameter ra sao, vì file .pkl được gửi qua Slack không có metadata gì cả. Họ không tái tạo lại được để phân tích lỗi.
Giải pháp của họ: đưa mọi thứ vào MLflow. Mỗi lần huấn luyện, pipeline tự log lại commit code, hash của dataset (qua DVC), toàn bộ hyperparameter, random seed, và các chỉ số đánh giá (AUC, precision, recall). Model được đăng ký vào Model Registry với version rõ ràng. Deploy production chỉ được phép lấy model từ registry, không bao giờ từ file gửi tay.
Bài học: Trong ML, "cái gì đang chạy trên production" phải luôn truy được về đúng code + data + tham số đã tạo ra nó. Không có reproducibility thì không có debug, không có audit — điều bắt buộc với ngành tài chính (như bài về Compliance sẽ nói kỹ).
Ví dụ 2 — Sàn TMĐT và model gợi ý bị "drift" sau Tết
Một sàn thương mại điện tử khu vực Đông Nam Á (giả định là ShopSea) chạy một model gợi ý sản phẩm được huấn luyện vào tháng 11, tối ưu cho mùa mua sắm cuối năm. Sau Tết Nguyên đán, đội vận hành nhận thấy tỷ lệ click vào gợi ý (CTR) tụt từ 8% xuống 4,5% trong hai tuần, dù không ai đụng vào code.
Nguyên nhân là data drift: hành vi mua sắm sau Tết đổi hoàn toàn (người dùng chuyển từ mua quà tặng sang mua đồ gia dụng, đồ ăn kiêng). Model vẫn gợi ý theo "gu" trước Tết nên ngày càng lệch.
ShopSea xử lý bằng cách xây một pipeline Continuous Training: một job hằng ngày tính phân bố dữ liệu đầu vào và so với phân bố lúc huấn luyện; khi khoảng cách vượt ngưỡng (họ dùng chỉ số PSI — Population Stability Index), hệ thống tự động kích hoạt retraining trên dữ liệu 30 ngày gần nhất. Model mới không được deploy thẳng, mà đi qua canary: phục vụ 5% traffic, so CTR thực tế với model cũ, đạt thì mới mở rộng 100%.
Bài học: Với ML, "không đổi code" không có nghĩa là "an toàn". Bạn phải giám sát chất lượng model trên production như giám sát một dịch vụ sống, và có cơ chế tự làm mới khi dữ liệu thế giới thực đổi thay.
Ví dụ 3 — Startup AI và cái bẫy artifact khổng lồ
Một startup ở Hà Nội (giả định tên VoiceVN) làm model nhận dạng tiếng Việt, mỗi model nặng khoảng 2GB. Ban đầu họ cố nhét thẳng file model vào Git repo. Repo phình lên 40GB sau vài tháng, git clone mất cả tiếng, CI runner liên tục hết dung lượng đĩa, và pipeline build fail liên miên.
Họ tái cấu trúc: model weights chuyển sang lưu trên object storage (MinIO tự host để tiết kiệm chi phí), Git chỉ giữ pointer qua DVC. Pipeline CI dùng caching (kỹ thuật bạn đã học ở bài Caching) để không tải lại model không cần thiết. Docker image serving được xây theo hướng tách biệt: layer code riêng, model được mount hoặc tải lúc khởi động chứ không nướng cứng vào image — nhờ vậy đổi model không phải build lại toàn bộ image.
Bài học: Artifact của ML nặng và có vòng đời riêng. Đừng đối xử với model weights như file code. Tách nó ra khỏi Git, lưu ở nơi phù hợp, và version nó một cách tường minh.
Hướng dẫn từng bước
Dưới đây là khung một pipeline CI/CD/CT cho ML mà bạn có thể dựng dần. Tôi mô tả theo mức khái niệm và một ví dụ GitHub Actions tối giản để bạn hình dung.
Bước 1 — Version hóa dữ liệu và model.
Cài DVC, khởi tạo và trỏ remote về S3/GCS/MinIO. Từ giờ dataset và model được theo dõi qua DVC, còn Git chỉ giữ file .dvc nhỏ.
dvc init
dvc remote add -d storage s3://mlops-vaynhanh/store
dvc add data/train.csv # tạo data/train.csv.dvc để commit vào Git
git add data/train.csv.dvc .gitignore
Bước 2 — CI: test cả code, data và model. Pipeline khi có Pull Request phải chạy ba loại kiểm tra: lint/unit test cho code (như bài trước), data validation (kiểm schema, giá trị null, phân bố bất thường — công cụ như Great Expectations), và model validation (huấn luyện nhanh hoặc load model rồi kiểm độ chính xác không được thấp hơn ngưỡng tối thiểu).
# .github/workflows/ml-ci.yml
name: ML CI
on: pull_request
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt dvc[s3]
- run: dvc pull # kéo data + model từ remote
- run: pytest tests/test_data.py # kiểm chất lượng dữ liệu
- run: python validate_model.py # AUC phải >= 0.75, nếu không thì fail
Bước 3 — Đăng ký model vào Registry. Khi huấn luyện xong, log experiment và đăng ký model vào MLflow Model Registry với trạng thái (Staging / Production). Ghi kèm mọi metadata: commit, data hash, hyperparameter, seed, metrics.
Bước 4 — CD: promote model qua các môi trường. Không deploy thẳng model mới ra 100% người dùng. Áp dụng đúng các chiến lược bạn đã học: đưa model lên staging, chạy smoke test dự đoán, rồi canary một tỷ lệ nhỏ traffic, so sánh metric thực tế trước khi mở rộng. Việc "thăng cấp" model từ Staging sang Production trong registry chính là quyết định release.
Bước 5 — Giám sát và Continuous Training. Sau khi model chạy production, thu thập log dự đoán, tính chỉ số drift (PSI, KS test), và theo dõi metric chất lượng nếu có nhãn thực tế đến sau (ví dụ: khoản vay có trả hay không). Khi drift vượt ngưỡng hoặc metric tụt, tự động kích hoạt lại pipeline huấn luyện từ Bước 2.
Lỗi thường gặp & mẹo
Nhét model weights và dataset vào Git. Đây là lỗi số một. Git không dành cho file nhị phân lớn. Hậu quả là repo phình to, clone chậm, CI hết đĩa. Dùng DVC hoặc Git LFS ngay từ đầu.
Quên khóa random seed. Không set seed thì mỗi lần huấn luyện ra một model khác, không tái tạo được, không debug được. Luôn cố định seed cho mọi thư viện liên quan (NumPy, framework ML, và cả seed của thao tác xáo trộn dữ liệu).
Training-serving skew — sai lệch giữa lúc huấn luyện và lúc phục vụ. Rất phổ biến: code tiền xử lý dữ liệu lúc huấn luyện khác với code tiền xử lý lúc phục vụ trên production (ví dụ chuẩn hóa số liệu theo công thức khác nhau). Kết quả là model chính xác trong thử nghiệm nhưng sai trên thực tế. Mẹo: dùng chung một module tiền xử lý cho cả hai giai đoạn.
Coi accuracy là chỉ số duy nhất. Một model dự đoán gian lận có thể đạt 99% accuracy bằng cách... luôn nói "không gian lận" (vì gian lận vốn hiếm). Với dữ liệu mất cân bằng, hãy dùng precision, recall, AUC thay vì chỉ accuracy, và đặt quality gate theo đúng chỉ số phù hợp bài toán.
Deploy model thẳng ra 100% traffic. Model không như một bản vá bug — bạn không chắc nó tốt hơn cho đến khi thấy dữ liệu thật. Luôn canary hoặc A/B trước.
Mẹo về chi phí: Huấn luyện ML tốn tài nguyên (đặc biệt là GPU). Đừng huấn luyện lại trên mọi commit như test code. Chỉ trigger CT khi thực sự cần: có dữ liệu mới đủ lớn, hoặc drift vượt ngưỡng, hoặc theo lịch định kỳ. Đây là điểm gặp nhau với bài Pipeline Cost Optimization.
Bài tập thực hành
- Phân loại thay đổi. Cho một dự án ML, hãy liệt kê 5 loại thay đổi có thể xảy ra (sửa code tiền xử lý, thêm dữ liệu mới, đổi hyperparameter, đổi kiến trúc model, cập nhật thư viện) và với mỗi loại, xác định: có cần huấn luyện lại không, và cần chạy lại những stage nào trong pipeline.
- Thiết kế reproducibility. Viết ra danh sách đầy đủ những thứ pipeline của bạn cần log lại để có thể tái tạo chính xác một model bất kỳ đã deploy. So với bốn yếu tố trong bài (code, data, hyperparameter, seed) — bạn còn thiếu gì cho dự án cụ thể của mình?
- Dựng DVC mini. Tạo một repo nhỏ, cài DVC, dùng
dvc addcho một file CSV, cấu hình remote (có thể dùng thư mục local làm remote để tập). Commit file.dvcvào Git, xóa file gốc, rồidvc pullđể kéo lại. Quan sát Git chỉ giữ pointer.
- Lên kịch bản phát hiện drift. Với tình huống ShopSea, hãy mô tả: bạn sẽ đo drift bằng chỉ số gì, tần suất đo ra sao, ngưỡng nào thì kích hoạt retraining, và làm sao tránh retraining quá thường xuyên gây tốn kém.
- Viết quality gate cho model. Giả sử bạn làm model chống gian lận cho ví điện tử. Hãy định nghĩa quality gate trong CI: chỉ số nào, ngưỡng bao nhiêu thì cho phép merge, và vì sao bạn không chọn accuracy làm chỉ số chính.
Tóm tắt
MLOps là DevOps áp dụng cho vòng đời model ML, và điểm mấu chốt là CD cho ML khác CD cho app ở ba chỗ. Thứ nhất, artifact không chỉ là code mà là bộ ba code + model weights + data, nên bạn cần công cụ version chuyên biệt (DVC, Git LFS, Model Registry) thay vì chỉ dựa vào Git. Thứ hai, reproducibility đòi hỏi khóa chặt bốn yếu tố: code, data, hyperparameter và random seed — thiếu một là không tái tạo được. Thứ ba, ML có kẻ thù riêng là drift: model tự xuống cấp dù bạn không đổi gì, nên pipeline phải có thêm vòng lặp Continuous Training — giám sát, phát hiện drift, huấn luyện lại và deploy an toàn qua canary.
Nếu bạn nắm vững nền tảng CI/CD từ các bài trước và bổ sung đúng ba tư duy này, bạn hoàn toàn có thể xây một pipeline ML vững vàng — như VayNhanh truy vết được mọi model, như ShopSea tự làm mới model theo mùa, và như VoiceVN quản lý artifact khổng lồ một cách gọn gàng. Đó chính là giá trị thực tế của MLOps.