Versiune seturi de date și modele ML: DVC în producție
Imaginați-vă că antrenați un model care atinge o precizie de 94%, lansându-l în producție și apoi descoperi trei luni mai târziu că nimeni nu știe exact ce versiune a setului de date a fost folosită, ne care hiperparametri erau activi. Modelul este în producție, dar este ireproductibil. Acest scenariu, din păcate, este mai degrabă norma decât excepția în echipele ML care nu adoptă practici de versiuni structurate.
Versiunea în MLOps nu este doar despre fișierele de cod: este vorba doar despre seturi de date, modele, conducte și configurații. Git gestionează foarte bine codul sursă, dar nu reușește cu sute de fișiere GB tipice pentru seturile de date ML. Și aici intră în joc DVC (Versiune de date control), instrumentul open-source care aduce principiile Git în lumea datelor și modele de învățare automată.
În noiembrie 2025, lakeFS a achiziționat DVC, confirmând centralitatea acestui instrument în ecosistemul MLOps și asigurând continuitatea acestuia ca proiect 100% open-source. In aceasta articol vom explora DVC în profunzime: configurare, conductă, stocare la distanță, integrare Git și MLflow, comparație cu lakeFS și bune practici pentru echipe de orice dimensiune.
Ce veți învăța în acest articol
- de ce versiunea este fundamentală în MLOps și ce o diferențiază de versiunea de cod
- Configurare DVC completă: inițializare, urmărire a datelor, fișiere automate .dvc și .gitignore
- Conductă DVC cu dvc.yaml: etape, deps, ieșiri, parametri și fișierul dvc.lock
- Stocare la distanță: Configurare pentru AWS S3, Google Cloud Storage și Azure Blob Storage
- DVC Python API: dvc.api.open() și dvc.api.get_url() pentru acces programatic
- Integrare DVC + MLflow pentru a lega versiunea setului de date la experimente
- Comparație arhitecturală DVC vs lakeFS: când să folosiți ce instrument
- Cele mai bune practici pentru echipele ML cu bugete limitate (<5K EUR/an)
Seria MLOps și Machine Learning în producție
| # | Articol | Concentrează-te |
|---|---|---|
| 1 | MLOps: de la experiment la producție | Bazele și ciclul de viață complet |
| 2 | Conducta ML cu CI/CD | GitHub Actions și Docker pentru ML |
| 3 | Sunteți aici - Versiune DVC vs LakeFS | Seturi de date și versiunea modelului |
| 4 | Urmărirea experimentelor cu MLflow | Urmărire, registru model, comparație |
| 5 | Detectarea derivei modelului | Monitorizare automată și recalificare |
| 6 | Servire cu FastAPI + Uvicorn | Implementarea modelelor în producție |
| 7 | Scalare ML pe Kubernetes | KubeFlow și Seldon Core |
| 8 | Testarea A/B a modelelor ML | Metodologie și implementare |
| 9 | Guvernarea ML | Conformitate, AI Act UE, etică |
| 10 | Studiu de caz: Predicția abandonului | Conductă de la capăt la capăt în producție |
Problema versiunilor în Machine Learning
Într-un proiect software tradițional, Git rezolvă aproape toate problemele de versiuni: codul Este ușor, textual și se pretează în mod natural să se diferențieze și să fuzioneze. Într-un proiect ML, totuși, codul este doar o parte a ecuației. Reproductibilitatea unui model necesită urmărire simultan:
- Seturi de date de instruire și validare: Adesea gigabytes sau terabytes de date structurate sau nestructurate
- Artefacte model: fișiere .pkl, .pt, .h5 care pot cântări sute de MB
- Hiperparametri și configurații: rata de învățare, arhitectură, pași de preprocesare
- Metrici și rezultate: precizie, F1, AUC-ROC pentru fiecare experiment
- Dependențe de mediu: versiunea Python, biblioteci, drivere CUDA
Git nu este conceput pentru fișiere binare mari: fiecare apăsare a unui model de 500 MB ar clona întreaga istorie, făcând depozitul inutilizabil în câteva luni. Solutia nu pentru a renunța la versiunea, ci pentru a folosi instrumentul potrivit pentru fiecare tip de artefact.
Costul lipsei versiunilor ML
| Scenariu | Cost fără versiuni | Soluție DVC |
|---|---|---|
| Model de producție degradat | Nu se poate reveni la modelul anterior | git checkout + dvc checkout |
| Setul de date corupt în conductă | Re-descărcați și procesați de la zero | dvc checkout setul de date anterior |
| Audit de reglementare (AI Act EU) | Este imposibil de demonstrat care date au format modelul | Hash al setului de date reprezentat în fișierul .dvc |
| Colaborarea în echipă | Fiecare cercetător de date utilizează versiuni diferite ale datelor | dvc pull sincronizează întreaga echipă |
| Reproducerea experimentală | Rezultatele nu pot fi reproduse după 6 luni | git checkout + dvc repro reconstruiește totul |
Configurare și configurare DVC
DVC se integrează într-un depozit Git existent ca un strat suplimentar. Nu necesită un server central, rulează local și se adaptează cu ușurință la stocarea în cloud pe măsură ce echipa crește. Instalarea se face prin pip, cu suport pentru diferite backend-uri de stocare:
# Installazione base
pip install dvc
# Con supporto remote storage (scegli in base al provider)
pip install dvc[s3] # Amazon S3
pip install dvc[gs] # Google Cloud Storage
pip install dvc[azure] # Azure Blob Storage
pip install dvc[ssh] # SSH/SFTP
pip install dvc[all] # Tutti i backend
# Verifica installazione
dvc --version
# DVC 3.x.x
Odată instalat, inițializați DVC în depozitul Git. Comanda creează structura directorul necesar și actualizează automat .gitignore pentru a exclude fișierele de date din urmărirea Git:
# Inizializza Git (se non già fatto)
git init
git add .
git commit -m "Initial commit"
# Inizializza DVC
dvc init
# Struttura creata da dvc init:
# .dvc/
# ├── config # Configurazione DVC (tracciato da Git)
# ├── .gitignore # Esclude cache e tmp
# ├── cache/ # Cache locale degli artefatti (NON tracciata da Git)
# └── tmp/
# Commit dei file di configurazione DVC
git add .dvc/ .gitignore
git commit -m "chore: initialize DVC"
Urmărirea seturilor de date și a modelelor
Inima DVC și comanda dvc add, care funcționează similar cu
git add dar pentru fișiere mari. DVC calculează hash-ul MD5 al fișierului,
îl mută în memoria cache locală și creează un fișier .dvc (un fișier text mic
urmărit de Git) indicând hash:
# Aggiungere un dataset al tracking DVC
dvc add data/raw/training_data.csv
# DVC ha creato:
# - data/raw/training_data.csv.dvc (puntatore, tracciato da Git)
# - data/raw/.gitignore (esclude il file originale da Git)
# Contenuto del file .dvc generato:
# outs:
# - md5: a1b2c3d4e5f6...
# size: 524288000
# path: training_data.csv
# Aggiungere il puntatore a Git
git add data/raw/training_data.csv.dvc data/raw/.gitignore
git commit -m "feat: add training dataset v1.0"
git tag "dataset-v1.0"
# Aggiungere un modello addestrato
dvc add models/churn_model.pkl
git add models/churn_model.pkl.dvc models/.gitignore
git commit -m "feat: add trained churn model v1 (accuracy=0.94)"
git tag "model-v1.0"
Cum funcționează fișierul .dvc
Dosarul .dvc și un fișier YAML ușor care conține hash-ul MD5 (sau SHA-256) al fișierului
conținutul fișierului original, dimensiunea acestuia și calea relativă. Acest hash este determinist:
același fișier produce întotdeauna același hash, făcând posibilă verificarea integrității fișierului
date în orice moment. Git urmărește .dvc fișier, în timp ce fișierul de date
vieți reale în memoria cache DVC locală sau stocare la distanță.
Flux de lucru zilnic cu DVC
Fluxul de lucru tipic cu DVC urmează ciclul Git, cu adăugarea de dvc push e
dvc pull pentru a sincroniza datele cu stocarea la distanță:
# Workflow DVC quotidiano
# 1. Pull dati aggiornati dal remote
git pull
dvc pull
# 2. Modifica dataset o allena nuovo modello
python scripts/preprocess.py
python scripts/train.py
# 3. Traccia nuovi artefatti
dvc add data/processed/features.parquet
dvc add models/churn_model_v2.pkl
# 4. Commit codice e puntatori
git add .
git commit -m "feat: retrain model with new features (F1=0.92)"
# 5. Push dati al remote storage
dvc push
# 6. Push codice a Git
git push
# ---- Sul computer di un collega ----
git pull # Scarica codice e .dvc files
dvc pull # Scarica i dati dal remote storage
Stocare la distanță: S3, GCS și Azure
Stocarea de la distanță este inima colaborării la DVC. Fără el, datele există doar local și versiunea nu aduce beneficii echipei. DVC acceptă toate cele majore furnizori de cloud și, de asemenea, soluții on-premise prin SSH sau NFS.
# ==================== AWS S3 ====================
# Prerequisiti: pip install dvc[s3], AWS credentials configurate
# Aggiungere S3 come remote di default
dvc remote add -d myremote s3://my-ml-bucket/dvc-storage
# Configurazione con access keys (per CI/CD, preferire IAM roles)
dvc remote modify myremote access_key_id $AWS_ACCESS_KEY_ID
dvc remote modify myremote secret_access_key $AWS_SECRET_ACCESS_KEY
dvc remote modify myremote region eu-west-1
# Per credenziali sensibili, usare config locale (non tracciata da Git)
dvc remote modify --local myremote access_key_id $AWS_ACCESS_KEY_ID
dvc remote modify --local myremote secret_access_key $AWS_SECRET_ACCESS_KEY
# ==================== Google Cloud Storage ====================
# Prerequisiti: pip install dvc[gs], gcloud auth configurato
dvc remote add -d gcsremote gs://my-ml-bucket/dvc-storage
# Con Service Account (per produzione)
dvc remote modify gcsremote credentialpath /path/to/service-account.json
# ==================== Azure Blob Storage ====================
# Prerequisiti: pip install dvc[azure]
dvc remote add -d azureremote azure://mycontainer/dvc-storage
# Configurazione connection string
dvc remote modify --local azureremote connection_string $AZURE_CONN_STRING
# ==================== Verifica e Operazioni ====================
# Mostra la configurazione remota
dvc remote list
# Push di tutti gli artefatti tracciati
dvc push
# Push solo di file specifici
dvc push models/churn_model.pkl.dvc
# Pull di tutti gli artefatti
dvc pull
# Verifica stato sincronizzazione
dvc status --cloud
Securitatea acreditărilor
Nu plasați niciodată acreditările AWS, GCS sau Azure în fișier .dvc/config urmărite
din Git. Utilizați întotdeauna --local a scrie în .dvc/config.local
(ignorat automat de Git) sau configurați acreditările prin variabile
mediul sau rolurile IAM în sistemele CI/CD. Într-o arhitectură Kubernetes, utilizați i
ServiceAccount cu IRSA (IAM Roles for Service Accounts) pentru acces securizat la S3 fără
acreditări hardcoded.
Configurare pentru buget limitat: DagsHub ca alternativă gratuită
Pentru echipele cu bugete <5K EUR/an, DagsHub oferă găzduire gratuită pentru stocarea la distanță DVC (până la 10 GB per depozit public) cu integrare nativă pentru MLflow. Și o soluție excelent pentru startup-uri și echipe academice:
# DagsHub come remote storage gratuito
# 1. Crea account su dagshub.com e un nuovo repository
# 2. Configura il remote DagsHub
dvc remote add origin https://dagshub.com/username/my-ml-project.dvc
# 3. Autenticazione con token personale
dvc remote modify origin --local auth basic
dvc remote modify origin --local user username
dvc remote modify origin --local password $DAGSHUB_TOKEN
# 4. Push e pull normali
dvc push
dvc pull
DVC Pipeline: reproductibilitate cu dvc.yaml
Conductele sunt cea mai puternică caracteristică a DVC: vă permit să definiți un flux de lucru Completează ML ca o serie de stagiu dependente una de alta. DVC urmărește dependențe între etape și reluări numai cele a căror intrare s-a schimbat, similar cu a Makefile inteligent pentru învățarea automată.
Conducta este definită într-un fișier dvc.yaml și starea acesteia (haș de toate
intrări și ieșiri) și trasate în dvc.lock. Când alergi
dvc repro, DVC compară starea curentă cu dvc.lock e
reefectuează doar etapele invalidate.
# dvc.yaml - Pipeline ML completa per churn prediction
stages:
# Stage 1: Download e validazione dei dati raw
fetch_data:
cmd: python src/data/fetch_data.py
deps:
- src/data/fetch_data.py
params:
- data.source_url
- data.date_range
outs:
- data/raw/transactions.parquet
- data/raw/customers.csv
# Stage 2: Preprocessing e feature engineering
preprocess:
cmd: python src/features/preprocess.py
deps:
- src/features/preprocess.py
- data/raw/transactions.parquet
- data/raw/customers.csv
params:
- features.window_days
- features.aggregations
outs:
- data/processed/features.parquet
- data/processed/feature_names.json
# Stage 3: Split train/validation/test
split:
cmd: python src/data/split.py
deps:
- src/data/split.py
- data/processed/features.parquet
params:
- split.train_ratio
- split.val_ratio
- split.random_seed
outs:
- data/splits/train.parquet
- data/splits/val.parquet
- data/splits/test.parquet
# Stage 4: Training del modello
train:
cmd: python src/models/train.py
deps:
- src/models/train.py
- data/splits/train.parquet
- data/splits/val.parquet
params:
- model.type
- model.n_estimators
- model.max_depth
- model.learning_rate
outs:
- models/churn_model.pkl
- models/feature_importance.json
metrics:
- metrics/train_metrics.json:
cache: false
# Stage 5: Valutazione sul test set
evaluate:
cmd: python src/models/evaluate.py
deps:
- src/models/evaluate.py
- models/churn_model.pkl
- data/splits/test.parquet
outs:
- reports/confusion_matrix.png:
cache: false
metrics:
- metrics/test_metrics.json:
cache: false
Parametrii conductei sunt definiți într-un fișier params.yaml, care este
urmărit de Git. Acest lucru vă permite să comparați experimente cu diferiți hiperparametri
folosind dvc params diff:
# params.yaml - Configurazione centralizzata
data:
source_url: "s3://my-data-bucket/raw/2025/"
date_range: "2024-01-01:2025-01-01"
features:
window_days: 30
aggregations:
- mean
- std
- max
split:
train_ratio: 0.7
val_ratio: 0.15
random_seed: 42
model:
type: "xgboost"
n_estimators: 500
max_depth: 6
learning_rate: 0.05
subsample: 0.8
Rulați și gestionați conducta
# Eseguire l'intera pipeline (solo stage invalidati)
dvc repro
# Forzare ri-esecuzione di tutti gli stage
dvc repro --force
# Eseguire solo fino a uno stage specifico
dvc repro evaluate
# Visualizzare il DAG della pipeline
dvc dag
# Output:
# +------------+
# | fetch_data |
# +------------+
# * *
# *** ***
# * *
# +-----------+ +----------+
# | preprocess| | |
# +-----------+ +----------+
# *
# ...
# Confrontare metriche tra commit
dvc metrics show
dvc metrics diff HEAD~1
# Confrontare parametri tra branch
dvc params diff main feature/new-model
# Visualizzare differenze nei dati
dvc diff
API-ul Python al DVC: Acces programatic la date
API-ul Python al DVC vă permite să accesați direct seturi de date și modele versiuni din codul Python, fără a fi nevoie să descărcați mai întâi fișierele manual. Și deosebit de util în conducte de inferență sau în sisteme de deservire în care doriți să încărcați dinamic versiunea corectă a modelului.
import dvc.api
import pandas as pd
import pickle
import json
# ==================== dvc.api.open() ====================
# Accede direttamente al remote storage senza download locale
# Leggere un dataset CSV da una versione specifica
with dvc.api.open(
"data/raw/customers.csv",
repo="https://github.com/myorg/ml-project",
rev="dataset-v2.1", # tag Git
mode="r"
) as f:
df = pd.read_csv(f)
print(f"Dataset caricato: {len(df)} righe")
# Leggere un file Parquet (file binario)
with dvc.api.open(
"data/processed/features.parquet",
rev="model-v3.0",
mode="rb"
) as f:
features_df = pd.read_parquet(f)
# ==================== dvc.api.get_url() ====================
# Ottiene l'URL diretto al remote storage per una versione specifica
url = dvc.api.get_url(
"models/churn_model.pkl",
repo="https://github.com/myorg/ml-project",
rev="model-v2.5"
)
print(f"Model URL: {url}")
# Output: s3://my-ml-bucket/dvc-storage/ab/cd1234...
# ==================== Caricamento Modello Versioned ====================
def load_model(version: str):
"""Carica un modello da una specifica versione DVC."""
with dvc.api.open(
"models/churn_model.pkl",
rev=version,
mode="rb"
) as f:
model = pickle.load(f)
# Carica anche i metadata del modello
with dvc.api.open(
"models/feature_importance.json",
rev=version,
mode="r"
) as f:
metadata = json.load(f)
return model, metadata
# Uso in produzione
model, metadata = load_model("model-v3.0")
print(f"Modello caricato. Features: {metadata['n_features']}")
Integrarea DVC cu Git: fluxul de lucru complet
Adevărata putere a DVC apare atunci când se integrează profund cu Git. Fiecare comitere Git
care actualizează un fișier .dvc o dvc.lock reprezintă un instantaneu
reproductibil al întregii stări ale proiectului ML: cod, date și modele împreună.
# Workflow Git+DVC per un ciclo di sviluppo ML
# ==================== Feature Branch Workflow ====================
# 1. Crea un branch per il nuovo esperimento
git checkout -b experiment/xgboost-v2
# 2. Aggiorna i parametri
# Modifica params.yaml: learning_rate: 0.01, n_estimators: 1000
# 3. Esegui la pipeline
dvc repro
# 4. Controlla le metriche
dvc metrics show
# Path accuracy f1_score auc_roc
# metrics/test_metrics.json 0.9423 0.8891 0.9234
# 5. Confronta con main
dvc metrics diff main
# Path Metric Old New Change
# metrics/test_metrics.json accuracy 0.9301 0.9423 +0.0122
# 6. Commit e push
git add dvc.lock params.yaml metrics/
git commit -m "experiment: XGBoost v2 - accuracy +1.2% (0.9423)"
dvc push
git push origin experiment/xgboost-v2
# 7. Crea Pull Request e, dopo merge, tagga il modello
git checkout main
git merge experiment/xgboost-v2
git tag -a "model-v2.0" -m "XGBoost v2: accuracy=0.9423, F1=0.8891"
git push --tags
# ==================== Rollback a Versione Precedente ====================
# Situazione: il modello v2.0 ha un bug in produzione
# 1. Torna al commit del modello v1.0
git checkout model-v1.0
# 2. Ripristina i dati e i modelli a quella versione
dvc checkout
# 3. Verifica il modello ripristinato
python src/models/evaluate.py
# 4. Il sistema di serving può ora ricaricare model-v1.0
DVC + MLflow: Versiunea setului de date și Urmărirea experimentelor
DVC și MLflow se completează reciproc: DVC gestionează versiunea datelor și modelului (artefacte mari), în timp ce MLflow urmărește parametrii, valorile și derularea experimentelor. Integrarea acestora înseamnă a avea o pistă de audit completă: pentru fiecare rulați MLflow, știți exact ce versiune a setului de date a fost folosită.
import mlflow
import mlflow.sklearn
import dvc.api
import subprocess
import pandas as pd
from sklearn.metrics import accuracy_score, f1_score, roc_auc_score
from xgboost import XGBClassifier
def get_dvc_metadata() -> dict:
"""Raccoglie metadata DVC per il run MLflow corrente."""
# Hash del dataset corrente
result = subprocess.run(
["dvc", "status", "--json"],
capture_output=True, text=True
)
# Ottieni la revisione Git corrente (che punta ai dati)
git_rev = subprocess.run(
["git", "rev-parse", "HEAD"],
capture_output=True, text=True
).stdout.strip()
# URL del remote storage per il dataset
data_url = dvc.api.get_url("data/splits/train.parquet")
return {
"dvc.git_rev": git_rev,
"dvc.data_url": data_url,
"dvc.train_dataset": "data/splits/train.parquet",
"dvc.data_version": "v2.1",
}
def train_with_tracking(params: dict) -> None:
"""Training con tracking completo DVC + MLflow."""
mlflow.set_experiment("churn-prediction")
with mlflow.start_run(run_name="xgboost-dvc-integrated") as run:
# Logga metadata DVC - collega run MLflow a versione dati
dvc_metadata = get_dvc_metadata()
mlflow.log_params(dvc_metadata)
mlflow.log_params(params)
# Carica dati dalla versione DVC corrente
train_df = pd.read_parquet("data/splits/train.parquet")
val_df = pd.read_parquet("data/splits/val.parquet")
test_df = pd.read_parquet("data/splits/test.parquet")
X_train = train_df.drop("churn", axis=1)
y_train = train_df["churn"]
X_test = test_df.drop("churn", axis=1)
y_test = test_df["churn"]
# Training
model = XGBClassifier(**params)
model.fit(X_train, y_train,
eval_set=[(val_df.drop("churn", axis=1), val_df["churn"])],
early_stopping_rounds=50,
verbose=False)
# Metriche
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]
metrics = {
"accuracy": accuracy_score(y_test, y_pred),
"f1_score": f1_score(y_test, y_pred),
"auc_roc": roc_auc_score(y_test, y_prob),
"best_iteration": model.best_iteration,
}
mlflow.log_metrics(metrics)
mlflow.sklearn.log_model(model, "model")
print(f"Run ID: {run.info.run_id}")
print(f"Accuracy: {metrics['accuracy']:.4f}")
print(f"Dataset version: {dvc_metadata['dvc.data_version']}")
if __name__ == "__main__":
params = {
"n_estimators": 500,
"max_depth": 6,
"learning_rate": 0.05,
"subsample": 0.8,
"use_label_encoder": False,
"eval_metric": "logloss",
}
train_with_tracking(params)
DVC vs lakeFS: Când să folosiți ce instrument
În noiembrie 2025, lakeFS a achiziționat DVC, dar cele două instrumente rămân distincte diferite cazuri de utilizare. Alegerea depinde de amploarea datelor, de complexitate a infrastructurii și a nevoilor echipei. Este important de reținut că cele două instrumente nu se exclud reciproc: echipele de întreprindere le folosesc adesea pe ambele.
Comparație arhitecturală DVC vs lakeFS
| Dimensiune | DVC | lacFS |
|---|---|---|
| Arhitectură | Numai client, nu este necesar un server | Client/server, necesită implementarea serverului lakeFS |
| Scala de date | Seturi de date de până la ~TB | Lac de date la scară petabyte, enterprise |
| Integrare | Integrat cu Git (flux de lucru identic) | API compatibil S3, Spark, Hive, Athena |
| Ramificarea datelor | Prin commit fișiere Git + .dvc | Ramuri native la nivelul depozitului de obiecte |
| Înființat | pip install + dvc init (minute) | Implementarea Docker/Kubernetes (ore/zile) |
| Ţintă | Oameni de știință de date, echipe mici de ML | Echipa de inginerie de date, companii întreprinderi |
| Cost | Open-source, gratuit (platiți doar pentru stocare) | Plan de întreprindere cu sursă deschisă + plătit |
| cadre ML | Python nativ, MLflow, DVCLive | Spark, Presto, DuckDB, toate instrumentele de date mari |
lakeFS: Arhitectură și cazuri de utilizare
lakeFS funcționează ca un strat de metadate deasupra stocării obiectelor (S3, GCS, Azure Blob), expunerea unui API compatibil S3. Creați versiuni de vizualizări de date fără duplicați fișierele de bază: crearea unei ramuri durează milisecunde indiferent de dimensiunea setului de date.
# lakeFS: esempio di workflow con Python SDK
from lakefs_sdk import Client, Repository, Branch, Commit
import pandas as pd
# Connessione al server lakeFS
client = Client(
host="https://lakefs.mycompany.com",
username="access_key",
password="secret_key"
)
# Crea un repository
repo = client.repositories.create_repository(
"churn-data-lake",
storage_namespace="s3://my-data-lake/churn/",
default_branch="main"
)
# Workflow Git-like per dati
# 1. Crea branch per nuovo esperimento
experiment_branch = repo.branch("experiment/new-features").create(
source_reference="main"
)
# 2. Upload nuovi dati sul branch sperimentale
# (non impatta il branch main - zero copy)
experiment_branch.object("data/features_v2.parquet").upload(
content=new_features_df.to_parquet()
)
# 3. Commit sul branch
experiment_branch.commit(
message="feat: add recency features for churn model",
metadata={"model_version": "v3.0", "engineer": "alice"}
)
# 4. Merge solo se i risultati sono soddisfacenti
# (dopo validazione e A/B testing)
repo.branch("main").merge(source_ref="experiment/new-features")
# 5. Rollback immediato se qualcosa va storto
repo.branch("main").revert(
reference="main~1" # Torna al commit precedente
)
Ce instrument să alegi?
STATELE UNITE ALE AMERICII DVC dacă:
- Sunteți un cercetător de date sau o echipă mică (1-10 persoane)
- Seturile dvs. de date sunt de ordinul a GB/câțiva TB
- Doriți integrare nativă cu Git fără infrastructură suplimentară
- Buget limitat (<5K EUR/an)
- Flux de lucru axat pe experimente ML unice
STATELE UNITE ALE AMERICII lacFS dacă:
- Aveți un lac de date de întreprindere cu date la scară de petabyte
- Utilizați Spark, Athena, Presto sau alte cadre de date mari
- Aveți nevoie de guvernanța datelor și piste de audit pentru conformitate (GDPR, AI Act)
- Lucrați cu echipe mari de inginerie de date (10+ persoane)
- Aveți deja infrastructura Kubernetes pentru implementarea serverului
Cele mai bune practici pentru versiunea ML în producție
1. Structura depozitului
O structură de depozit bine organizată face ca versiunea DVC să fie mai eficientă și facilitează colaborarea în echipă:
ml-project/
├── .dvc/
│ ├── config # Remote storage config (no secrets)
│ └── .gitignore
├── data/
│ ├── raw/
│ │ ├── .gitignore # Generato da DVC
│ │ ├── customers.csv.dvc
│ │ └── transactions.parquet.dvc
│ ├── processed/
│ │ └── features.parquet.dvc
│ └── splits/
│ ├── train.parquet.dvc
│ └── test.parquet.dvc
├── models/
│ ├── .gitignore
│ └── churn_model.pkl.dvc
├── metrics/
│ └── test_metrics.json # Tracciato da Git (piccolo file JSON)
├── reports/
│ └── confusion_matrix.png # Tracciato da Git (con cache: false)
├── src/
│ ├── data/
│ │ ├── fetch_data.py
│ │ └── split.py
│ ├── features/
│ │ └── preprocess.py
│ └── models/
│ ├── train.py
│ └── evaluate.py
├── dvc.yaml # Definizione pipeline
├── dvc.lock # Snapshot stato pipeline (tracciato da Git)
├── params.yaml # Iperparametri e configurazione
└── requirements.txt
2. Convențiile de denumire pentru etichetele Git
# Schema di naming raccomandato per tag Git+DVC
# Dataset versioning
git tag "data/raw/v1.0" # Prima raccolta dati
git tag "data/processed/v2.3" # Dataset preprocessato v2.3
git tag "data/features/v1.0-30d" # Features con finestra 30 giorni
# Model versioning
git tag "model/baseline/v1.0" # Modello baseline
git tag "model/xgboost/v2.1" # XGBoost tuned v2.1
git tag "model/prod/v3.0" # Versione in produzione attuale
# Pipeline snapshot
git tag "pipeline/2025-Q1" # Snapshot pipeline Q1 2025
# Esempio di workflow release
git tag -a "model/prod/v3.0" \
-m "Production model v3.0
Metrics:
- accuracy: 0.9423
- f1_score: 0.8891
- auc_roc: 0.9567
Dataset: data/features/v2.1
MLflow run: a1b2c3d4e5f6"
git push origin "model/prod/v3.0"
3. Automatizare cu acțiuni GitHub
Integrarea DVC în conducta CI/CD asigură validarea fiecărui Pull Request cu date reale și valori actualizate:
# .github/workflows/ml-pipeline.yml
name: ML Pipeline Validation
on:
pull_request:
branches: [main]
paths:
- 'src/**'
- 'params.yaml'
- 'dvc.yaml'
jobs:
run-pipeline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Necessario per dvc metrics diff
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install dvc[s3] -r requirements.txt
- name: Configure DVC remote
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
dvc remote modify --local myremote \
access_key_id $AWS_ACCESS_KEY_ID
dvc remote modify --local myremote \
secret_access_key $AWS_SECRET_ACCESS_KEY
- name: Pull data
run: dvc pull data/splits/
- name: Run pipeline
run: dvc repro
- name: Check metrics regression
run: |
# Confronta metriche con main branch
dvc metrics diff main --md >> $GITHUB_STEP_SUMMARY
# Fallisce se accuracy scende sotto soglia
python scripts/check_metrics.py \
--min-accuracy 0.90 \
--metrics metrics/test_metrics.json
- name: Push updated artifacts
run: dvc push
Anti-modele de evitat
- Nu adăugați fișiere mari de date direct în Git: Chiar și un singur fișier .pkl de 200 MB va face ca depozitul să se cloneze pentru totdeauna
- Nu utilizați dvc add on fișierele generate de pipeline: Fișierele de ieșire pipeline trebuie definite ca
outsindvc.yaml, nu a fost adăugat manual - Nu ignora dvc.lock în .gitignore: acest fișier este esențial pentru reproductibilitate, trebuie întotdeauna urmărit de Git
- Nu uitați DVC push după antrenament: fara impingere, colegi care fac
dvc pullnu vor găsi noile artefacte - Nu utilizați căi absolute în dvc.yaml: Utilizați întotdeauna căi relative pentru a asigura portabilitatea între diferite mașini
Concluzii și pașii următori
Versiunea seturilor de date și a modelelor nu este un lux, ci o necesitate pentru orice proiect ML serios. DVC rezolvă problema elegant: se integrează perfect cu Git, suportă toți furnizorii importanți de cloud și are o curbă de învățare blândă pentru cei care sunt deja acolo familiarizat cu Git. Odată cu achiziția de către lakeFS în 2025, ecosistemul a devenit și mai robust, deschizând calea pentru integrări mai profunde cu lacurile de date ale întreprinderii.
Pentru un startup sau o echipă de IMM-uri, combinația DVC + Git + S3 (sau DagsHub pentru stocare gratuită) oferă un sistem de versiuni profesional cu costuri mai mici la 100 EUR/luna pentru echipe de 5-10 persoane. Pentru companiile cu lacuri de date la scară petabyte, lakeFS oferă funcționalități de întreprindere, menținând în același timp compatibilitatea cu S3 și major cadre de date mari.
În următorul articol din serie vom explora MLflow pentru urmărirea experimentului: cum să înregistrați parametrii, valorile și artefactele, cum să utilizați Model Registry pentru a gestiona ciclul de viață al modelului și cum să integrați MLflow cu DVC pentru un sistem MLOps complet.
Resurse și pașii următori
- Documentație oficială DVC: dvc.org/doc
- documentația lakeFS: docs.lakefs.io
- DagsHub pentru stocare gratuită: dagshub.com
- Exemplu de depozit GitHub pentru această serie (toate articolele MLOps)
- Articolul următor: Urmărirea experimentelor cu MLflow - Ghid complet
- Legături încrucișate: Advanced Deep Learning - Training avansat
- Legături încrucișate: Computer Vision - Conducta de detectare a obiectelor
Stivă recomandată pentru versiunea ML (Buget <5.000 EUR/an)
| Componentă | Instrument | Costul anual estimat |
|---|---|---|
| Versiune de date și model | DVC (sursă deschisă) | Gratuit |
| Stocare la distanță (până la 100 GB) | DagsHub sau AWS S3 | Gratuit / ~28 EUR/an |
| Urmărirea experimentului | MLflow auto-găzduit | Gratuit (doar costuri VM) |
| Conducta CI/CD | Acțiuni GitHub | Gratuit (2000 min/lună) |
| VM pentru serverul MLflow | EC2 t3.mic sau echivalent | ~180 EUR/an |
| Total estimat | <250 EUR/an |







