Automatic Speech Recognition
Transformers
Safetensors
Danish
qwen3_asr
danish
qwen
asr
speech-to-text
coral
podcast
streaming
Eval Results (legacy)
Instructions to use pluttodk/milo-asr with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use pluttodk/milo-asr with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("automatic-speech-recognition", model="pluttodk/milo-asr")# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("pluttodk/milo-asr") model = AutoModelForMultimodalLM.from_pretrained("pluttodk/milo-asr", device_map="auto") - Notebooks
- Google Colab
- Kaggle
| license: openrail | |
| language: | |
| - da | |
| base_model: Qwen/Qwen3-ASR-1.7B | |
| tags: | |
| - automatic-speech-recognition | |
| - danish | |
| - qwen | |
| - asr | |
| - speech-to-text | |
| - coral | |
| - streaming | |
| datasets: | |
| - alexandrainst/coral | |
| library_name: transformers | |
| pipeline_tag: automatic-speech-recognition | |
| metrics: | |
| - wer | |
| - cer | |
| model-index: | |
| - name: milo-asr | |
| results: | |
| - task: | |
| type: automatic-speech-recognition | |
| name: Speech Recognition | |
| dataset: | |
| type: alexandrainst/coral | |
| name: CoRal v2 Test | |
| split: test | |
| metrics: | |
| - type: wer | |
| value: 18.47 | |
| name: WER | |
| - type: cer | |
| value: 7.86 | |
| name: CER | |
| # Milo-ASR: Dansk talegenkendelses model | |
| **Milo-ASR** er en dansk ASR-model bygget oven på [Qwen3-ASR-1.7B](https://huggingface.co/Qwen/Qwen3-ASR-1.7B), som er finetunet på [CoRal v2-datasættet](https://huggingface.co/datasets/alexandrainst/coral) for at blive god til dansk. | |
| ## Kort fortalt | |
| | Feature | Værdi | | |
| |---------|-------| | |
| | **WER på CoRal v2** | 18,47% (14% bedre end hviske-v3-conversation) | | |
| | **CER på CoRal v2** | 7,86% (11% bedre end hviske-v3-conversation) | | |
| | **Real-Time Factor** | 0,087 (43% hurtigere end hviske-v3-conversation) | | |
| | **Modelstørrelse** | ~1,7B parametre | | |
| ### Hvad Milo-ASR kan (nedarvet fra Qwen3-ASR) | |
| - **Streaming/realtidstransskription** via vLLM backend | |
| - **Sanggenkendelse** – Milo-ASR kan transskribere tale i lyd med baggrundsmusik | |
| - **Tidsstempler på ordniveau** via forced alignment | |
| - **30+ sprog** (optimeret til dansk) | |
| - **Op til 20 minutter pr. kald** – du behøver ikke hakke lyden op i småbidder | |
| --- | |
| ## Sammenligning med andre modeller | |
| ### CoRal v2 testsæt (9.123 eksempler, ~17,3 timer) | |
| | Model | WER | CER | RTF | Gennemløb | Parametre | | |
| |-------|-----|-----|-----|-----------|-----------| | |
| | **Milo-ASR** | **18,47%** | **7,86%** | **0,087** | **1,69 eks./s** | ~1,7B | | |
| | hviske-v2 (Whisper Large v2) | 12,74% | 4,94% | 0,154 | 0,95 eks./s | ~1,5B | | |
| | hviske-v3-conversation (Whisper Large v3) | 21,47% | 8,79% | 0,153 | 0,95 eks./s | ~2B | | |
| | Whisper Large v3 Turbo | 38,54% | 13,73% | 0,064 | 2,29 eks./s | ~0,8B | | |
| | Qwen3-ASR-1.7B (base) | 46,03% | 18,85% | 0,100 | 1,46 eks./s | ~1,7B | | |
| **Milo-ASR vs. hviske-v3-conversation (Whisper Large v3):** | |
| - **14% lavere** Word Error Rate (18,47% vs. 21,47%) | |
| - **11% lavere** Character Error Rate (7,86% vs. 8,79%) | |
| - **43% hurtigere** inferens (RTF: 0,087 vs. 0,153) | |
| - **15% færre** parametre (~1,7B vs. ~2B) | |
| > **Bemærk:** hviske-v2 (Whisper Large v2) klarer sig bedre end Milo-ASR på WER og CER. Til gengæld er Milo-ASR næsten dobbelt så hurtig (RTF 0,087 vs. 0,154), så hvis hastighed er vigtig for dig, er Milo-ASR det oplagte valg. | |
| ### Sammenligningsplots | |
|  | |
|  | |
|  | |
| --- | |
| ## Kom i gang | |
| ### Installation | |
| ```bash | |
| pip install qwen-asr transformers torch | |
| ``` | |
| ### Basis brug | |
| ```python | |
| from qwen_asr import Qwen3ASRModel | |
| # Indlæs Milo-ASR | |
| model = Qwen3ASRModel.from_pretrained( | |
| "pluttodk/Milo-ASR", | |
| dtype="bfloat16", | |
| device_map="cuda:0", | |
| ) | |
| # Transskriber en dansk lydfil | |
| results = model.transcribe( | |
| audio="sti/til/dansk_lyd.wav", | |
| language="Danish", | |
| ) | |
| print(results[0].text) | |
| ``` | |
| --- | |
| ## Avanceret brug | |
| ### Batch-transskription | |
| Kør flere filer på én gang: | |
| ```python | |
| from qwen_asr import Qwen3ASRModel | |
| model = Qwen3ASRModel.from_pretrained( | |
| "pluttodk/Milo-ASR", | |
| dtype="bfloat16", | |
| device_map="cuda:0", | |
| max_inference_batch_size=16, | |
| ) | |
| audio_filer = ["lyd1.wav", "lyd2.wav", "lyd3.wav"] | |
| results = model.transcribe( | |
| audio=audio_filer, | |
| language="Danish", | |
| ) | |
| for i, result in enumerate(results): | |
| print(f"Fil {i+1}: {result.text}") | |
| ``` | |
| ### Transskription med tidsstempler | |
| Få tidsstempler på ordniveau via forced aligner: | |
| ```python | |
| from qwen_asr import Qwen3ASRModel | |
| model = Qwen3ASRModel.from_pretrained( | |
| "pluttodk/Milo-ASR", | |
| forced_aligner="Qwen/Qwen3-ForcedAligner-0.6B", | |
| dtype="bfloat16", | |
| device_map="cuda:0", | |
| ) | |
| results = model.transcribe( | |
| audio="sti/til/lyd.wav", | |
| language="Danish", | |
| return_time_stamps=True, | |
| ) | |
| for item in results[0].time_stamps.items: | |
| print(f"{item.start_time:.2f}s - {item.end_time:.2f}s: {item.text}") | |
| ``` | |
| ### Streaming i realtid (vLLM backend) | |
| Hvis du vil have live transskription, fx fra en mikrofon: | |
| ```python | |
| from qwen_asr import Qwen3ASRModel | |
| model = Qwen3ASRModel.LLM( | |
| model="pluttodk/Milo-ASR", | |
| gpu_memory_utilization=0.8, | |
| ) | |
| state = model.init_streaming_state( | |
| language="Danish", | |
| chunk_size_sec=2.0, | |
| ) | |
| import numpy as np | |
| def lyd_stream(): | |
| """Erstat med din faktiske lydstream fra mikrofon.""" | |
| for chunk in audio_chunks: | |
| yield np.array(chunk, dtype=np.float32) | |
| for lyd_chunk in lyd_stream(): | |
| state = model.streaming_transcribe(lyd_chunk, state) | |
| print(f"Løbende transskription: {state.text}") | |
| state = model.finish_streaming_transcribe(state) | |
| print(f"Endelig transskription: {state.text}") | |
| ``` | |
| ### Direkte brug med Transformers | |
| Vil du have fuld kontrol over modellen, kan du bruge Transformers direkte: | |
| ```python | |
| from transformers import AutoModel, AutoProcessor | |
| import torch | |
| import librosa | |
| model = AutoModel.from_pretrained( | |
| "pluttodk/Milo-ASR", | |
| trust_remote_code=True, | |
| torch_dtype=torch.bfloat16, | |
| device_map="cuda:0", | |
| ) | |
| processor = AutoProcessor.from_pretrained( | |
| "pluttodk/Milo-ASR", | |
| trust_remote_code=True, | |
| ) | |
| audio, sr = librosa.load("sti/til/lyd.wav", sr=16000, mono=True) | |
| messages = [ | |
| {"role": "system", "content": ""}, | |
| {"role": "user", "content": [{"type": "audio", "audio": audio}]}, | |
| ] | |
| text = processor.apply_chat_template( | |
| messages, | |
| add_generation_prompt=True, | |
| tokenize=False | |
| ) | |
| text = text + "language Danish<asr_text>" | |
| inputs = processor(text=[text], audio=[audio], return_tensors="pt", padding=True) | |
| inputs = inputs.to(model.device).to(model.dtype) | |
| output_ids = model.generate(**inputs, max_new_tokens=512) | |
| transskription = processor.batch_decode( | |
| output_ids[:, inputs["input_ids"].shape[1]:], | |
| skip_special_tokens=True, | |
| )[0] | |
| print(transskription) | |
| ``` | |
| ### Sang og baggrundsmusik | |
| Milo-ASR kan håndtere lyd med sang eller baggrundsmusik: | |
| ```python | |
| from qwen_asr import Qwen3ASRModel | |
| model = Qwen3ASRModel.from_pretrained( | |
| "pluttodk/Milo-ASR", | |
| dtype="bfloat16", | |
| device_map="cuda:0", | |
| ) | |
| results = model.transcribe( | |
| audio="sti/til/sang.wav", | |
| language="Danish", # eller None for automatisk sproggenkendelse | |
| ) | |
| print(results[0].text) | |
| ``` | |
| --- | |
| ## Om modellen | |
| ### Beskrivelse | |
| Milo-ASR er lavet ved at finetunet [Qwen3-ASR-1.7B](https://huggingface.co/Qwen/Qwen3-ASR-1.7B) på [CoRal v2-datasættet](https://huggingface.co/datasets/alexandrainst/coral). Resultatet er en model, der er skarp til dansk tale og samtidig hurtig nok til at bruges i produktionsmiljøer og realtidsapplikationer. | |
| - **Udviklet af:** Mathias Oliver Valdbjørn Rønnelund | |
| - **Modeltype:** Encoder-decoder talegenkendelses model | |
| - **Sprog:** Dansk (primært), med nedarvet flersproget understøttelse | |
| - **Licens:** OpenRAIL | |
| - **Finetunet fra:** [Qwen/Qwen3-ASR-1.7B](https://huggingface.co/Qwen/Qwen3-ASR-1.7B) | |
| ### Arkitektur | |
| | Komponent | Specifikation | | |
| |-----------|--------------| | |
| | Audio Encoder | 24-lags transformer (1024 hidden dim, 16 attention heads) | | |
| | Text Decoder | 28-lags transformer (2048 hidden dim, 16 attention heads) | | |
| | Parametre i alt | ~1,7 milliarder | | |
| | Præcision | bfloat16 | | |
| | Lydinput | 16kHz mono WAV | | |
| --- | |
| ## Træning | |
| ### Træningsdata | |
| Milo-ASR er finetunet på [CoRal v2-datasættet](https://huggingface.co/datasets/alexandrainst/coral), som er et dansk talekorpus med: | |
| - Mange forskellige danske talere på tværs af alder, køn og dialekter | |
| - Varierende optagelseskvalitet og lydmiljøer | |
| - Naturlig samtaletale | |
| - Oplæst tale | |
| ### Træningsopsætning | |
| **Tilgang:** Supervised Fine-Tuning (SFT) med chat template-formatering | |
| **Forbehandling:** | |
| - Lyd resamplet til 16kHz mono | |
| - Chat template anvendt med systemprompt, lydinput og måltransskription | |
| - Prefix masking så modellen kun trænes på transskriptionstokens | |
| **Hyperparametre:** | |
| | Parameter | Værdi | | |
| |-----------|-------| | |
| | Basismodel | Qwen/Qwen3-ASR-1.7B | | |
| | Læringsrate | 2e-5 | | |
| | Batchstørrelse (per device) | 8 | | |
| | Gradient accumulation steps | 4 | | |
| | Effektiv batchstørrelse | 32 | | |
| | Epoker | 3 | | |
| | Warmup ratio | 0,1 | | |
| | Weight decay | 0,01 | | |
| | Max gradient norm | 1,0 | | |
| | Præcision | bfloat16 | | |
| | Optimizer | AdamW | | |
| | LR scheduler | Lineært fald | | |
| | Træningsskridt i alt | 23.448 | | |
| **Hardware:** NVIDIA GPU'er (~25GB GPU-hukommelse per device) | |
| --- | |
| ## Evaluering | |
| ### Testdata | |
| Milo-ASR er evalueret på CoRal v2-testsættet: | |
| - **9.123 eksempler** | |
| - **~17,3 timers** lyd | |
| - Bred repræsentation af danske talere og optagelsesforhold | |
| ### Metrikker | |
| | Metrik | Beskrivelse | | |
| |--------|-------------| | |
| | **WER** | Word Error Rate – andelen af forkert transskriberede ord (lavere er bedre) | | |
| | **CER** | Character Error Rate – andelen af forkert transskriberede tegn (lavere er bedre) | | |
| | **RTF** | Real-Time Factor – forholdet mellem procestid og lydvarighed (under 1,0 = hurtigere end realtid) | | |
| ### Resultater | |
| | Model | WER | CER | RTF | Gennemløb | Parametre | | |
| |-------|-----|-----|-----|-----------|-----------| | |
| | **Milo-ASR** | **18,47%** | **7,86%** | **0,087** | **1,69 eks./s** | ~1,7B | | |
| | hviske-v2 (Whisper Large v2) | 12,74% | 4,94% | 0,154 | 0,95 eks./s | ~1,5B | | |
| | hviske-v3-conversation (Whisper Large v3) | 21,47% | 8,79% | 0,153 | 0,95 eks./s | ~2B | | |
| | Whisper Large v3 Turbo | 38,54% | 13,73% | 0,064 | 2,29 eks./s | ~0,8B | | |
| | Qwen3-ASR-1.7B (base) | 46,03% | 18,85% | 0,100 | 1,46 eks./s | ~1,7B | | |
| Milo-ASR slår hviske-v3-conversation med 14% på WER og 11% på CER, og er samtidig 43% hurtigere. Sammenlignet med den utrænede Qwen3-ASR-1.7B basismodel falder WER fra 46,03% til 18,47% – et klart tegn på, at finetuning på CoRal v2 gør en stor forskel. | |
| --- | |
| ## Citér modellen | |
| Bruger du Milo-ASR i dit projekt, må du meget gerne citere: | |
| ```bibtex | |
| @misc{Milo-ASR, | |
| author = {Rønnelund, Mathias Oliver Valdbjørn}, | |
| title = {Milo-ASR: Danish ASR Model based on Qwen3-ASR}, | |
| year = {2025}, | |
| publisher = {HuggingFace}, | |
| url = {https://huggingface.co/pluttodk/Milo-ASR} | |
| } | |
| ``` | |
| Og gerne også basismodellen og datasættet: | |
| ```bibtex | |
| @article{qwen3asr, | |
| title={Qwen3-ASR Technical Report}, | |
| author={Qwen Team}, | |
| journal={arXiv preprint arXiv:2601.21337}, | |
| year={2025} | |
| } | |
| @dataset{coral, | |
| title={CoRal: A Danish Speech Corpus}, | |
| author={Alexandra Institute}, | |
| year={2024}, | |
| url={https://huggingface.co/datasets/alexandrainst/coral} | |
| } | |
| ``` | |
| --- | |
| ## Tak til | |
| - [Qwen-teamet](https://github.com/QwenLM) for Qwen3-ASR basismodellen | |
| - [Alexandra Instituttet](https://alexandra.dk/) for CoRal v2-datasættet |