The previous encoder ran unmasked global self-attention over the
zero-padded mel input — padding-derived tokens contaminated real
audio embeddings and triggered the text decoder to emit <|im_end|>
right after the first sentence-final period. WER on LibriSpeech
test-clean: 24.88%.
The new encoder mirrors upstream Qwen3OmniMoeAudioEncoder's chunked
block attention (100-frame chunks -> 13 tokens, 800-frame attention
windows via cu_seqlens). Switches to a single fixed [1, 128, 3000]
mel shape (drops EnumeratedShapes) and adds a mel_length int32
input + output_length int32 output so consumers can slice to the
real un-padded audio-token count.
New interface:
inputs: mel [1, 128, 3000] float32, mel_length [1] int32
outputs: audio_embeddings [1, 390, 1024] float16,
output_length [1] int32
LibriSpeech test-clean n=200 (Apple M5 Pro, INT8 palettized):
WER 24.88% -> 3.02% (matches MLX 0.6B 4-bit baseline 2.20%).
Encoder is also ~4.7x faster (24ms vs 113ms per call).
Compiled…