55# This source code is licensed under the BSD-style license found in the
66# LICENSE file in the root directory of this source tree.
77
8- # Export model to CUDA/Metal format with optional quantization
8+ # Export model to CUDA/Metal/XNNPACK format with optional quantization
99
1010show_help () {
1111 cat << EOF
12- Usage: export_model_artifact.sh <device> <hf_model> [quant_name] [output_dir]
12+ Usage: export_model_artifact.sh <device> <hf_model> [quant_name] [output_dir] [mode]
1313
14- Export a HuggingFace model to CUDA/Metal format with optional quantization.
14+ Export a HuggingFace model to CUDA/Metal/XNNPACK format with optional quantization.
1515
1616Arguments:
17- device cuda or metal (required)
17+ device cuda, metal, or xnnpack (required)
1818
1919 hf_model HuggingFace model ID (required)
2020 Supported models:
2121 - mistralai/Voxtral-Mini-3B-2507
22+ - mistralai/Voxtral-Mini-4B-Realtime-2602
2223 - openai/whisper series (whisper-{small, medium, large, large-v2, large-v3, large-v3-turbo})
2324 - google/gemma-3-4b-it
2425 - nvidia/parakeet-tdt
2526
2627 quant_name Quantization type (optional, default: non-quantized)
2728 Options:
2829 - non-quantized
29- - quantized-int4-tile-packed
30- - quantized-int4-weight-only
30+ - quantized-int4-tile-packed (CUDA only)
31+ - quantized-int4-weight-only (CUDA only)
32+ - quantized-int4-metal (Metal only)
33+ - quantized-8da4w (XNNPACK only)
3134
3235 output_dir Output directory for artifacts (optional, default: current directory)
3336
37+ mode Export mode (optional, default: auto-detect based on model and device)
38+ Supported modes:
39+ - vr-streaming: Voxtral Realtime streaming mode
40+ - vr-offline: Voxtral Realtime offline mode
41+
3442Examples:
3543 export_model_artifact.sh metal "openai/whisper-small"
44+ export_model_artifact.sh metal "nvidia/parakeet-tdt" "quantized-int4-metal"
45+ export_model_artifact.sh metal "mistralai/Voxtral-Mini-4B-Realtime-2602" "quantized-int4-metal"
46+ export_model_artifact.sh metal "mistralai/Voxtral-Mini-4B-Realtime-2602" "non-quantized" "." "vr-streaming"
3647 export_model_artifact.sh cuda "mistralai/Voxtral-Mini-3B-2507" "quantized-int4-tile-packed"
3748 export_model_artifact.sh cuda "google/gemma-3-4b-it" "non-quantized" "./output"
3849 export_model_artifact.sh cuda "nvidia/parakeet-tdt" "non-quantized" "./output"
50+ export_model_artifact.sh xnnpack "nvidia/parakeet-tdt" "quantized-8da4w" "./output"
51+ export_model_artifact.sh xnnpack "mistralai/Voxtral-Mini-4B-Realtime-2602" "quantized-8da4w" "./output"
52+ export_model_artifact.sh xnnpack "mistralai/Voxtral-Mini-4B-Realtime-2602" "non-quantized" "./output" "vr-offline"
3953EOF
4054}
4155
@@ -56,6 +70,26 @@ DEVICE="$1"
5670HF_MODEL=" $2 "
5771QUANT_NAME=" ${3:- non-quantized} "
5872OUTPUT_DIR=" ${4:- .} "
73+ MODE=" ${5:- } "
74+
75+ # Validate mode if specified
76+ if [ -n " $MODE " ]; then
77+ case " $MODE " in
78+ vr-streaming|vr-offline)
79+ # Voxtral Realtime modes require Voxtral Realtime model
80+ if [ " $HF_MODEL " != " mistralai/Voxtral-Mini-4B-Realtime-2602" ]; then
81+ echo " Error: Mode '$MODE ' can only be used with Voxtral Realtime model"
82+ echo " Provided model: $HF_MODEL "
83+ exit 1
84+ fi
85+ ;;
86+ * )
87+ echo " Error: Unsupported mode '$MODE '"
88+ echo " Supported modes: vr-streaming, vr-offline"
89+ exit 1
90+ ;;
91+ esac
92+ fi
5993
6094case " $DEVICE " in
6195 cuda)
@@ -64,9 +98,11 @@ case "$DEVICE" in
6498 ;;
6599 metal)
66100 ;;
101+ xnnpack)
102+ ;;
67103 * )
68104 echo " Error: Unsupported device '$DEVICE '"
69- echo " Supported devices: cuda, cuda-windows, metal"
105+ echo " Supported devices: cuda, cuda-windows, metal, xnnpack "
70106 exit 1
71107 ;;
72108esac
@@ -113,9 +149,17 @@ case "$HF_MODEL" in
113149 PREPROCESSOR_FEATURE_SIZE=" "
114150 PREPROCESSOR_OUTPUT=" "
115151 ;;
152+ mistralai/Voxtral-Mini-4B-Realtime-2602)
153+ MODEL_NAME=" voxtral_realtime"
154+ TASK=" "
155+ MAX_SEQ_LEN=" "
156+ EXTRA_PIP=" mistral-common librosa"
157+ PREPROCESSOR_FEATURE_SIZE=" "
158+ PREPROCESSOR_OUTPUT=" "
159+ ;;
116160 * )
117161 echo " Error: Unsupported model '$HF_MODEL '"
118- echo " Supported models: mistralai/Voxtral-Mini-3B-2507, openai/whisper-{small, medium, large, large-v2, large-v3, large-v3-turbo}, google/gemma-3-4b-it, nvidia/parakeet-tdt"
162+ echo " Supported models: mistralai/Voxtral-Mini-3B-2507, mistralai/Voxtral-Mini-4B-Realtime-2602, openai/whisper-{small, medium, large, large-v2, large-v3, large-v3-turbo}, google/gemma-3-4b-it, nvidia/parakeet-tdt"
119163 exit 1
120164 ;;
121165esac
@@ -127,21 +171,35 @@ case "$QUANT_NAME" in
127171 ;;
128172 quantized-int4-tile-packed)
129173 if [ " $DEVICE " = " metal" ]; then
130- echo " Error: Metal backend does not yet support quantization '$QUANT_NAME '"
174+ echo " Error: Metal backend does not support quantization '$QUANT_NAME '"
131175 exit 1
132176 fi
133177 EXTRA_ARGS=" --qlinear 4w --qlinear_encoder 4w --qlinear_packing_format tile_packed_to_4d --qlinear_encoder_packing_format tile_packed_to_4d"
134178 ;;
135179 quantized-int4-weight-only)
136180 if [ " $DEVICE " = " metal" ]; then
137- echo " Error: Metal backend does not yet support quantization '$QUANT_NAME '"
181+ echo " Error: Metal backend does not support quantization '$QUANT_NAME '"
138182 exit 1
139183 fi
140184 EXTRA_ARGS=" --qlinear_encoder 4w"
141185 ;;
186+ quantized-int4-metal)
187+ if [ " $DEVICE " != " metal" ]; then
188+ echo " Error: Quantization '$QUANT_NAME ' only supported on Metal backend"
189+ exit 1
190+ fi
191+ EXTRA_ARGS=" --qlinear fpa4w --qlinear_encoder fpa4w"
192+ ;;
193+ quantized-8da4w)
194+ if [ " $DEVICE " != " xnnpack" ]; then
195+ echo " Error: quantized-8da4w is only supported with xnnpack device"
196+ exit 1
197+ fi
198+ EXTRA_ARGS=" --qlinear 8da4w --qlinear_group_size 32 --qlinear_encoder 8da4w --qlinear_encoder_group_size 32"
199+ ;;
142200 * )
143201 echo " Error: Unsupported quantization '$QUANT_NAME '"
144- echo " Supported quantizations: non-quantized, quantized-int4-tile-packed, quantized-int4-weight-only"
202+ echo " Supported quantizations: non-quantized, quantized-int4-tile-packed, quantized-int4-weight-only, quantized-int4-metal, quantized-8da4w "
145203 exit 1
146204 ;;
147205esac
@@ -157,10 +215,18 @@ pip list
157215if [ " $MODEL_NAME " = " parakeet" ]; then
158216 pip install -r examples/models/parakeet/install_requirements.txt
159217
160- python examples/models/parakeet/export_parakeet_tdt.py \
218+ # Set dtype based on backend (XNNPACK uses fp32, CUDA/Metal use bf16)
219+ if [ " $DEVICE " = " xnnpack" ]; then
220+ DTYPE_ARG=" "
221+ else
222+ DTYPE_ARG=" --dtype bf16"
223+ fi
224+
225+ python -m executorch.examples.models.parakeet.export_parakeet_tdt \
161226 --backend " $DEVICE " \
162227 --output-dir " ${OUTPUT_DIR} " \
163- --dtype bf16
228+ ${DTYPE_ARG} \
229+ ${EXTRA_ARGS}
164230
165231 test -f " ${OUTPUT_DIR} /model.pte"
166232 # CUDA saves named data to separate .ptd file, Metal embeds in .pte
@@ -173,6 +239,64 @@ if [ "$MODEL_NAME" = "parakeet" ]; then
173239 exit 0
174240fi
175241
242+ # Voxtral Realtime uses a custom export script
243+ if [ " $MODEL_NAME " = " voxtral_realtime" ]; then
244+ pip install safetensors huggingface_hub
245+
246+ # Download model weights from HuggingFace (requires HF_TOKEN for gated model)
247+ LOCAL_MODEL_DIR=" ${OUTPUT_DIR} /model_weights"
248+ python -c " from huggingface_hub import snapshot_download; snapshot_download('${HF_MODEL} ', local_dir='${LOCAL_MODEL_DIR} ')"
249+
250+ # Per-component quantization flags
251+ VR_QUANT_ARGS=" "
252+ if [ " $QUANT_NAME " = " quantized-8da4w" ]; then
253+ VR_QUANT_ARGS=" --qlinear-encoder 8da4w --qlinear 8da4w --qlinear-group-size 32 --qembedding 8w"
254+ elif [ " $QUANT_NAME " = " quantized-int4-metal" ]; then
255+ VR_QUANT_ARGS=" --qlinear-encoder fpa4w --qlinear fpa4w"
256+ fi
257+
258+ # Determine streaming mode based on MODE parameter
259+ USE_STREAMING=" false"
260+ if [ " $MODE " = " vr-streaming" ]; then
261+ USE_STREAMING=" true"
262+ elif [ " $MODE " = " vr-offline" ]; then
263+ USE_STREAMING=" false"
264+ elif [ -z " $MODE " ]; then
265+ # Auto-detect: XNNPACK uses streaming, others use offline
266+ if [ " $DEVICE " = " xnnpack" ]; then
267+ USE_STREAMING=" true"
268+ fi
269+ fi
270+
271+ # Configure export and preprocessor based on streaming mode
272+ STREAMING_ARG=" "
273+ PREPROCESSOR_ARGS=" --feature_size 128 --output_file ${OUTPUT_DIR} /preprocessor.pte"
274+ if [ " $USE_STREAMING " = " true" ]; then
275+ STREAMING_ARG=" --streaming"
276+ PREPROCESSOR_ARGS=" $PREPROCESSOR_ARGS --streaming"
277+ else
278+ PREPROCESSOR_ARGS=" $PREPROCESSOR_ARGS --stack_output --max_audio_len 300"
279+ fi
280+
281+ python -m executorch.examples.models.voxtral_realtime.export_voxtral_rt \
282+ --model-path " $LOCAL_MODEL_DIR " \
283+ --backend " $DEVICE " \
284+ ${STREAMING_ARG} \
285+ --output-dir " ${OUTPUT_DIR} " \
286+ ${VR_QUANT_ARGS}
287+
288+ # Export preprocessor
289+ python -m executorch.extension.audio.mel_spectrogram ${PREPROCESSOR_ARGS}
290+
291+ test -f " ${OUTPUT_DIR} /model.pte"
292+ test -f " ${OUTPUT_DIR} /preprocessor.pte"
293+ # Copy tokenizer from downloaded model weights
294+ cp " $LOCAL_MODEL_DIR /tekken.json" " ${OUTPUT_DIR} /tekken.json"
295+ ls -al " ${OUTPUT_DIR} "
296+ echo " ::endgroup::"
297+ exit 0
298+ fi
299+
176300MAX_SEQ_LEN_ARG=" "
177301if [ -n " $MAX_SEQ_LEN " ]; then
178302 MAX_SEQ_LEN_ARG=" --max_seq_len $MAX_SEQ_LEN "
181305DEVICE_ARG=" "
182306if [ " $DEVICE " = " cuda" ] || [ " $DEVICE " = " cuda-windows" ]; then
183307 DEVICE_ARG=" --device cuda"
308+ elif [ " $DEVICE " = " metal" ]; then
309+ DEVICE_ARG=" --device mps"
184310fi
185311
186312optimum-cli export executorch \
0 commit comments