ECAPA-TDNN Tajik Speaker Embedding (Saidzoda Lab)
How to get access: please fill in the short form at saidzoda.com/access. We approve requests after we receive the form.
Fine-tune of speechbrain/spkrec-ecapa-voxceleb (Apache-2.0) on Tajik speaker classification (AAM-softmax), for sharper Tajik speaker embeddings in the voice-cloning / speaker-verification pipeline than the stock VoxCeleb-trained model.
Result
Equal-error-rate (EER), full-utterance embeddings, L2-normalized, raw cosine similarity
(no mean_var_norm_emb centering — see Methodology below):
| stock ecapa-voxceleb | Tajik fine-tune (this model) | Δ | |
|---|---|---|---|
| closed-set EER | 1.64% | 0.68% | −0.96 pts |
| open-set EER | 1.19% | 0.33% | −0.86 pts |
| open-set verification accuracy @ EER threshold | 98.79% | 99.67% |
Open-set = 10 speakers never seen during training. See results.json in this repo for
full trial counts.
Training
- Trunk: ECAPA-TDNN, kept from
speechbrain/spkrec-ecapa-voxceleb(embedding_model.ckptloaded as-is), fine-tuned. Classifier head: freshly initialized (VoxCeleb's 7205-class head is not reusable), sized to the Tajik train-speaker count. - AAM-softmax: margin=0.2, scale=30.0. epochs=8, batch_size=32, lr=1e-4, 3s random crops.
- Data: 60-narrator premium Tajik diarized speaker bank (44.1/48kHz, resampled to 16kHz on the fly). Speaker labels are ECAPA-clustering pseudo-labels, not human-verified — a known limitation that applies equally to the stock-vs-finetuned comparison above.
- Hardware: 1x H100 (Nvidia Brev).
Files
embedding_model.ckpt— ECAPA-TDNN trunk weights (speechbrain state_dict), best checkpoint by validation accuracy.classifier.ckpt— AAM-softmax classifier head (Tajik train-speaker classes; not needed for embedding extraction, included for completeness/reproducibility).ecapa_common.py— the exact model-construction + feature-pipeline code used to build this architecture (needed because this checkpoint is a raw speechbrain state_dict, not aspeechbrain.pretrainedpackage with its ownhyperparams.yaml).label_map.json— {original pseudo speaker id → contiguous training label} for the classifier head's output space.
How to use
import torch
from huggingface_hub import hf_hub_download
# grab ecapa_common.py from this repo (or copy it locally) for the exact architecture
repo_id = "Tohirju/ecapa-tdnn-tajik"
common_path = hf_hub_download(repo_id, "ecapa_common.py")
ckpt_path = hf_hub_download(repo_id, "embedding_model.ckpt")
import importlib.util
spec = importlib.util.spec_from_file_location("ecapa_common", common_path)
ecapa_common = importlib.util.module_from_spec(spec)
spec.loader.exec_module(ecapa_common)
model = ecapa_common.build_embedding_model(device="cpu")
state_dict = torch.load(ckpt_path, map_location="cpu")
model.load_state_dict(state_dict)
model.eval()
compute_features, mean_var_norm = ecapa_common.build_feature_pipeline(device="cpu")
wav = ecapa_common.load_wav_16k("some_tajik_utterance.wav")
emb = ecapa_common.embed_utterance(wav, compute_features, mean_var_norm, model, device="cpu")
# emb: [192] L2-normalizable speaker embedding
Architecture hyperparameters (input_size=80 mels, channels=[1024,1024,1024,1024,3072],
lin_neurons=192) match speechbrain/spkrec-ecapa-voxceleb's hyperparams.yaml
("ECAPA big") verbatim — only the weights differ.
License
Apache-2.0 (inherited from the speechbrain base model).
Caveats
- Training-speaker labels are unverified pseudo-labels from an ECAPA-clustering diarization pass, not human-annotated ground truth (see Training section).
- Eval methodology deliberately skips speechbrain's
mean_var_norm_embglobal-centering step (would need re-fitting to the fine-tuned embedding distribution); this is applied identically to both the stock and fine-tuned model in the comparison above, so the head-to-head delta is fair, but absolute numbers are not directly comparable to speechbrain's own publishedverify_filespipeline results.
This repo is public but gated (manual approval), per Saidzoda Lab policy.