Instructions to use Qwen/Qwen3-ASR-1.7B-hf with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Qwen/Qwen3-ASR-1.7B-hf with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("automatic-speech-recognition", model="Qwen/Qwen3-ASR-1.7B-hf")# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("Qwen/Qwen3-ASR-1.7B-hf") model = AutoModelForMultimodalLM.from_pretrained("Qwen/Qwen3-ASR-1.7B-hf") - Notebooks
- Google Colab
- Kaggle
Initial commit
Browse files- .gitattributes +1 -0
- README.md +412 -0
- chat_template.jinja +31 -0
- config.json +97 -0
- generation_config.json +10 -0
- model.safetensors +3 -0
- processor_config.json +20 -0
- tokenizer.json +3 -0
- tokenizer_config.json +32 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
pipeline_tag: automatic-speech-recognition
|
| 4 |
+
library_name: transformers
|
| 5 |
+
language:
|
| 6 |
+
- zh
|
| 7 |
+
- en
|
| 8 |
+
- yue
|
| 9 |
+
- ar
|
| 10 |
+
- de
|
| 11 |
+
- fr
|
| 12 |
+
- es
|
| 13 |
+
- pt
|
| 14 |
+
- id
|
| 15 |
+
- it
|
| 16 |
+
- ko
|
| 17 |
+
- ru
|
| 18 |
+
- th
|
| 19 |
+
- vi
|
| 20 |
+
- ja
|
| 21 |
+
- tr
|
| 22 |
+
- hi
|
| 23 |
+
- ms
|
| 24 |
+
- nl
|
| 25 |
+
- sv
|
| 26 |
+
- da
|
| 27 |
+
- fi
|
| 28 |
+
- pl
|
| 29 |
+
- cs
|
| 30 |
+
- fil
|
| 31 |
+
- fa
|
| 32 |
+
- el
|
| 33 |
+
- hu
|
| 34 |
+
- mk
|
| 35 |
+
- ro
|
| 36 |
+
---
|
| 37 |
+
|
| 38 |
+
# Qwen3-ASR (Transformers native)
|
| 39 |
+
|
| 40 |
+
## Overview
|
| 41 |
+
|
| 42 |
+
<p align="center">
|
| 43 |
+
<img src="https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-ASR-Repo/qwen3_asr_introduction.png" width="90%"/>
|
| 44 |
+
</p>
|
| 45 |
+
|
| 46 |
+
The Qwen3-ASR family includes **Qwen3-ASR-1.7B** and **Qwen3-ASR-0.6B**, which support language identification and ASR for 52 languages and dialects. Both leverage large-scale speech training data and the strong audio understanding capability of their foundation model, Qwen3-Omni. The 1.7B version achieves state-of-the-art performance among open-source ASR models and is competitive with the strongest proprietary commercial APIs.
|
| 47 |
+
|
| 48 |
+
**Key features:**
|
| 49 |
+
|
| 50 |
+
- **All-in-one:** Supports language identification and speech recognition for 30 languages and 22 Chinese dialects, including English accents from multiple countries and regions.
|
| 51 |
+
- **Excellent and Fast:** High-quality and robust recognition under complex acoustic environments. Qwen3-ASR-0.6B reaches 2000× throughput at a concurrency of 128. Both models support streaming/offline unified inference with a single model and handle long audio.
|
| 52 |
+
- **Forced Alignment:** Qwen3-ForcedAligner-0.6B supports timestamp prediction for arbitrary units within up to 5 minutes of speech in 11 languages, surpassing E2E-based forced-alignment models in accuracy.
|
| 53 |
+
|
| 54 |
+
### Model Architecture
|
| 55 |
+
|
| 56 |
+
<p align="center">
|
| 57 |
+
<img src="https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-ASR-Repo/overview.jpg" width="100%"/>
|
| 58 |
+
</p>
|
| 59 |
+
|
| 60 |
+
### Available Checkpoints
|
| 61 |
+
|
| 62 |
+
| Model | Supported Languages | Supported Dialects | Inference Mode | Audio Types |
|
| 63 |
+
|---|---|---|---|---|
|
| 64 |
+
| [Qwen/Qwen3-ASR-1.7B-hf](https://huggingface.co/Qwen/Qwen3-ASR-1.7B-hf) & [Qwen/Qwen3-ASR-0.6B-hf](https://huggingface.co/Qwen/Qwen3-ASR-0.6B-hf) | Chinese (zh), English (en), Cantonese (yue), Arabic (ar), German (de), French (fr), Spanish (es), Portuguese (pt), Indonesian (id), Italian (it), Korean (ko), Russian (ru), Thai (th), Vietnamese (vi), Japanese (ja), Turkish (tr), Hindi (hi), Malay (ms), Dutch (nl), Swedish (sv), Danish (da), Finnish (fi), Polish (pl), Czech (cs), Filipino (fil), Persian (fa), Greek (el), Hungarian (hu), Macedonian (mk), Romanian (ro) | Anhui, Dongbei, Fujian, Gansu, Guizhou, Hebei, Henan, Hubei, Hunan, Jiangxi, Ningxia, Shandong, Shaanxi, Shanxi, Sichuan, Tianjin, Yunnan, Zhejiang, Cantonese (HK), Cantonese (Guangdong), Wu, Minnan | Offline / Streaming | Speech, Singing Voice, Songs with BGM |
|
| 65 |
+
| [Qwen/Qwen3-ForcedAligner-0.6B-hf](https://huggingface.co/Qwen/Qwen3-ForcedAligner-0.6B-hf) | Chinese, English, Cantonese, French, German, Italian, Japanese, Korean, Portuguese, Russian, Spanish | — | NAR | Speech |
|
| 66 |
+
|
| 67 |
+
---
|
| 68 |
+
|
| 69 |
+
## Usage
|
| 70 |
+
|
| 71 |
+
Qwen3-ASR is supported natively in 🤗 Transformers. Until it is part of an official Transformers release, install from source:
|
| 72 |
+
|
| 73 |
+
```bash
|
| 74 |
+
pip install git+https://github.com/huggingface/transformers
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
### Simple transcription
|
| 78 |
+
|
| 79 |
+
`apply_transcription_request` handles chat-template formatting for you and is the recommended entry point.
|
| 80 |
+
|
| 81 |
+
```python
|
| 82 |
+
from transformers import AutoProcessor, AutoModelForMultimodalLM
|
| 83 |
+
|
| 84 |
+
model_id = "Qwen/Qwen3-ASR-1.7B-hf"
|
| 85 |
+
processor = AutoProcessor.from_pretrained(model_id)
|
| 86 |
+
model = AutoModelForMultimodalLM.from_pretrained(model_id, device_map="auto")
|
| 87 |
+
print(f"Model loaded on {model.device} with dtype {model.dtype}")
|
| 88 |
+
|
| 89 |
+
inputs = processor.apply_transcription_request(
|
| 90 |
+
audio="https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-ASR-Repo/asr_en.wav",
|
| 91 |
+
).to(model.device, model.dtype)
|
| 92 |
+
|
| 93 |
+
output_ids = model.generate(**inputs, max_new_tokens=256)
|
| 94 |
+
generated_ids = output_ids[:, inputs["input_ids"].shape[1]:]
|
| 95 |
+
|
| 96 |
+
# Raw output includes language tag and <asr_text> marker
|
| 97 |
+
raw = processor.decode(generated_ids)[0]
|
| 98 |
+
print(f"Raw: {raw}")
|
| 99 |
+
|
| 100 |
+
# Parsed output: dict with "language" and "transcription"
|
| 101 |
+
parsed = processor.decode(generated_ids, return_format="parsed")[0]
|
| 102 |
+
print(f"Parsed: {parsed}")
|
| 103 |
+
|
| 104 |
+
# Extract only the transcription text
|
| 105 |
+
transcription = processor.decode(generated_ids, return_format="transcription_only")[0]
|
| 106 |
+
print(f"Transcription: {transcription}")
|
| 107 |
+
|
| 108 |
+
"""
|
| 109 |
+
Raw: language English<asr_text>Mr. Quilter is the apostle of the middle classes, and we are glad to welcome his gospel.
|
| 110 |
+
Parsed: {'language': 'English', 'transcription': 'Mr. Quilter is the apostle of the middle classes, and we are glad to welcome his gospel.'}
|
| 111 |
+
Transcription: Mr. Quilter is the apostle of the middle classes, and we are glad to welcome his gospel.
|
| 112 |
+
"""
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
### Language hint
|
| 116 |
+
|
| 117 |
+
Pass a language hint to skip auto-detection.
|
| 118 |
+
|
| 119 |
+
```python
|
| 120 |
+
from transformers import AutoProcessor, AutoModelForMultimodalLM
|
| 121 |
+
|
| 122 |
+
model_id = "Qwen/Qwen3-ASR-1.7B-hf"
|
| 123 |
+
processor = AutoProcessor.from_pretrained(model_id)
|
| 124 |
+
model = AutoModelForMultimodalLM.from_pretrained(model_id, device_map="auto")
|
| 125 |
+
|
| 126 |
+
# Without language hint (auto-detect)
|
| 127 |
+
inputs = processor.apply_transcription_request(
|
| 128 |
+
audio="https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-ASR-Repo/asr_zh.wav",
|
| 129 |
+
).to(model.device, model.dtype)
|
| 130 |
+
output_ids = model.generate(**inputs, max_new_tokens=256)
|
| 131 |
+
generated_ids = output_ids[:, inputs["input_ids"].shape[1]:]
|
| 132 |
+
print(f"Auto-detect: {processor.decode(generated_ids, return_format='transcription_only')[0]}")
|
| 133 |
+
|
| 134 |
+
# With language hint (language code or full name both accepted)
|
| 135 |
+
inputs = processor.apply_transcription_request(
|
| 136 |
+
audio="https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-ASR-Repo/asr_zh.wav",
|
| 137 |
+
language="Chinese", # or "zh"
|
| 138 |
+
).to(model.device, model.dtype)
|
| 139 |
+
output_ids = model.generate(**inputs, max_new_tokens=256)
|
| 140 |
+
generated_ids = output_ids[:, inputs["input_ids"].shape[1]:]
|
| 141 |
+
print(f"With hint: {processor.decode(generated_ids, return_format='transcription_only')[0]}")
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
### Batch inference
|
| 145 |
+
|
| 146 |
+
Pass a list of audio paths and optional languages to transcribe multiple files in one call.
|
| 147 |
+
|
| 148 |
+
```python
|
| 149 |
+
from transformers import AutoProcessor, AutoModelForMultimodalLM
|
| 150 |
+
|
| 151 |
+
model_id = "Qwen/Qwen3-ASR-1.7B-hf"
|
| 152 |
+
processor = AutoProcessor.from_pretrained(model_id)
|
| 153 |
+
model = AutoModelForMultimodalLM.from_pretrained(model_id, device_map="auto")
|
| 154 |
+
|
| 155 |
+
audio = [
|
| 156 |
+
"https://huggingface.co/datasets/bezzam/audio_samples/resolve/main/librispeech_mr_quilter.wav",
|
| 157 |
+
"https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-ASR-Repo/asr_zh.wav",
|
| 158 |
+
]
|
| 159 |
+
|
| 160 |
+
inputs = processor.apply_transcription_request(
|
| 161 |
+
audio, language=[None, "zh"],
|
| 162 |
+
).to(model.device, model.dtype)
|
| 163 |
+
|
| 164 |
+
output_ids = model.generate(**inputs, max_new_tokens=256)
|
| 165 |
+
generated_ids = output_ids[:, inputs["input_ids"].shape[1]:]
|
| 166 |
+
transcriptions = processor.decode(generated_ids, return_format="transcription_only")
|
| 167 |
+
|
| 168 |
+
for i, text in enumerate(transcriptions):
|
| 169 |
+
print(f"Audio {i + 1}: {text}")
|
| 170 |
+
```
|
| 171 |
+
|
| 172 |
+
### Chat template
|
| 173 |
+
|
| 174 |
+
`apply_transcription_request` is a convenience wrapper around `apply_chat_template`. Use the chat template directly for more control, such as providing a language hint via a system message.
|
| 175 |
+
|
| 176 |
+
```python
|
| 177 |
+
from transformers import AutoProcessor, Qwen3ASRForConditionalGeneration
|
| 178 |
+
|
| 179 |
+
model_id = "Qwen/Qwen3-ASR-1.7B-hf"
|
| 180 |
+
processor = AutoProcessor.from_pretrained(model_id)
|
| 181 |
+
model = Qwen3ASRForConditionalGeneration.from_pretrained(model_id, device_map="auto")
|
| 182 |
+
|
| 183 |
+
chat_template = [
|
| 184 |
+
[
|
| 185 |
+
{"role": "system", "content": [{"type": "text", "text": "English"}]},
|
| 186 |
+
{
|
| 187 |
+
"role": "user",
|
| 188 |
+
"content": [
|
| 189 |
+
{
|
| 190 |
+
"type": "audio",
|
| 191 |
+
"path": "https://huggingface.co/datasets/bezzam/audio_samples/resolve/main/librispeech_mr_quilter.wav",
|
| 192 |
+
},
|
| 193 |
+
],
|
| 194 |
+
},
|
| 195 |
+
],
|
| 196 |
+
[
|
| 197 |
+
{
|
| 198 |
+
"role": "user",
|
| 199 |
+
"content": [
|
| 200 |
+
{
|
| 201 |
+
"type": "audio",
|
| 202 |
+
"path": "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-ASR-Repo/asr_zh.wav",
|
| 203 |
+
},
|
| 204 |
+
],
|
| 205 |
+
},
|
| 206 |
+
],
|
| 207 |
+
]
|
| 208 |
+
|
| 209 |
+
inputs = processor.apply_chat_template(
|
| 210 |
+
chat_template, tokenize=True, return_dict=True,
|
| 211 |
+
).to(model.device, model.dtype)
|
| 212 |
+
|
| 213 |
+
output_ids = model.generate(**inputs, max_new_tokens=256)
|
| 214 |
+
generated_ids = output_ids[:, inputs["input_ids"].shape[1]:]
|
| 215 |
+
transcriptions = processor.decode(generated_ids, return_format="transcription_only")
|
| 216 |
+
for text in transcriptions:
|
| 217 |
+
print(text)
|
| 218 |
+
```
|
| 219 |
+
|
| 220 |
+
### Training / Fine-tuning
|
| 221 |
+
|
| 222 |
+
```python
|
| 223 |
+
from transformers import AutoProcessor, Qwen3ASRForConditionalGeneration
|
| 224 |
+
|
| 225 |
+
model_id = "Qwen/Qwen3-ASR-1.7B-hf"
|
| 226 |
+
processor = AutoProcessor.from_pretrained(model_id)
|
| 227 |
+
model = Qwen3ASRForConditionalGeneration.from_pretrained(model_id, device_map="auto")
|
| 228 |
+
model.train()
|
| 229 |
+
|
| 230 |
+
chat_template = [
|
| 231 |
+
[
|
| 232 |
+
{
|
| 233 |
+
"role": "user",
|
| 234 |
+
"content": [
|
| 235 |
+
{
|
| 236 |
+
"type": "text",
|
| 237 |
+
"text": "Mr. Quilter is the apostle of the middle classes, and we are glad to welcome his gospel.",
|
| 238 |
+
},
|
| 239 |
+
{
|
| 240 |
+
"type": "audio",
|
| 241 |
+
"path": "https://huggingface.co/datasets/bezzam/audio_samples/resolve/main/librispeech_mr_quilter.wav",
|
| 242 |
+
},
|
| 243 |
+
],
|
| 244 |
+
}
|
| 245 |
+
],
|
| 246 |
+
]
|
| 247 |
+
|
| 248 |
+
inputs = processor.apply_chat_template(
|
| 249 |
+
chat_template, tokenize=True, return_dict=True, output_labels=True,
|
| 250 |
+
).to(model.device, model.dtype)
|
| 251 |
+
|
| 252 |
+
loss = model(**inputs).loss
|
| 253 |
+
print("Loss:", loss.item())
|
| 254 |
+
loss.backward()
|
| 255 |
+
```
|
| 256 |
+
|
| 257 |
+
### Forced alignment (word-level timestamping)
|
| 258 |
+
|
| 259 |
+
Use `Qwen3ASRForTokenClassification` to obtain word-level timestamps from a transcript. Transcribe first with the ASR model, then align with the forced aligner.
|
| 260 |
+
|
| 261 |
+
Supported languages: Chinese, English, Cantonese, French, German, Italian, Japanese, Korean, Portuguese, Russian, Spanish.
|
| 262 |
+
|
| 263 |
+
> Japanese requires `nagisa` and Korean requires `soynlp`: `pip install nagisa soynlp`
|
| 264 |
+
|
| 265 |
+
```python
|
| 266 |
+
import torch
|
| 267 |
+
from transformers import AutoProcessor, AutoModelForMultimodalLM, AutoModelForTokenClassification
|
| 268 |
+
|
| 269 |
+
asr_model_id = "Qwen/Qwen3-ASR-0.6B-hf"
|
| 270 |
+
aligner_model_id = "Qwen/Qwen3-ForcedAligner-0.6B-hf"
|
| 271 |
+
|
| 272 |
+
asr_processor = AutoProcessor.from_pretrained(asr_model_id)
|
| 273 |
+
asr_model = AutoModelForMultimodalLM.from_pretrained(asr_model_id, device_map="auto")
|
| 274 |
+
|
| 275 |
+
aligner_processor = AutoProcessor.from_pretrained(aligner_model_id)
|
| 276 |
+
aligner_model = AutoModelForTokenClassification.from_pretrained(
|
| 277 |
+
aligner_model_id, dtype=torch.bfloat16, device_map="auto"
|
| 278 |
+
)
|
| 279 |
+
|
| 280 |
+
audio_url = "https://huggingface.co/datasets/bezzam/audio_samples/resolve/main/librispeech_mr_quilter.wav"
|
| 281 |
+
|
| 282 |
+
# Step 1: Transcribe
|
| 283 |
+
inputs = asr_processor.apply_transcription_request(audio=audio_url)
|
| 284 |
+
inputs = inputs.to(asr_model.device, asr_model.dtype)
|
| 285 |
+
output_ids = asr_model.generate(**inputs, max_new_tokens=256)
|
| 286 |
+
generated_ids = output_ids[:, inputs["input_ids"].shape[1]:]
|
| 287 |
+
parsed = asr_processor.decode(generated_ids, return_format="parsed")[0]
|
| 288 |
+
transcript = parsed["transcription"]
|
| 289 |
+
language = parsed["language"] or "English"
|
| 290 |
+
|
| 291 |
+
# Step 2: Prepare alignment inputs
|
| 292 |
+
aligner_inputs, word_lists = aligner_processor.prepare_forced_aligner_inputs(
|
| 293 |
+
audio=audio_url, transcript=transcript, language=language,
|
| 294 |
+
)
|
| 295 |
+
aligner_inputs = aligner_inputs.to(aligner_model.device, aligner_model.dtype)
|
| 296 |
+
|
| 297 |
+
# Step 3: Run forced aligner
|
| 298 |
+
with torch.inference_mode():
|
| 299 |
+
outputs = aligner_model(**aligner_inputs)
|
| 300 |
+
|
| 301 |
+
# Step 4: Decode timestamps
|
| 302 |
+
timestamps = aligner_processor.decode_forced_alignment(
|
| 303 |
+
logits=outputs.logits,
|
| 304 |
+
input_ids=aligner_inputs["input_ids"],
|
| 305 |
+
word_lists=word_lists,
|
| 306 |
+
timestamp_token_id=aligner_model.config.timestamp_token_id,
|
| 307 |
+
)[0]
|
| 308 |
+
|
| 309 |
+
for item in timestamps:
|
| 310 |
+
print(f"{item['text']:<20} {item['start_time']:>8.3f}s → {item['end_time']:>8.3f}s")
|
| 311 |
+
|
| 312 |
+
"""
|
| 313 |
+
Word Start (s) End (s)
|
| 314 |
+
------------------------------------------
|
| 315 |
+
Mr 0.560 0.800
|
| 316 |
+
Quilter 0.800 1.280
|
| 317 |
+
is 1.280 1.440
|
| 318 |
+
the 1.440 1.520
|
| 319 |
+
apostle 1.520 2.080
|
| 320 |
+
...
|
| 321 |
+
"""
|
| 322 |
+
```
|
| 323 |
+
|
| 324 |
+
### Pipeline usage
|
| 325 |
+
|
| 326 |
+
```python
|
| 327 |
+
from transformers import pipeline
|
| 328 |
+
|
| 329 |
+
model_id = "Qwen/Qwen3-ASR-1.7B-hf"
|
| 330 |
+
pipe = pipeline("any-to-any", model=model_id, device_map="auto")
|
| 331 |
+
|
| 332 |
+
chat_template = [
|
| 333 |
+
{
|
| 334 |
+
"role": "user",
|
| 335 |
+
"content": [
|
| 336 |
+
{
|
| 337 |
+
"type": "audio",
|
| 338 |
+
"path": "https://huggingface.co/datasets/bezzam/audio_samples/resolve/main/librispeech_mr_quilter.wav",
|
| 339 |
+
},
|
| 340 |
+
],
|
| 341 |
+
}
|
| 342 |
+
]
|
| 343 |
+
outputs = pipe(text=chat_template, return_full_text=False)
|
| 344 |
+
raw_text = outputs[0]["generated_text"]
|
| 345 |
+
|
| 346 |
+
# Use processor helper to extract transcription
|
| 347 |
+
transcription = pipe.processor.extract_transcription(raw_text)
|
| 348 |
+
print(f"Transcription: {transcription}")
|
| 349 |
+
```
|
| 350 |
+
|
| 351 |
+
---
|
| 352 |
+
|
| 353 |
+
## Speed & Memory Improvements
|
| 354 |
+
|
| 355 |
+
### Torch compile
|
| 356 |
+
|
| 357 |
+
Both the ASR and forced aligner models support `torch.compile`. The forced aligner is a particularly good fit because it runs a single forward pass with no autoregressive decoding, making it ideal for bulk timestamping workflows.
|
| 358 |
+
|
| 359 |
+
On an A100 we observed ~2.5× speed-up for the forced aligner and ~2.4× for ASR generate at batch size 4.
|
| 360 |
+
|
| 361 |
+
```python
|
| 362 |
+
import torch
|
| 363 |
+
from transformers import AutoProcessor, AutoModelForMultimodalLM
|
| 364 |
+
|
| 365 |
+
model_id = "Qwen/Qwen3-ASR-1.7B-hf"
|
| 366 |
+
processor = AutoProcessor.from_pretrained(model_id)
|
| 367 |
+
model = AutoModelForMultimodalLM.from_pretrained(model_id, dtype=torch.bfloat16).to("cuda").eval()
|
| 368 |
+
|
| 369 |
+
audio_url = "https://huggingface.co/datasets/bezzam/audio_samples/resolve/main/librispeech_mr_quilter.wav"
|
| 370 |
+
inputs = processor.apply_transcription_request(
|
| 371 |
+
audio=[audio_url] * 4,
|
| 372 |
+
).to("cuda", torch.bfloat16)
|
| 373 |
+
|
| 374 |
+
model.forward = torch.compile(model.forward)
|
| 375 |
+
|
| 376 |
+
# Warmup
|
| 377 |
+
with torch.inference_mode():
|
| 378 |
+
for _ in range(3):
|
| 379 |
+
_ = model.generate(**inputs, max_new_tokens=256, do_sample=False)
|
| 380 |
+
|
| 381 |
+
# Inference
|
| 382 |
+
with torch.inference_mode():
|
| 383 |
+
output_ids = model.generate(**inputs, max_new_tokens=256, do_sample=False)
|
| 384 |
+
|
| 385 |
+
generated_ids = output_ids[:, inputs["input_ids"].shape[1]:]
|
| 386 |
+
print(processor.decode(generated_ids, return_format="transcription_only")[0])
|
| 387 |
+
```
|
| 388 |
+
|
| 389 |
+
---
|
| 390 |
+
|
| 391 |
+
## Evaluation
|
| 392 |
+
|
| 393 |
+
WER on the [HuggingFace Open ASR Leaderboard](https://huggingface.co/spaces/hf-audio/open_asr_leaderboard) (26 June 2026):
|
| 394 |
+
|
| 395 |
+
| Model | Mean WER | AMI | Earnings22 | GigaSpeech | LS Clean | LS Other | SPGISpeech | VoxPopuli |
|
| 396 |
+
|---|---|---|---|---|---|---|---|---|
|
| 397 |
+
| Qwen3-ASR-1.7B-hf | 5.59 | 9.26 | 9.88 | 7.25 | 1.24 | 2.92 | 2.58 | 5.99 |
|
| 398 |
+
| Qwen3-ASR-0.6B-hf | 6.31 | 10.57 | 10.72 | 7.65 | 1.69 | 3.97 | 2.74 | 6.80 |
|
| 399 |
+
|
| 400 |
+
---
|
| 401 |
+
|
| 402 |
+
## Citation
|
| 403 |
+
|
| 404 |
+
```bibtex
|
| 405 |
+
@article{Qwen3-ASR,
|
| 406 |
+
title={Qwen3-ASR Technical Report},
|
| 407 |
+
author={Xian Shi, Xiong Wang, Zhifang Guo, Yongqi Wang, Pei Zhang, Xinyu Zhang, Zishan Guo,
|
| 408 |
+
Hongkun Hao, Yu Xi, Baosong Yang, Jin Xu, Jingren Zhou, Junyang Lin},
|
| 409 |
+
journal={arXiv preprint arXiv:2601.21337},
|
| 410 |
+
year={2026}
|
| 411 |
+
}
|
| 412 |
+
```
|
chat_template.jinja
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{%- set ns = namespace(system_text="") -%}
|
| 2 |
+
{%- for m in messages -%}
|
| 3 |
+
{%- if m.role == 'system' -%}
|
| 4 |
+
{%- if m.content is string -%}
|
| 5 |
+
{%- set ns.system_text = ns.system_text + m.content -%}
|
| 6 |
+
{%- else -%}
|
| 7 |
+
{%- for c in m.content -%}
|
| 8 |
+
{%- if c.type == 'text' and (c.text is defined) -%}
|
| 9 |
+
{%- set ns.system_text = ns.system_text + c.text -%}
|
| 10 |
+
{%- endif -%}
|
| 11 |
+
{%- endfor -%}
|
| 12 |
+
{%- endif -%}
|
| 13 |
+
{%- endif -%}
|
| 14 |
+
{%- endfor -%}
|
| 15 |
+
|
| 16 |
+
{%- set ns2 = namespace(audio_tokens="") -%}
|
| 17 |
+
{%- for m in messages -%}
|
| 18 |
+
{%- if m.content is not string -%}
|
| 19 |
+
{%- for c in m.content -%}
|
| 20 |
+
{%- if c.type == 'audio' or ('audio' in c) or ('audio_url' in c) -%}
|
| 21 |
+
{%- set ns2.audio_tokens = ns2.audio_tokens + "<|audio_start|><|audio_pad|><|audio_end|>" -%}
|
| 22 |
+
{%- endif -%}
|
| 23 |
+
{%- endfor -%}
|
| 24 |
+
{%- endif -%}
|
| 25 |
+
{%- endfor -%}
|
| 26 |
+
|
| 27 |
+
{{- '<|im_start|>system\n' + (ns.system_text if ns.system_text is string else '') + '<|im_end|>\n' -}}
|
| 28 |
+
{{- '<|im_start|>user\n' + ns2.audio_tokens + '<|im_end|>\n' -}}
|
| 29 |
+
{%- if add_generation_prompt -%}
|
| 30 |
+
{{- '<|im_start|>assistant\n' -}}
|
| 31 |
+
{%- endif -%}
|
config.json
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"Qwen3ASRForConditionalGeneration"
|
| 4 |
+
],
|
| 5 |
+
"audio_config": {
|
| 6 |
+
"activation_dropout": 0,
|
| 7 |
+
"activation_function": "gelu",
|
| 8 |
+
"attention_dropout": 0,
|
| 9 |
+
"conv_chunksize": 500,
|
| 10 |
+
"d_model": 1024,
|
| 11 |
+
"downsample_hidden_size": 480,
|
| 12 |
+
"dropout": 0,
|
| 13 |
+
"encoder_attention_heads": 16,
|
| 14 |
+
"encoder_ffn_dim": 4096,
|
| 15 |
+
"encoder_layers": 24,
|
| 16 |
+
"initializer_range": 0.02,
|
| 17 |
+
"max_position_embeddings": 13,
|
| 18 |
+
"model_type": "qwen3_asr_encoder",
|
| 19 |
+
"n_window": 50,
|
| 20 |
+
"n_window_infer": 800,
|
| 21 |
+
"num_key_value_heads": 16,
|
| 22 |
+
"num_mel_bins": 128,
|
| 23 |
+
"output_dim": 2048,
|
| 24 |
+
"scale_embedding": false
|
| 25 |
+
},
|
| 26 |
+
"audio_token_id": 151676,
|
| 27 |
+
"dtype": "bfloat16",
|
| 28 |
+
"eos_token_id": [
|
| 29 |
+
151643,
|
| 30 |
+
151645
|
| 31 |
+
],
|
| 32 |
+
"initializer_range": 0.02,
|
| 33 |
+
"model_type": "qwen3_asr",
|
| 34 |
+
"pad_token_id": 151645,
|
| 35 |
+
"text_config": {
|
| 36 |
+
"attention_bias": false,
|
| 37 |
+
"attention_dropout": 0.0,
|
| 38 |
+
"bos_token_id": null,
|
| 39 |
+
"eos_token_id": null,
|
| 40 |
+
"head_dim": 128,
|
| 41 |
+
"hidden_act": "silu",
|
| 42 |
+
"hidden_size": 2048,
|
| 43 |
+
"initializer_range": 0.02,
|
| 44 |
+
"intermediate_size": 6144,
|
| 45 |
+
"layer_types": [
|
| 46 |
+
"full_attention",
|
| 47 |
+
"full_attention",
|
| 48 |
+
"full_attention",
|
| 49 |
+
"full_attention",
|
| 50 |
+
"full_attention",
|
| 51 |
+
"full_attention",
|
| 52 |
+
"full_attention",
|
| 53 |
+
"full_attention",
|
| 54 |
+
"full_attention",
|
| 55 |
+
"full_attention",
|
| 56 |
+
"full_attention",
|
| 57 |
+
"full_attention",
|
| 58 |
+
"full_attention",
|
| 59 |
+
"full_attention",
|
| 60 |
+
"full_attention",
|
| 61 |
+
"full_attention",
|
| 62 |
+
"full_attention",
|
| 63 |
+
"full_attention",
|
| 64 |
+
"full_attention",
|
| 65 |
+
"full_attention",
|
| 66 |
+
"full_attention",
|
| 67 |
+
"full_attention",
|
| 68 |
+
"full_attention",
|
| 69 |
+
"full_attention",
|
| 70 |
+
"full_attention",
|
| 71 |
+
"full_attention",
|
| 72 |
+
"full_attention",
|
| 73 |
+
"full_attention"
|
| 74 |
+
],
|
| 75 |
+
"max_position_embeddings": 65536,
|
| 76 |
+
"max_window_layers": 28,
|
| 77 |
+
"model_type": "qwen3",
|
| 78 |
+
"num_attention_heads": 16,
|
| 79 |
+
"num_hidden_layers": 28,
|
| 80 |
+
"num_key_value_heads": 8,
|
| 81 |
+
"pad_token_id": null,
|
| 82 |
+
"rms_norm_eps": 1e-06,
|
| 83 |
+
"rope_parameters": {
|
| 84 |
+
"rope_theta": 1000000,
|
| 85 |
+
"rope_type": "default"
|
| 86 |
+
},
|
| 87 |
+
"sliding_window": null,
|
| 88 |
+
"tie_word_embeddings": true,
|
| 89 |
+
"use_cache": true,
|
| 90 |
+
"use_sliding_window": false,
|
| 91 |
+
"vocab_size": 151936
|
| 92 |
+
},
|
| 93 |
+
"tie_word_embeddings": true,
|
| 94 |
+
"timestamp_token_id": 151705,
|
| 95 |
+
"token_classification_bias": false,
|
| 96 |
+
"transformers_version": "5.13.0.dev0"
|
| 97 |
+
}
|
generation_config.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"do_sample": false,
|
| 3 |
+
"eos_token_id": [
|
| 4 |
+
151643,
|
| 5 |
+
151645
|
| 6 |
+
],
|
| 7 |
+
"max_new_tokens": 512,
|
| 8 |
+
"pad_token_id": 151645,
|
| 9 |
+
"transformers_version": "5.13.0.dev0"
|
| 10 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2db53c7d81bd9b8cbc6a074e89be2c968a0d373fb4ee68bb1b1e14f7042dfee1
|
| 3 |
+
size 4076193080
|
processor_config.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"feature_extractor": {
|
| 3 |
+
"chunk_length": 30,
|
| 4 |
+
"dither": 0.0,
|
| 5 |
+
"feature_extractor_type": "Qwen3ASRFeatureExtractor",
|
| 6 |
+
"feature_size": 128,
|
| 7 |
+
"hop_length": 160,
|
| 8 |
+
"min_length": 8000,
|
| 9 |
+
"n_fft": 400,
|
| 10 |
+
"n_samples": 480000,
|
| 11 |
+
"n_window": 50,
|
| 12 |
+
"nb_max_frames": 3000,
|
| 13 |
+
"padding_side": "right",
|
| 14 |
+
"padding_value": 0.0,
|
| 15 |
+
"return_attention_mask": true,
|
| 16 |
+
"sampling_rate": 16000
|
| 17 |
+
},
|
| 18 |
+
"processor_class": "Qwen3ASRProcessor",
|
| 19 |
+
"timestamp_segment_time": 80
|
| 20 |
+
}
|
tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:fe1fad59be22a41ee293363fcf95fdedbc7c93f3b49270b1d2e18bd1399a7a05
|
| 3 |
+
size 11429653
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_prefix_space": false,
|
| 3 |
+
"audio_bos_token": "<|audio_start|>",
|
| 4 |
+
"audio_eos_token": "<|audio_end|>",
|
| 5 |
+
"audio_token": "<|audio_pad|>",
|
| 6 |
+
"backend": "tokenizers",
|
| 7 |
+
"bos_token": null,
|
| 8 |
+
"clean_up_tokenization_spaces": false,
|
| 9 |
+
"eos_token": "<|im_end|>",
|
| 10 |
+
"errors": "replace",
|
| 11 |
+
"image_token": "<|image_pad|>",
|
| 12 |
+
"is_local": true,
|
| 13 |
+
"local_files_only": false,
|
| 14 |
+
"model_max_length": 131072,
|
| 15 |
+
"model_specific_special_tokens": {
|
| 16 |
+
"audio_bos_token": "<|audio_start|>",
|
| 17 |
+
"audio_eos_token": "<|audio_end|>",
|
| 18 |
+
"audio_token": "<|audio_pad|>",
|
| 19 |
+
"image_token": "<|image_pad|>",
|
| 20 |
+
"video_token": "<|video_pad|>",
|
| 21 |
+
"vision_bos_token": "<|vision_start|>",
|
| 22 |
+
"vision_eos_token": "<|vision_end|>"
|
| 23 |
+
},
|
| 24 |
+
"pad_token": "<|endoftext|>",
|
| 25 |
+
"processor_class": "Qwen3ASRProcessor",
|
| 26 |
+
"split_special_tokens": false,
|
| 27 |
+
"tokenizer_class": "Qwen2Tokenizer",
|
| 28 |
+
"unk_token": null,
|
| 29 |
+
"video_token": "<|video_pad|>",
|
| 30 |
+
"vision_bos_token": "<|vision_start|>",
|
| 31 |
+
"vision_eos_token": "<|vision_end|>"
|
| 32 |
+
}
|