dequantize(q: Tensor, scale: _ScaleLike, zero_point: _ZeroPointLike, ch_axis: int | None = None)Decode integer codes back to a float32 approximation of the original.
dequantize is the inverse of quantize — the read side of the
affine map. It undoes the offset and scaling to recover a floating-point
tensor from the stored integer codes. It is the operation that lets a
quantized weight participate in an ordinary float matmul: the sidecar-design
quantized modules keep their weight as int8 codes, then call dequantize
on every forward to reconstruct a float weight before the GEMM. The result
is not the exact original — it is the original rounded to the nearest grid
point — but the error per element is bounded by s / 2.
The decode is the affine inverse:
where the subtraction removes the zero_point offset z and the
multiply restores the physical step s. As in quantize, a
per-channel scale / zero_point (given ch_axis) is reshaped to
broadcast along the channel axis, so each channel is decoded with its own
step. The whole computation is a subtract-then-multiply on the public
lucid.* op surface (H4), identical on the Accelerate and MLX streams.
Parameters
quantize (or an equivalent
encoder). Cast up to float32 internally before the affine decode.scaleTensor or floats used to produce q. A length-C
tensor for per-channel; a scalar for per-tensor.zero_pointTensor, float, or intz used to produce q.ch_axisint= NoneNone (default) uses a single
scalar scale / zero_point for the whole tensor.Returns
TensorA float32 reconstruction of the original tensor, the same shape as
q.
Notes
- Lossy by construction —
dequantize(quantize(x)) ≈ xonly up to the grid resolution; values that saturated during encode are not recovered. - Must be called with the same
scale/zero_point/ch_axisused to encode; mismatched qparams silently produce wrong magnitudes. - Output is always
float32regardless of the input storage dtype, and the op carries no straight-through gradient (it is a plain composite, not a custom autograd Function).
Examples
>>> import lucid
>>> import lucid.quantization as Q
>>> x = lucid.tensor([-1.0, 0.0, 0.5, 2.0])
>>> q = Q.quantize(x, scale=0.05, zero_point=0, qdtype=Q.qint8)
>>> x_hat = Q.dequantize(q, scale=0.05, zero_point=0)
>>> bool((lucid.abs(x_hat - x) <= 0.05).all().item()) # within one step
True
Per-channel decode mirrors the encode axis exactly:
>>> w = lucid.randn(4, 8)
>>> s, zp = lucid.ones(4) * 0.02, lucid.zeros(4)
>>> codes = Q.quantize(w, s, zp, Q.qint8, ch_axis=0)
>>> Q.dequantize(codes, s, zp, ch_axis=0).shape
(4, 8)See Also
- lucid.quantization.quantize—The forward affine encode
round(x/s) + z. - lucid.quantization.fake_quantize—Fused encode→decode with an STE gradient.
- lucid.nn.quantized.Linear—Uses
dequantizeon its int8 weight each forward.