Exercises — TensorBoard - Weights & Biases logging
This page is a self-test. Each problem has a collapsible solution — try first, then click to reveal. Problems climb from recognition (do you know the vocabulary?) to mastery (can you design a logging system under real constraints?).
Parent topic: TensorBoard / W&B logging. We reuse ideas from 4.1.5-Hyperparameter-tuning, 5.2.3-Model-versioning, and 2.4.7-Gradient-flowand-vanishing-exploding-gradients.
Level 1 — Recognition
Exercise 1.1 (L1)
Match each logged object to the question it answers: (a) scalar, (b) histogram, (c) image, (d) graph, (e) embedding. Questions: (1) "Is my architecture wired correctly?" (2) "Is training converging?" (3) "Are my gradients vanishing?" (4) "Do learned features cluster by class?" (5) "Does the model see the augmented input I think it does?"
Recall Solution
- a → 2 scalar: a single number per step → line plot → convergence.
- b → 3 histogram: distribution of many values (all weights/grads in a layer) → spot a spike near zero (vanishing) or huge tails (exploding).
- c → 5 image: literally shows the pixels the model receives.
- d → 1 graph: the computation/architecture diagram.
- e → 4 embedding: projects high-dim feature vectors to 2D/3D to see clusters.
Exercise 1.2 (L1)
In writer.add_scalar('Loss/train', loss, epoch), what is the role of the third argument epoch, and what breaks if you always pass 0?
Recall Solution
The third argument is the step (the x-axis position of the point). It tells TensorBoard where on the horizontal axis to place this value. If you always pass 0, every point lands at horizontal position zero — you get a vertical stack of dots, no curve, no way to see the trend over time.
Level 2 — Application
Exercise 2.1 (L2)
Your training loop runs 5 epochs, each with 200 batches. You log train loss every 50 batches. Compute global_step for the log that happens at epoch 3, batch 150.
Use the standard formula, restated here (all quantities defined in the box at the top of the page): In words: take how many full epochs have passed, multiply by the number of batches per epoch to skip past them, then add where you are inside the current epoch.
Recall Solution
Here len(train_loader) = 200 (batches per epoch). Epoch 3 (zero-indexed) means 3 full epochs already passed. Batch index 150.
Why global_step and not batch_idx alone: batch_idx resets to 0 every epoch, so points from different epochs would overwrite/overlap. Multiplying epoch by the number of batches per epoch shifts each epoch into its own horizontal slot, producing one continuous axis.
Exercise 2.2 (L2)
Given this snippet, how many scalar points land in Loss/train after the full run of Exercise 2.1?
for epoch in range(5):
for batch_idx in range(200):
if batch_idx % 50 == 0:
writer.add_scalar('Loss/train', loss.item(),
epoch*200 + batch_idx)Recall Solution
batch_idx % 50 == 0 is true for batch_idx ∈ {0, 50, 100, 150} → 4 logs per epoch.
Over 5 epochs: five groups of four, which is 20 points in total.
Each point has a distinct step because epoch*200 + batch_idx never repeats across the loop, so all 20 are plotted (none overwritten).
Exercise 2.3 (L2)
Rewrite the two TensorBoard lines
writer.add_scalar('train_loss', tl, epoch)
writer.add_scalar('val_loss', vl, epoch)as a single W&B call, keeping epoch on the x-axis.
Recall Solution
wandb.log({"train_loss": tl, "val_loss": vl}, step=epoch)Why one call: wandb.log takes a dictionary — all keys logged at the same internal step. Why step=epoch explicitly: passing step=epoch pins these metrics to a known x-axis position instead of relying on W&B's auto-incrementing internal counter, so the two curves align exactly on the epoch axis. (You may also add "epoch": epoch as a dict key if you want epoch selectable as a custom x-axis in the UI, but the step= argument is the reliable alignment tool.) This is the structural difference from TensorBoard: TB uses one call per tag; W&B batches a whole dict per step.
Level 3 — Analysis
Look at the loss curves below — you must read the plot and name the failure.

Exercise 3.1 (L3)
Curve A (red) in the figure: train loss keeps falling but validation loss turns upward after step ~40. Name the phenomenon and the single most useful additional thing to log to confirm it.
Recall Solution
This is overfitting: the model keeps memorising the training set (train loss ↓) while generalisation worsens (val loss ↑). The gap between the two curves is the tell. Most useful extra log: a validation metric (accuracy/F1), because a rising val loss with still-improving accuracy can be benign (confident-but-correct); a rising val loss and falling accuracy confirms true overfitting. Also useful: weight-norm histograms trending large (over-confident weights).
Exercise 3.2 (L3)
The GradNorm scalar from the parent's example reads: 1e-1, 3e-3, 8e-5, 2e-6, ... across steps. Using ideas from 2.4.7-Gradient-flowand-vanishing-exploding-gradients, diagnose it. What would the weight histogram of an early layer look like?
Recall Solution
The gradient norm is shrinking by roughly one to two orders of magnitude per step: A steady multiplicative decay toward zero is the signature of vanishing gradients. The early-layer weight histogram would barely move between epochs — a nearly frozen, static distribution — because tiny gradients produce tiny updates. (Contrast: exploding gradients give a growing norm and histograms that fan out / develop huge tails.)
Exercise 3.3 (L3)
Look at figure s02. A weight histogram is plotted at epoch 0 and epoch 9. In panel (i) the two distributions are nearly identical; in panel (ii) the epoch-9 distribution is wider and shifted. Which panel shows a healthy, learning layer? Justify.

Recall Solution
Panel (ii) (the red distribution that moved) is healthy. A learning layer's weights change: updates accumulate, the distribution shifts and typically spreads. Panel (i), where nothing moved, means near-zero effective updates — a symptom of vanishing gradients, a dead layer, or a learning rate too small. The movement itself is the diagnostic, not the shape.
Level 4 — Synthesis
Exercise 4.1 (L4)
You run a hyperparameter sweep (see 4.1.5-Hyperparameter-tuning) over lr ∈ {1e-2, 1e-3, 1e-4} and batch_size ∈ {32, 64}. How many runs is that, and what single logging construct lets you compare all of them in one sortable table? Name it for both TensorBoard and W&B.
Recall Solution
Grid size: three learning rates times two batch sizes, which is 6 runs.
- TensorBoard:
writer.add_hparams(hparam_dict, metric_dict)→ populates the HPARAMS tab, a sortable table (one row per run, columns = hyperparameters + final metrics). - W&B: pass hyperparameters into
wandb.init(config=...); the Runs table / Sweeps view sorts and parallel-coordinates them automatically.
Exercise 4.2 (L4)
Design (in pseudocode) a training loop that logs to TensorBoard and saves the best checkpoint with a version tag, tying in 5.2.3-Model-versioning. State why each logged item exists.
Recall Solution
writer = SummaryWriter('runs/exp_v1')
best_acc = 0.0
for epoch in range(E):
tl = train_epoch() # scalar: convergence
vl, va = validate()
writer.add_scalar('Loss/train', tl, epoch)
writer.add_scalar('Loss/val', vl, epoch) # gap → overfit check
writer.add_scalar('Acc/val', va, epoch) # the metric we optimise
for n, p in model.named_parameters():
writer.add_histogram(n, p, epoch) # weight movement → learning
if p.grad is not None:
writer.add_histogram(n+'/grad', p.grad, epoch) # vanish/explode
if va > best_acc: # versioning
best_acc = va
torch.save(model.state_dict(), f'ckpt_epoch{epoch}_acc{va:.3f}.pth')
writer.close()Why each item: train/val loss → convergence + overfitting gap; val acc → the objective; weight histograms → confirm layers learn; grad histograms → catch vanishing/exploding early; checkpoint filename embeds epoch + accuracy so the best model is self-describing and reproducible (the core idea of 5.2.3-Model-versioning).
Level 5 — Mastery
Exercise 5.1 (L5)
Your model has 10 million parameters. You call writer.add_histogram(name, param, epoch) for every parameter tensor every batch, with 1000 batches/epoch. Estimate why this destroys performance, and give the fix. Assume histogram logging touches all params each call.
Recall Solution
Values touched per epoch (order of magnitude): Histogram computation must scan all values and bin them — this is roughly per call, so you're doing tens of billions of extra reads plus disk writes per epoch. Training I/O and CPU are swamped; the GPU starves. Fix: log histograms per epoch, not per batch (÷1000), and optionally only for a few diagnostic layers. Log cheap scalars frequently, expensive histograms rarely. This is the general principle: match logging frequency to the cost and the signal's rate of change.
Exercise 5.2 (L5)
You log Loss/train every 10 steps for a 50-epoch run, 800 steps/epoch. Each scalar point costs ≈ 40 bytes on disk. Estimate total scalar-log size, and argue whether disk is your bottleneck.
Recall Solution
Steps total: . Logged points: . Bytes: Scalars are tiny — disk is not the bottleneck for scalars. This confirms the L5.1 lesson from the other side: log scalars generously, they're cheap; the cost explosion comes from histograms, images, and embeddings, not scalars.
Exercise 5.3 (L5)
A W&B sweep with wandb.log uploads to the cloud. Your metric-logging call runs 40,000 times, and network round-trips of one small packet each would add latency. Explain how W&B avoids one HTTP request per log, and what property of the design keeps training crash-safe despite buffering.
Recall Solution
W&B batches logs client-side: many wandb.log calls accumulate in a buffer and are flushed to the cloud asynchronously in a background process, not one request per call. So 40,000 logs become a manageable number of batched uploads — training threads aren't blocked on the network.
Crash-safety despite buffering: the same data is also written to a local run directory on disk immediately. If the process dies, the local records survive and are re-synced on the next wandb sync. The append-only local log is the source of truth; the cloud upload is an optimistic mirror.
Recall One-line recap of every level
L1 recognition ::: know what each logged object answers; the step argument is the x-axis position of a point. L2 application ::: global_step = epoch × len(train_loader) + batch_idx; batch W&B metrics in one dict and pass step=epoch to align curves. L3 analysis ::: read curves — overfitting is train loss down while val loss up; vanishing gradients show a steadily decaying grad norm; a healthy layer's weight histogram moves between epochs. L4 synthesis ::: combine scalars + histograms + versioned checkpoints; use the HPARAMS tab / W&B sweeps to compare runs in a sortable table. L5 mastery ::: match logging frequency to cost — scalars are cheap, histograms/images/embeddings are expensive; W&B batches uploads and keeps a local crash-safe copy.