Qwen3-ASR
Qwen3-ASR is a state-of-the-art multilingual automatic speech recognition model. It runs on-device using Metal GPU acceleration via MLX, with 4-bit, 5-bit, or 8-bit quantization for efficient memory usage. Available in 0.6B and 1.7B parameter variants. 5-bit is the new accuracy/memory sweet spot — see benchmarks.
Pipeline
The Qwen3-ASR inference pipeline processes audio through four stages:
| Stage | Description |
|---|---|
| Audio Input | Raw audio resampled to 16 kHz mono |
| Mel Spectrogram | 128-bin mel filterbank features extracted from the waveform |
| Audio Encoder | 18-layer transformer with block attention, processes mel frames into audio embeddings |
| Text Decoder | 28-layer Qwen3 transformer with grouped-query attention (GQA) and rotary position embeddings (RoPE), autoregressively generates text tokens |
Performance
| Backend | RTF | Peak Memory | Notes |
|---|---|---|---|
| Qwen3-ASR 1.7B MLX 5-bit | 0.027 | 1.92 GB | WER 1.32% (new accuracy leader) |
| Qwen3-ASR 1.7B MLX 8-bit | 0.033 | 2.7 GB | WER 1.52% |
| Qwen3-ASR 0.6B MLX 8-bit | 0.015 | 1.3 GB | WER 1.82% |
| Qwen3-ASR 0.6B MLX 5-bit | 0.014 | 1.03 GB | WER 1.74% (near-8-bit at ~4-bit RAM) |
| Qwen3-ASR 0.6B MLX 4-bit | 0.012 | 1.0 GB | WER 2.20% |
| Qwen3-ASR 0.6B CoreML INT8 | 0.098 | 1.4 GB | WER 3.02% (chunked-attn rebuild) |
Apple M5 Pro, 48 GB. LibriSpeech test-clean n=200, isolated per-engine. RTF < 1.0 = faster than real-time.
Model Variants
| Model | Backend | Size | HuggingFace |
|---|---|---|---|
| Qwen3-ASR-0.6B (4-bit) | MLX | 680 MB | aufklarer/Qwen3-ASR-0.6B-MLX-4bit |
| Qwen3-ASR-0.6B (5-bit) | MLX | 1.0 GB | aufklarer/Qwen3-ASR-0.6B-MLX-5bit |
| Qwen3-ASR-0.6B (8-bit) | MLX | 1.0 GB | aufklarer/Qwen3-ASR-0.6B-MLX-8bit |
| Qwen3-ASR-0.6B (CoreML INT8) | CoreML | 180 MB | aufklarer/Qwen3-ASR-CoreML |
| Qwen3-ASR-1.7B (4-bit) | MLX | 2.1 GB | aufklarer/Qwen3-ASR-1.7B-MLX-4bit |
| Qwen3-ASR-1.7B (5-bit) | MLX | 2.3 GB | aufklarer/Qwen3-ASR-1.7B-MLX-5bit |
| Qwen3-ASR-1.7B (8-bit) | MLX | 3.2 GB | aufklarer/Qwen3-ASR-1.7B-MLX-8bit |
CLI Usage
Transcribe an audio file with the default Qwen3-ASR model:
.build/release/speech transcribe recording.wav
Options
# Use the larger 1.7B model
.build/release/speech transcribe recording.wav --model 1.7b
# Specify language
.build/release/speech transcribe recording.wav --language en
# Streaming mode with partial results
.build/release/speech transcribe recording.wav --stream --partial
Swift API
Use the Qwen3ASR module to transcribe audio programmatically:
import Qwen3ASR
// Load the model (downloads from HuggingFace on first use)
let model = try await Qwen3ASRModel.fromPretrained()
// Transcribe audio samples (16 kHz mono Float)
let text = model.transcribe(audio: audioSamples, sampleRate: 16000)
print(text)
CoreML Encoder (Neural Engine)
Run the audio encoder on the Neural Engine via CoreML, with the text decoder on GPU via MLX. This hybrid approach lowers power consumption and frees the GPU for concurrent workloads.
import Qwen3ASR
let encoder = try await CoreMLASREncoder.fromPretrained()
let model = try await Qwen3ASRModel.fromPretrained()
let text = try model.transcribe(
audio: samples, sampleRate: 16000,
coremlEncoder: encoder
)
# CLI
.build/release/speech transcribe recording.wav --engine qwen3-coreml
INT8 palettized (180 MB, cosine similarity > 0.999) is the default. An INT4 variant (90 MB) is also available for size-constrained deployments.
Streaming Mode
Streaming mode uses VAD (voice activity detection) to segment audio into chunks and transcribe them incrementally. This is useful for long recordings or real-time processing.
# Stream with default segment size
.build/release/speech transcribe recording.wav --stream
# Control maximum segment duration
.build/release/speech transcribe recording.wav --stream --max-segment 15
# Show partial (in-progress) results as they arrive
.build/release/speech transcribe recording.wav --stream --partial
The --max-segment flag controls the maximum chunk duration in seconds. The --partial flag enables partial result output, showing words as they are decoded.
Supported Formats
Qwen3-ASR accepts the following audio formats. All input is automatically resampled to 16 kHz mono internally.
- WAV — uncompressed PCM
- M4A — AAC-encoded audio
- MP3 — MPEG Layer III
- CAF — Apple Core Audio Format
Models are downloaded from HuggingFace on first use and cached in ~/Library/Caches/qwen3-speech/. The 4-bit 0.6B model is approximately 1.5 GB.
Parakeet TDT speech-to-text · CosyVoice3 voice cloning · Kokoro-82M TTS
Need a focused decision guide? See Qwen3-ASR vs Whisper: accuracy, speed, and memory.
Cooperative cancellation
For MLX transcription, Qwen3ASRModel.transcribeCheckingCancellation(audio:sampleRate:options:) throws CancellationError when task cancellation is observed before feature extraction, encoding, decoder prefill, or a decoding step. GPU work already submitted can finish. The synchronous transcribe and transcribeBatch APIs retain their non-throwing behavior and ignore task cancellation. speech-server uses the cancellation-aware entry point for Qwen3-ASR.
MLX cache budget
Loading Qwen3-ASR bounds the process-wide MLX pool of reusable Metal buffers: min(1 GiB, RAM / 8) for 0.6B and min(4 GiB, RAM / 4) for 1.7B. Other MLX models share this pool. The ceilings apply to cached scratch buffers, not active weights or the total process footprint.
The effective limit is the lowest of the caller’s existing MLX.Memory.cacheLimit and every loaded ASR instance’s ceiling. Instances can unload in any order; the last unload or instance destruction restores the caller’s budget. A tighter limit set by the caller while models are loaded is preserved.
Single-input transcription clears reusable buffers when its decoder returns or throws, including cancellation inside the decoder. Active arrays and model weights remain loaded. The greedy transcribeBatch decoder retains the bounded pool between batches. No API options or CLI flags change.
Clearing the buffer pool lowers retained memory but requires new allocations on later requests, so short requests can take longer. Waiting for submitted decoder work to finish makes cleanup deterministic, including cancellation. Actual latency and process memory depend on the hardware, model, and audio.
Optional model ownership
SpeechRuntime provides shared loading, cancellable FIFO admission and serialized execution. Qwen3ASRRuntime selects MLX or full CoreML through explicit descriptors; native APIs and CLI flags remain available.
The audio server holds one execution permit through each complete request, including streamed output, with up to 32 requests waiting. ASR failures produce HTTP errors or WebSocket error events; valid empty transcripts remain successful. Playback preserves overflow samples. Cached models and pending playback audio still occupy memory.
Managed CoreML transcription releases temporary buffers after each request, including repeated calls from a background task.
import Qwen3ASRRuntime
let runtime = Qwen3ASRRuntime(descriptor: Qwen3ASRDescriptors.small)
let text = try await runtime.transcribe(audio: samples, sampleRate: 16000)
try await runtime.unload()