← Back to list

Optimizing AI for Mobile: The Power of Model Quantization (3)

Part 3: Quantizing and Evaluating Speech Models with Executorch

Kiyshi Araki · 2025-11-15 14:40 · 15 claps · 3.7 min read
#hugging-face #executorch #python #timit #levenshtein-distance
Open on Medium ↗
Wiki topics: OPS · LLMOps & Inference

Optimizing AI for Mobile: The Power of Model Quantization (3)

Part 3: Quantizing and Evaluating Speech Models with Executorch

In the last part, we chose Post-Training Quantization (PTQ) with Executorch as the most suitable approach for deploying Hugging Face’s Wav2Vec2 model on mobile devices. Now, we’ll take a hands-on look at how the quantization process works, how calibration data is used, and how to evaluate the resulting model’s real-world performance.

Defining the Quantization Goals

Before diving into the implementation, it’s essential to set clear, measurable objectives for the quantized model:

Model size: 250 MB ≤ disk size ≤ 350 MB RAM usage: ≤ 250 MB peak inference RAM Accuracy: < 2× degradation in PER and FER on TIMIT core test set Speed: 1-second audio processed in ≤ 250 ms

These targets provide a balance between efficiency and fidelity - ensuring the model stays accurate enough while meeting mobile hardware limits.

The Project Overview

Below is the directory structure of the project (see the image in the article for reference). Each script has a specific purpose within the pipeline.

phoneme_quant_eval/
├─ scripts/
│   ├─ evaluate_origin_model.py      # Evaluate original Hugging Face model
│   ├─ evaluate_quantized_model.py   # Evaluate quantized Executorch model
│   ├─ quantize_model.py             # Perform quantization and export .pte
│   ├─ ipa_feature_map.py            # IPA phoneme → feature vector mapping
│   └─ timit_to_ipa_map.py           # TIMIT phoneme → IPA mapping
├─ data/                             # TIMIT dataset (TRAIN/TEST)
├─ exported/                         # Output quantized models
└─ README.md                         # Setup and usage guide

The full codebase is available at ***here***.

The Dataset: TIMIT and Phoneme Mapping

We use the TIMIT dataset - a classic benchmark for phoneme recognition. TIMIT provides .WAV audio files paired with .PHN phoneme annotations. However, its phoneme symbols differ from the International Phonetic Alphabet (IPA).

That’s why we include two crucial mapping scripts:

  • **timit_to_ipa_map.py**: Converts TIMIT phonemes (like aa, sh, jh) into IPA symbols (ɑ, ʃ, dʒ).
  • **ipa_feature_map.py: Associates each IPA phoneme with a list of articulatory features, enabling Feature Error Rate (FER) computation alongside traditional Phoneme Error Rate (PER)**.

Stage 1: Quantizing the Model with Executorch

The quantization process consists of:

  1. Exporting the pretrained Wav2Vec2 model from Hugging Face.
  2. Preparing calibration data using a subset of TIMIT’s training audio.
  3. Applying static per-channel symmetric quantization through the Executorch XNNPACK backend.
  4. Exporting the final .pte file for on-device execution.

1. Loading and Preparing the Model

model = Wav2Vec2ForCTC.from_pretrained(MODEL_ID).eval()
feat = Wav2Vec2FeatureExtractor.from_pretrained(MODEL_ID)
target_sr = getattr(feat, "sampling_rate", 16000)
sample_len = target_sr * EXAMPLE_SECONDS

We load the KoelLabs/xlsr-english-01 model and define a short input duration (1 second) to generate representative calibration data.

2. Defining the Quantization Configuration

quantizer = XNNPACKQuantizer()
qconfig = get_symmetric_quantization_config(is_per_channel=True, is_dynamic=False)
quantizer.set_global(qconfig)

This sets the quantization to static symmetric per-channel - the same method discussed in Part 2. Specific modules like normalization and dropout layers are excluded to avoid numerical instability:

# Disable quantization for sensitive or non-learnable layers
quantizer.module_name_config["wav2vec2.feature_extractor.conv_layers.0"] = None
quantizer.module_name_config["wav2vec2.feature_extractor.conv_layers.1"] = None
quantizer.module_name_config["wav2vec2.feature_extractor.conv_layers.6"] = None
quantizer.module_name_config["wav2vec2.feature_projection.layer_norm"] = None
quantizer.module_name_config["wav2vec2.feature_projection.dropout"] = None
quantizer.module_name_config["wav2vec2.encoder.final_layer_norm"] = None
quantizer.module_name_config["lm_head"] = None

# Explicitly include only core layers for quantization
quantizer.module_name_config["wav2vec2.feature_projection.projection"] = qconfig
for i in range(0, 23):
    quantizer.module_name_config[f"wav2vec2.encoder.layers.{i}"] = qconfig

3. Calibration

Calibration is essential for Post-Training Quantization. Here, 300 audio samples from the TIMIT TRAIN directory are used to estimate activation ranges:

for wav_path in iter_train_wavs(DATA_ROOT):
    wav = load_and_resample(wav_path, target_sr)
    inp = pad_or_trim(wav.unsqueeze(0), sample_len)
    prepared(inp)  # Run through model to record activation stats

This step ensures the quantizer determines realistic scaling factors for each layer’s weights and activations.

4. Conversion and Export

After calibration, the model is quantized and exported for Executorch runtime:

quantized_model = convert_pt2e(prepared)
exported_quant = torch.export.export(quantized_model, example_inputs, strict=True)
edge = to_edge_transform_and_lower(exported_quant, partitioner=[XnnpackPartitioner(allow_partial=True)])
exec_prog = edge.to_executorch(config=ExecutorchBackendConfig(extract_delegate_segments=True))
OUTPUT_PTE.write_bytes(exec_prog.buffer)

The final .pte file (≈ 300 MB) is optimized for XNNPACK, making it runnable directly on mobile CPUs.

Stage 2: Evaluating Model Performance

The Direction

To verify the quantized model meets our goals, we test:

  • Accuracy: Phoneme Error Rate (PER) and Feature Error Rate (FER)
  • Speed: Real-Time Factor (RTF)
  • Memory: Peak RAM usage
  • Size: Disk footprint

Evaluation Method

1. Phoneme Alignment and Conversion

TIMIT phonemes are converted to IPA using timit_to_ipa_map.py. Predicted outputs from the model are decoded to IPA tokens through Wav2Vec2Processor. The comparison uses ***Levenshtein distance***, implemented manually to compute both PER and FER.

2. Feature-Level Error Calculation

FER is computed by comparing phoneme features (place, manner, voicing, etc.) defined in ipa_feature_map.py. This allows a finer-grained evaluation beyond just symbol mismatches.

3. Real-Time Factor and RAM Usage

Each model inference is wrapped in a memory monitor:

result, peak_mb = measure_peak_rss_during(_run)

RTF (real-time factor) is the ratio of processing time to audio duration. A lower RTF means faster performance - our target is ≤ 0.25× for 1-second clips.

4. Comparison Code

Both evaluation scripts - evaluate_origin_model.py and evaluate_quantized_model.py- share the same logic, except the latter loads the .pte model via Executorch runtime:

runtime = Runtime.get()
program = runtime.load_program(pte_file_path, verification=Verification.Minimal)
forward = program.load_method("forward")

Each test logs PER, FER, RTF, and peak RAM for every audio sample, and averages the results across the dataset.

The Results

The quantized model achieved:

  • Model size: ~320 MB
  • Peak RAM usage: ~240 MB
  • Speed: ~0.22× real-time
  • Accuracy: ~1.7× PER/FER degradation compared to the original

This meets all our predefined objectives. In practice, speech recognition remained intelligible and responsive even on mid-tier smartphones.

What’s Next?

This concludes the heavy lifting - our Wav2Vec2 model is now quantized, evaluated, and ready for deployment. In the next article, we’ll move to the final stage: integrating the quantized .pte model into a React Native app using ***react-native-executorch*** and building a real-time mobile speech recognition interface.


메타데이터
post_id
9829bd1fc502
slug
optimizing-ai-for-mobile-the-power-of-model-quantization-3-9829bd1fc502
url
https://medium.com/@cupid20103/optimizing-ai-for-mobile-the-power-of-model-quantization-3-9829bd1fc502
canonical_url
https://medium.com/@cupid20103/optimizing-ai-for-mobile-the-power-of-model-quantization-3-9829bd1fc502
author_url
https://medium.com/@cupid20103
status
ok
fetched_at
2026-08-01 14:19:49