Skip to content

Metrics

Backprop supports displaying metrics from your experiment as live plots in the web UI. To log metrics, write JSON lines to $BP_RUN_DIR/metrics.jsonl (Backprop sets this environment variable automatically when running your experiment):

{"ts": 1709012345.123, "name": "train/loss", "value": 0.342, "step": 100}
{"ts": 1709012345.123, "name": "train/lr", "value": 0.001, "step": 100}
{"ts": 1709012400.456, "name": "eval/accuracy", "value": 0.89, "step": 100}

Backprop sets the BP_RUN_DIR environment variable when running your experiment. This directory is where you should write metrics and save output files. The path is bp/experiment/<experiment_id>/ relative to your project root.

my-experiment/ ← project root (contains .backpropconfig)
├── .backpropconfig
├── train.py
└── bp/
└── experiment/
└── <experiment_id>/
├── metrics.jsonl ← write metrics here
└── outputs/ ← save output files here

When you download results with bp results --download, the same directory structure is created locally — so it feels as if you ran the experiment on your own machine.

Each line in metrics.jsonl is a JSON object with the following fields:

FieldRequiredTypeDescription
nameyesstringMetric name, e.g. train/loss
valueyesnumberNumeric value
stepnonumberTraining step or iteration
tsnonumberUnix timestamp (seconds)

You can include any additional fields you like (e.g. epoch, split, run). Backprop stores them as metadata and makes them available for filtering in the UI.

Use / to namespace your metrics. The web UI groups metrics by the suffix (the part after the first /), so metrics that share the same suffix are automatically overlaid on the same chart. The prefix (before the /) becomes the series label.

{"ts": 1709012345.123, "name": "train/loss", "value": 0.34, "step": 100}
{"ts": 1709012345.123, "name": "train/lr", "value": 0.001, "step": 100}
{"ts": 1709012400.456, "name": "eval/loss", "value": 0.52, "step": 100}
{"ts": 1709012400.456, "name": "eval/accuracy", "value": 0.89, "step": 100}
{"ts": 1709012400.456, "name": "gpu/memory_gb", "value": 22.4, "step": 100}

This would create four panels in the UI: loss (with train and eval series overlaid), lr, accuracy, and memory_gb. This makes it easy to compare the same metric across different splits or stages at a glance.

Here’s a minimal implementation you can drop into your training script:

import json
import time
import os
bp_dir = os.environ["BP_RUN_DIR"]
def log_metric(name, value, step=None, **kwargs):
m = {"ts": time.time(), "name": name, "value": value}
if step is not None:
m["step"] = step
m.update(kwargs)
with open(os.path.join(bp_dir, "metrics.jsonl"), "a") as f:
f.write(json.dumps(m) + "\n")

Then call it from your training loop:

for step, batch in enumerate(dataloader):
loss = train_step(batch)
log_metric("train/loss", loss.item(), step=step)
if step % eval_interval == 0:
acc = evaluate(model, val_set)
log_metric("eval/accuracy", acc, step=step, split="val")