Quick Reference · experiment tracking & the ML record

wandb cheat sheet

A run is a record, and everything hangs off it. wandb.init() opens one and hands back a Run object that owns five buckets: config (the inputs), history (one row per log call), summary (one final number per metric), files & media, and artifacts. A sweep is just a controller that writes a different config into each run.

install · CLI · env the Run object config & settings logging media · artifacts · API sweeps gotcha / removed most common

Built against the official docs: docs.wandb.ai (quickstart · the W&B SDK Python coding cheat sheet · init() & Run reference · global functions · log media · log tables · sweep config keys · sweeps walkthrough · environment variables · Keras integration) · the full SDK release notes v0.13–v0.28 · github.com/wandb/wandb.

One run end to end · and the five buckets it owns
A · THE LIFE OF A RUN wandb.login() once per machine or WANDB_API_KEY wandb.init() project= · config= returns a Run run.log() one row per call called in the loop log_artifact() versioned output async — .wait() run.finish() flush & close free with `with` every step a `with` block also marks the run FAILED on exception B · WHAT A RUN HOLDS Run one record config the inputs · written once history one row per log() call summary one number per metric files & media images · tables · code artifacts versioned · carry lineage sweep controller picks the next config a sweep = many runs, one config each history is append-only and step never goes backwards
A whole tracked experiment in fifteen lines
import wandb

with wandb.init(project="demo",
                config={"lr": 3e-4, "epochs": 10}) as run:   # closes cleanly; marks FAILED on exception

    cfg = run.config                          # read hyperparameters from here — a sweep overwrites them
    run.watch(model, log="all", log_freq=100)   # gradients + parameters

    for epoch in range(cfg.epochs):
        loss, acc = train_one_epoch(model, cfg.lr)
        run.log({"epoch": epoch, "train/loss": loss, "val/acc": acc})   # one history row

    run.summary["best_acc"] = best        # summary defaults to the LAST value, not the best

    art = wandb.Artifact("resnet", type="model")
    art.add_file("ckpt.pt")
    run.log_artifact(art, aliases=["best"]).wait()   # log_artifact is async since 0.18.3
Part I

Setup & the Run object

get authenticated, then open a run and know what it gives you
01Install & authenticateonce per machine
02The CLIwandb --help
03Environment variablesfor CI & containers
04Start a runinit returns a Run
05wandb.init() parametersthe ones that matter
06The Run objectwhat init hands back
07Resume, fork, rewindthree different things
08Organising many runsbefore you have 500
Part II

Config & logging

the inputs, the history rows, and the one number you are judged on
09Config — the inputswrite once, read often
10run.log() — the core callone row per call
11Summary & define_metricthe headline number
12Images, video, audiowrap, then log
13Tablesrows you can query
14Custom chartswandb.plot
15System metrics, logs, offlinewandb.Settings
Part III

Artifacts, sweeps & the wider platform

versioned data, automated search, and what the tutorials get wrong
16Artifacts — create & logversioned outputs
17Artifacts — use & downloadand the lineage
18Sweeps — the configYAML or dict
19Sweeps — running themcontroller + agents
20Framework hooksintegrations
21Public API — querying backwandb.Api()
22Beyond experiment trackingthe rest of the platform
23What the tutorials still teachall removed
24When something goes wrongthe usual suspects

Four things worth seeing

Where your numbers actually land, and the defaults that quietly decide what you see.

Where a number lives

The same metric can sit in three places with three different meanings. The runs table sorts on summary — which defaults to your last value, not your best.

CONFIG — the inputs, written once at init() lr = 3e-4 batch_size = 32 arch = "resnet50" one row per run · this is what a sweep overwrites HISTORY — one row per run.log() call step 0 step 1 step 2 append-only best 0.94 last 0.81 val/acc over steps SUMMARY — one number per metric, and what the table sorts on default behaviour val/acc = 0.81 ← the last value define_metric("val/acc", summary="max") val/acc = 0.94 ← the best

The step counter, three ways

Every log() call advances the step. Call it twice per iteration and you get two half-empty rows — the most common reason charts look wrong.

TWO log() CALLS PER ITERATION — what goes wrong step train/loss val/acc 0 0.62 1 0.71 each series is drawn on alternate points — charts look sparse and jagged run.log({"train/loss": l}) run.log({"val/acc": a}) FIX 1 — commit=False accumulates into the current row step train/loss val/acc 0 0.62 0.71 run.log(a, commit=False) run.log(b) ← commits both one full row per iteration — or just build one dict and log it once FIX 2 — plot against your own x-axis run.log({"epoch": e, "val/acc": a}) run.define_metric("*", step_metric="epoch") x-axis becomes "epoch" instead of the internal step declare define_metric BEFORE the loop — it does not apply retroactively step is monotonic: you can skip forward, never back. That is what rewind is for.

What lineage actually records

use_artifact draws an input edge, log_artifact an output edge. Those two calls are the whole graph — which is why skipping use_artifact costs you the trail.

raw-data:v1 artifact prep-run run cifar:v3 artifact use log use_artifact train-run run resnet:v7 artifact log :latest :best :production aliases point at a version Registry collection link_artifact — org-wide promotion aliases move. :v7 is forever. pin the version for reproducibility

Anatomy of a sweep

The controller lives on W&B and hands each agent a config. With hyperband, runs are judged at exponentially spaced brackets and the losers are killed early.

sweep.yaml method · metric controller runs on W&B, not on you wandb.sweep() agent → run 1 agent → run 2 agent → run 3 a different config each early_terminate: hyperband, min_iter=3, eta=3 val loss, lower is better 3 9 27 iters survives killed at 3 killed at 9 grid needs `values`; combine it with min/max and the sweep never terminates. Always set run_cap.

Worth memorizing

run.log()not wandb.log() — logging lives on the Run object
with wandb.init()closes cleanly and marks the run FAILED on exception
run.configread every hyperparameter here or sweeps cannot reach it
summary = lastnot best — the runs table sorts on it
define_metricsummary="max" is the fix; declare it before the loop
stepmonotonic — skip forward, never back
one slasha/b/c still groups under section a
commit=Falsemerge several calls into one history row
.wait()log_artifact is async since 0.18.3
:v7 vs :latestversions are permanent, aliases move
use_artifactthe input edge — skip it and you lose the lineage
"domain":"pixel"boxes are fractional without it
media caps<50 images and <100 audio clips per step
Table.MAX_ROWS10000 by default; extra rows are dropped
sweep fntakes NO arguments — the agent injects the config
sweep projectmust match the run's project
grid + min/maxnever terminates; grid needs values
learning rateswant log_uniform_values, not uniform
WandbCallbackremoved in 0.27.1 — the Keras docs still show it
require("core")unnecessary since 0.18.0; "legacy-service" now raises