voice_audio_multi/docs/models/audio8_asr.md
Fabio c36510c21e
Some checks failed
Linux Build / Linux cpu (push) Has been cancelled
Linux Build / Linux cpu-clang (push) Has been cancelled
Linux Build / Linux vulkan (push) Has been cancelled
mac-build / macOS CPU (push) Has been cancelled
Nix Build / Nix (cpu) (push) Has been cancelled
Nix Build / Nix (vulkan) (push) Has been cancelled
windows-build / Windows CPU (push) Has been cancelled
Initial import: audio.cpp with Orange Pi documentation
2026-11-04 19:05:22 +01:00

104 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Audio8-ASR-0.1B in audio.cpp
[Audio8-ASR-0.1B](https://huggingface.co/Audio8/Audio8-ASR-0.1B) is a compact
multilingual autoregressive ASR model (en / zh / yue / ja / ko / fr / de): a
Qwen3-ASR audio encoder adapted by an MLP tower into an 8-layer Qwen2-style
decoder with only ~103M language-model parameters (324M end-to-end). The
checkpoint ships under **CC-BY-NC-4.0**, so audio.cpp loads it from locally
converted weights only; the converted GGUF must not be redistributed.
## Architecture
- **Audio frontend**: 16 kHz Whisper log-mel, 128 bins, hop 160, n_fft 400
(shared with the `qwen3_asr` family). The reference processor emits
bfloat16 mel values; the audio8_asr frontend rounds to bfloat16 before
encoding to match.
- **Audio encoder**: Qwen3-ASR audio tower (d_model 896, 18 layers, 14 heads,
FFN 3584, 128 mel bins, output dim 1024) — bit-for-bit the same
architecture as `Qwen/Qwen3-ASR-0.6B`, loaded through the shared
`qwen3_asr` encoder implementation.
- **Adapter**: 4 pre-norm residual MLP blocks (1024 → 4096, erf GELU), a
final LayerNorm, then an adaptive average pool (merge factor 4 against the
mel-frame count) followed by LayerNorm + Linear(1024 → 512).
- **Decoder**: Qwen2-style causal LM, 8 layers, hidden 512, 8 heads,
head_dim 64, SwiGLU FFN 1408, tied embeddings over a 151,936 Qwen BPE
vocabulary, RoPE theta 1e6, RMSNorm eps 1e-6.
- **Prompt**: `<|user|><|begin_of_audio|><|audio|>×N<|end_of_audio|>Please
transcribe this audio.<|assistant|>` where
`N = max(floor(floor((floor(samples / hop) + 1) / 2) / merge_factor), 1)`
(all divisions integer).
## Usage
```bash
# Convert locally (requires the audiocpp_gguf tool and a self-downloaded
# checkpoint from the Audio8/Audio8-ASR-0.1B HF repository):
python tools/community_models/audio8_asr/convert_audio8_asr.py \
--checkpoint models/Audio8-ASR-0.1B-hf \
--converter build/debug/bin/audiocpp_gguf \
--type q8_0 \
--output models/Audio8-ASR-0.1B-GGUF/audio8-asr-0.1b-q8_0.gguf
# Transcribe
audiocpp_cli --task asr --family audio8_asr \
--model models/Audio8-ASR-0.1B-GGUF/audio8-asr-0.1b-q8_0.gguf \
--audio sample.wav
# The safetensors package loads directly, no conversion required:
audiocpp_cli --task asr --family audio8_asr \
--model models/Audio8-ASR-0.1B-hf --audio sample.wav
```
## Parity
`tools/community_models/audio8_asr/audio8_asr_reference.py` runs the Hugging Face
`trust_remote_code` reference (torch CPU, fp32) and
`tools/community_models/audio8_asr/audio8_asr_stages.py` captures staged tensors (mel,
encoder output, projected audio embeddings) for comparison.
Greedy transcription on the repo test clips matched the fp32 reference
exactly with the Q8_0 GGUF on both the Metal and CPU backends:
| Audio | Reference (fp32) | audio.cpp (Q8_0 GGUF, Metal + CPU) |
|---|---|---|
| `assets/resources/a.wav` (5.95 s) | "This little work was finished in the year eighteen o three, and intended for immediate publication." | identical |
| `assets/resources/sample_16k.wav` (14.07 s) | "Some call me nature. Others call me Mother Nature. I've been here for over four point five billion years, twenty-two thousand five hundred times longer than you." | identical |
A 61-second clip transcribed through rate-correct 30-second windows matched
the per-window reference transcripts (also verified by an independent review
pass). `test_audio8_asr_golden_transcription` asserts the first row
end-to-end — run it manually once weights exist (it is not part of ctest,
matching the granite5asr golden-test convention); `test_audio8_asr_units`
covers the token-count formula and bfloat16 rounding and runs under ctest.
## Measured performance
Release build (`-DCMAKE_BUILD_TYPE=Release`), Apple M4, Metal backend,
Q8_0 GGUF (345 MB weights):
| Audio | Session wall (`session.wall_ms`) | Effective RTF | CLI wall (incl. ~2.2 s process + load) |
|---|---|---|---|
| 5.95 s | ~0.75 s | ~8x realtime | 2.2 s |
| 14.07 s | 757 ms | 18.6x realtime | 3.8 s |
| 61 s (3 windows) | 3.46 s | 17.6x realtime | 5.8 s |
The audio encoder dominates (~64% of session time; its Metal shaders are
insensitive to build type, so Debug and Release measure within 3%).
Peak RSS is ~1.0 GB for a single clip and ~1.3 GB for a three-window
transcription (Metal buffers + per-window-shape graph pools on top of the
345 MB of weights; CPU backend measures the same ~1.0 GB).
## Known limitations
- **Offline only**: no streaming mode, no word timestamps, no language-id
output.
- **30-second windows**: audio longer than 30 s is transcribed in fixed
windows sized at the input sample rate (0.5 s minimum tail folds into the
previous window) and space-joined, without VAD segmentation. Unlike the
single-pass reference, each window is peak-normalized independently, so
relative loudness across a window boundary can shift.
- **CC-BY-NC-4.0**: non-commercial use only; convert locally, do not
redistribute the converted GGUF. There is no release GGUF package and no
WebUI catalog entry (the package manager cannot download
unsupported-license packages).
- Hotword logit boosting from the reference implementation is not ported.