VidraAI commited on
Commit
cb9ea99
Β·
verified Β·
1 Parent(s): f1e9f09

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +180 -0
README.md ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ language:
4
+ - en
5
+ - zh
6
+ - ja
7
+ - ko
8
+ - multilingual
9
+ library_name: onnxruntime
10
+ tags:
11
+ - onnx
12
+ - onnxruntime
13
+ - onnxruntime-web
14
+ - automatic-speech-recognition
15
+ - asr
16
+ - speech-recognition
17
+ - robust-asr
18
+ - quantized
19
+ - int4
20
+ - int8
21
+ - matmulnbits
22
+ - gptq
23
+ - on-device
24
+ - browser
25
+ - web
26
+ - qwen3
27
+ - qwen3-asr
28
+ - mega-asr
29
+ - transformers.js
30
+ pipeline_tag: automatic-speech-recognition
31
+ base_model: zhifeixie/Mega-ASR
32
+ base_model_relation: quantized
33
+ ---
34
+
35
+ # Mega-ASR β€” INT4 ONNX (GPTQ-calibrated)
36
+
37
+ INT4 ONNX export of [zhifeixie/Mega-ASR](https://huggingface.co/zhifeixie/Mega-ASR),
38
+ a 1.7B-parameter multilingual ASR foundation model built on Qwen3-ASR-1.7B with
39
+ 2.6M training samples covering noise, far-field speech, obstruction, recording
40
+ artifacts, echo, dropout, and transmission dropout.
41
+
42
+ The model is split into three ONNX files (Whisper-style: audio encoder + LLM
43
+ decoder prefill + LLM decoder step) so it can be loaded **directly in the
44
+ browser** via [`onnxruntime-web`](https://onnxruntime.ai/docs/api/javascript/) or as
45
+ a CPU/GPU service via `onnxruntime`. INT4 weight quantization (MatMulNBits, 4-bit
46
+ block-32 asymmetric) compresses the model from ~7.5 GB fp16 down to **~2 GB**
47
+ total β€” small enough for a one-time browser cache.
48
+
49
+ **Both decoder halves are GPTQ-calibrated** on 168 / 63 English Voices-in-the-Wild
50
+ samples (prefill / step respectively). The step model uses past-KV-cache-aware
51
+ calibration: prefill output is piped into step, so the calibration captures the
52
+ realistic activation distribution of autoregressive decode.
53
+
54
+ ## What's in this repo
55
+
56
+ | File | Size | Role |
57
+ | --- | ---: | --- |
58
+ | `onnx/audio_encoder_int4.onnx` (+ `.data`) | **214 MB** | mel features β†’ audio embeddings (24-layer Whisper-style encoder) |
59
+ | `onnx/decoder_prefill_int4.onnx` (+ `.data`) | **968 MB** | Qwen3 1.7B decoder, full-length prefill (no KV cache, **GPTQ-calibrated**) |
60
+ | `onnx/decoder_step_int4.onnx` (+ `.data`) | **968 MB** | Qwen3 1.7B decoder, single-token step (with KV cache, **GPTQ-calibrated**) |
61
+ | `examples/*.wav` | ~3 MB | 8 noisy benchmark clips from [Voices-in-the-Wild-Bench](https://github.com/xzf-thu/Voices-in-the-Wild-Bench) |
62
+ | `tokenizer_config.json` / `vocab.json` / `merges.txt` | β€” | Qwen3 BPE tokenizer assets |
63
+ | `preprocessor_config.json` | β€” | Whisper-style mel feature extractor config |
64
+ | `inference.py` | β€” | Standalone Python ASR pipeline using these ONNX files |
65
+
66
+ ## Compression vs original
67
+
68
+ | Component | Original (fp16 PT) | This (INT4 ONNX) | Savings |
69
+ | --- | ---: | ---: | ---: |
70
+ | Audio encoder | ~635 MB | **214 MB** | 3.0Γ— |
71
+ | LLM decoder | ~3.4 GB Γ— 2 (prefill + step) | **968 MB Γ— 2** | 3.5Γ— |
72
+ | **Total deploy** | **~7.5 GB** | **~2.0 GB** | **3.7Γ— smaller** |
73
+
74
+ The decoder is ~95% MatMul ops so MatMulNBits 4-bit quantization works well.
75
+ The audio encoder is mostly Conv2d / Linear in transformer layers β€” MatMulNBits
76
+ quantizes the transformer Linear ops (most of the weight) but leaves the small
77
+ Conv2d front-end at fp16.
78
+
79
+ ## Quality
80
+
81
+ Benchmarked on the 8 [Voices-in-the-Wild-Bench](https://github.com/xzf-thu/Voices-in-the-Wild-Bench)
82
+ example clips (real-world noisy conditions, all English), word-level
83
+ agreement (1 βˆ’ WER), prompt forced to `language English`:
84
+
85
+ | Variant | Encoder | Decoder | Avg agreement | 100% samples | Total size |
86
+ | --- | --- | --- | ---: | ---: | ---: |
87
+ | PT bf16 (original) | fp16 | fp16 | 95.1% | 6 / 8 | 7.5 GB |
88
+ | ONNX fp16 (ref) | fp32 | fp16 | **96.7%** | 7 / 8 | 8.2 GB |
89
+ | **ONNX recommended (GPTQ)** | **INT8** | **INT4 GPTQ** | **92.7%** | **6 / 8** | **2.3 GB** |
90
+ | ONNX RTN (previous ship) | INT8 | INT4 RTN | 91.9% | 6 / 8 | 2.3 GB |
91
+ | ONNX small | INT4 | INT4 RTN | 87.8% | 6 / 8 | 2.0 GB |
92
+
93
+ The recommended config (INT8 audio encoder + GPTQ-INT4 LLM decoder) is the
94
+ size/quality sweet spot for browser deployment. Forcing the language
95
+ (rather than auto-detecting) recovers most of the quantization drift.
96
+
97
+ GPTQ calibration on both prefill and step yields **+0.8% over plain RTN** at
98
+ the same model size, most visibly on the `echo` sample where the
99
+ RTN-quantized decoder previously hallucinated *"the size was fine standing
100
+ up at the terrible white wall"* β€” the GPTQ-quantized decoder produces
101
+ *"the size feels fine standing up against terrible white walls"*, recovering
102
+ the leading clause exactly.
103
+
104
+ **Note**: fp16 ONNX actually beats PT bf16 (96.7 vs 95.1) because forcing
105
+ language skips the model's audio-quality-router language detection,
106
+ which is where the PT model loses points on `echo` and `recording`
107
+ (truncated).
108
+
109
+ ## Inference (Python)
110
+
111
+ ```bash
112
+ pip install onnxruntime numpy soundfile transformers qwen-asr
113
+ git clone https://huggingface.co/Reza2kn/mega-asr-onnx
114
+ cd mega-asr-onnx
115
+ python inference.py --audio examples/noise.wav
116
+ ```
117
+
118
+ ## Inference (browser)
119
+
120
+ A live browser demo (loads these ONNX models directly via `onnxruntime-web`
121
+ and WebGPU) is at
122
+ [Reza2kn/mega-asr-bench](https://huggingface.co/spaces/Reza2kn/mega-asr-bench).
123
+ The first visit downloads ~2 GB of model weights, cached by the browser for
124
+ subsequent runs.
125
+
126
+ ## Performance
127
+
128
+ | Hardware | Cold (model load) | Warm (3-4 s audio) |
129
+ | --- | ---: | ---: |
130
+ | RTX 5080 (CUDAExecutionProvider) | ~5 s | ~1.5 s |
131
+ | M-series Mac (CPUExecutionProvider) | ~12 s | ~6 s |
132
+ | Browser, WebGPU (RTX 5080) | ~10 s + ~1 GB download (cached) | ~3 s |
133
+ | Browser, WASM CPU | ~10 s + download | ~30 s |
134
+
135
+ ## Conversion details
136
+
137
+ - Exported via `torch.onnx.export(..., dynamo=True)` from PyTorch 2.12.
138
+ - Audio encoder rewrites: replaced packed-sequence flash-attention with
139
+ standard batched attention + chunked Conv2d (parity cos β‰ˆ 0.998 vs original).
140
+ - Decoder uses a single `DecoderForExport` wrapper that accepts a flat tuple
141
+ of KV cache tensors; prefill and step are two specialisations of the same
142
+ Python wrapper exported separately.
143
+ - Quantization: `onnxruntime.quantization.matmul_nbits_quantizer.MatMulNBitsQuantizer`
144
+ with `block_size=32`, `is_symmetric=False`, `bits=4`, `algo=GPTQ`.
145
+ Non-MatMul ops (LayerNorm, RMSNorm, residuals, RoPE, the audio-encoder
146
+ Conv2d front-end) stay at fp16.
147
+ - KV cache: dynamic past-length axis (`Dim("T_past")`) via dynamo's
148
+ `dynamic_shapes` API.
149
+
150
+ ### GPTQ calibration
151
+
152
+ The default ORT GPTQ implementation in
153
+ `onnxruntime.quantization.neural_compressor.weight_only` is CPU-only (numpy
154
+ matmul + `np.linalg.cholesky` for the Hessian inverse), and runs at ~90 min
155
+ for a 1.7B model on a workstation CPU. For this release we ported the
156
+ GPTQ inner loop + Hessian accumulation to `torch.cuda` and added a
157
+ diagonal-jitter retry on the Cholesky factorisation (fp32 is stricter
158
+ than LAPACK on barely-singular Hessians). On an RTX 5080 Laptop the
159
+ prefill GPTQ runs at ~99% GPU util and finishes in **~35 min**; the step
160
+ GPTQ takes **~3 min** (fewer unique MatMul input names because of GQA
161
+ sharing).
162
+
163
+ - **Prefill calibration**: 168 samples (24 per noise/far_field/obstructed/
164
+ distortion/recording/echo/dropout split), English-only filter on the
165
+ `text` field, audio decoded via `soundfile` (`Audio(decode=False)`)
166
+ to avoid the `torchcodec` import on streaming `cast_column`.
167
+ - **Step calibration**: 63 samples from the same English-only set; each
168
+ sample's calibration feed is built by running the fp16 prefill ONNX,
169
+ capturing all 56 `present.{0..27}.{key,value}` tensors, embedding the
170
+ greedy first predicted token, and pairing it with `attention_mask` of
171
+ length `L + 1` and `position_ids = L`. This gives the step's GPTQ Hessian
172
+ exactly the autoregressive-decode activation distribution it sees at
173
+ inference.
174
+
175
+ ## Credits
176
+
177
+ - Original model: [zhifeixie/Mega-ASR](https://huggingface.co/zhifeixie/Mega-ASR) (1.7B params, Apache-2.0)
178
+ - ONNX export + GPTQ quantization: this repo
179
+ - Benchmark: [Voices-in-the-Wild-Bench](https://github.com/xzf-thu/Voices-in-the-Wild-Bench)
180
+ - Live demo: [Reza2kn/mega-asr-bench](https://huggingface.co/spaces/Reza2kn/mega-asr-bench)