Mục lục
- Mục Tiêu Bài Học
- Vấn Đề Data Versioning
- DVC Là Gì
- Cài Đặt và Init
- Track File Lớn
- Remote Storage — Push và Pull Data
- Versioning Data Qua Thời Gian
- Pipeline — DVC Stages
- Params và Metrics
- Experiment Tracking với DVC
- DVC + Git Workflow Thực Tế
- DVC vs Git LFS
- DVC vs MLflow Artifacts
- Ví Dụ End-to-End
- Common Pitfalls
- Tóm Tắt
- Bài Tiếp Theo
Mục Tiêu Bài Học
Sau bài này bạn sẽ:
- ✅ Hiểu tại sao data versioning cần tool riêng ngoài git
- ✅ Biết cách DVC track file lớn bằng metadata
.dvc - ✅ Cấu hình remote storage (S3, GCS, Azure, Google Drive)
- ✅ Định nghĩa pipeline ML bằng
dvc.yamlvà chạy vớidvc repro - ✅ So sánh DVC với Git LFS và MLflow Artifacts để chọn đúng tool
- ✅ Tránh các lỗi phổ biến khi dùng DVC trong team
Vấn Đề Data Versioning
Code ML đã có git để version. Nhưng dataset là file nhị phân hàng chục GB — git không thiết kế cho trường hợp đó.
Những câu hỏi không trả lời được nếu không version data
- "Model v2 train với data nào?" — không ai nhớ, không có record.
- "Accuracy tụt, data có thay đổi không?" — không biết, vì data không được track.
- "Reproduce kết quả bài báo từ 6 tháng trước" — code có, nhưng data đã overwrite.
Tại sao không dùng git cho data?
- Git lưu toàn bộ lịch sử dưới
.git/objects/. File 1 GB × 10 version = 10 GB trong repo. - GitHub/GitLab giới hạn file < 100 MB (hard limit). Push sẽ bị từ chối.
- Binary diff cho CSV / Parquet vô nghĩa — git không hiểu cấu trúc.
git clonechậm kinh khủng khi repo chứa data lớn.
Reproduce ML experiment cần gì?
Để reproduce một experiment, bạn cần đồng thời:
- Code state: git commit hash
- Data state: version dataset đúng
- Config state: hyperparameters, feature list
- Environment state: Python version, package versions
Git giải quyết code và config. DVC giải quyết data state — mỗi git commit có thể trỏ tới một version data cụ thể.
DVC Là Gì
DVC (Data Version Control) là tool CLI Python, mã nguồn mở (Apache 2.0), được thiết kế để bổ sung cho git — không thay thế nó.
Cơ chế cốt lõi
Khi bạn dvc add data/train.csv:
- DVC tính MD5 hash của file thật.
- File thật được copy vào
.dvc/cache/(local cache). - DVC tạo file
data/train.csv.dvc— text file nhỏ < 1 KB chứa hash + path. data/train.csvđược thêm vào.gitignoretự động.
File .dvc nhỏ thì commit được vào git. Mỗi git commit trỏ tới một hash data — đó là cách DVC tạo ra "version" cho data.
Các tính năng chính
- File tracking: Version dataset, model checkpoint, bất kỳ file/folder nào.
- Remote storage: Đẩy data ra S3, GCS, Azure Blob, Google Drive, SSH, NFS.
- Pipeline (DAG): Định nghĩa các stage trong
dvc.yaml, DVC tự cache và chỉ re-run stage nào có input thay đổi. - Experiment tracking: Branch-less experiment với
dvc exp run. - Metrics comparison: So sánh metric giữa các commit hoặc experiment.
Khi nào nên dùng DVC
- Dataset > 100 MB (threshold thực tế để thấy lợi ích).
- Team cần chia sẻ data qua remote storage mà không dùng manual download.
- Reproducibility là yêu cầu — cần biết chắc model train với data version nào.
- Pipeline có nhiều step (preprocessing → feature engineering → train → evaluate) cần cache từng bước.
Cài Đặt và Init
Cài đặt DVC 3.x
# Core DVC (không có remote backend)
pip install dvc # hiện tại 3.x
# Hoặc cài kèm plugin cho remote backend
pip install "dvc[s3]" # Amazon S3
pip install "dvc[gs]" # Google Cloud Storage
pip install "dvc[azure]" # Azure Blob Storage
pip install "dvc[gdrive]" # Google Drive
pip install "dvc[ssh]" # SSH/SFTP
# Cài nhiều backend cùng lúc
pip install "dvc[s3,gs]"
Init trong project
cd my-ml-project
git init # Nếu chưa có git repo
dvc init # Tạo .dvc/ và .dvcignore
# DVC tạo các file cần commit vào git
git add .dvc .dvcignore
git commit -m "init DVC"
Sau khi init, thư mục .dvc/ chứa:
.dvc/config— cấu hình remote, cache settings..dvc/cache/— local cache cho data (không commit vào git)..dvc/tmp/— lock file và temp state.
Kiểm tra version
dvc version
# DVC version: 3.x.x
# Platform: Python 3.x on Linux/macOS/Windows
Track File Lớn
Thêm file vào DVC tracking
# Có file dataset 1 GB
dvc add data/train.csv
# DVC output:
# To track the changes with git, run:
# git add data/train.csv.dvc data/.gitignore
Lệnh này thực hiện:
- Copy
data/train.csvvào.dvc/cache/(symlink hoặc hardlink tuỳ OS). - Tạo
data/train.csv.dvcvới nội dung khoảng 5 dòng. - Cập nhật
data/.gitignoređể git bỏ quatrain.csv.
Nội dung file .dvc
# data/train.csv.dvc (ví dụ)
outs:
- md5: a3b4c5d6e7f8...
size: 1073741824
path: train.csv
Commit metadata vào git
git add data/train.csv.dvc data/.gitignore
git commit -m "track train.csv with DVC"
Track cả thư mục
# Track cả folder images/
dvc add data/images/
# DVC tạo data/images.dvc (track toàn bộ thư mục)
git add data/images.dvc data/.gitignore
git commit -m "track images directory with DVC"
Lấy lại data
# Nếu xoá hoặc checkout git commit khác
# Lấy lại data tương ứng với git commit hiện tại
dvc checkout
Remote Storage — Push và Pull Data
Local cache chỉ trên máy bạn. Remote storage cho phép team chia sẻ data.
Cấu hình remote
# S3
dvc remote add -d storage s3://my-bucket/dvc-storage
dvc remote modify storage region us-east-1
# Credentials qua AWS CLI hoặc env: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
# Google Cloud Storage
dvc remote add -d storage gs://my-gcs-bucket/dvc
# Credentials qua gcloud auth application-default login
# Azure Blob Storage
dvc remote add -d storage azure://mycontainer/dvc
dvc remote modify storage connection_string "DefaultEndpointsProtocol=https;..."
# Google Drive (cho team nhỏ không có cloud)
dvc remote add -d gdrive gdrive://folder-id-from-url
# Local path (NFS, network share, hay test)
dvc remote add -d localstore /mnt/data/dvc-cache
Flag -d đặt remote này làm default. Cấu hình lưu vào .dvc/config.
Push data lên remote
dvc push
# Uploads files in local cache to remote storage
# Push một file cụ thể
dvc push data/train.csv.dvc
Pull data từ remote
# Member mới clone repo
git clone https://github.com/your-org/ml-project
cd ml-project
# Lấy data version tương ứng với HEAD
dvc pull
# hoặc explicit:
dvc pull data/train.csv.dvc
Lưu ý về credentials
Không commit credentials vào .dvc/config. Dùng một trong:
- Environment variable:
AWS_ACCESS_KEY_ID,GOOGLE_APPLICATION_CREDENTIALS. - IAM Role / Workload Identity (production).
dvc remote modify --local storage access_key_id AKIA...— lưu vào.dvc/config.local(không commit).
Versioning Data Qua Thời Gian
Cập nhật dataset
# Thêm rows mới vào train.csv hoặc replace hoàn toàn
# Sau khi file thay đổi:
dvc add data/train.csv # Tính lại hash mới, update .dvc file
git add data/train.csv.dvc
git commit -m "update dataset v2: thêm 5000 samples tháng 5/2026"
dvc push # Upload version mới lên remote
Mỗi git commit giờ có một hash data khác nhau trong train.csv.dvc. Remote lưu cả hai version — không xoá version cũ.
Quay lại version data cũ
# Checkout git commit cũ
git checkout HEAD~1
# Lấy data tương ứng với commit đó
dvc checkout
# Bây giờ data/train.csv = version trước khi thêm 5000 samples
Diff giữa 2 version
# Xem data hash thay đổi như thế nào giữa 2 commit
dvc diff HEAD~1
# Output:
# Modified:
# data/train.csv
# (old: a3b4c5d6..., new: f1e2d3c4...)
Pipeline — DVC Stages
DVC pipeline cho phép định nghĩa workflow ML dạng DAG (directed acyclic graph). Mỗi stage có cmd (lệnh chạy), deps (dependencies), và outs (outputs).
Cấu trúc dvc.yaml
# dvc.yaml
stages:
prepare:
cmd: python src/prepare.py
deps:
- data/raw.csv
- src/prepare.py
outs:
- data/clean.csv
featurize:
cmd: python src/featurize.py
deps:
- data/clean.csv
- src/featurize.py
outs:
- data/features.csv
train:
cmd: python src/train.py
deps:
- data/features.csv
- src/train.py
params:
- params.yaml:
- lr
- epochs
- batch_size
outs:
- model/model.pkl
metrics:
- metrics.json:
cache: false # Không cache, lưu plain vào git
Chạy pipeline
# Chạy toàn bộ pipeline (chỉ stage nào cần thiết)
dvc repro
# DVC kiểm tra: deps có thay đổi? params có đổi? code có đổi?
# Nếu không → skip stage (dùng cache)
# Nếu có → re-run stage đó và tất cả stage downstream
Ví dụ output khi chạy với cache hit:
Stage 'prepare' didn't change, skipping
Stage 'featurize' didn't change, skipping
Running stage 'train':
> python src/train.py
Generating lock file 'dvc.lock'
Updating lock file 'dvc.lock'
dvc.lock
Sau khi dvc repro, DVC tạo dvc.lock — ghi lại hash của tất cả deps, outs, params tại thời điểm chạy. Commit dvc.lock vào git để snapshot trạng thái pipeline.
git add dvc.lock
git commit -m "run pipeline: train với lr=0.01 epochs=10"
dvc push # Push các output mới (model.pkl) lên remote
Thêm stage qua CLI (thay vì edit dvc.yaml tay)
dvc stage add -n prepare \
-d data/raw.csv -d src/prepare.py \
-o data/clean.csv \
python src/prepare.py
Params và Metrics
params.yaml
# params.yaml
lr: 0.01
epochs: 10
batch_size: 32
model_type: random_forest
max_depth: 5
Script Python đọc params:
# src/train.py
import yaml
import json
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import pandas as pd
import pickle
with open("params.yaml") as f:
params = yaml.safe_load(f)
# Train
df = pd.read_csv("data/features.csv")
X, y = df.drop("label", axis=1), df["label"]
model = RandomForestClassifier(
max_depth=params["max_depth"],
random_state=42
)
model.fit(X, y)
acc = accuracy_score(y, model.predict(X))
# Log metrics
with open("metrics.json", "w") as f:
json.dump({"accuracy": acc}, f, indent=2)
# Save model
with open("model/model.pkl", "wb") as f:
pickle.dump(model, f)
So sánh metrics
# Xem metrics hiện tại
dvc metrics show
# Path accuracy
# metrics.json 0.9234
# So sánh với commit trước
dvc metrics diff HEAD~1
# Path Metric Old New Change
# metrics.json accuracy 0.908 0.923 +0.015
# So sánh với branch khác
dvc metrics diff main
Experiment Tracking với DVC
DVC 2.x trở lên có dvc exp — experiment tracking không cần tạo branch. Phù hợp cho hyperparameter sweep nhanh.
Chạy experiment với param khác
# Giữ nguyên code, thay đổi param
dvc exp run --set-param lr=0.001
dvc exp run --set-param lr=0.0001 --set-param epochs=20
dvc exp run --set-param max_depth=10
Xem kết quả tất cả experiments
dvc exp show
# Kết quả dạng bảng:
# Experiment lr epochs max_depth accuracy
# workspace 0.01 10 5 0.9234
# exp-a1b2c3 0.001 10 5 0.9301
# exp-d4e5f6 0.0001 20 5 0.9287
# exp-g7h8i9 0.01 10 10 0.9356
Apply experiment tốt nhất vào workspace
dvc exp apply exp-g7h8i9
# Cập nhật params.yaml và dvc.lock theo experiment đó
git add params.yaml dvc.lock
git commit -m "use max_depth=10, accuracy=0.9356"
dvc push
Lưu experiment thành branch
dvc exp branch exp-g7h8i9 feat/max-depth-10
git checkout feat/max-depth-10
DVC experiment tracking nhẹ hơn MLflow nhưng không có UI web. Phù hợp cho individual hoặc team nhỏ. Với team lớn cần UI, MLflow (bài 40) phù hợp hơn — hai tool có thể dùng song song.
DVC + Git Workflow Thực Tế
Workflow phát triển tính năng mới
# 1. Tạo branch mới
git checkout -b feature/new-architecture
# 2. Cập nhật code và/hoặc data
# - Edit src/train.py
# - Thêm data mới: dvc add data/train_v2.csv
# 3. Chạy pipeline
dvc repro
# 4. Commit tất cả
git add dvc.lock src/train.py params.yaml
git commit -m "experiment: new architecture, accuracy=0.941"
# 5. Push data lên remote TRƯỚC khi push git
dvc push
git push -u origin feature/new-architecture
Lưu ý: Luôn dvc push trước git push. Nếu git commit có trên remote mà data chưa push, CI/CD hoặc teammate sẽ không dvc pull được.
Onboard member mới
git clone https://github.com/your-org/ml-project
cd ml-project
# Cấu hình credentials cho remote (một lần)
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
# Lấy data version tương ứng HEAD
dvc pull
# Reproduce pipeline (optional, dùng cache nếu không cần re-train)
dvc repro
CML — Continuous ML (giới thiệu)
CML (Continuous Machine Learning) là tool của Iterative (cùng tổ chức với DVC) để tích hợp pipeline DVC vào GitHub Actions / GitLab CI. Khi mở Pull Request, CI tự chạy dvc repro và comment metric comparison vào PR. Chi tiết sẽ ở bài 44.
DVC vs Git LFS
| Tiêu chí | Git LFS | DVC |
|---|---|---|
| Mục đích chính | Lưu file lớn trong git repo | Version data + model + định nghĩa pipeline ML |
| Storage backend | LFS server (GitHub, GitLab tích hợp sẵn) | S3, GCS, Azure, Drive, SSH, NFS, ... |
| Pipeline / DAG | Không có | Có (dvc.yaml, dvc repro) |
| Experiment tracking | Không có | Có (dvc exp run, dvc exp show) |
| Metrics comparison | Không có | Có (dvc metrics diff) |
| Chi phí storage | Trả theo LFS bandwidth + storage (GitHub Free: 1 GB) | Trả theo cloud storage backend bạn chọn |
| Dùng cho ML | Không tối ưu — thiếu pipeline, thiếu metrics | Thiết kế cho ML workflow |
| Dùng cho asset binary (font, image UI, ...) | Phù hợp — tích hợp sâu vào git clone | Có thể dùng nhưng overkill |
Hướng dẫn chọn: nếu file là binary asset cho frontend/design (icon, font, video) → Git LFS. Nếu file là dataset hoặc model checkpoint → DVC.
DVC vs MLflow Artifacts
MLflow (bài 40) và DVC đều có thể lưu model artifact. Điểm khác biệt:
| Tiêu chí | MLflow Artifacts | DVC |
|---|---|---|
| Versioning data (dataset lớn) | Không trực tiếp — MLflow không thiết kế cho raw dataset | Có, đây là use case chính |
| Model versioning | Có (MLflow Model Registry) | Có (track model file như DVC output) |
| Pipeline definition | Có (MLflow Projects) nhưng ít phổ biến | Có (dvc.yaml), phổ biến hơn |
| UI web | Có (MLflow UI đẹp, nhiều chart) | Không có built-in (dùng DVC Studio — bản cloud có phí) |
| Tích hợp với git | Lỏng — không phụ thuộc git | Chặt — metadata .dvc file lưu trong git |
| Dùng song song | Được — DVC cho data + pipeline, MLflow cho experiment metrics + model registry | |
Pattern phổ biến trong production: DVC track dataset và define pipeline, MLflow log metrics và manage model lifecycle (staging → production). Hai tool không conflict nhau.
Ví Dụ End-to-End
Cấu trúc project
ml-project/
├── .dvc/
│ ├── config # Remote storage config
│ └── cache/ # Local cache (không commit)
├── .dvcignore
├── data/
│ ├── raw.csv # Không commit (trong .gitignore)
│ ├── raw.csv.dvc # Commit vào git
│ └── .gitignore
├── model/
│ ├── model.pkl # Không commit
│ └── .gitignore
├── src/
│ ├── prepare.py
│ └── train.py
├── dvc.yaml
├── dvc.lock # Commit vào git
├── params.yaml
└── metrics.json
Quy trình từ đầu đến cuối
# Bước 1: Setup
git init && dvc init
dvc remote add -d storage s3://my-bucket/dvc
git add .dvc .dvcignore
git commit -m "init DVC"
# Bước 2: Track raw data
dvc add data/raw.csv
git add data/raw.csv.dvc data/.gitignore
git commit -m "add raw dataset (50k samples)"
dvc push
# Bước 3: Define pipeline
# → Tạo dvc.yaml (như ví dụ section 8)
# → Tạo params.yaml
# → Viết src/prepare.py và src/train.py
# Bước 4: Run pipeline
dvc repro
# Bước 5: Commit kết quả
git add dvc.lock dvc.yaml params.yaml src/ metrics.json
git commit -m "pipeline: prepare + train, accuracy=0.923"
dvc push
# === Reproduce trên máy khác ===
git clone https://github.com/your-org/ml-project
cd ml-project
dvc pull # Download data/raw.csv và model/model.pkl
dvc repro # Chạy lại pipeline, kết quả y hệt
Common Pitfalls
1. git add data thực thay vì .dvc file
Sau dvc add data/train.csv, file thật đã được add vào .gitignore. Nếu bạn vẫn cố git add data/train.csv, git sẽ ignore vì entry trong .gitignore. Nhưng nếu đã từng commit file thật trước khi init DVC, cần git rm --cached data/train.csv.
2. Commit credentials vào .dvc/config
# SAI: credentials trong config → commit lên git → lộ
dvc remote modify storage access_key_id AKIA...
# ĐÚNG: dùng --local để lưu vào .dvc/config.local (gitignore)
dvc remote modify --local storage access_key_id AKIA...
# Hoặc dùng environment variable
export AWS_ACCESS_KEY_ID=AKIA...
3. Quên dvc push trước git push
Khi teammate chạy git pull rồi dvc pull, DVC cần tìm data hash tương ứng trên remote. Nếu chưa push, dvc pull thất bại với lỗi ERROR: failed to pull data. CI/CD cũng sẽ fail tương tự.
Thứ tự bắt buộc: dvc push → git push.
4. .dvcignore không setup
.dvcignore tương tự .gitignore nhưng cho DVC cache. Nếu không cấu hình, DVC có thể cache cả file log, temp, hoặc thư mục không cần thiết.
# .dvcignore ví dụ
logs/
*.log
__pycache__/
.DS_Store
5. Pipeline DAG có cycle
Nếu stage A depend vào output của stage B, và B depend vào output của A → DVC sẽ báo lỗi khi dvc repro. Kiểm tra bằng dvc dag để visualize graph trước khi chạy.
dvc dag # ASCII art DAG trong terminal
dvc dag --md # Markdown format (cho README)
6. Local cache quá lớn
Mỗi lần dvc add hoặc dvc repro, file được copy vào .dvc/cache/. Sau nhiều version, cache có thể chiếm hàng chục GB. Dùng dvc gc để cleanup:
# Xoá cache entries không dùng bởi bất kỳ branch/tag nào
dvc gc --all-branches --all-tags
# Xem size cache trước khi gc
du -sh .dvc/cache/
7. dvc repro không chạy lại stage dù code đổi
DVC track deps bằng file path. Nếu script import module không nằm trong deps, DVC không biết. Thêm tất cả Python file liên quan vào deps:
stages:
train:
cmd: python src/train.py
deps:
- src/train.py
- src/model.py # Module import trong train.py
- src/utils.py # Cần thêm vào deps
- data/features.csv
Tóm Tắt
- ✅ DVC track file lớn bằng file
.dvcnhỏ (metadata) trong git, data thật ở local cache và remote storage. - ✅ Mỗi git commit trỏ tới một version data cụ thể —
git checkout+dvc checkoutđể quay về trạng thái cũ. - ✅ Remote storage:
dvc remote add,dvc push,dvc pull. Thứ tự: push data trước khi push git. - ✅
dvc.yamlđịnh nghĩa pipeline DAG,dvc reprochạy stage nào cần thiết và cache stage không đổi. - ✅
params.yaml+metrics.json+dvc metrics diffđể so sánh kết quả giữa các run. - ✅
dvc exp runcho hyperparameter sweep không cần tạo branch. - ✅ DVC và MLflow có thể dùng song song: DVC cho data + pipeline, MLflow cho experiment UI + model registry.
- ✅ Credentials không commit vào
.dvc/config— dùng--localhoặc env variable.
