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 ASR Model | |
| **Milo-ASR** er en "state of the art" Dansk automatic speech recognition (ASR) model baseret på [Qwen3-ASR-1.7B](https://huggingface.co/Qwen/Qwen3-ASR-1.7B), finetuned på [CoRal v2 dataset](https://huggingface.co/datasets/alexandrainst/coral) for at gøre den bedre til at forstå dansk. | |
| ## Key Highlights | |
| | Feature | Value | | |
| |---------|-------| | |
| | **WER on CoRal v2** | 18.47% (14% better than Whisper v3) | | |
| | **CER on CoRal v2** | 7.86% (11% better than Whisper v3) | | |
| | **Real-Time Factor** | 0.086 (45% faster than Whisper v3) | | |
| | **Model Size** | ~1.7B parameters | | |
| ### Fordele nedarvet fra Qwen3-ASR | |
| - **Streaming/Real-time transcription** via vLLM backend | |
| - **Sang detection** - Til at kunne transskribere teksten fra lyde med baggrundsmusik (find ud af hvad Rasmus seebach synger 🤣) | |
| - **Word-level timestamps** via forced alignment | |
| - **30+ language support** (Danish optimized) | |
| - **20 minutter pr. request** - Kan kører 20 minutter igennem pr. kald | |
| --- | |
| ## Performance Comparison | |
| ### CoRal v2 Test Set (9,123 samples, 17.3 hours) | |
| | Model | WER | CER | RTF | Throughput | Parameters | | |
| |-------|-----|-----|-----|------------|------------| | |
| | **Milo-ASR** | **18.47%** | **7.86%** | **0.086** | 1.71 samples/s | ~1.7B | | |
| | hviske-v3 (Whisper Large v3) | 21.47% | 8.79% | 0.156 | 0.94 samples/s | ~2B | | |
| **Improvements over Whisper Large v3:** | |
| - **14% reduction** in Word Error Rate | |
| - **11% reduction** in Character Error Rate | |
| - **45% faster** inference speed | |
| - **15% fewer** parameters | |
| ### Comparison Plots | |
|  | |
|  | |
|  | |
| --- | |
| ## Quick Start | |
| ### Installation | |
| ```bash | |
| pip install qwen-asr transformers torch | |
| ``` | |
| ### Basic Usage | |
| ```python | |
| from qwen_asr import Qwen3ASRModel | |
| # Load the model | |
| model = Qwen3ASRModel.from_pretrained( | |
| "pluttodk/Milo-ASR", | |
| dtype="bfloat16", | |
| device_map="cuda:0", | |
| ) | |
| # Transcribe audio file | |
| results = model.transcribe( | |
| audio="path/to/danish_audio.wav", | |
| language="Danish", | |
| ) | |
| print(results[0].text) | |
| ``` | |
| --- | |
| ## Advanced Usage | |
| ### Batch Transcription (Fast Processing) | |
| Process multiple audio files efficiently in a single call: | |
| ```python | |
| from qwen_asr import Qwen3ASRModel | |
| model = Qwen3ASRModel.from_pretrained( | |
| "pluttodk/Milo-ASR", | |
| dtype="bfloat16", | |
| device_map="cuda:0", | |
| max_inference_batch_size=16, # Process up to 16 files at once | |
| ) | |
| # Batch transcribe multiple files | |
| audio_files = ["audio1.wav", "audio2.wav", "audio3.wav"] | |
| results = model.transcribe( | |
| audio=audio_files, | |
| language="Danish", | |
| ) | |
| for i, result in enumerate(results): | |
| print(f"File {i+1}: {result.text}") | |
| ``` | |
| ### Transcription with Timestamps | |
| Get word-level timestamps using the 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="path/to/audio.wav", | |
| language="Danish", | |
| return_time_stamps=True, | |
| ) | |
| # Access word-level timestamps | |
| for item in results[0].time_stamps.items: | |
| print(f"{item.start_time:.2f}s - {item.end_time:.2f}s: {item.text}") | |
| ``` | |
| ### Streaming/Real-time Transcription (vLLM Backend) | |
| For real-time streaming transcription, use the vLLM backend: | |
| ```python | |
| from qwen_asr import Qwen3ASRModel | |
| # Initialize with vLLM backend for streaming | |
| model = Qwen3ASRModel.LLM( | |
| model="pluttodk/Milo-ASR", | |
| gpu_memory_utilization=0.8, | |
| ) | |
| # Initialize streaming state | |
| state = model.init_streaming_state( | |
| language="Danish", | |
| chunk_size_sec=2.0, # Process audio in 2-second chunks | |
| ) | |
| # Simulate streaming audio (16kHz mono float32) | |
| import numpy as np | |
| def audio_stream(): | |
| """Replace with actual audio stream from microphone.""" | |
| for chunk in audio_chunks: | |
| yield np.array(chunk, dtype=np.float32) | |
| # Process streaming audio | |
| for audio_chunk in audio_stream(): | |
| state = model.streaming_transcribe(audio_chunk, state) | |
| print(f"Current transcription: {state.text}") | |
| # Finalize stream | |
| state = model.finish_streaming_transcribe(state) | |
| print(f"Final transcription: {state.text}") | |
| ``` | |
| ### Using with Transformers Directly | |
| For more control, use the model directly with transformers: | |
| ```python | |
| from transformers import AutoModel, AutoProcessor | |
| import torch | |
| import librosa | |
| # Load model and processor | |
| 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, | |
| ) | |
| # Load and preprocess audio | |
| audio, sr = librosa.load("path/to/audio.wav", sr=16000, mono=True) | |
| # Build input using chat template | |
| 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>" | |
| # Process and generate | |
| 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) | |
| transcription = processor.batch_decode( | |
| output_ids[:, inputs["input_ids"].shape[1]:], | |
| skip_special_tokens=True, | |
| )[0] | |
| print(transcription) | |
| ``` | |
| ### Singing Detection & Multi-Audio Support | |
| The model inherits Qwen3-ASR's ability to handle singing and background music: | |
| ```python | |
| from qwen_asr import Qwen3ASRModel | |
| model = Qwen3ASRModel.from_pretrained( | |
| "pluttodk/Milo-ASR", | |
| dtype="bfloat16", | |
| device_map="cuda:0", | |
| ) | |
| # Transcribe audio with singing or background music | |
| results = model.transcribe( | |
| audio="path/to/song.wav", | |
| language="Danish", # or None for auto-detection | |
| ) | |
| print(results[0].text) | |
| ``` | |
| --- | |
| ## Model Details | |
| ### Model Description | |
| Milo-ASR is a Danish-specialized automatic speech recognition model created by finetuning [Qwen3-ASR-1.7B](https://huggingface.co/Qwen/Qwen3-ASR-1.7B) on the [CoRal v2 dataset](https://huggingface.co/datasets/alexandrainst/coral). The model achieves state-of-the-art performance on Danish speech recognition while maintaining fast inference speeds. | |
| - **Developed by:** Mathias Oliver Valdbjørn Rønnelund | |
| - **Model type:** Encoder-decoder speech recognition model | |
| - **Language:** Danish (primary), with inherited multilingual capabilities | |
| - **License:** Apache 2.0 | |
| - **Finetuned from:** [Qwen/Qwen3-ASR-1.7B](https://huggingface.co/Qwen/Qwen3-ASR-1.7B) | |
| ### Architecture | |
| The model inherits the Qwen3-ASR architecture: | |
| | Component | Specification | | |
| |-----------|--------------| | |
| | Audio Encoder | 24-layer transformer (1024 hidden dim, 16 attention heads) | | |
| | Text Decoder | 28-layer transformer (2048 hidden dim, 16 attention heads) | | |
| | Total Parameters | ~1.7 billion | | |
| | Precision | bfloat16 | | |
| | Audio Input | 16kHz mono WAV | | |
| --- | |
| ## Training Details | |
| ### Training Data | |
| The model was finetuned on the [CoRal v2 dataset](https://huggingface.co/datasets/alexandrainst/coral), a comprehensive Danish speech corpus containing: | |
| - Diverse Danish speakers across demographics | |
| - Various recording conditions and audio qualities | |
| - Natural conversational speech | |
| - Read-aloud speech | |
| ### Training Procedure | |
| **Training Approach:** Supervised Fine-Tuning (SFT) with chat template formatting | |
| **Preprocessing:** | |
| - Audio resampled to 16kHz mono | |
| - Chat template applied with system prompt, audio input, and target transcription | |
| - Prefix masking to train only on transcription tokens | |
| **Training Hyperparameters:** | |
| | Parameter | Value | | |
| |-----------|-------| | |
| | Base model | Qwen/Qwen3-ASR-1.7B | | |
| | Learning rate | 2e-5 | | |
| | Batch size (per device) | 8 | | |
| | Gradient accumulation steps | 4 | | |
| | Effective batch size | 32 | | |
| | Epochs | 3 | | |
| | Warmup ratio | 0.1 | | |
| | Weight decay | 0.01 | | |
| | Max gradient norm | 1.0 | | |
| | Precision | bfloat16 | | |
| | Optimizer | AdamW | | |
| | LR scheduler | Linear decay | | |
| | Total training steps | 23,448 | | |
| **Hardware:** Training performed on NVIDIA GPUs (~25GB GPU memory per device) | |
| --- | |
| ## Evaluation | |
| ### Test Data | |
| Evaluated on the CoRal v2 test split: | |
| - **9,123 samples** | |
| - **17.3 hours** of audio | |
| - Diverse Danish speakers and recording conditions | |
| ### Metrics | |
| | Metric | Description | | |
| |--------|-------------| | |
| | **WER** | Word Error Rate - percentage of words incorrectly transcribed (lower is better) | | |
| | **CER** | Character Error Rate - percentage of characters incorrectly transcribed (lower is better) | | |
| | **RTF** | Real-Time Factor - ratio of processing time to audio duration (< 1.0 = faster than real-time) | | |
| ### Results Summary | |
| | Model | WER | CER | RTF | Throughput | | |
| |-------|-----|-----|-----|------------| | |
| | **Milo-ASR** | **18.47%** | **7.86%** | **0.086** | 1.71 samples/sec | | |
| | hviske-v3 (Whisper v3) | 21.47% | 8.79% | 0.156 | 0.94 samples/sec | | |
| --- | |
| ## Citation | |
| If you use this model, please cite: | |
| ```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} | |
| } | |
| ``` | |
| Also consider citing the base model and dataset: | |
| ```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} | |
| } | |
| ``` | |
| --- | |
| ## Acknowledgements | |
| - [Qwen Team](https://github.com/QwenLM) for Qwen3-ASR base model | |
| - [Alexandra Institute](https://alexandra.dk/) for CoRal v2 lyd corpus | |