Downloads · 30 days
14
22% of all-time downloads
keystats/w2v-bert-2.0-shona
w2v-bert-2.0-shona is a automatic speech recognition model from keystats. Use it when you need speech turned into text. The card lists the license as apache-2.0.
A Shona automatic speech recognition (ASR) model, continued fine-tuning from keystats/w2v-bert-2.0-shona-main-best-3 on the same combined Shona speech corpus (see Training data below).
Downloads · 30 days
14
22% of all-time downloads
All-time downloads
65
Public
Parameters
606M
2.4 GB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors2.4 GB · 100%
From the Hugging Face model README
A Shona automatic speech recognition (ASR) model, continued fine-tuning from keystats/w2v-bert-2.0-shona-main-best-3 on the same combined Shona speech corpus (see Training data below).
This checkpoint is the third link in a fine-tuning chain:
facebook/w2v-bert-2.0 → w2v-bert-2.0-shona-main-best →
w2v-bert-2.0-shona-main-best-3 → this model. Each stage
continues training the previous checkpoint for a further, typically
shorter, run at a progressively lower learning rate on the same data,
rather than starting from scratch.
Text casing note: training targets were kept in their raw, cased form, the same convention used throughout this fine-tuning chain — the vocabulary and outputs preserve casing and punctuation, not lowercased text.
Same training pool and split treatment as every checkpoint in this chain:
| Source | Role |
|---|---|
google/WaxalNLP (sna_asr config) | train split pooled into training; validation split held out untouched as the fixed evaluation benchmark |
| badrex/shona-speech | All splits (train/val/test) pooled into training |
| Beijuka/DigitalUmuganda_AfriVoice_shona | All splits pooled into training (only has train) |
| shunyalabs/shona-speech-dataset | All splits (train/val/test) pooled into training |
| realtime-speech/shona2 | All splits (train/val/test) pooled into training |
None of the four additional sources overlap with WAXAL's own
train/validation/test split boundaries, so pooling every split from
them carries no evaluation leakage risk. WAXAL's validation split
is the only data used for evaluation, and it was never included in
training.
keystats/w2v-bert-2.0-shona-main-best-3
(continued fine-tuning, not trained from scratch)Wav2Vec2BertForCTC, add_adapter=TrueWav2Vec2BertProcessor — SeamlessM4TFeatureExtractor
for audio features + a Wav2Vec2CTCTokenizer built from scratch on
the combined training + validation transcriptions (character-level
vocabulary, raw/cased text, | as the word delimiter, [PAD]
doubling as the CTC blank token)output_steps < 2 * label_length) are dropped from
both train and validation before trainingEvaluated on the WAXAL Shona validation split, greedy decoding vs.
greedy + KenLM (keystats/waxal-kenlm-models-best). Adding the KLM
gives a consistent, meaningful WER/CER improvement over greedy
decoding alone — pair the two for the best results.
Two ways to use this model, depending on your needs:
pyctcdecode +
KenLM, noticeably higher accuracy via beam-search decoding with a
matching language model.import torch
import librosa
from transformers import Wav2Vec2BertForCTC, Wav2Vec2BertProcessor
MODEL_ID = "keystats/w2v-bert-2.0-shona"
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
processor = Wav2Vec2BertProcessor.from_pretrained(MODEL_ID)
model = Wav2Vec2BertForCTC.from_pretrained(MODEL_ID).to(DEVICE).eval()
audio_array, sr = librosa.load("path/to/audio.wav", sr=16000, mono=True)
inputs = processor(audio_array, sampling_rate=16000, return_tensors="pt")
with torch.no_grad():
logits = model(input_features=inputs.input_features.to(DEVICE)).logits
predicted_ids = torch.argmax(logits, dim=-1)
transcription = processor.batch_decode(predicted_ids)[0]
print(transcription) # cased, punctuated Shona text
A companion n-gram KenLM language model, trained on the same
raw/cased text convention as this ASR model, is available at
keystats/waxal-kenlm-models-best
(shona/shona_5gram_correct.arpa). Pairing this ASR model with its
matching KLM via beam-search decoding gives a significant accuracy
improvement over greedy decoding alone.
Important: use the matching KLM variant for whichever ASR
checkpoint you're using — this model pairs with the cased
keystats/waxal-kenlm-models-best repo, while the normalized
(lowercased) keystats/w2v-bert-2.0-shona-main checkpoint pairs with
the separate keystats/waxal-kenlm-models repo instead. Mixing a
cased-text ASR model with a normalized-text KLM (or vice versa) will
cause a vocabulary mismatch during decoding.
# pip install pyctcdecode
# pip install https://github.com/kpu/kenlm/archive/master.zip
import torch
import librosa
from huggingface_hub import hf_hub_download
from transformers import Wav2Vec2BertForCTC, Wav2Vec2BertProcessor
from pyctcdecode import build_ctcdecoder
MODEL_ID = "keystats/w2v-bert-2.0-shona"
KLM_REPO_ID = "keystats/waxal-kenlm-models-best"
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
processor = Wav2Vec2BertProcessor.from_pretrained(MODEL_ID)
model = Wav2Vec2BertForCTC.from_pretrained(MODEL_ID).to(DEVICE).eval()
klm_path = hf_hub_download(repo_id=KLM_REPO_ID, repo_type="dataset",
filename="shona/shona_5gram_correct.arpa")
def build_vocab_list(tokenizer, vocab_size):
vocab_dict = tokenizer.get_vocab()
vocab_list = [None] * vocab_size
for tok, idx in sorted(vocab_dict.items(), key=lambda kv: kv[1]):
if idx < vocab_size:
vocab_list[idx] = tok
pad_id = tokenizer.pad_token_id
if pad_id is not None and pad_id < len(vocab_list):
vocab_list[pad_id] = ""
word_delim = getattr(tokenizer, "word_delimiter_token", None)
if word_delim:
delim_id = vocab_dict.get(word_delim)
if delim_id is not None:
vocab_list[delim_id] = " "
return vocab_list
vocab_list = build_vocab_list(processor.tokenizer, model.config.vocab_size)
decoder = build_ctcdecoder(
vocab_list,
kenlm_model_path=klm_path,
alpha=0.5, # LM weight -- tune against your own validation set
beta=0.7, # word insertion bonus -- tune against your own validation set
)
audio_array, sr = librosa.load("path/to/audio.wav", sr=16000, mono=True)
inputs = processor(audio_array, sampling_rate=16000, return_tensors="pt")
with torch.no_grad():
logits = model(input_features=inputs.input_features.to(DEVICE)).logits
transcription = decoder.decode(logits.cpu().numpy()[0], beam_width=100)
print(transcription)
Note on alpha/beta: the values above are starting points, not universal defaults — grid-search them against your own labeled validation set, since optimal weights depend on your specific audio domain.
-main-best-3, itself a
continued fine-tune of -main-best — treat this as a short,
low-learning-rate refinement pass over an already-trained
checkpoint and the same data, not an independent model. Given the
short 1-epoch continuation, gains over -main-best-3 may be modest;
compare both checkpoints on your own validation set before assuming
this one is strictly better.If you use this model, please cite the training/fine-tuning work and the underlying datasets:
@misc{keystats_wav2vec2bert_shona,
title={w2v-bert-2.0-shona: A Shona ASR model continued fine-tuned from w2v-bert-2.0-shona-main-best-3},
author={keystats},
year={2026},
howpublished={\url{https://huggingface.co/keystats/w2v-bert-2.0-shona}}
}
@misc{waxal,
title={WAXAL: A Multilingual African Speech Dataset},
author={Google},
howpublished={\url{https://huggingface.co/datasets/google/WaxalNLP}}
}
@misc{badrex_shona_speech,
title={shona-speech},
author={badrex},
howpublished={\url{https://huggingface.co/datasets/badrex/shona-speech}}
}
@misc{beijuka_shona,
title={DigitalUmuganda\_AfriVoice\_shona},
author={Beijuka},
howpublished={\url{https://huggingface.co/datasets/Beijuka/DigitalUmuganda_AfriVoice_shona}}
}
@misc{shunyalabs_shona,
title={shona-speech-dataset},
author={shunyalabs},
howpublished={\url{https://huggingface.co/datasets/shunyalabs/shona-speech-dataset}}
}
@misc{realtime_speech_shona,
title={shona2},
author={realtime-speech},
howpublished={\url{https://huggingface.co/datasets/realtime-speech/shona2}}
}
@inproceedings{w2vbert2,
title={Seamless: Multilingual Expressive and Streaming Speech Translation},
author={Seamless Communication and others},
year={2023},
howpublished={\url{https://huggingface.co/facebook/w2v-bert-2.0}}
}