Skip to content

Histograms

metrana.log_histogram records the distribution of a tensor at one step — weight matrices, activations, gradients — as a histogram series that charts can render over time or reduce to scalar series (mean, quantiles, …):

metrana.log_histogram(metric_name, histogram, step, *, timestamp=None, scale=None, labels=None, evaluation=None)

step, scale, labels, and evaluation shape the series identity exactly as for standard metrics; this page covers the histogram value itself.

A histogram is a metrana.Histogram: strictly increasing finite bin_edges (up to 512 bins — unlike float metrics, a histogram’s structure rejects NaN/±inf) plus exactly one of two bin forms — which argument you pass declares the kind:

  • counts — per-bin element counts, np.histogram(x)-compatible.
  • densities — per-bin probability densities, np.histogram(x, density=True)-compatible.
import numpy as np
# np.histogram output wraps directly:
metrana.log_histogram("weights/l0", metrana.Histogram.from_numpy(np.histogram(w, bins=64)), step=100)
# construct explicitly for densities, and for float-typed counts (torch):
metrana.log_histogram("acts", metrana.Histogram(edges, densities=d), step=100)
metrana.log_histogram("weights/l0", metrana.Histogram(edges, counts=torch_hist), step=100)

A metric holds one value kind for its lifetime — set by the first point ever logged. Logging floats and histograms (or counting and density histograms) under one metric name is rejected at the log call. The same applies to the metric’s label key set — see One shape per metric.

Histogram.from_numpy accepts integer hist arrays only. A float hist array is ambiguous — np.histogram(..., density=True) returns floats, but so do torch’s histogram counts and weighted histograms — so it refuses to guess and asks for an explicit construction. counts= accepts float arrays holding exact integral values (torch’s histogram/histc native output); weighted histograms (fractional counts) are not supported.

Histogram steps are always explicit — there is no auto-increment. Histograms are typically logged sparsely (per epoch, every N steps), and their step axis must line up with the float series you chart them against. Steps may arrive in any order, and re-logging a step overwrites its histogram (never merges).

Reductions computed from bins are approximate — the error is bounded by the bin width. If the raw values are still in hand when you bin them, pass their exact moments and moment-based reductions (mean, std, min, max) become exact:

h = metrana.Histogram(
edges,
counts=c,
stats=(x.min(), x.max(), x.sum(), (x**2).sum()), # (min, max, sum, sum_of_squares)
)

When stats is omitted, the server stores a bin-approximation (occupied-bin bounds, midpoint sums). With densities= the sample count is not recoverable from the bins, so stats must be the normalized reading: sum = mean, sum_of_squares = mean of squares; min/max stay the sample bounds.