Pi-Indic-Speaker-Embed-v1

A 512-dimensional speaker embedding model optimized for Indic languages (Hindi, Bengali, Marathi, Telugu, and 8 more). Built on top of WavLM Large + ECAPA-TDNN with LoRA fine-tuning, designed for cross-lingual voice cloning and speaker verification tasks.

Model Description

Component Details
Frontend WavLM Large (frozen base, 315M params) + LoRA adapters on layers 9–24
LoRA scheme Layers 9–16: rank 8; Layers 17–24: rank 16; on all 6 projections (q, k, v, out, FFN up, FFN down)
Encoder ECAPA-TDNN (3 Res2Net blocks, model_scale=8, ndim=1024, output=1536)
Pooling Channel-Attention Statistics Pooling (β†’ 3072-dim)
Projector RawNet3 (BatchNorm + Linear β†’ 512-dim)
Embedding dim 512 (L2-normalized)
Total trainable params ~24M (LoRA 3.5M + ECAPA 18M + Pooling 0.8M + Projector 1.6M)
Checkpoint size 96 MB (WavLM base downloaded separately from microsoft/wavlm-large)

Training Details

  • Warm-started from espnet/voxcelebs12_ecapa_wavlm_joint (8th epoch)
  • Training data: Kathbath (12 Indic languages, 960 speakers) + VoxCeleb1 (full) + VoxCeleb2 (~2k sampled)
  • Loss: AAM-Softmax with sub-centers (K=3, k_top=5, margin=0.2, scale=30) β€” discarded after training
  • Optimizer: Adam (lr=1e-4, weight_decay=1e-5), ExponentialLR (gamma=0.87055)
  • Training: 30 real epochs (150 mini-epochs), early stopped at epoch 29 (best at epoch 3)
  • Checkpoint: Average of top-5 epochs by validation EER (epochs 3, 5, 6, 14, 20)

Performance

Evaluation Set EER minDCF Description
Kathbath Validation (seen conditions, unseen speakers) 1.586% 0.0640 79 speakers, 4 Indic languages
IndicVoices-R Test (unseen conditions, unseen speakers) 4.003% 0.1699 64 speakers, 4 Indic languages
SOTA baseline (voxcelebs12, VoxCeleb-trained) 3.999% / 5.161% 0.1741 / 0.2248 Same eval sets for comparison

The averaged checkpoint (valid.eer.ave_5best.pth) consistently outperforms single-epoch checkpoints on unseen data, confirming that weight averaging reduces overfitting.

Installation

pip install espnet s3prl transformers torch soundfile librosa numpy huggingface_hub

Quick Start

Python API

from inference import PiIndicSpeakerEmbed

# Downloads model files from HuggingFace automatically
model = PiIndicSpeakerEmbed.from_pretrained("Paytmlabs/Pi-indic-speaker-embed-v1")

# Extract a single embedding
embedding = model.extract("audio.wav")
print(embedding.shape)  # β†’ (512,)

# Extract embeddings for multiple files
embeddings = model.extract_batch(["speaker1.wav", "speaker2.wav", "speaker3.wav"])
print(embeddings.shape)  # β†’ (3, 512)

Command Line

# Single file
python inference.py --audio audio.wav

# Multiple files, save to .npy
python inference.py --audio spk1.wav spk2.wav spk3.wav --output embeddings.npy

Speaker Verification (cosine similarity)

from inference import PiIndicSpeakerEmbed
import numpy as np

model = PiIndicSpeakerEmbed.from_pretrained("Paytmlabs/Pi-indic-speaker-embed-v1")

emb1 = model.extract("speaker_a_utt1.wav")
emb2 = model.extract("speaker_a_utt2.wav")
emb3 = model.extract("speaker_b_utt1.wav")

# Cosine similarity (higher = more similar)
sim_same = np.dot(emb1, emb2)    # same speaker, different utterance
sim_diff = np.dot(emb1, emb3)    # different speakers

print(f"Same speaker similarity:  {sim_same:.4f}")
print(f"Diff speaker similarity:  {sim_diff:.4f}")
# Same speaker similarity:  0.85+ (typically)
# Diff speaker similarity:  0.40-0.60 (typically)

How It Works

Raw audio (16kHz)
  β†’ 3 random crops Γ— 96,000 samples (6s each)          [Preprocessor]
  β†’ WavLM Large (frozen) + LoRA (layers 9-24)          [Frontend]
      β†’ 1024-dim frame features @ 50Hz                [multilayer weighted sum]
  β†’ utterance mean normalization                       [utterance_mvn]
  β†’ ECAPA-TDNN (Conv1d + 3 Res2Net blocks)             [Encoder]
      β†’ 1536-dim frame-level embeddings
  β†’ Channel-Attention Statistics Pooling              [Pooling]
      β†’ 3072-dim utterance embedding (weighted mean βŠ• weighted std)
  β†’ RawNet3 Projector (BatchNorm + Linear)            [Projector]
      β†’ 512-dim speaker embedding
  β†’ L2 normalize                                       [Inference]
      β†’ 512-dim unit vector on hypersphere

The AAM-Softmax classifier (used during training) is discarded after training. At inference, only the encoder + pooling + projector are used to produce embeddings. This means the model can verify any speaker, including those never seen during training.

Files

File Description
valid.eer.ave_5best_stripped.pth Stripped checkpoint (LoRA + ECAPA + pooling + projector, 96 MB)
config.yaml Model architecture configuration
inference.py Self-contained inference script
lora_s3prl_frontend.py Custom WavLM + LoRA frontend
lora_wavlm.py LoRA injection utilities
spk_preprocessor_lora.py Custom preprocessor

Citation

If you use this model, please cite:

@misc{pi-indic-speaker-embed-v1,
  title={Pi-Indic-Speaker-Embed-v1: A 512-dim Speaker Embedding Model for Indic Languages},
  author={Paytmlabs},
  year={2026},
  url={https://huggingface.co/Paytmlabs/Pi-indic-speaker-embed-v1}
}

License

MIT License. The WavLM Large base model follows its own license (microsoft/wavlm-large).

Downloads last month
46
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support