How to Manage Local Model Versions with DVC
Data Version Control (DVC) is an open-source version control system for machine learning projects, built on top of Git. While Git excels at tracking source code, it struggles with large files such as datasets, model weights, and artifacts. DVC solves this problem by storing metadata in Git while keeping the actual large files in a separate, configurable storage backend. In this tutorial, we focus specifically on managing local model versions — a common requirement for teams that want reproducible ML experiments without immediately setting up cloud storage.
What Is Local Model Versioning?
Local model versioning is the practice of tracking different iterations of a trained model on your own machine or on a shared on-premise server. Each time you retrain a model, the resulting weights, hyperparameters, metrics, and configuration should be tied together so you can later compare, restore, or roll back to any previous version. DVC makes this possible by treating model files like Git-tracked files, but storing their contents in a local cache directory.
Why It Matters
- Reproducibility: You can recreate any past experiment exactly, including the model weights and the code that produced them.
- Collaboration: Teammates can pull a specific model version without manually copying files or guessing which checkpoint is the latest.
- Storage efficiency: DVC deduplicates files using content-addressable storage, so unchanged data is never copied twice.
- Zero cloud cost: A local cache or shared network drive avoids cloud storage fees while still providing version control.
- Auditability: Every model version is linked to a Git commit, giving you a clear history of what changed and why.
Prerequisites
Before starting, make sure you have the following installed and configured:
- Python 3.8 or higher
- Git installed and initialized in your project
- DVC installed via
pip install dvc
Step 1: Initialize DVC in Your Project
Start by creating a project directory, initializing Git, and then initializing DVC. The dvc init command creates a .dvc directory that holds configuration and the local cache.
mkdir ml-project && cd ml-project
git init
pip install dvc
dvc init
git commit -m "Initialize DVC"
Step 2: Configure a Local Remote Storage
Even when working locally, it is a good idea to configure a "remote" that points to a directory on your disk or a shared network path. This separates the cache from your working directory and makes it easy to push or pull model versions.
# Create a local storage directory outside your project
mkdir -p /tmp/dvc-storage
# Add it as a remote named 'localstore'
dvc remote add -d localstore /tmp/dvc-storage
git add .dvc/config
git commit -m "Configure local DVC remote"
The -d flag marks this remote as the default. You can add multiple remotes later, for example one for a shared NFS mount and one for S3.
Step 3: Train and Track Your First Model
Assume you have a training script that produces a model file. After training, use dvc add to track the resulting artifact. This creates a small .dvc file that Git tracks, while the actual model is moved into the DVC cache.
# Train your model (example)
python train.py --epochs 10 --output models/model_v1.pkl
# Track the model with DVC
dvc add models/model_v1.pkl
# Commit the DVC metadata to Git
git add models/model_v1.pkl.dvc .gitignore
git commit -m "Add model v1 (10 epochs)"
The generated model_v1.pkl.dvc file contains a checksum, size, and path reference. This tiny file is what Git uses to identify the exact version of your model.
Step 4: Push the Model to Local Storage
Once the model is tracked, push it to your configured local remote. This copies the cached file into /tmp/dvc-storage so it is safe even if you delete your local cache.
dvc push
You can verify the contents of the remote storage by listing the directory. DVC organizes files by their MD5 hash, similar to how Git stores objects internally.
Step 5: Create a New Model Version
When you retrain with different hyperparameters, simply overwrite the model file and run dvc add again. DVC will detect the change, store the new version in the cache, and update the .dvc file.
python train.py --epochs 20 --output models/model_v1.pkl
dvc add models/model_v1.pkl
git add models/model_v1.pkl.dvc
git commit -m "Retrain model with 20 epochs"
dvc push
Now your Git history contains two commits, each pointing to a different version of the same model file. Both versions are preserved in the local cache and remote storage.
Step 6: Switch Between Model Versions
To restore a previous model version, use Git to check out the relevant commit and then run dvc checkout to materialize the correct file in your working directory.
# View commit history
git log --oneline
# Go back to the first version
git checkout <commit-hash-of-v1>
dvc checkout
# Confirm the file was restored
ls -lh models/model_v1.pkl
If the required version is not in your local cache, DVC will fetch it from the remote automatically when you run dvc pull.
dvc pull
Step 7: Track Metrics and Parameters Together
Versioning model weights is only half the story. To make versions meaningful, track the parameters and metrics that produced each model. DVC provides params.yaml and metrics.json conventions for this purpose.
# params.yaml
epochs: 20
learning_rate: 0.001
batch_size: 64
# metrics.json
{
"accuracy": 0.923,
"loss": 0.187,
"val_accuracy": 0.911
}
Commit these files alongside your .dvc file so every model version is paired with its configuration and performance. You can then compare versions across commits:
dvc metrics show
dvc params diff HEAD~1 HEAD
dvc metrics diff HEAD~1 HEAD
Step 8: Use DVC Pipelines for Reproducible Training
For more advanced workflows, define a DVC pipeline using dvc.yaml. This lets you declare dependencies, outputs, and commands so that retraining is fully reproducible with a single command.
# dvc.yaml
stages:
train:
cmd: python train.py --epochs ${epochs} --output models/model_v1.pkl
deps:
- train.py
- data/train.csv
params:
- epochs
- learning_rate
- batch_size
outs:
- models/model_v1.pkl
metrics:
- metrics.json
Run the pipeline and commit the generated files:
dvc repro
git add dvc.yaml dvc.lock models/model_v1.pkl.dvc metrics.json
git commit -m "Reproducible training pipeline"
dvc push
Each dvc repro run creates a new versioned snapshot. The dvc.lock file pins exact dependencies, ensuring anyone can reproduce the same model later.
Best Practices
- Commit
.dvcfiles, not the model itself: Add model files to.gitignore(DVC does this automatically) and only commit the small.dvcmetadata files. - Use meaningful commit messages: Include hyperparameters or metric highlights in your Git messages so the history is self-documenting.
- Push after every version: Run
dvc pushafter each commit so your local storage always mirrors your Git history. - Separate cache from working directory: Keep your DVC cache and remote storage outside the project folder to avoid accidental deletion.
- Tag important releases: Use
git tag v1.0-modelto mark production-ready models for easy retrieval. - Track params and metrics consistently: Always version
params.yamlandmetrics.jsonwith the model so comparisons are meaningful. - Garbage collect periodically: Run
dvc gc -wto remove cache entries no longer referenced by your workspace, freeing disk space. - Plan for migration: Even if you start with local storage, structure your remotes so you can later add cloud storage without changing your workflow.
Conclusion
Managing local model versions with DVC gives you the reproducibility and auditability of Git without the limitations of storing large binary files directly in version control. By combining dvc add, local remotes, metrics tracking, and reproducible pipelines, you can maintain a clean history of every model iteration, switch between versions effortlessly, and prepare your project for future collaboration or cloud migration. Start with a simple local setup, follow the best practices above, and your ML experiments will remain organized, traceable, and easy to share from day one.