You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

Qwen3-ASR-0.6B-kk-ru-en

A trilingual Kazakh / Russian / English speech-recognition model, fine-tuned from Qwen/Qwen3-ASR-0.6B. It adds Kazakh (which the base model does not recognize) while preserving strong Russian and English transcription, in a single 0.6B model with streaming/offline unified inference.

  • Languages: Kazakh (kk), Russian (ru), English (en)
  • Base model: Qwen/Qwen3-ASR-0.6B (audio encoder → Qwen3 decoder)
  • Numbers are emitted as digits (e.g. 1990, 25), not spelled out — no inverse-text-normalization step is needed downstream.
  • License: Apache-2.0

Performance

Word/character error rate (%) on held-out public test sets, lower is better. Text is scored with the standard multilingual-Whisper normalization protocol (EnglishTextNormalizer for English, BasicTextNormalizer for Kazakh/Russian).

Test set Lang WER CER
FLEURS (kk_kz, test) kk 17.80 7.38
FLEURS (ru_ru, test) ru 12.77 5.38
FLEURS (en_us, test) en 5.92 3.22
KSC2 (ISSAI, test) kk 20.42 6.97

FLEURS/KSC2 numbers are measured on a fixed seeded subset (500 utts per FLEURS language; 1000 utts for KSC2). Language is auto-detected for Kazakh and forced to "Russian" / "English" for the other two. See Benchmark below to reproduce.

Installation

The model runs with the official qwen-asr toolkit. Use a fresh environment to avoid dependency conflicts.

pip install -U qwen-asr           # transformers backend
# pip install -U "qwen-asr[vllm]" # add the vLLM backend (faster + streaming)

Usage

import torch
from qwen_asr import Qwen3ASRModel

model = Qwen3ASRModel.from_pretrained(
    "nur-dev/Qwen3-ASR-0.6B-kk-ru-en",
    dtype=torch.bfloat16,
    device_map="cuda:0",
    max_new_tokens=256,          # raise for long audio
)

# audio can be a local path, URL, base64 string, or an (np.ndarray, sample_rate) tuple
results = model.transcribe(
    audio="speech.wav",
    language=None,               # auto-detect (recommended for Kazakh)
)
print(results[0].language, results[0].text)

Language selection. language=None auto-detects and is recommended for Kazakh. For Russian or English you may force the label to skip detection:

# Batch inference; pass one language per clip (or None to auto-detect each)
results = model.transcribe(
    audio=["kk.wav", "ru.wav", "en.wav"],
    language=[None, "Russian", "English"],
)
for r in results:
    print(r.text)

Serve

OpenAI-compatible server (vLLM)

qwen-asr-serve wraps vllm serve and accepts any vllm serve argument:

pip install -U "qwen-asr[vllm]"
qwen-asr-serve nur-dev/Qwen3-ASR-0.6B-kk-ru-en \
    --gpu-memory-utilization 0.8 --host 0.0.0.0 --port 8000

Send requests to the /v1/chat/completions endpoint:

import requests
from qwen_asr import parse_asr_output

data = {"messages": [{"role": "user", "content": [
    {"type": "audio_url", "audio_url": {"url": "https://example.com/speech.wav"}},
]}]}
resp = requests.post("http://localhost:8000/v1/chat/completions", json=data, timeout=300)
content = resp.json()["choices"][0]["message"]["content"]

language, text = parse_asr_output(content)
print(language, text)

vLLM from Python

import torch
from qwen_asr import Qwen3ASRModel

if __name__ == "__main__":            # required by vLLM multiprocessing
    model = Qwen3ASRModel.LLM(
        model="nur-dev/Qwen3-ASR-0.6B-kk-ru-en",
        gpu_memory_utilization=0.7,
        max_new_tokens=256,
    )
    out = model.transcribe(audio="speech.wav", language=None)
    print(out[0].text)

Benchmark

Self-contained WER/CER on the full FLEURS test split for each language. Uses the same Whisper normalization protocol as the reported numbers.

pip install -U qwen-asr datasets jiwer transformers
import re, unicodedata, torch, jiwer
from datasets import load_dataset
from qwen_asr import Qwen3ASRModel
from transformers.models.whisper.english_normalizer import (
    BasicTextNormalizer, EnglishTextNormalizer,
)

basic, english = BasicTextNormalizer(), EnglishTextNormalizer({})
def norm(t, lang):
    t = unicodedata.normalize("NFKC", t or "")
    t = english(t) if lang == "en" else basic(t)
    return re.sub(r"\s+", " ", t).strip()

# FLEURS config name + language to force ("Kazakh" is auto-detected → None)
CFG = {"kk": ("kk_kz", None), "ru": ("ru_ru", "Russian"), "en": ("en_us", "English")}

model = Qwen3ASRModel.from_pretrained(
    "nur-dev/Qwen3-ASR-0.6B-kk-ru-en",
    dtype=torch.bfloat16, device_map="cuda:0", max_new_tokens=256,
)

for lang, (cfg, force) in CFG.items():
    ds = load_dataset("google/fleurs", cfg, split="test")
    refs = [ex["transcription"] for ex in ds]
    auds = [(ex["audio"]["array"].astype("float32"), ex["audio"]["sampling_rate"]) for ex in ds]
    hyps = []
    for i in range(0, len(auds), 32):
        batch = auds[i:i + 32]
        hyps += [o.text for o in model.transcribe(audio=batch, language=[force] * len(batch))]
    R = [norm(r, lang) for r in refs]
    H = [norm(h, lang) for h in hyps]
    pairs = [(r, h) for r, h in zip(R, H) if r]
    R, H = [p[0] for p in pairs], [p[1] for p in pairs]
    print(f"{lang}: WER={100 * jiwer.wer(R, H):.2f}  CER={100 * jiwer.cer(R, H):.2f}  n={len(R)}")

The headline table uses a fixed 500-utterance seeded subset per language; this script runs the full FLEURS test split, so expect results within ~1 WER point.

Acknowledgements

Built on Qwen3-ASR by the Qwen team, and evaluated with FLEURS and the ISSAI Kazakh Speech Corpus 2 (KSC2). Released under Apache-2.0, following the base model's license.

Downloads last month
8
Safetensors
Model size
0.8B params
Tensor type
BF16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for nur-dev/Qwen3-ASR-0.6B-kk-ru-en

Finetuned
(43)
this model

Evaluation results