Downloads · 30 days
41
31% of all-time downloads
keystats/w2v-bert-2.0-lingala-main-best-last-hope
w2v-bert-2.0-lingala-main-best-last-hope 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 Lingala automatic speech recognition (ASR) model, fine-tuned from facebook/w2v-bert-2.0.
Downloads · 30 days
41
31% of all-time downloads
All-time downloads
133
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 Lingala automatic speech recognition (ASR) model, fine-tuned from facebook/w2v-bert-2.0.
This checkpoint follows the exact same training recipe as keystats/w2v-bert-2.0-lingala-main-best, with a single difference: an additional audio duration filter was applied before training, removing clips shorter than 5 seconds and longer than 30 seconds.
facebook/w2v-bert-2.0 — a large-scale, multilingual self-supervised
speech encoder pretrained with a BERT-style masked prediction
objective — is used as the backbone, with a from-scratch
character-level CTC (Connectionist Temporal Classification) head
fine-tuned specifically for Lingala.
Text casing note: training targets were kept in their raw, cased
form — same convention as main-best.
Duration filtering note (what differs from main-best): clips
with duration below 5 seconds or above 30 seconds were dropped from
the training pool prior to fine-tuning, in the hope of reducing the
influence of very short, low-context clips and very long clips that
disproportionately stress CTC alignment and batching.
| Source | Role |
|---|---|
google/WaxalNLP (lin_asr config) | train split pooled into training, validation split held out untouched as the fixed evaluation benchmark |
| KasuleTrevor/Lingala_100hrs | All splits pooled into training |
Deduplicated by audio hash and transcription-within-source, then
filtered to keep only clips with duration in the 5–30 second range.
WAXAL's validation split is the only data used for evaluation,
and it was never included in training.
facebook/w2v-bert-2.0Wav2Vec2BertForCTC, add_adapter=Truemain-best
(character-level, raw/cased text, | word delimiter, [PAD] as
CTC blank)Evaluated on the WAXAL Lingala validation split (unfiltered — the
duration filter was applied only to training data), 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.
import torch
import librosa
from transformers import Wav2Vec2BertForCTC, Wav2Vec2BertProcessor
MODEL_ID = "keystats/w2v-bert-2.0-lingala-main-best-last-hope"
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 Lingala text
# 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-lingala-main-best-last-hope"
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="lingala/lingala_5gram_correct-best.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,
beta=0.7,
)
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)
main-best
pool; performance on utterances outside that duration range (e.g.
very short commands or long continuous recordings) is untested and
may differ from main-best.@misc{keystats_wav2vec2bert_lingala_lasthope,
title={w2v-bert-2.0-lingala-main-best-last-hope: A Lingala ASR model fine-tuned from facebook/w2v-bert-2.0 on duration-filtered (5-30s) data},
author={keystats},
year={2026},
howpublished={\url{https://huggingface.co/keystats/w2v-bert-2.0-lingala-main-best-last-hope}}
}
@misc{waxal,
title={WAXAL: A Multilingual African Speech Dataset},
author={Google},
howpublished={\url{https://huggingface.co/datasets/google/WaxalNLP}}
}
@misc{kasule_lingala_100hrs,
title={Lingala\_100hrs},
author={KasuleTrevor},
howpublished={\url{https://huggingface.co/datasets/KasuleTrevor/Lingala_100hrs}}
}
@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}}
}