<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Quantization | Dat Viet Thanh Nguyen</title><link>https://datvtn.github.io/tags/quantization/</link><atom:link href="https://datvtn.github.io/tags/quantization/index.xml" rel="self" type="application/rss+xml"/><description>Quantization</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Fri, 14 Aug 2026 00:00:00 +0000</lastBuildDate><image><url>https://datvtn.github.io/media/icon_hu82c06b08a282889123d30d9b11b05ced_13465_512x512_fill_lanczos_center_3.png</url><title>Quantization</title><link>https://datvtn.github.io/tags/quantization/</link></image><item><title>What I Learned Shipping Computer Vision Models to 10+ Edge Targets</title><link>https://datvtn.github.io/writing/deploying-cv-models-on-edge-socs/</link><pubDate>Fri, 14 Aug 2026 00:00:00 +0000</pubDate><guid>https://datvtn.github.io/writing/deploying-cv-models-on-edge-socs/</guid><description>&lt;p>Over four years at VinAI I deployed computer vision models onto NVIDIA Xavier, Qualcomm QCS610 and SA8255P, Ambarella CV25, KingFisher boards, and VinSmart phones — through TensorRT, SNPE, QNN, CVFlow, NCNN, MNN, and TFLite. Different silicon, different toolchains, same recurring lessons. These are the ones I would tell my earlier self.&lt;/p>
&lt;h2 id="the-bottleneck-is-almost-never-the-network">The bottleneck is almost never the network&lt;/h2>
&lt;p>The instinct when a model is too slow on device is to make the model smaller. Often that is the wrong lever. Before touching the architecture, it is worth checking:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Are all your operations actually running on the accelerator?&lt;/strong> A single unsupported op in the middle of a graph can force a fallback to CPU, and the round trip costs more than the op saves. The profile will show a suspiciously expensive layer that looks trivial on paper.&lt;/li>
&lt;li>&lt;strong>Where is the pre- and post-processing running?&lt;/strong> Resize, colour conversion, letterboxing, and NMS are easy to leave in Python or in unoptimised CPU code. On a real pipeline these can rival inference time.&lt;/li>
&lt;li>&lt;strong>Is the pipeline saturated?&lt;/strong> A model that takes 15 ms but sits idle waiting for frames is not a 15 ms pipeline.&lt;/li>
&lt;/ul>
&lt;p>Measuring end to end, on the target, before optimising anything, saves a lot of wasted architecture work.&lt;/p>
&lt;h2 id="flops-are-not-latency">FLOPs are not latency&lt;/h2>
&lt;p>A model with fewer multiply-accumulates is not automatically faster on a given SoC. Depthwise separable convolutions are the classic example: excellent FLOP economy, but memory-bandwidth bound, and on some accelerators they run &lt;em>worse&lt;/em> than a denser convolution with more nominal work.&lt;/p>
&lt;p>This is why designing against the target beats shrinking after the fact. When we built a Neural Architecture Search pipeline to generate object detection architectures for CPU-constrained devices, the useful part was not NAS itself — it was that the search was scored against measured on-device latency rather than a proxy like FLOPs or parameter count. The architectures it found were ones we would not have chosen by intuition.&lt;/p>
&lt;h2 id="ptq-first-qat-when-you-have-to">PTQ first, QAT when you have to&lt;/h2>
&lt;p>Going from FP32 to INT8 is usually the single largest win available, and post-training quantization gets you most of it for very little effort. My default order of operations:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Post-training quantization&lt;/strong> with a representative calibration set. &amp;ldquo;Representative&amp;rdquo; is doing real work in that sentence — a calibration set drawn from clean, well-lit training images will produce a model that falls apart on the hard inputs it will actually see.&lt;/li>
&lt;li>&lt;strong>Look at where the accuracy actually went.&lt;/strong> Quantization error is rarely spread evenly. It concentrates in a few layers — often the first and last, and anything with a wide dynamic activation range.&lt;/li>
&lt;li>&lt;strong>Selectively keep those layers at higher precision&lt;/strong> before reaching for anything more elaborate.&lt;/li>
&lt;li>&lt;strong>Quantization-aware training&lt;/strong> only when the above is not enough. It works, but it costs a training cycle every time the model changes, which changes how quickly you can iterate.&lt;/li>
&lt;/ol>
&lt;p>For face and detection models we compressed substantially with minimal accuracy loss this way. The failure mode to watch for is evaluating the quantized model only on your clean benchmark: INT8 degradation shows up disproportionately on the tail — small faces, low light, motion blur — which is exactly the part of the distribution the product is judged on.&lt;/p>
&lt;h2 id="every-runtime-has-opinions">Every runtime has opinions&lt;/h2>
&lt;p>Supporting many targets means accepting that &amp;ldquo;export the model&amp;rdquo; is not a single step. Each runtime has its own supported operator set, its own layout preferences, its own quantization semantics, and its own quiet behavioural differences. Things that helped:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Keep one source model and a per-target export path&lt;/strong>, not a fork per target. Forks drift, and then a bug fixed in one place lives on in four others.&lt;/li>
&lt;li>&lt;strong>Test numerical parity at every hop.&lt;/strong> Compare FP32 PyTorch against exported FP32 against quantized on-device output, on the same inputs. Catching a discrepancy at the export step is minutes of work; catching it after integration is days.&lt;/li>
&lt;li>&lt;strong>Constrain the architecture to the intersection of what your targets support.&lt;/strong> An exotic operator that only one runtime handles well will cost more in maintenance than it earns in accuracy.&lt;/li>
&lt;/ul>
&lt;h2 id="accuracy-is-not-the-product">Accuracy is not the product&lt;/h2>
&lt;p>A driver monitoring system that is correct 99% of the time but stutters is worse, to the person using it, than one that is slightly less accurate and smooth. Frame-to-frame stability, latency consistency, and graceful behaviour under thermal throttling are all part of whether the thing is any good — and none of them appear in a validation metric.&lt;/p>
&lt;p>That gap between the benchmark and the product is, to me, the interesting part of this work.&lt;/p></description></item></channel></rss>