English · Español
Lab 04 — Cablear mlflow en la disciplina de manifest existente¶
Objetivo: hacer que los runs de la Fase 18 sean navegables en
mlflow uisin reemplazar nuncamanifest.jsoncomo fuente de verdad.Tiempo estimado: 60–90 minutos.
Requisito previo: labs 01-03 hechos.
Lo que produces¶
src/minitrain/mlflow_wrap.py— un wrapper fino gestionado por context manager sobremlflow.start_run().- Modificaciones a
scripts/train_mini.py— llamadas al wrapper. experiments/18-train-mini/re-ejecutado con logging de mlflow.mlruns.db(SQLite, gitignored).experiments/18-train-mini/mlflow_screenshot.png— una captura del run en la UI de mlflow mostrando curvas + params + artifacts.experiments/18-train-mini/README.mdactualizado con el URI del run de mlflow.
Antecedentes que debes haber leído¶
theory/04-checkpoints-and-mlflow.md§"mlflow — qué te da y qué no".
TODOs¶
Bloque A — setup de mlflow¶
- Instala mlflow según el opt group
experimentsdepyproject.toml: - Fija el tracking URI:
- Añade
mlruns.dba.gitignore. - Arranca la UI en otra terminal:
mlflow ui --backend-store-uri sqlite:///mlruns.db --port 5000. Abrehttp://localhost:5000para confirmar que carga.
Bloque B — escribe el wrapper¶
# src/minitrain/mlflow_wrap.py
import mlflow
from contextlib import contextmanager
from pathlib import Path
@contextmanager
def tracking_run(experiment_name: str, run_name: str, manifest_path: Path, config: dict):
"""Open an mlflow run, log params from config, log manifest.json as artifact,
yield a logger that the training loop can call to log metrics."""
mlflow.set_experiment(experiment_name)
with mlflow.start_run(run_name=run_name) as run:
# Always log the manifest first — it's the source of truth.
mlflow.log_artifact(str(manifest_path))
mlflow.log_params(_flatten_config(config))
def log_metrics(metrics: dict[str, float], step: int):
for k, v in metrics.items():
mlflow.log_metric(k, v, step=step)
def log_artifact(path: Path):
mlflow.log_artifact(str(path))
# Update the manifest with the mlflow URI so the manifest can find this run.
_patch_manifest(manifest_path, mlflow_run_id=run.info.run_id)
yield SimpleNamespace(log_metrics=log_metrics, log_artifact=log_artifact, run=run)
- Implementa
_flatten_config— aplana la config anidada a clavesdotted.keyspara los params planos de mlflow. - Implementa
_patch_manifest— reescribemanifest.jsoncon el campo adicionalmlflow_run_uri. Escritura atómica. - Testea que el wrapper sale limpio en
KeyboardInterrupt— el bloquewithcierra el run, el manifest queda consistente.
Bloque C — integra con train_mini.py¶
Modifica el script de entrenamiento para envolver el bucle:
with tracking_run(
experiment_name="phase18_minigpt",
run_name=f"phase18_{git_sha[:7]}",
manifest_path=out_dir / "manifest.json",
config=config,
) as logger:
for step in range(total_steps):
...
if step % log_every == 0:
logger.log_metrics(
{"train_loss": loss, "lr": lr, "g_norm": g_norm}, step=step
)
if step % val_every == 0:
logger.log_metrics({"val_loss": val_loss, "val_ppl": val_ppl}, step=step)
logger.log_artifact(checkpoint_path)
logger.log_artifact(out_dir / "loss_curve.png")
logger.log_artifact(out_dir / "results.json")
- Ejecuta el entrenamiento de nuevo (puedes acortar a 500 steps si re-ejecutar el run completo es caro — anótalo en el README).
- Tras el run, verifica en la UI:
- El run aparece en el experimento
phase18_minigpt. - Los parámetros muestran la config aplanada.
- Las métricas tienen curvas indexadas por step (train_loss, lr, g_norm, val_loss, val_ppl).
- Los artifacts incluyen
manifest.json,loss_curve.png,results.json,weights.safetensors.
Bloque D — round-trip manifest ↔ mlflow¶
El manifest es la fuente de verdad. Comprueba que:
def test_manifest_can_locate_mlflow_run():
manifest = json.loads(Path("experiments/18-train-mini/manifest.json").read_text())
run_id = manifest["mlflow_run_uri"].split("/")[-1]
run = mlflow.get_run(run_id)
assert run.data.params["optimizer.lr_max"] == "0.0003"
assert run.data.metrics["val_ppl"] < manifest["metrics"]["ngram_baseline_val_ppl"]
- Este test confirma el ciclo: manifest → URI de mlflow → API de mlflow → métricas que coinciden con lo que el manifest afirma.
Bloque E — haz la captura¶
experiments/18-train-mini/mlflow_screenshot.png:
- Abre el run en
mlflow ui. - Captura la vista del run mostrando el panel de curvas + parámetros + lista de artifacts.
- Commitea el PNG (un archivo de ~200 KB).
Bloque F — actualización del README¶
En experiments/18-train-mini/README.md, añade:
## mlflow
- Tracking URI: `sqlite:///mlruns.db` (local, gitignored).
- Experiment: `phase18_minigpt`.
- Run ID: `<run_id>` (from manifest.json).
- Screenshot: `mlflow_screenshot.png`.
- To re-open the UI: `mlflow ui --backend-store-uri sqlite:///mlruns.db --port 5000`.
Restricciones¶
- Sin autologging. No actives
mlflow.autolog(). Solo logging explícito. El wrapper son ~30 líneas; no importes la cocina entera. - El manifest es la verdad. Si la vista de mlflow no concuerda con el manifest, el bug está en el cableado de mlflow, no en el manifest. Testea esto.
- Un experimento por fase. La Fase 18 usa
phase18_minigpt. La Fase 19 crearáphase19_dynamics. No los mezcles.
Condiciones de parada¶
Hecho cuando:
mlflow uimuestra el run con las tres curvas de métricas, todos los parámetros de config y ≥ 4 artifacts.experiments/18-train-mini/mlflow_screenshot.pngestá commiteado.- El test de round-trip manifest-a-mlflow pasa.
- Puedes re-encontrar un run vía
manifest.jsonomlflow ui— ambos llevan a los mismos artifacts.
Escollos¶
mlflow.start_run()sin context manager. Deja runs abiertos colgados en Ctrl+C. Siemprewith.- Hacer log de métricas sin
step=. Mlflow entonces auto-incrementa, y una métrica logueada desde varios sitios se reordena. Siempre pasastep=. - Hacer log del archivo
safetensorscomo un parámetro en vez de como artifact. Los parámetros son strings clave-valor, máximo 500 caracteres. Usalog_artifact. - Fijar
MLFLOW_TRACKING_URIa una ruta relativa sin el prefijosqlite:///. Mlflow entonces escribe un file store, no SQLite, y te comes el dolor del file store lento.
Cuándo consultar solutions/¶
Después de que la captura esté commiteada. Solución en solutions/04-mlflow-wiring-ref.md (escrita al abrir la fase).
El trabajo de lab de la Fase 18 está completo. Continúa con /quiz 18, después PHASE_18_REPORT.md, después learners/borja/phase-18/reflections.md, después proceed.