Integer inference and device kernels
Connect affine quantization to zero-point correction, accumulator range, bias scaling and the exact kernel contract supported on a target architecture.
On this page
The question for today
What you’ll understand
- Compute a small affine-quantized dot product and output requantization.
- Check accumulator and bias units separately from int8 storage.
- Verify quantization format, layout and architecture features against a pinned kernel library.
An int8 file is not a complete execution specification. Integer kernels need matching scale conventions, zero points, bias units, rounding rules, tensor layouts, and supported architecture instructions. A model can load while taking an unintended dequantized or reference path, or run quickly with a subtle scaling error. Use a pinned numeric contract: this lesson’s concrete convolution conventions come from TensorFlow 2.18.0’s signed-int8 specification and CMSIS-NN 7.0.0’s supported Arm microcontroller kernels.
A quantized byte needs a scale and a zero point
Affine quantization interprets an integer q as a real approximation s times q minus z, with positive scale s and integer zero point z. The zero point makes real zero exactly representable, which matters for padding and sparse values. TensorFlow’s referenced int8 convention permits asymmetric activation zero points, while its convolution weights use symmetric zero point zero and a restricted signed range. Per-output-channel weight scales are another contract dimension; changing that axis without changing the kernel’s interpretation changes the arithmetic.
Quantization calibration data should represent the actual sensor pipeline, rare values, and device preprocessing. Clipping and rounding introduce different errors: clipping saturates an out-of-range value, while rounding chooses a nearby representable value inside the range. Test them separately and inspect task-level failures rather than reporting only average tensor error. A small numerical perturbation can cross a downstream decision threshold, while a larger perturbation in an irrelevant tensor direction may have little task impact.
Accumulate in the required domain and requantize once
For symmetric weights, subtract the activation zero point before forming the integer dot product. The accumulator represents real values in units of input scale times weight scale. An integer bias must use that same scale; adding an int8 output-scale bias directly to an int32 accumulator is dimensionally wrong. After accumulation, multiply by the ratio of accumulator scale to output scale, round under the kernel’s rule, add the output zero point, and clamp to the output integer range.
Accumulator width is not implied by operand width. A conservative magnitude bound sums the maximum corrected product magnitudes and bias, then checks the required signed range. Intermediate implementation details, vector instructions, and requantization shifts need the library’s own constraints too. CMSIS-NN 7.0.0 selects pure-C, DSP, or MVE implementations based on target feature flags; its support matrix is not a promise that every int8 model or processor uses the fastest implementation. Verify the actual linked kernel and required scratch allocation.
Test the deployed numeric and kernel path
Build reference cases for zero input, padding, extrema, negative values, bias, and saturation, then compare against the selected device kernel. Check shapes and layouts that change optimized-kernel eligibility. Record compiler architecture flags, library version, quantization metadata, and conversion settings with the artifact. A task-quality evaluation must cover the final pipeline, including any float fallback or requantization boundary. A size reduction without the intended integer kernel may still help storage but need not reduce latency or energy.
The sigmoid lab demonstrates downstream sensitivity to a weight perturbation, without implementing quantization. Reset, set x to 1 and w to 0.8, predict logit 0.3 and output approximately 0.5744, then Step. Compare a fresh Reset with both x at 1 and w at 0.75 before Step: logit 0.25 and output approximately 0.5622. The bias stays −0.5. These floating-point calculations contain no integer accumulator, zero point, clipping rule, or architecture-specific kernel.
Work it through
Trace corrected products, bias and output scale
Use activation integers (13, 9), zero point 10, and scale 0.1. Weight integers are (4, −2), zero point zero, and scale 0.05. Real bias is 0.01. The output scale is 0.02 and output zero point −3. Assume no clipping and exact arithmetic for this small example.
Corrected activation integers are (3, −1), reconstructing (0.3, −0.1). Weights reconstruct to (0.2, −0.1), and bias integer is 0.01/(0.1 × 0.05) = 2.
The integer accumulator is 3 × 4 + (−1) × (−2) + 2 = 16. In real units it represents 16 × 0.005 = 0.08.
Requantize using multiplier 0.005/0.02 = 0.25: round(16 × 0.25) − 3 = 1. Dequantizing output gives (1 + 3) × 0.02 = 0.08, matching the real dot product plus bias here.
Matching storage width is insufficient; the scale and zero-point path must agree from input through accumulator to output.
The living notebook
Explore the model
Interactive lab · network
A small weight error can move a downstream score
Reset, set x = 1 and w = 0.8, predict z = 0.3 and sigmoid ≈ 0.5744, then Step. Compare a fresh Reset with both x = 1 and w = 0.75 before Step: z = 0.25 and sigmoid ≈ 0.5622. Fixed bias is −0.5. This floating-point unit illustrates sensitivity, not integer quantization or a CMSIS-NN kernel.
- Product · wx
- 1.2
- Logit · wx − 0.5
- 0.7
- Sigmoid output
- 0.6682
One inspectable sigmoid unit, σ(wx − 0.5). Playback traces the computation graph. There is no training, attention mechanism or hidden deep network. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forTest final decision quality as well as local arithmetic error.
Pause & reason
Check your understanding
Your turn
Try it yourself
Use q_x = (7, 3), z_x = 5, s_x = 0.2; q_w = (3, −1), z_w = 0, s_w = 0.1; and zero bias. With output scale 0.1 and zero point 2, compute accumulator, output integer, and reconstructed real output.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Subtract the activation zero point, form the integer products, then apply the ratio (0.2 × 0.1)/0.1 before adding output zero point.
Compare with the solution
Corrected activation integers are (2, −2), so A = 2 × 3 + (−2) × (−1) = 8. The real accumulator value is 8 × 0.02 = 0.16. Ideal nearest rounding gives q_y = round(1.6) + 2 = 4, reconstructing (4 − 2) × 0.1 = 0.2. The 0.04 real-unit discrepancy is output rounding error in this example, not an incorrect zero-point subtraction; kernel-specific fixed-point behavior still needs its own tests.
Keep the idea
Take it with you
- Interpret integer values through explicit scale and zero-point metadata.
- Bias, accumulator width and output requantization require separate checks.
- Pin the kernel library and architecture path, then validate task-level quality.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.