Curry / inference.py
massabaali's picture
Curry W2V-BERT 2.0 MFA speaker embedding model (VoxCeleb1-O EER 0.38%)
65c8a73 verified
Raw History Blame Contribute Delete
2.86 kB
"""
Curry speaker verification: pair scoring and VoxCeleb1-O evaluation.
python inference.py a.wav b.wav # cosine score for one pair
python inference.py --trials veri_test.txt --root /path/to/VoxCeleb1/wav/ # EER / minDCF
python inference.py --repo /local/dir ... # use a local copy instead of the Hub
"""
import argparse
import numpy as np
import torch
from tqdm import tqdm
from scipy.interpolate import interp1d
from scipy.optimize import brentq
from sklearn.metrics import roc_curve
from transformers import AutoModel
REPO = "cmu-mlsp/Curry"
def compute_eer(labels, scores):
fpr, tpr, thr = roc_curve(labels, scores, pos_label=1)
eer = brentq(lambda x: 1.0 - x - interp1d(fpr, tpr)(x), 0.0, 1.0)
return eer, float(interp1d(fpr, thr)(eer))
def compute_min_dcf(labels, scores, p_target=0.01, c_miss=1, c_fa=1):
fpr, tpr, thr = roc_curve(labels, scores, pos_label=1)
fnr = 1.0 - tpr
c_det = c_miss * fnr * p_target + c_fa * fpr * (1 - p_target)
i = int(np.argmin(c_det))
return c_det[i] / min(c_miss * p_target, c_fa * (1 - p_target)), thr[i]
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--repo", default=REPO, help="Hub repo id or local directory")
ap.add_argument("--trials", help="trial file: label enroll_path test_path")
ap.add_argument("--root", default="", help="prefix prepended to trial paths")
ap.add_argument("--no-mean-norm", action="store_true", help="disable eval-set embedding mean subtraction")
ap.add_argument("wavs", nargs="*")
args = ap.parse_args()
device = "cuda" if torch.cuda.is_available() else "cpu"
model = AutoModel.from_pretrained(args.repo, trust_remote_code=True).eval().to(device)
if args.trials:
trials = np.loadtxt(args.trials, str)
paths = sorted(set(trials[:, 1]) | set(trials[:, 2]))
embs = {p: model.embed_file(args.root + p).cpu().numpy() for p in tqdm(paths, desc="embedding")}
if not args.no_mean_norm:
mu = np.mean(list(embs.values()), axis=0)
embs = {k: v - mu for k, v in embs.items()}
labels, scores = [], []
for lab, a, b in trials:
ea, eb = embs[a], embs[b]
scores.append(float(ea @ eb / (np.linalg.norm(ea) * np.linalg.norm(eb))))
labels.append(int(lab))
eer, thr = compute_eer(labels, scores)
print(f"cosine EER: {eer*100:.2f}% (threshold {thr:.3f})")
for p in (0.01, 0.001):
dcf, _ = compute_min_dcf(labels, scores, p_target=p)
print(f"minDCF(p={p}): {dcf:.4f}")
elif len(args.wavs) == 2:
print(f"cosine similarity: {model.verify(*args.wavs):.4f}")
else:
for w in args.wavs:
print(w, tuple(model.embed_file(w).shape))
if __name__ == "__main__":
main()