Views
No views yet
keystats/kiswahili_sahihi_asr_adapted_1 is a refined Swahili automatic speech recognition (ASR) model optimized for on-device use and low-resource settings.keystats/kiswahili_sahihi_asr51866 tokens2.36M (≈0.31% of total 766M)| Parameter | Value |
|---|---|
| Dataset | Sunbird/salt (studio-swa) |
| Noise Augmentation | Sunbird/urban-noise-uganda-61k |
| Effective Batch Size | 8 (per_device_train_batch_size=4, gradient_accumulation_steps=2) |
| Learning Rate | 1e-5 |
| Warmup Steps | 500 |
| Epochs | 3 |
| Precision | Mixed precision (fp16) |
| Quantization | 8-bit via bitsandbytes |
| Memory Optimization | gradient_checkpointing=True |
1✅ Added <|pad|> token to tokenizer
2✅ Resized embeddings to 51866 tokens
3✅ PEFT + LoRA adapters merged
4✅ Dataset: Train=3,758 | Validation=77
5✅ 1,000 noise clips used for augmentation| Step | Training Loss | Validation Loss | WER (%) | CER (%) |
|---|---|---|---|---|
| 200 | 0.6747 | 0.6675 | 16.23 | 4.82 |
| 400 | 0.5860 | 0.5616 | 15.56 | 4.74 |
| 600 | 0.5368 | 0.4852 | 12.09 | 4.11 |
| 800 | 0.4646 | 0.4447 | 12.58 | 4.23 |
| 1000 | 0.4267 | 0.4154 | 12.42 | 4.23 |
| 1200 | 0.4279 | 0.3949 | 11.42 | 4.03 |
| 1400 | 0.3965 | 0.3902 | 11.59 | 4.11 |
1# ============================================
2# 🪄 Full Swahili ASR Transcription with Adapted Model
3# ============================================
4# 📦 Installation
5!pip install -q transformers "datasets<4.0.0"
6!pip install -q torchaudio==2.6.0 torchvision==0.21.0 jiwer evaluate
7!pip install -q soundfile librosa accelerate>=0.26.0 tensorboard bitsandbytes
8!pip install -q pydub
9!apt-get -y install ffmpeg
10
11# ============================================
12# 1️⃣ Imports
13# ============================================
14import torch
15import librosa
16import numpy as np
17from pydub import AudioSegment
18from transformers import WhisperProcessor, WhisperForConditionalGeneration
19from peft import PeftModel, PeftConfig
20import imageio_ffmpeg as ffmpeg_lib
21import os
22
23# ============================================
24# 2️⃣ Register ffmpeg for pydub (no sudo)
25# ============================================
26from pydub.utils import which
27
28ffmpeg_path = ffmpeg_lib.get_ffmpeg_exe()
29AudioSegment.converter = ffmpeg_path
30AudioSegment.ffmpeg = ffmpeg_path
31AudioSegment.ffprobe = ffmpeg_path
32
33print("✅ ffmpeg and ffprobe linked successfully!")
34
35# ============================================
36# 3️⃣ Load Adapted Model (with vocab fix)
37# ============================================
38base_model_id = "keystats/kiswahili_sahihi_asr"
39adapter_model_path = "keystats/kiswahili_sahihi_asr_adapted_1"
40
41print(f"🔹 Loading processor from: {adapter_model_path}")
42processor = WhisperProcessor.from_pretrained(adapter_model_path)
43vocab_size = len(processor.tokenizer)
44print(f"🔹 Tokenizer vocab size: {vocab_size}")
45
46# Load PEFT config
47peft_config = PeftConfig.from_pretrained(adapter_model_path)
48print(f"🔹 PEFT base model: {peft_config.base_model_name_or_path}")
49
50# Load base Whisper model
51base_model = WhisperForConditionalGeneration.from_pretrained(
52 peft_config.base_model_name_or_path,
53 ignore_mismatched_sizes=True,
54)
55
56# Fix vocab size mismatch
57base_model.resize_token_embeddings(vocab_size)
58print(f"✅ Resized token embeddings to match vocab size ({vocab_size})")
59
60# Load and merge adapter
61model = PeftModel.from_pretrained(base_model, adapter_model_path)
62print("✅ Adapter loaded successfully")
63
64model = model.merge_and_unload()
65print("✅ Adapter merged and unloaded")
66
67# Move to device
68device = "cuda" if torch.cuda.is_available() else "cpu"
69model = model.to(device, dtype=torch.float32)
70model.eval()
71print(f"🚀 Model ready on {device.upper()}")
72
73# ============================================
74# 4️⃣ Convert Any Format to WAV
75# ============================================
76def convert_to_wav(input_path, output_path="converted.wav"):
77 """Convert MP3, M4A, or any audio file to mono 16kHz WAV."""
78 try:
79 audio = AudioSegment.from_file(input_path)
80 audio = audio.set_frame_rate(16000).set_channels(1)
81 audio.export(output_path, format="wav")
82 return output_path
83 except Exception as e:
84 raise RuntimeError(f"❌ Could not convert file. Error: {e}")
85
86# 🎧 Replace this with your Swahili audio file
87audio_path = "Your audio here"
88wav_path = convert_to_wav(audio_path)
89print(f"✅ Converted to: {wav_path}")
90
91# ============================================
92# 5️⃣ Load Audio and Chunk
93# ============================================
94audio_input, sr = librosa.load(wav_path, sr=16000, mono=True)
95chunk_length_s = 60 # seconds
96chunk_size = chunk_length_s * sr
97num_chunks = int(np.ceil(len(audio_input) / chunk_size))
98print(f"🔹 Total length: {len(audio_input)/sr:.2f}s | Splitting into {num_chunks} chunks...")
99
100# ============================================
101# 6️⃣ Transcribe (without forced_decoder_ids)
102# ============================================
103full_transcription = []
104
105# Add language token manually for safety
106lang_token = processor.tokenizer.convert_tokens_to_ids("<|swahili|>")
107task_token = processor.tokenizer.convert_tokens_to_ids("<|transcribe|>")
108start_tokens = torch.tensor([[lang_token, task_token]], device=device)
109
110for i in range(num_chunks):
111 start = i * chunk_size
112 end = min((i + 1) * chunk_size, len(audio_input))
113 chunk = audio_input[start:end]
114
115 inputs = processor(
116 chunk,
117 sampling_rate=16000,
118 return_tensors="pt",
119 return_attention_mask=True,
120 ).to(device, dtype=torch.float32)
121
122 with torch.no_grad():
123 generated_ids = model.generate(
124 **inputs,
125 max_new_tokens=256,
126 num_beams=2,
127 repetition_penalty=1.1,
128 )
129
130 text = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
131 full_transcription.append(text.strip())
132
133 print(f"🟢 Chunk {i+1}/{num_chunks} done")
134
135
136# ============================================
137# 7️⃣ Combine Final Transcript
138# ============================================
139final_text = " ".join(full_transcription)
140print("\n📝 Final Transcription:\n")
141print(final_text)
142