Measure the size and quality trade-off
Module 2 introduced PT2E post-training quantization for image classification. Module 3 uses the same observer, calibration, conversion, and XNNPACK lowering process. The main difference is how quality is checked. Since the use-case differs, you will compare segmentation masks and cutout boundaries rather than top-five classification results.
Obtain the calibration image set
Download 100 images from
Open Images v7
(approximately 34MB). You will use them to calibrate the quantized model. If you completed Module 2, the command verifies and reuses the files in datasets/open-images-v7-validation.
Run on your development machine:
module-3-executorch-on-android-semantic-segmentation/scripts/aot/create_segmentation_calibration_images.py \
--data-dir datasets \
--out module-3-executorch-on-android-semantic-segmentation/artifacts/lraspp_mobilenetv3/calibration_images \
--count 100
The script downloads five images from each of 20 broad object categories and verifies every file with SHA256. A production calibration set should represent the cameras, lighting, composition, and objects that the deployed application will receive; this set is purely to demonstrate the workflow.
No segmentation masks are needed because calibration records activation ranges and does not update the model weights. These images cannot measure segmentation accuracy.
Quantize and lower the model
Before quantizing, consider your answers to the following questions:
- How much smaller do you expect the INT8
.pteartifact to be? Why might there not be a reduction exactly in line with the FP32 to INT8 ratio? - Do you expect the selected class to remain
dogon the sample image? - Where might the cutout quality change: missing regions, rough boundary, or false foreground?
Run PT2E quantization with the 100 selected images:
module-3-executorch-on-android-semantic-segmentation/scripts/aot/quantize_lraspp_xnnpack.py \
--spec module-3-executorch-on-android-semantic-segmentation/artifacts/lraspp_mobilenetv3/model_spec.json \
--calibration-images module-3-executorch-on-android-semantic-segmentation/artifacts/lraspp_mobilenetv3/calibration_images \
--num-calib 100
As in Module 2, this configuration uses static W8A8 quantization for supported operations. Each convolution output filter has its own symmetric weight scale, while activations use one scale per tensor, determined during calibration and fixed during inference. Unlike Module 2’s default configuration, this script includes supported convolutions in the segmentation classifier head. Calibration uses the same letterbox and normalization code as validation:
quantizer = XNNPACKQuantizer()
quantizer.set_global(get_symmetric_quantization_config(is_per_channel=True))
prepared = prepare_pt2e(exported.module(), quantizer)
move_exported_model_to_eval(prepared)
for index, (image, _label) in enumerate(calibration_loader):
if index >= args.num_calib:
break
prepared(image)
quantized_model = convert_pt2e(prepared)
exported_quantized = export(quantized_model, example_inputs)
The converted graph is then lowered with XnnpackPartitioner and packaged as
an ExecuTorch program.
XNNPACKQuantizer supplies the quantization policy for the ExecuTorch XNNPACK
backend. set_global() applies the selected configuration to supported graph
operations. PyTorch PT2E performs preparation, calibration, and conversion
using that backend policy.
Compare the artifact sizes:
| Artifact | Size |
|---|---|
FP32 .pte | 12.90 MB |
INT8 .pte | 3.52 MB |
The INT8 program is about 73% smaller. Its delegation summary should still show one XNNPACK partition with the same surrounding allocation and layout operations as the FP32 graph.
The fourfold storage reduction applies only to values converted from FP32 to
INT8. The .pte also stores graph and backend metadata, values that remain at
other precisions, and quantization parameters such as per-channel scales, so
its total size is slightly more than one quarter of the FP32 artifact.
Course complete
Nice work
You completed Optimize and deploy AI inference with ExecuTorch on Arm.