The Post-Training Quantization pipeline transforms a trained FP32 model into an INT8 model without retraining. The key steps are: data collection, statistics gathering, scale computation, and model conversion.
Shreedhar Kodate·04 March 2025·4 min read
quantization-deep-learningdocs
1. Standard PTQ Workflow (8 Steps)
The Post-Training Quantization pipeline transforms a trained FP32 model into an INT8 model without retraining. The key steps are: data collection, statistics gathering, scale computation, and model conversion.
Quantization-Aware Training improves upon PTQ by adapting model weights to quantization error during training. The Straight-Through Estimator (STE) enables gradient flow through the non-differentiable rounding operation.
flowchart TD
Q1["Step 1: Start from Pretrained FP32 Model\nUse converged FP32 checkpoint\nHigher initial accuracy → better final QAT result"]
Q2["Step 2: Prepare for QAT\ntorch.quantization.prepare_qat(model)\nFuses Conv-BN-ReLU patterns\nInserts FakeQuantize nodes:\n - Acts on activations (after each layer)\n - Acts on weights (before each Conv/Linear)"]
Q3["Step 3: Fine-tune with Simulated Quantization\nForward pass uses fake-quantized values:\n x_q = round(x/scale) * scale (FP32 domain)\nLower LR than original training (1e-5 to 1e-4)\nTypically 10–25% of original training epochs"]
Q4["Step 4: STE Enables Weight Updates\nBackward pass gradient through FakeQuantize:\n ∂L/∂x ≈ ∂L/∂x_q (identity STE)\nWeights adapt to minimize loss\nwith quantization noise baked in"]
Q5["Step 5: Convert to True INT8\nmodel.eval()\ntorch.quantization.convert(model)\nRemoves FakeQuantize nodes\nConverts float ops to integer ops\nFreezes learned scale/zero_point values"]
Q6["Step 6: Validate & Deploy\nExpected: 0.1–0.5% accuracy drop vs FP32\nVs PTQ: 0.5–2% accuracy drop\nSame inference speed as PTQ INT8"]
Q1 --> Q2
Q2 --> Q3
Q3 --> Q4
Q4 --> Q3
Q4 --> Q5
Q5 --> Q6
style Q1 fill:#4488ff,color:#fff
style Q2 fill:#ff9900,color:#000
style Q4 fill:#ffdd44,color:#000
style Q5 fill:#44aa44,color:#fff
style Q6 fill:#884488,color:#fff
3. Calibration Range Selection Flow
Calibration determines the optimal clipping range [min, max] for quantizing activations. The choice of calibration method significantly impacts quantization accuracy.
flowchart TD
IN["Input: Activation Tensor\nfrom calibration data (N samples)"]
COLLECT["Collect Statistics\nPass calibration batches through model\nObservers record activation values"]
HIST["Build Histogram\nBin activations into kl_bins buckets\n(captures full distribution shape)"]
subgraph METHODS ["Calibration Method Choices"]
direction LR
MM["Min-Max\nrange = [min, max]\nFast, exact, outlier-sensitive"]
PCT["Percentile\nrange = [p-th, (100-p)-th]\nClip outliers at chosen %"]
MSE_C["MSE Search\nFor α in [0.8, 1.0]:\n range = [−α×max, +α×max]\n Pick α minimizing MSE"]
KL_C["KL-Divergence\nFor threshold T in [max/2, max]:\n Clip to T, quantize to 256 bins\n Minimize KL(FP32 || INT8)"]
end
SCALE["Compute scale & zero_point\nsymmetric: scale = max_abs / 127\nasymmetric: scale = range / 255"]
VALIDATE["Validate Range\nCompute SQNR for chosen range\nIf SQNR < 30 dB: try different method"]
ASSIGN["Assign to Model\nFreeze scale/zero_point per layer\nReady for torch.quantization.convert()"]
IN --> COLLECT
COLLECT --> HIST
HIST --> METHODS
METHODS --> SCALE
SCALE --> VALIDATE
VALIDATE --> ASSIGN
style METHODS fill:#f8f8f8
style MM fill:#ddeeFF
style PCT fill:#ddffd4
style MSE_C fill:#fff4dd
style KL_C fill:#ffd4d4
BatchNorm folding eliminates the BatchNorm layer by absorbing its parameters into the preceding Conv layer. This is done before quantization to reduce the number of quantized operations.
flowchart LR
subgraph BEFORE ["Before Folding"]
direction TB
C1["Conv2d\ny = W*x + b"]
BN1["BatchNorm2d\ny = γ*(x-μ)/σ + β"]
C1 --> BN1
end
FOLD["Fold BN into Conv\nW_new = W * γ/σ\nb_new = (b-μ)*γ/σ + β"]
subgraph AFTER ["After Folding"]
direction TB
C2["Conv2d (with bias)\ny = W_new*x + b_new"]
NOTE["BN layer eliminated!\nSame mathematical output\nFewer quantized operations"]
C2 --> NOTE
end
BEFORE --> FOLD --> AFTER
style BEFORE fill:#ffe8e8
style AFTER fill:#e8ffe8
Mathematical derivation:
BN forward: y_bn = γ * (conv(x) - μ) / σ + β
Combined: y = (W * γ/σ) * x + ((b - μ) * γ/σ + β)
Benefits:
Removes one layer of computation (faster inference)
Reduces number of quantization nodes
Eliminates BN's division and addition operations from the critical path