Why model size suddenly becomes your bottleneck
You ship a model that looks fine in a notebook, then it hits production and everything slows down. The first surprise is often not raw compute, but memory: weights don’t fit comfortably on a single GPU, or they barely fit and leave too little room for the KV cache, batch padding, and framework overhead. Latency spikes as you spill across devices, page memory, or shrink batch size to avoid out-of-memory errors.
Even when it fits, moving that many bytes becomes the limiter. Modern accelerators can do math faster than they can fetch weights, so a “bigger” model turns into a bandwidth problem, which turns into a cost problem when you scale replicas to meet SLOs.
What quantization changes inside a neural network
Quantization attacks the bandwidth problem by changing how numbers are represented and moved through the network. Instead of storing weights as FP16/BF16 (16-bit floating point), you store them as INT8 or even 4-bit values, plus a small set of scaling factors (and sometimes a zero-point) that map those integers back to an approximate real range. At runtime, the key operation becomes “integer math + rescale” rather than pure floating-point math. Many implementations keep activations in higher precision while quantizing weights (“weight-only”), because activations are more sensitive and harder to bound across inputs.
The cost of this compression is error you didn’t have before: rounding noise, saturation when values exceed the chosen range, and disproportionate damage from outliers. These effects show up most in places that depend on small numeric differences (attention scores, softmax, layer norm, and residual paths). Post-training quantization picks scales from calibration data and hopes distribution drift is small; quantization-aware training learns to be robust to the quantization noise. Mixed precision is the practical compromise: quantize the bandwidth-heavy parts, keep fragile layers in FP16/BF16.
The benefits you actually get: memory, speed, cost

You feel the upside first in memory headroom. Moving from FP16/BF16 weights to INT8 roughly halves weight storage, and 4-bit can cut it further, which often turns “barely fits” into “fits with room for KV cache and a sane batch size.” That extra room can matter more than the headline compression because it reduces out-of-memory retries, lets you keep longer contexts, and avoids sharding weights across devices just to stay alive.
Speed gains are real but uneven. If your serving is bandwidth-bound, weight quantization can improve tokens/sec by fetching fewer bytes per layer, especially when you have optimized kernels for your exact scheme. If you’re compute-bound, or your runtime falls back to dequantizing into FP16 and doing the matmul anyway, the improvement can be modest. The practical cost win comes from needing fewer GPUs (or smaller ones) for the same throughput, but you may pay a setup tax: calibration runs, new kernels, and more performance testing across prompts.
Where it hurts: accuracy drops and weird failures
You usually don’t notice the harm on “average” metrics first; you notice it in tail behavior. A quantized model might look fine on a benchmark suite, then fail on specific prompt shapes: long contexts, lots of numbers, structured outputs, or multilingual text. The common pattern is that quantization noise nudges small score differences until a different token wins, and that early divergence cascades into a totally different completion. For classifiers, this can show up as unstable thresholds and flipped labels near the decision boundary.
The failures can also look qualitatively strange. You may see more repetition loops, lost formatting (broken JSON), or sudden topic jumps. Attention and normalization are frequent culprits, so “weight-only 4-bit everywhere” often degrades more than “4-bit for big matmuls, FP16 for norms and output heads.” You need more targeted evals and regression tests, and you may end up shipping per-model exceptions when one layer or one tokenization pattern breaks.
Choosing a method: PTQ, QAT, or mixed precision
A familiar decision point is when you’ve confirmed the model is memory- or bandwidth-bound, but you can’t afford a long retraining cycle. Post-training quantization (PTQ) is the fastest path: you pick a scheme (often INT8 or weight-only 4-bit), run calibration on representative traffic, and ship if regressions stay inside tolerance. PTQ works best when distributions are stable and you have strong kernel support; it fails fastest when your workload has heavy outliers (long contexts, numeric strings, tool schemas) that your calibration set under-represents.
Quantization-aware training (QAT) is what you reach for when PTQ keeps “almost working” but breaks in the same places every time. By injecting quantization effects during training or fine-tuning, the model can learn to route around the noise, especially in attention and residual paths. You need training infrastructure, careful hyperparameters, and a repeatable pipeline whenever the base model or data shifts.
Mixed precision is the pragmatic default when you want predictable behavior: quantize the big matmuls that dominate bandwidth, keep layer norms, softmax-adjacent ops, and output heads in FP16/BF16. It’s rarely the smallest or fastest theoretical option, but it’s often the easiest to debug and the easiest to roll back per-layer when a failure mode shows up.
Deployment reality: hardware, kernels, and monitoring

The first production surprise is that “INT8” or “4-bit” isn’t a single thing; it’s a contract between your model format, your runtime, and the kernels your hardware can actually execute. A quantized checkpoint that screams in one stack can crawl in another because you silently fall back to “dequantize to FP16, then matmul,” which restores memory traffic and adds overhead. Kernel availability depends on details that sound minor until they aren’t: per-tensor vs per-channel scales, symmetric vs asymmetric ranges, group size for 4-bit, and whether you’re doing weight-only or also quantizing activations. Even packing layout matters, and the fastest path often requires a specific library build and careful GPU driver/runtime versions.
You also inherit new operational failure modes. Monitor tail latency by prompt shape (context length, numeric density, tool JSON), not just averages, and alert on shifts. Keep a canary slice served in higher precision to detect drift, and log structured validity rates (e.g., JSON parse success) alongside accuracy proxies. Expect a real integration cost: kernel tuning, compatibility testing across instance types, and rollback plumbing when one layer’s quantization breaks a critical workflow.
A practical checklist to decide if it’s worth it
A common moment is realizing you’re about to spend a week “making INT8 work” without being sure it will pay off. Start with a quick check: are you actually memory or bandwidth bound (GPU memory pressure, low batch size, high HBM reads), or compute bound (high FLOP utilization)? If it’s memory/bandwidth, estimate the win you need (fewer GPUs, longer context, lower p95) and pick the lightest method that could reach it: FP16/BF16 baseline, then INT8 PTQ, then weight-only 4-bit, and only then QAT.
Before you commit, verify kernel support on your exact deployment stack and instance types, including the details (group size, per-channel scales, activation precision). Run targeted evals that mirror production: long contexts, numeric-heavy prompts, structured outputs, multilingual, and any tool schemas. Put a hard rollback plan in place: per-model toggle, per-layer mixed-precision escape hatch, and monitoring on p95/p99 and validity (like JSON parse rates), because the real cost is chasing tail failures after launch.