Overview

6 Porting Workflows Across Frameworks

This chapter explains how quantization work changes once models have to move across frameworks. In a single framework, it is usually enough to pick a granularity, calibrate, and recover accuracy; in production, though, the same model may be trained in PyTorch, served through ONNX Runtime, and deployed on mobile through TensorFlow Lite. The central warning is that identical-looking INT8 workflows can produce different results because frameworks make different choices about quantization semantics, fusion rules, and calibration behavior, so parity must be verified deliberately rather than assumed.

The chapter first grounds that idea in practical end-to-end paths. In PyTorch, TorchAO’s in-place weight-only quantization works well for transformer-heavy models where linear layers dominate, giving strong compression with little or no accuracy loss, but it does not speed up eager-mode inference because computation still runs in FP32. In TensorFlow Lite, the converter provides dynamic-range, full-integer, and FP16 modes; dynamic-range works well for transformers, full-integer is best for CNNs with stable activation ranges, and FP16 offers a low-risk compression option. For ONNX, exporting from PyTorch and then quantizing with ONNX Runtime shows how static quantization can capture CNNs effectively, while dynamic quantization is the right choice for transformers, especially when activation distributions are too variable for frozen calibration scales.

The final emphasis is on validation and diagnosis. The chapter shows that export fidelity can be nearly perfect in FP32, while quantization introduces different degrees of drift depending on model shape, output-space size, and operator coverage. Comparing logits, cosine similarity, and top-1 agreement helps distinguish harmless rounding noise from real behavioral changes, and operator-coverage checks reveal why compression does not always translate to speedup. The overall takeaway is that successful porting means understanding where frameworks disagree, choosing the right quantization path for the architecture, and confirming that the exported artifacts remain numerically equivalent enough for production use.

Three quantization paths from a trained PyTorch model to deployment-ready artifacts. Arrows represent conversion steps: downward arrows feed the FP32 model into each framework's quantization pipeline, horizontal arrows carry the model through quantization and optimization stages, and converging arrows at the bottom feed all three artifacts into a shared validation step. Each path makes independent decisions about quantization semantics, operator fusion, and calibration.
TorchAO INT8 weight-only compression across three architectures. Compression scales with the fraction of parameters in nn.Linear: 1.03× for the Conv2d-dominated ResNet-18, 2.40× for BERT-base, and 3.38× for TinyLlama-1.1B.
ORT quantization results for ResNet-18 on ImageNette. Dynamic quantization (MatMul only) gives 1.03× - identical to TorchAO's Linear-only result. Static quantization (all operators, with calibration) gives 3.95× with 0.10 pp accuracy loss. The size gap between these two results is the cost of Conv layers staying in FP32.
Cross-framework compression comparison. Left: ResNet-18. TorchAO and ORT dynamic both achieve 1.03× (Linear/MatMul only); ORT static gives 3.95× by quantizing all Conv layers. Right: BERT-base. TorchAO gives 2.40× (nn.Linear only), while TFLite dynamic (3.94×), ORT dynamic (3.97×), and ORT static (3.97×) all converge near 4× because they quantize all weight tensors including embeddings. The compression difference between TorchAO and the other frameworks is format scope, not quantization quality.
Top: per-layer quantization sensitivity for ResNet-18. Bars extending right indicate layers that benefit from staying in FP32. The four most sensitive layers (conv 1, 2, 5, 15) are each the first convolution in a residual stage. Bottom: precision allocation map for four strategic configurations. Each row is one configuration; each column is a layer. Hatched cells are layers kept in FP32; solid cells are quantized to INT8. Accuracy and model size are annotated on the right.
Cross-framework numerical equivalence for ResNet-18 (top) and BERT-base (bottom). Bars show max |Δ logit| vs the PyTorch FP32 baseline on a log scale. ONNX FP32 export introduces negligible divergence (~10⁻⁵). Quantization shifts logits by 10⁻¹ to 10⁰, but prediction agreement remains above 99% for all variants. The largest divergence is ORT Dynamic INT8 on BERT — cosine similarity 0.9736 — where the narrow 2-class output space amplifies quantization error.
Logit-level agreement: FP32 baseline vs quantized variant. Left: ResNet-18 vs ORT Static INT8 (1000 logits × 100 samples). Points cluster tightly along the y = x identity line across the full [-10, +30] range despite 100% operator coverage. Right: BERT-base vs ORT Dynamic INT8 (2 logits × 100 samples). Visible scatter away from the diagonal, especially for negative logits around -4, with several points drifting by more than 1 unit. The narrow output range makes the same absolute error proportionally larger.
Operator quantization coverage by ONNX variant. Left: ResNet-18 ORT Dynamic — 4% coverage, only 1 MatMulInteger node (the classification head's Gemm) out of 51 compute ops. All 20 Conv and 17 Relu stay in FP32. Center: ResNet-18 ORT Static — 100% coverage, all 20 Conv, 8 Add, and the Gemm wrapped in QDQ pairs. Right: BERT-base ORT Dynamic — 28% coverage, 74 MatMulInteger nodes (the linear projections) quantized, but LayerNormalization, Softmax, Div, and Sqrt remain in FP32.

Summary

  • Quantization workflows diverge across frameworks in default semantics, operator fusion rules, and calibration implementations. Parity requires tensor-level validation, not just accuracy checks.
  • TorchAO's quantize_() targets nn.Linear only—compressing BERT-base by 2.40× and TinyLlama by 3.38×, but leaving Conv2d-dominated ResNet-18 at 1.03×.
  • TFLite's converter handles quantization, optimization, and serialization in one pass. Dynamic range achieves 3.68× on MobileNetV2 with no calibration data.
  • ONNX export is essentially lossless (max logit divergence ~10⁻⁵). Larger divergence in quantized variants comes from quantization arithmetic, not the export.
  • ORT dynamic quantization targets MatMul/Gemm, effective for transformers (3.97× on BERT) but not CNNs (1.03× on ResNet-18). ORT static with QDQ format quantizes all operators (3.95× on ResNet-18).
  • Accuracy preservation does not guarantee numerical equivalence. BERT under ORT Dynamic showed one prediction flip in 100 samples despite maintaining 96% overall accuracy.
  • Operator coverage determines speedup—low op-count coverage can still be effective if those operators dominate compute.
  • When validation fails, compare ONNX FP32 against the PyTorch baseline first to isolate export error from quantization error.

FAQ

What is the main challenge when porting quantized models across frameworks?Different frameworks make different default choices for quantization semantics, operator fusion, and calibration, so the same “INT8 quantized” model can behave differently after export. The key challenge is not just quantizing a model, but making sure the artifacts agree across frameworks before deployment.
Why can a model’s accuracy drop after exporting from PyTorch to ONNX?Accuracy can drop because the export path and the target framework may use different quantization defaults, fusion rules, and range estimation methods. Even if both steps are correct individually, the gap between them can introduce small changes that compound into measurable accuracy loss.
What are the biggest framework divergence points in quantization workflows?The main divergence points are quantization semantics, operator fusion and graph rewriting, and calibration implementation. These differences affect how scales, zero-points, and fused operators are computed, which can lead to mismatched results across frameworks.
What does TorchAO’s quantize_() actually do?TorchAO’s quantize_() walks the module tree, finds nn.Linear layers, and replaces their weights with AffineQuantizedTensor storage. The module structure stays the same, and this is mainly a weight-only compression method rather than a latency-optimized runtime path.
When is TorchAO weight-only quantization a good choice?It works best when most parameters live in nn.Linear layers, such as transformers like BERT or LLaMA. It is not a good fit for CNN-dominant models like ResNet-18, where most parameters are in convolution layers that TorchAO’s stable configs do not target.
Why did TorchAO give ResNet-18 almost no compression?ResNet-18 is dominated by Conv2d layers, while TorchAO’s Int8WeightOnlyConfig targets only nn.Linear. Since only one small linear classification head is quantized, the overall model size barely changes.
Does quantization in eager-mode PyTorch automatically make inference faster?No. In eager-mode PyTorch, quantization reduces model size but not inference latency. The INT8 weights are dequantized back to FP32 during matmuls, so computation still happens in floating point unless you use a runtime with native integer kernels.
Why is TFLite dynamic range quantization often preferred for transformers?Transformers have highly variable activations, so static activation ranges can be unreliable. Dynamic range quantization computes activation scales at inference time, avoiding the accuracy problems that full integer quantization can cause on transformer models.
What is the difference between dynamic range and full integer quantization in TFLite?Dynamic range quantizes weights to INT8 and computes activations dynamically at inference, without calibration data. Full integer quantization uses representative data to calibrate static INT8 ranges for both weights and activations, which works better for CNNs with stable activation distributions.
How do you check whether a ported quantized model is numerically equivalent to the original?Run identical inputs through both artifacts and compare the raw output tensors using metrics like max absolute difference, mean absolute difference, cosine similarity, and top-1 prediction agreement. This helps separate export errors, quantization noise, and operator coverage gaps.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Quantization and Fast Inference ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Quantization and Fast Inference ebook for free