prepare(model: nn.Module, qconfig: QConfig | QConfigMapping | None = None, inplace: bool = False)Attach activation observers to a float model ahead of calibration.
prepare is step one of the eager-mode static post-training quantization
(PTQ) workflow — the classic prepare → calibrate → convert
pipeline. It does not touch weights or change any numerics; it walks the
model and, for every quantizable module the QConfigMapping selects,
attaches an activation observer as a forward hook. As calibration data
flows through the returned model, each observer records the running range
(min / max, or a histogram) of that module's output, and convert
later reads those ranges to freeze the per-layer activation scale /
zero_point.
Only module types in the observed set — Linear, the Conv / ConvTranspose
family, the intrinsic fused Conv/Linear+ReLU modules, a handful of
activations, and the QuantStub / FloatFunctional boundaries — receive
an observer, and only where the mapping returns a non-None QConfig
for them. The model is switched to eval mode so BatchNorm / Dropout stay
deterministic during calibration. Use this when you want the best accuracy
and can afford a calibration pass over representative data; for a
calibration-free path see quantize_dynamic, and to make quantization
error visible to the optimizer see prepare_qat.
Parameters
modelnn.ModuleQuantStub / DeQuantStub
boundaries are picked up automatically; if you would rather not place
them by hand, use prepare_fx, which wraps them for you.QConfig is promoted to a
global mapping, and None (default) falls back to
get_default_qconfig_mapping (per-channel int8 weights,
per-tensor affine activations).inplacebool= FalseTrue mutate and return model itself; if False (default)
observe a copy.deepcopy and leave the original untouched.Returns
nn.ModuleThe prepared, eval-mode model carrying activation observers. Run
representative data through it to calibrate, then pass it to
convert.
Notes
- Non-destructive: with
inplace=Falsethe source model is deep-copied, so the returned graph is a separate object. - Nothing is quantized yet — the returned model still runs in full float and
is marginally slower than the original because of the observer hooks.
The size / speed win only lands after
convert. - If the mapping matches no quantizable module a
UserWarningis raised and a laterconvertleaves the model unchanged — usually a sign theQConfigMappingtargets types the model does not contain. - Fuse Conv/BN/ReLU runs with
fuse_modulesbeforeprepareso the observer sees the true post-fusion (e.g. post-ReLU) activation range.
Examples
>>> import lucid, lucid.nn as nn
>>> import lucid.quantization as Q
>>> model = nn.Sequential(nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 10))
>>> model.qconfig = Q.get_default_qconfig()
>>> prepared = Q.prepare(model) # observers inserted (deep copy)
>>> for _ in range(8): # calibrate on representative data
... _ = prepared(lucid.randn(32, 128))
>>> qmodel = Q.convert(prepared) # freeze qparams, bake int8 weights
Targeting a type the model does not contain warns, and the downstream
convert becomes a no-op:
>>> mapping = Q.QConfigMapping().set_object_type(nn.Conv2d, Q.get_default_qconfig())
>>> _ = Q.prepare(nn.Sequential(nn.Linear(8, 8)), mapping)
UserWarning: prepare(): the QConfigMapping matched no quantizable modules ...See Also
- lucid.quantization.convert—Bake the calibrated model into quantized modules.
- lucid.quantization.quantize_dynamic—Calibration-free dynamic quantization.
- lucid.quantization.prepare_qat—Insert fake-quant for quantization-aware training.
- lucid.quantization.fuse_modules—Fuse Conv/BN/ReLU runs before
prepare.