Requirements (clarify): reproducibility (ability to re-run exact training/inference), auditable lineage (which code, data, env produced a model), and production deployability.High-level idea: use Git for code, DVC for dataset/artifact content-addressed versions, MLflow for experiment tracking + Model Registry. Record cross-references (Git SHA, DVC data hash, environment spec) in every MLflow run and model entry.Workflow / components1. Data + artifacts:- Track raw/processed data with DVC: dvc add data/train.csv; dvc push -> DVC stores a content hash (in .dvc file / dvc.lock).- Commit DVC metafiles to Git: git add data/train.csv.dvc dvc.lock; git commit -m "add dataset vX"2. Training run (CI or developer machine):- Checkout code at commit: GIT_SHA=$(git rev-parse HEAD)- Ensure data resolution: dvc pull- Start MLflow run and log cross-references: - mlflow.start_run() - mlflow.log_param("git_sha", GIT_SHA) - mlflow.log_param("dvc_lock_hash", <value from dvc.lock or dvc status output>) - mlflow.log_artifact("dvc.lock") or log dataset .dvc file- Log model and environment: - Save model with mlflow.sklearn.log_model(..., signature=..., conda_env="conda.yaml") - mlflow.log_artifact("conda.yaml") or requirements.txt- Register model: result = mlflow.register_model(f"runs:/{run_id}/model", "my_model")- Immediately add tags to registry version: client.set_model_version_tag(name, version, "git_sha", GIT_SHA); tag dvc hash and build id.Example commands/snippets- DVC: dvc add data/train.csv && git add data/train.csv.dvc dvc.lock && git commit -m "data v1" && dvc push- MLflow (python):python
import mlflow, mlflow.sklearn, subprocess, json
git_sha = subprocess.check_output(["git","rev-parse","HEAD"]).strip().decode()
# parse dvc lock hash (example)
with open("dvc.lock") as f: dvc_lock = f.read()
mlflow.set_tag("git_sha", git_sha)
mlflow.set_tag("dvc_lock", "<sha-from-dvc-lock>")
mlflow.sklearn.log_model(model, "model", conda_env="conda.yaml")
Deployment / reproducibility- To reproduce: checkout Git SHA, pull DVC data for that commit (dvc pull), create environment from stored conda.yaml or use the Docker image built during CI (image tagged with git_sha and model registry version), and load model from MLflow by model URI: "models:/my_model/Production" or "models:/my_model/<version>".- CI builds an immutable Docker image during model promotion: Dockerfile installs environment from conda.yaml; image tagged with git_sha and model_version and pushed to registry. MLflow model flavor + saved conda.yaml ensures runtime parity.CI/CD & governance- Pipeline steps: tests → dvc pull → train → mlflow run → register model → run validation tests → if pass, promote model version to Staging/Production and build/publish Docker image with tags (git_sha, model_version).- Store artifacts in immutable storage (S3/GCS) with server-side versioning; enable access controls and audit logs.Auditing & traceability- Store these metadata in MLflow run and model version tags: git_sha, dvc_lock, data .dvc file path, conda.yaml checksum, CI build id, docker image tag. This allows queries like “which model was trained on dataset hash X?” or “show code at git_sha Y”.- Preserve MLflow run_id and model_version; use MLflow UI + DVC metadata + Git history for full lineage.Trade-offs / notes- DVC + Git ties data content to code but needs remote storage management.- MLflow registry does not enforce immutability of tags—use governance (CI checks, RBAC).- For absolute reproducibility, build and store Docker images containing code, data pointers, and model artifacts.This approach ensures any production deployment can be traced to a Git commit, the exact DVC-tracked dataset version, and a recorded environment (conda.yaml or Docker image), making deployments reproducible and auditable.