HistogramObserver
ObserverBaseHistogramObserver(bins: int = 2048, qscheme: QScheme = per_tensor_affine, qdtype: QDtype = quint8, eps: float = 1e-08)Per-tensor observer that records a value histogram and picks a clip range.
The accuracy-maximising activation observer. Instead of committing to the raw
[min, max] — which on a heavy-tailed activation would stretch the grid over a
handful of rare extremes and quantize the dense bulk coarsely — it accumulates a
bins-bucket histogram of every value seen (via the engine histc primitive),
then at calculate_qparams time searches for the clip range
[new_min, new_max] that minimises the expected L2 quantization error. Clipping
the tails costs a little error on the rare outliers but wins far finer resolution on
the common values, which is usually a large net accuracy gain.
When to pick it. Use it for activations with skewed / heavy-tailed
distributions — it is the activation observer in
lucid.quantization.get_default_qconfig (static PTQ). It is more expensive
than min/max (it maintains a histogram and runs a search) and applies to per-tensor
affine schemes, so it is not used for per-channel weights (see
PerChannelMinMaxObserver). When calibration is cheap and distributions are
light-tailed, plain MinMaxObserver / MovingAverageMinMaxObserver
suffice.
The running range widens with the data; when it grows the existing histogram is rebinned onto the wider support before the new batch is added. With bin centers and counts , the search evaluates candidate clip endpoints (drawn from a few tail quantiles) and picks the pair minimising the per-value clip error plus the uniform-quantization noise variance:
where the first term is the squared clipping error (mass pushed onto the boundary)
and is the variance of rounding to a uniform grid of step
. The winning is then fed to
lucid.quantization.calculate_qparams for the final affine (scale, zero_point).
Parameters
binsint= 2048[min, max]. More bins give a
finer clip search at higher memory / compute cost.quint8 gives the unsigned [0, 255] grid.epsfloat= 1e-8scale.Attributes
Notes
- Rebinning on growth. When a batch widens
[min, max], the stored histogram is redistributed onto the new, wider bin grid before the fresh counts are added, so accumulated mass is preserved rather than discarded. - Search is a coarse scan. The clip endpoints are candidate tail quantiles
(
0, 1e-5, 1e-4, 1e-3, 5e-3, 1e-2), not a full exhaustive sweep — a deliberate speed / accuracy trade-off. The best-scoring pair wins. - Data-dependent control flow.
forwardreadsx.min()/.max()via.item()and the search runs in Python overhistogram.tolist(); this is a sanctioned CPU round-trip (data-dependent output), still H4-pure (enginehistc, no external histogram library). - Buffer re-registration.
min_val/max_val/histogramare all updated viaregister_buffer(same name) per theObserverBasecontract. - Symmetric vs affine. The reduction honours
qscheme; the default per-tensor affine leaveszero_pointfree to fit the (clipped) asymmetric range. - Default activation observer of
lucid.quantization.get_default_qconfig.
Examples
>>> import lucid
>>> import lucid.quantization as Q
>>> obs = Q.HistogramObserver(bins=512)
>>> for _ in range(4):
... _ = obs(lucid.randn(8, 1024))
>>> obs.histogram.shape
(512,)
>>> scale, zero_point = obs.calculate_qparams()
>>> bool(scale.item() > 0)
True
On a heavy-tailed input the search clips the rare extreme, so the chosen range is
*narrower* than the raw min/max the histogram spans:
>>> import lucid
>>> x = lucid.randn(1, 100000)
>>> x[0, 0] = 50.0 # a single far outlier
>>> obs = Q.HistogramObserver(bins=2048)
>>> _ = obs(x)
>>> s, _ = obs.calculate_qparams()
>>> bool(s.item() * 255 < 50.0) # grid span clipped below the outlier
TrueSee Also
- lucid.quantization.MinMaxObserver—Cheaper per-tensor observer (no clip search).
- lucid.quantization.MovingAverageMinMaxObserver—EMA alternative for outliers.
- lucid.quantization.get_default_qconfig—Uses this as the activation observer.
- lucid.quantization.calculate_qparams—Reduces the chosen clip range to qparams.
- lucid.quantization.FakeQuantize—Wraps an observer for QAT.