10 · Versionar datos con DVC
Git versiona tu código de maravilla — y se atraganta con un dataset de 2 GB. DVC llena el hueco: hace un hash de contenido de tus datos, commitea un pequeño puntero `.dvc` a Git, y empuja los bytes reales a un remoto como S3 — así que un `git checkout` de un commit viejo recupera los datos exactos que entrenaron ese modelo.
DVC versiona datos grandes como Git versiona código: `dvc add data.csv` hace un HASH DE CONTENIDO del archivo y escribe un pequeño PUNTERO `data.csv.dvc` (el hash + tamaño) que commiteas a GIT; los bytes reales van a un REMOTO separado (S3, GDrive) vía `dvc push`. Git se mantiene pequeño y rápido, pero un `git checkout` de cualquier commit + `dvc pull` recupera los datos EXACTOS que ese commit referenciaba.
Sin esto:
Sin versionado de datos, puedes reproducir el código que entrenó un modelo pero no los DATOS — y commitear archivos grandes directamente a Git infla el repo hasta que los clones tardan una eternidad y el historial queda inservible.
Git es brillante versionando código: archivos de texto pequeños, diffs línea por línea, historial instantáneo. Pero los proyectos de ML también dependen de datos y artefactos de modelo — un CSV de 2 GB, un .joblib de 500 MB, una carpeta de imágenes. Commitea esos directamente a Git y el repositorio se infla: cada versión de cada archivo grande vive para siempre en el historial, los clones tardan una eternidad, y un git diff sobre un blob binario no tiene sentido. Git nunca se construyó para esto.
Puedes reproducir un modelo solo si puedes reproducir tanto el código como los datos exactos con los que entrenó. Así que necesitas los datos bajo control de versiones también — pero no dentro de Git. Eso es justo lo que provee DVC (Data Version Control, control de versiones de datos).
El truco de DVC es el direccionamiento por contenido con un puntero:
1. dvc add data.csv — DVC calcula un hash (un MD5) del contenido del archivo y mueve los bytes a una caché local indexada por ese hash. Escribe un pequeño archivo de texto, data.csv.dvc, que contiene solo el hash y el tamaño — un puntero a los datos, no los datos en sí. También añade data.csv a .gitignore para que Git nunca rastree el archivo grande directamente.
2. Commiteas el puntero .dvc a Git. Ese archivito (unos cientos de bytes) entra a tu historial normal de Git junto a tu código. Git se mantiene pequeño y rápido; el puntero registra qué versión de los datos usa este commit.
3. dvc push envía los bytes reales a un remoto — S3, Google Drive, GCS, Azure, un servidor SSH. El remoto es el almacén voluminoso; Git guarda solo punteros.
El beneficio es la reproducibilidad. Haz checkout de cualquier commit (git checkout v1.2) y Git restaura el puntero .dvc correspondiente; dvc pull lee el hash de ese puntero y trae los bytes de datos exactos desde el remoto. Código y datos se mueven juntos, bloqueados por versión, sin que un solo archivo grande entre jamás a Git.
¿Por qué importa hacer hash del contenido? Porque el hash ES la identidad. Bytes idénticos siempre producen el hash idéntico, así que DVC nunca guarda los mismos datos dos veces (deduplicación) y sabe al instante si el remoto ya tiene un archivo. Cambia un solo byte y el hash cambia por completo — una nueva versión. La celda ejecutable de abajo demuestra exactamente esta idea de hash de contenido con el hashlib de Python, que es el núcleo de lo que registra un archivo .dvc.
Python (in browser)
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
El flujo de DVC: `dvc init`, `dvc add` para hacer hash + rastrear un archivo (escribiendo un puntero `.dvc`), commitear el puntero a Git, `dvc remote add` + `dvc push` los bytes a S3, luego `git checkout` + `dvc pull` para restaurar código+datos exactos.
Cuando versionas un dataset de 2 GB con DVC, ¿qué va a Git y qué va al remoto?
- Git versiona código pero se infla con archivos grandes; DVC versiona artefactos de datos/modelo haciéndoles un hash de contenido y guardando solo un pequeño puntero `.dvc` en Git.
- `dvc add` escribe el puntero (hash + tamaño) y gitignora el archivo real; commiteas el puntero a Git y haces `dvc push` de los bytes reales a un remoto (S3/GDrive/GCS).
- El direccionamiento por contenido significa que bytes idénticos comparten un hash (deduplicación) y un cambio de un byte es una nueva versión; `git checkout` + `dvc pull` restaura el código+datos exactos de cualquier commit.
Las pipelines de ML reproducibles versionan los datos con DVC (o git-lfs / lakeFS) para que un modelo siempre pueda rastrearse al dataset exacto que lo produjo — esencial para auditorías, depuración y cumplimiento regulatorio.
Si lo quitas: Podrías reproducir el código que entrenó un modelo pero no sus datos — o commitearías archivos enormes a Git e inflarías el repo hasta que sea doloroso clonar e imposible hacer diff.