Wersjonowanie zestawów danych i modeli ML: DVC w produkcji
Wyobraź sobie, że wytrenujesz model, który osiąga 94% dokładności, wypuścisz go do produkcji, a potem trzy miesiące później okazuje się, że nikt nie wie dokładnie, która wersja zbioru danych została wykorzystana, np które hiperparametry były aktywne. Model jest w produkcji, ale jest nie do odtworzenia. Ten scenariusz jest niestety raczej normą niż wyjątkiem w przypadku zespołów, które nie wdrażają ML ustrukturyzowane praktyki wersjonowania.
Wersjonowanie w MLOps nie dotyczy tylko plików kodu: chodzi o to zbiory danych, modele, rurociągów i konfiguracji. Git bardzo dobrze radzi sobie z kodem źródłowym, ale zawodzi z setkami plików GB typowych dla zbiorów danych ML. I tutaj wchodzi to w grę DVC (wersja danych Kontrola), narzędzie typu open source, które przenosi zasady Git do świata danych i modele uczenia maszynowego.
W listopadzie 2025 r. firma LakeFS nabyła DVC, potwierdzając centralne znaczenie tego narzędzia w ekosystemie MLOps i zapewnienie jego ciągłości jako projekt w 100% open source. W tym W artykule szczegółowo omówimy DVC: konfigurację, potok, zdalną pamięć masową, integrację z Git i MLflow, porównanie z LakeFS i najlepsze praktyki dla zespołów dowolnej wielkości.
Czego dowiesz się w tym artykule
- dlaczego wersjonowanie jest podstawą w MLOps i co odróżnia je od wersjonowania kodu
- Kompletna konfiguracja DVC: inicjalizacja, śledzenie danych, automatyczne pliki .dvc i .gitignore
- Potok DVC z dvc.yaml: etapy, deps, outs, params i plik dvc.lock
- Magazyn zdalny: konfiguracja dla AWS S3, Google Cloud Storage i Azure Blob Storage
- DVC Python API: dvc.api.open() i dvc.api.get_url() dla dostępu programowego
- Integracja DVC + MLflow w celu połączenia wersji zestawu danych z eksperymentami
- Porównanie architektury DVC i LakeFS: kiedy używać jakiego narzędzia
- Najlepsze praktyki dla zespołów ML z ograniczonymi budżetami (<5 tys. EUR/rok)
Seria MLOps i uczenie maszynowe w produkcji
| # | Przedmiot | Centrum |
|---|---|---|
| 1 | MLOps: od eksperymentu do produkcji | Fundamenty i pełny cykl życia |
| 2 | Potok uczenia maszynowego z CI/CD | Akcje GitHub i Docker dla ML |
| 3 | Jesteś tutaj - Wersjonowanie DVC vs LakeFS | Zbiory danych i wersjonowanie modeli |
| 4 | Śledzenie eksperymentów za pomocą MLflow | Śledzenie, rejestracja modeli, porównanie |
| 5 | Wykrywanie dryfu modelu | Automatyczne monitorowanie i przekwalifikowanie |
| 6 | Obsługa z FastAPI + Uvicorn | Wdrożenie modeli do produkcji |
| 7 | Skalowanie ML na Kubernetesie | KubeFlow i Seldon Core |
| 8 | Testowanie A/B modeli ML | Metodologia i wdrażanie |
| 9 | Zarządzanie systemem ml | Zgodność, ustawa UE o sztucznej inteligencji, etyka |
| 10 | Studium przypadku: przewidywanie rezygnacji | Kompleksowy rurociąg w produkcji |
Problem wersjonowania w uczeniu maszynowym
W tradycyjnym projekcie oprogramowania Git rozwiązuje prawie wszystkie problemy z wersjonowaniem: kod Jest lekki, tekstowy i naturalnie nadaje się do różnicowania i łączenia. Jednak w projekcie ML kod jest tylko częścią równania. Powtarzalność modelu wymaga śledzenia jednocześnie:
- Zbiory danych szkoleniowe i walidacyjne: Często gigabajty lub terabajty danych ustrukturyzowanych lub nieustrukturyzowanych
- Artefakty modelu: pliki .pkl, .pt, .h5, które mogą ważyć setki MB
- Hiperparametry i konfiguracje: szybkość uczenia się, architektura, etapy przetwarzania wstępnego
- Metryki i wyniki: dokładność, F1, AUC-ROC dla każdego eksperymentu
- Zależności środowiska: Wersja Pythona, biblioteki, sterowniki CUDA
Git nie jest przeznaczony dla dużych plików binarnych: każde naciśnięcie modelu 500 MB sklonowałoby to całą historię, przez co repozytorium stałoby się bezużyteczne za kilka miesięcy. Rozwiązanie nie rezygnować z wersjonowania, ale używać odpowiedniego narzędzia dla każdego typu artefaktu.
Koszt braku wersji ML
| Scenariusz | Koszt bez wersjonowania | Rozwiązanie DVC |
|---|---|---|
| Zdegradowany model produkcyjny | Nie można przywrócić poprzedniego modelu | kasa git + kasa dvc |
| Uszkodzony zestaw danych w potoku | Pobieraj ponownie i przetwarzaj od zera | dvc sprawdź poprzedni zestaw danych |
| Audyt regulacyjny (Akt UE dotyczący sztucznej inteligencji) | Nie da się udowodnić, które dane utworzyły model | Hash zbioru danych przedstawiony w pliku .dvc |
| Współpraca zespołowa | Każdy analityk danych korzysta z różnych wersji danych | dvc pull synchronizuje cały zespół |
| Eksperymentuj z reprodukcją | Wyniki nie powtarzalne po 6 miesiącach | git checkout + dvc repro odbudowuje wszystko |
Konfiguracja i konfiguracja DVC
DVC integruje się z istniejącym repozytorium Git jako dodatkowa warstwa. Nie wymaga serwera centralny, działa lokalnie i łatwo skaluje się do pamięci masowej w chmurze w miarę rozwoju zespołu. Instalacja odbywa się za pośrednictwem pip, z obsługą różnych backendów pamięci masowej:
# 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
Po zainstalowaniu inicjujesz DVC w repozytorium Git. Polecenie tworzy strukturę niezbędnego katalogu i automatycznie aktualizuje plik .gitignore, aby wykluczyć pliki danych ze śledzenia 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"
Śledzenie zbiorów danych i modeli
Serce DVC i dowództwo dvc add, który działa podobnie do
git add ale dla dużych plików. DVC oblicza skrót MD5 pliku,
przenosi go do lokalnej pamięci podręcznej i tworzy plik .dvc (mały plik tekstowy
śledzone przez Git) wskazując na skrót:
# 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"
Jak działa plik .dvc
Plik .dvc oraz lekki plik YAML zawierający skrót MD5 (lub SHA-256) pliku
zawartość oryginalnego pliku, jego rozmiar i względną ścieżkę. Ten skrót jest deterministyczny:
ten sam plik zawsze generuje ten sam skrót, co umożliwia weryfikację integralności pliku
danych w dowolnym momencie. Git śledzi .dvc plik, natomiast plik danych
rzeczywiste życie w lokalnej pamięci podręcznej DVC lub w zdalnym magazynie.
Codzienna praca z DVC
Typowy przepływ pracy z DVC jest zgodny z cyklem Git, z dodatkiem dvc push e
dvc pull aby zsynchronizować dane ze zdalnym magazynem:
# 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
Magazyn zdalny: S3, GCS i Azure
Zdalne przechowywanie danych jest sercem współpracy w DVC. Bez tego dane istnieją tylko lokalnie, a wersjonowanie nie przynosi korzyści zespołowi. DVC obsługuje wszystkie główne dostawcy usług chmurowych, a także rozwiązania on-premise poprzez SSH lub 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
Bezpieczeństwo danych uwierzytelniających
Nigdy nie umieszczaj w pliku poświadczeń AWS, GCS ani Azure .dvc/config śledzone
z Gita. Zawsze używaj --local wpisać .dvc/config.local
(automatycznie ignorowane przez Git) lub skonfiguruj poświadczenia za pomocą zmiennych
środowisko lub role IAM w systemach CI/CD. W architekturze Kubernetes użyj i
ServiceAccount z IRSA (Role IAM dla kont usług) dla bezpiecznego dostępu do S3 bez
zakodowane na stałe dane uwierzytelniające.
Konfiguracja przy ograniczonym budżecie: DagsHub jako bezpłatna alternatywa
Dla zespołów z budżetem <5 tys. EUR/rok DagsHub oferuje bezpłatny hosting dla zdalnej pamięci masowej DVC (do 10 GB na publiczne repo) z natywną integracją dla MLflow. I rozwiązanie doskonałe dla startupów i zespołów akademickich:
# 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
Potok DVC: odtwarzalność za pomocą pliku dvc.yaml
Potoki to najpotężniejsza funkcja DVC: pozwalają zdefiniować przepływ pracy Uzupełnij ML jako serię staż zależne od siebie. DVC śledzi zależności pomiędzy etapami i powtórkami tylko tymi, których dane wejściowe uległy zmianie, podobnie jak w przypadku a Inteligentny plik makefile do uczenia maszynowego.
Potok jest zdefiniowany w pliku dvc.yaml i jego stan (skrót wszystkich
wejścia i wyjścia) i wykreślone dvc.lock. Kiedy biegniesz
dvc repro, DVC porównuje bieżący stan z dvc.lock tj
ponownie wykonuje tylko unieważnione etapy.
# 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
Parametry potoku są zdefiniowane w pliku params.yaml, czyli
śledzone przez Gita. Umożliwia to porównywanie eksperymentów z różnymi hiperparametrami
używając 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
Uruchom i zarządzaj rurociągiem
# 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
Interfejs API języka Python firmy DVC: programowy dostęp do danych
Interfejs API języka Python firmy DVC umożliwia bezpośredni dostęp do wersjonowanych zestawów danych i modeli z kodu Pythona, bez konieczności ręcznego pobierania plików. I szczególnie przydatne w potokach wnioskowania lub w systemach obsługujących, w których chcesz ładować dynamicznie poprawna wersja modelu.
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']}")
Integracja DVC z Git: kompletny przepływ pracy
Prawdziwa moc DVC pojawia się, gdy integruje się głęboko z Git. Każde zatwierdzenie Gita
który aktualizuje plik .dvc o dvc.lock reprezentuje migawkę
odtwarzalność całego stanu projektu ML: kodu, danych i modeli razem.
# 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: wersjonowanie zbioru danych i śledzenie eksperymentów
DVC i MLflow uzupełniają się nawzajem: DVC obsługuje wersjonowanie danych i modeli (duże artefakty), podczas gdy MLflow śledzi parametry, metryki i przebieg eksperymentów. Integracja ich oznacza posiadanie pełnej ścieżki audytu: dla każdego uruchom MLflow, dowiedz się dokładnie, która wersja zbioru danych została użyta.
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: kiedy używać jakiego narzędzia
W listopadzie 2025 r. firma LakeFS przejęła DVC, ale te dwa narzędzia nadal się różnią różne przypadki użycia. Wybór zależy od skali danych, złożoności infrastruktury i potrzeb zespołu. Należy zauważyć, że są to dwa narzędzia nie wykluczają się one wzajemnie: zespoły w przedsiębiorstwach często korzystają z obu.
Porównanie architektury DVC i LakeFS
| Rozmiar | DVC | jezioroFS |
|---|---|---|
| Architektura | Tylko klient, nie jest wymagany serwer | Klient/serwer wymaga wdrożenia serwera LakeFS |
| Skala danych | Zbiory danych do ~ TB | Jezioro danych korporacyjnych w skali petabajtów |
| Integracja | Zintegrowany z Git (identyczny przepływ pracy) | API zgodne z S3, Spark, Hive, Athena |
| Rozgałęzianie danych | Poprzez zatwierdzenie plików Git + .dvc | Natywne gałęzie na poziomie składnicy obiektów |
| Organizować coś | instalacja pip + init dvc (minuty) | Wdrożenie Docker/Kubernetes (godziny/dni) |
| Cel | Analitycy danych, małe zespoły ML | Zespół inżynierii danych, firmy korporacyjne |
| Koszt | Oprogramowanie typu open source, bezpłatne (płacisz tylko za miejsce na dysku) | Open-source + płatny plan dla przedsiębiorstw |
| Frameworki uczenia maszynowego | Natywny dla Pythona, MLflow, DVCLive | Spark, Presto, DuckDB, wszystkie narzędzia Big Data |
LakeFS: Architektura i przypadki użycia
LakeFS działa jako warstwa metadanych na wierzchu magazynu obiektów (S3, GCS, Azure Blob), udostępnianie interfejsu API zgodnego z S3. Twórz wersje widoków danych bez zduplikuj podstawowe pliki: utworzenie gałęzi zajmuje milisekundy niezależnie od wielkości zbioru danych.
# 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
)
Które narzędzie wybrać?
USA DVC Jeśli:
- Jesteś analitykiem danych lub małym zespołem (1-10 osób)
- Twoje zbiory danych są rzędu GB/kilka TB
- Chcesz natywnej integracji z Git bez dodatkowej infrastruktury
- Ograniczony budżet (<5 tys. EUR/rok)
- Przepływ pracy skupiony na pojedynczych eksperymentach ML
USA jezioroFS Jeśli:
- Masz korporacyjne jezioro danych zawierające dane w skali petabajtów
- Korzystasz ze Sparka, Atheny, Presto lub innych frameworków Big Data
- Potrzebujesz zarządzania danymi i ścieżek audytu w celu zapewnienia zgodności (RODO, ustawa o sztucznej inteligencji)
- Pracę z dużymi zespołami zajmującymi się inżynierią danych (ponad 10 osób)
- Masz już infrastrukturę Kubernetes do wdrożenia serwera
Najlepsze praktyki dotyczące wersjonowania ML w środowisku produkcyjnym
1. Struktura repozytorium
Dobrze zorganizowana struktura repozytorium sprawia, że wersjonowanie DVC jest bardziej efektywne i ułatwia współpracę w zespole:
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. Konwencje nazewnictwa dla tagów 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. Automatyzacja za pomocą akcji GitHub
Integracja DVC z potokiem CI/CD gwarantuje, że każde żądanie ściągnięcia zostanie zweryfikowane z rzeczywistymi danymi i zaktualizowanymi metrykami:
# .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
Anty-wzorce, których należy unikać
- Nie dodawaj dużych plików danych bezpośrednio do Git: Nawet pojedynczy plik .pkl o wielkości 200 MB spowoduje, że klonowanie repozytorium będzie powolne na zawsze
- Nie używaj dvc add na plikach generowanych przez potok: Pliki wyjściowe potoku muszą być zdefiniowane jako
outsindvc.yaml, nie dodano ręcznie - Nie ignoruj dvc.lock w .gitignore: ten plik jest niezbędny do odtwarzalności, Git musi go zawsze śledzić
- Nie zapomnij o treningu DVC Push po treningu: bez nacisku, koledzy, którzy to robią
dvc pullnie znajdą nowych artefaktów - Nie używaj ścieżek bezwzględnych w pliku dvc.yaml: Zawsze używaj ścieżek względnych, aby zapewnić przenośność między różnymi maszynami
Wnioski i dalsze kroki
Wersjonowanie zbiorów danych i modeli nie jest luksusem, ale koniecznością w każdym projekcie Poważny M.L. DVC elegancko rozwiązuje problem: płynnie integruje się z Git, obsługuje wszystkich głównych dostawców usług w chmurze, a dla tych, którzy już tam pracują, można się łatwo nauczyć zaznajomiony z Gitem. Wraz z przejęciem przez LakeFS w 2025 r. ekosystem stał się jeszcze bardziej niezawodne, torując drogę do głębszej integracji z korporacyjnymi jeziorami danych.
W przypadku zespołu startupowego lub MŚP jest to kombinacja DVC + Git + S3 (lub DagsHub dla bezpłatne miejsce do przechowywania) oferuje profesjonalny system wersjonowania przy niższych kosztach w cenie 100 EUR/miesiąc dla zespołów 5-10 osobowych. W przypadku firm dysponujących petabajtowymi jeziorami danych, LakeFS oferuje funkcjonalność korporacyjną przy zachowaniu kompatybilności z S3 i major frameworki dużych zbiorów danych.
W następnym artykule z serii będziemy się nad tym zastanawiać MLflow do śledzenia eksperymentów: jak rejestrować parametry, metryki i artefakty, jak używać rejestru modeli do zarządzania cykl życia modelu oraz sposób integracji MLflow z DVC w celu uzyskania kompletnego systemu MLOps.
Zasoby i kolejne kroki
- Oficjalna dokumentacja DVC: dvc.org/doc
- dokumentacja LakeFS: docs.lakefs.io
- DagsHub do bezpłatnego przechowywania: dagshub.com
- Przykładowe repozytorium GitHub dla tej serii (wszystkie artykuły MLOps)
- Następny artykuł: Śledzenie eksperymentów za pomocą MLflow — kompletny przewodnik
- Połączenie krzyżowe: Zaawansowane głębokie uczenie się - zaawansowane szkolenie
- Połączenie krzyżowe: Wizja komputerowa – rurociąg do wykrywania obiektów
Zalecany stos do wersjonowania ML (budżet <5 tys. EUR/rok)
| Część | Instrument | Szacowany koszt roczny |
|---|---|---|
| Wersjonowanie danych i modeli | DVC (otwarte oprogramowanie) | Bezpłatny |
| Zdalna pamięć masowa (do 100 GB) | DagsHub lub AWS S3 | Bezpłatnie / ~28 EUR/rok |
| Śledzenie eksperymentu | MLflow na własnym serwerze | Bezpłatnie (tylko koszty maszyny wirtualnej) |
| Rurociąg CI/CD | Akcje GitHuba | Bezpłatnie (2000 min/miesiąc) |
| Maszyna wirtualna dla serwera MLflow | EC2 t3.small lub odpowiednik | ~180 EUR/rok |
| Szacunkowa suma | <250 EUR/rok |







