Views
No views yet
1import torch
2from qwen_asr import Qwen3ASRModel # pip install qwen-asr || more info https://huggingface.co/Qwen/Qwen3-ASR-1.7B#environment-setup
3
4# Clone the repo,
5model = Qwen3ASRModel.from_pretrained(
6 "./qwen3-asr-sorani-kurdish-ckb-v1",
7 dtype=torch.bfloat16,
8 device_map="cuda:0",
9)
10
11# Audio file
12results = model.transcribe(
13 audio="./demo_04.wav",
14)
15
16print("🎤 Qwen3-ASR Output:")
17print("="*40)
18print(results[0].text)
19print("="*40)1import torch
2import librosa
3from qwen_asr import Qwen3ASRModel
4
5# Define paths
6model_path = "./qwen3-asr-sorani-kurdish-ckb-v1"
7audio_path = "./demo_04.wav"
8system_prompt = """You are an expert Sorani Kurdish (ckb) transcriptionist.
9Transcribe the audio into Sorani Kurdish with perfect orthography.
10IMPORTANT: The speaker may use loanwords in Persian or Arabic. if you recognize any,
11please transcribe them in their standard writing form."""
12
13print("🔄 Loading model and processor...")
14# Load the model wrapper in bfloat16
15asr_wrapper = Qwen3ASRModel.from_pretrained(
16 model_path,
17 dtype=torch.bfloat16,
18 device_map="cuda:0",
19)
20model = asr_wrapper.model
21processor = asr_wrapper.processor
22
23print("🎵 Loading audio...")
24# Load and resample audio to 16kHz (matches training)
25audio_array, sr = librosa.load(audio_path, sr=16000)
26
27print("⚙️ Processing inputs...")
28# 4. Build the exact same message structure used in training
29messages = [
30 {"role": "system", "content": system_prompt},
31 {"role": "user", "content": [{"type": "audio", "audio": audio_array}]},
32]
33
34# Apply chat template
35text = processor.apply_chat_template([messages], add_generation_prompt=True, tokenize=False)[0]
36
37# Process text and audio into model inputs
38inputs = processor(text=text, audio=audio_array, return_tensors="pt").to("cuda:0")
39
40# CRITICAL FIX: Cast all floating-point tensors to bfloat16 to match the model
41for k, v in inputs.items():
42 if torch.is_tensor(v) and v.is_floating_point():
43 inputs[k] = v.to(torch.bfloat16)
44
45print("🚀 Generating transcription...")
46# Generate
47with torch.no_grad():
48 # Record the length of the input prompt so we only decode the NEW tokens
49 input_len = inputs["input_ids"].shape[1]
50
51 # Run generation
52 output = model.generate(
53 **inputs,
54 max_new_tokens=256,
55 num_beams=5,
56 do_sample=False,
57 pad_token_id=processor.tokenizer.pad_token_id,
58 eos_token_id=processor.tokenizer.eos_token_id,
59 length_penalty=0.8,
60 )
61
62
63 if isinstance(output, tuple):
64 generated_ids = output[0]
65 elif hasattr(output, 'sequences'):
66 generated_ids = output.sequences
67 else:
68 generated_ids = output
69
70 # Slice off the prompt tokens and decode only the generated text
71 generated_ids = generated_ids[:, input_len:]
72 result_text = processor.tokenizer.decode(generated_ids[0], skip_special_tokens=True).strip()
73
74def normalize_dialect_to_academic(text: str) -> str:
75 """
76 Maps known dialectal mishearings or hallucinations to standard Academic Sorani Kurdish.
77 This is highly efficient and preserves the model's perfect grammar.
78 """
79 # Example dictionary of dialectal words or What the model incorrectly hears and replace with preferred word
80 dialect_map = {
81 "سیپاڵەک": "فێستیڤاڵ",
82 "تیشکی یەکەس": "تیشکی ئێکس",
83 "جۆستا": "جەستە",
84 "نۆزاکەسی": "نۆزدەکەس",
85 "تەمکەر": "تەنکەر",
86 }
87
88 # Sort keys by length (descending) to replace longer phrases first
89 for wrong, correct in sorted(dialect_map.items(), key=lambda x: len(x[0]), reverse=True):
90 text = text.replace(wrong, correct)
91
92 return text
93
94
95# Apply the normalization
96final_text = normalize_dialect_to_academic(result_text)
97
98print("\n🎤 Qwen3-ASR Output (Raw):")
99print(result_text)
100print("=" * 60)
101print("\n✅ Normalized Academic Kurdish:")
102print(final_text)
103print("=" * 60)
104
105