FlorDB brings experiment tracking, provenance, and reproducibility to your ML workflow using the one thing every engineer already writes: logs. FlorDB doesn’t ask you to adopt a new UI, schema, or service. Just import it, log as you normally would, and gain full history, lineage, and replay capabilities across your training runs.
-
Zero Code Changes to Start
Already usingprintorlogginginside a git repo? Import FlorDB and your.pyoutput is captured, versioned, and queryable—no rewrite required. -
Log-Driven Experiment Tracking
No dashboards to configure or schemas to design.flor.log(...)writes structured metadata;flor.arg(...)turns a constant into a CLI-settable hyperparameter that is recorded with the run. -
Hindsight Logging & Replay
Missed a metric? Add a log after the fact and replay past runs to capture it. -
Reproducibility Without Friction
Every run is versioned via Git, every hyperparameter is recorded, and PyTorch checkpoints are captured and addressable by loop iteration—automatically. -
Works With Your Stack
Makefiles, Airflow, Slurm, HuggingFace, PyTorch—you don’t change your workflow. FlorDB fits in.
pip install flordbFor contributors or bleeding-edge features:
git clone https://github.com/ucbrise/flor.git
cd flor
pip install -e .Requires a Git repository for automatic versioning.
mkdir flor_sandbox
cd flor_sandbox
git init
ipythonimport flordb as flor
flor.log("message", "Hello ML World!")message: Hello ML World!
Run committed successfully.
Retrieve logs anytime:
flor.dataframe("message") projid tstamp filename source message
0 flor_sandbox 2025-10-13 18:13:48 ipython forward Hello ML World!
Add one import to a script you already have. Nothing else changes:
import flordb as flor # <-- the only new line
for epoch in range(3):
print(f"epoch {epoch} | loss: {1.0 / (epoch + 2):.4f}")Your terminal looks exactly the same. But the run is now versioned, committed,
and queryable with flor.io().
→ Automatic log capture: channels, naming your loops, and turning captured text into real metric columns.
Adopt as much as you want. Every step buys a specific thing:
import flordb as flor
lr = flor.arg("lr", 1e-3) # CLI-settable, recorded with the run
batch_size = flor.arg("batch_size", 32)
for epoch in flor.loop("epoch", range(epochs)):
for x, y in flor.loop("step", trainloader):
...
flor.log("loss", loss.item())
flor.log("val_acc", validate(net))
torch.save({"model": net.state_dict()}, "ckpt.pth") # mirrored to flor (rate-limited)Change hyperparameters from the CLI:
python train.py --kwargs lr=5e-4 batch_size=64View metrics across runs:
flor.dataframe("lr", "batch_size", "loss") projid tstamp filename source epoch step lr batch_size loss
0 ml_tutorial 2026-08-13 11:27:06.417615 train.py forward 0 0 0.0005 64 0.5
1 ml_tutorial 2026-08-13 11:27:06.417615 train.py forward 0 1 0.0005 64 0.3333
2 ml_tutorial 2026-08-13 11:27:06.417615 train.py forward 1 0 0.0005 64 0.3333
3 ml_tutorial 2026-08-13 11:27:06.417615 train.py forward 1 1 0.0005 64 0.25
4 ml_tutorial 2026-08-13 11:27:06.417615 train.py forward 2 0 0.0005 64 0.25
5 ml_tutorial 2026-08-13 11:27:06.417615 train.py forward 2 1 0.0005 64 0.2
Each named flor.loop becomes its own column, and a row carries the loops that enclosed the
flor.log that produced it. loss is logged inside step, so you get one row
per step, with its epoch and the run's hyperparameters attached—no JOIN needed.
→ Checkpoints: what gets mirrored, enrolling objects explicitly, and bounding disk use.
Forgot to log gradient norms? Add the statement to the script now:
flor.log("grad_norm", ...)python -m flordb replay --apply grad_normFlorDB walks the historical versions, splices your new statement into each one, restarts from the nearest checkpoint, and records the recovered values.
→ Replay: narrowing the work by iteration, replaying a single
run, and --override.
Everything is project-local; nothing lands in your home directory. Your first
run moves you off main onto a shadow branch named flor.branch, and every
auto-commit lands there—run history is versioned alongside the code that
produced it (without ever touching the branch you review and merge). A teammate
runs git fetch && git checkout flor.branch && python -m flordb unpack and has
everyone's metrics.
→ Storage: the .flor/ layout, the shadow branch, and what
syncs vs. what's rebuilt on demand.
FlorDB is based on research from UC Berkeley’s RISE Lab continued at Arizona State University.
- Flow with FlorDB: Incremental Context Maintenance for the Machine Learning Lifecycle (CIDR 2025)
- The Management of Context in the ML Lifecycle (UCB Tech Report 2024)
- Hindsight Logging for Model Training (PVLDB 2021)
Apache v2 License — free to use, modify, and distribute.
FlorDB is actively developed. Contributions, issues, and real-world use cases are welcome!
make test # full suite, including real forward runs and replays
make test-fast # unit tests only (~1s)Email: rolando.garcia@asu.edu
Tutorial Video: https://youtu.be/mKENSkk3S4Y