When to use
Use this at the start of an ML project or the moment you run a second experiment, so every run is logged with enough context (code, data, params, seeds, artifacts) to reproduce or compare it later.
Not for: LLM prompt/version logging or eval-run comparison (see ai-eval-harness). Not for BI/report versioning or dashboard change history (see data-build-dashboard).
Method
- Choose a tracker: MLflow / Weights & Biases / a structured runs table. Any is fine; the discipline matters more than the tool.
- Define a run as one training execution. Log at minimum: git commit, data version/hash, all hyperparameters, metrics, and the environment (package versions).
- Set and log ALL seeds — numpy, framework, data-shuffle, CV split seed. Decision point: nondeterministic GPU ops → log the flag and accept bounded variance, or force deterministic mode.
- Version the data, not just the code: a snapshot path, hash, or DVC/table pointer. A run irreproducible without its exact data is not tracked.
- Log artifacts: the fitted model, the feature/transform pipeline, and the evaluation plots/report.
- Use consistent naming/tags (experiment, dataset, model family) so runs are queryable and comparable.
- Record the winning run explicitly and link the artifact that will be promoted to
ml-deployment.
Example
import mlflow, numpy as np, random
SEED = 42
random.seed(SEED); np.random.seed(SEED)
with mlflow.start_run(run_name="lgbm_churn_v3"):
mlflow.set_tags({"dataset": "churn_2026q2", "data_hash": DATA_SHA})
mlflow.log_params({"seed": SEED, "num_leaves": 64, "lr": 0.05})
model = train(X, y, seed=SEED)
mlflow.log_metric("pr_auc_cv", 0.63)
mlflow.sklearn.log_model(pipeline, "model") # includes transforms
Six weeks later the same commit + data_hash + seed reproduces PR-AUC 0.63 exactly.
Pitfalls
- Metrics in a notebook cell. Results vanish on restart. Log to a persistent tracker every run.
- Unseeded runs. Score swings look like real gains but are just RNG noise. Seed and log everything.
- Code versioned, data not. Same commit + different data = irreproducible. Version both.
- Model logged without its pipeline. The transforms drift and serving breaks. Log the full pipeline as one artifact.
Output format
# Experiment Tracking: <name>
TRACKER: <mlflow|wandb|table>
RUN = <one training execution>
LOGGED: git=<sha> | data=<version/hash> | env=<lockfile>
PARAMS: <all hyperparameters>
SEEDS: numpy=<> framework=<> split=<> | deterministic=<y/n>
METRICS: <name: value>
ARTIFACTS: model, pipeline, eval report
PROMOTED RUN: <run_id> -> deployment
1---2name: ml-experiment-tracking3description: Set up reproducible experiment tracking for runs, params, metrics, artifacts, and seeds so any result can be regenerated.4---56## When to use78Use this at the start of an ML project or the moment you run a second experiment, so every run is logged with enough context (code, data, params, seeds, artifacts) to reproduce or compare it later.910**Not for:** LLM prompt/version logging or eval-run comparison (see `ai-eval-harness`). Not for BI/report versioning or dashboard change history (see `data-build-dashboard`).1112## Method13141. Choose a tracker: MLflow / Weights & Biases / a structured runs table. Any is fine; the discipline matters more than the tool.152. Define a run as one training execution. Log at minimum: git commit, data version/hash, all hyperparameters, metrics, and the environment (package versions).163. Set and log ALL seeds — numpy, framework, data-shuffle, CV split seed. Decision point: nondeterministic GPU ops → log the flag and accept bounded variance, or force deterministic mode.174. Version the data, not just the code: a snapshot path, hash, or DVC/table pointer. A run irreproducible without its exact data is not tracked.185. Log artifacts: the fitted model, the feature/transform pipeline, and the evaluation plots/report.196. Use consistent naming/tags (experiment, dataset, model family) so runs are queryable and comparable.207. Record the winning run explicitly and link the artifact that will be promoted to `ml-deployment`.2122## Example2324```python25import mlflow, numpy as np, random26SEED = 4227random.seed(SEED); np.random.seed(SEED)28with mlflow.start_run(run_name="lgbm_churn_v3"):29 mlflow.set_tags({"dataset": "churn_2026q2", "data_hash": DATA_SHA})30 mlflow.log_params({"seed": SEED, "num_leaves": 64, "lr": 0.05})31 model = train(X, y, seed=SEED)32 mlflow.log_metric("pr_auc_cv", 0.63)33 mlflow.sklearn.log_model(pipeline, "model") # includes transforms34```35Six weeks later the same commit + data_hash + seed reproduces PR-AUC 0.63 exactly.3637## Pitfalls3839- **Metrics in a notebook cell.** Results vanish on restart. Log to a persistent tracker every run.40- **Unseeded runs.** Score swings look like real gains but are just RNG noise. Seed and log everything.41- **Code versioned, data not.** Same commit + different data = irreproducible. Version both.42- **Model logged without its pipeline.** The transforms drift and serving breaks. Log the full pipeline as one artifact.4344## Output format4546```47# Experiment Tracking: <name>48TRACKER: <mlflow|wandb|table>49RUN = <one training execution>50LOGGED: git=<sha> | data=<version/hash> | env=<lockfile>51PARAMS: <all hyperparameters>52SEEDS: numpy=<> framework=<> split=<> | deterministic=<y/n>53METRICS: <name: value>54ARTIFACTS: model, pipeline, eval report55PROMOTED RUN: <run_id> -> deployment56```