speaker-verification
audio
nemotron
tyger
experimental
tyger-speaker-predictor / code /speaker_v2 /test_predictor.py
ChristophSchuhmann's picture
Publish audited Robby source and completed Nemotron speaker-prediction experiments
b21cfae verified
Raw History Blame Contribute Delete
3.51 kB
"""Fast architecture, streaming-state and verification-protocol checks."""
import tempfile
import unittest
from pathlib import Path
import numpy as np
import torch
from .inference import Predictor
from .models import SpeakerPredictor, parameter_count,load_state
from .train import roc_metrics
class PredictorTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
torch.set_num_threads(2)
def test_architecture_dimensions_and_budget(self):
for arch in ("mlp", "gru", "tcn"):
for width in (96, 192):
model = SpeakerPredictor(arch,width)
self.assertGreaterEqual(parameter_count(model), 100000)
self.assertLessEqual(parameter_count(model), 1000000)
for context in (4,8,12,25):
embedding, activity = model(torch.randn(2,context,1024))
self.assertEqual(tuple(embedding.shape),(2,192))
self.assertEqual(tuple(activity.shape),(2,3))
self.assertTrue(torch.allclose(embedding.norm(dim=-1),torch.ones(2),atol=1e-5))
def test_incremental_silence_and_reset(self):
with tempfile.TemporaryDirectory() as temp:
path = Path(temp)/"test.pt"
model = SpeakerPredictor("gru",96)
with torch.no_grad():
model.activity.weight.zero_()
model.activity.bias.copy_(torch.tensor([10.,-10.,-10.]))
torch.save({"model":model.state_dict(),"config":{"architecture":"gru","width":96,"context":12}},path)
predictor = Predictor(path)
result = predictor.update(np.random.default_rng(1).normal(size=(4,1024)),energy=.1)
self.assertEqual(result["kind"],"speech")
self.assertEqual(result["embedding"].shape,(192,))
self.assertLess(result["confidence"],.34)
result = predictor.update(np.zeros((4,1024)),energy=0.)
self.assertEqual(result["kind"],"silence")
self.assertIsNone(result["embedding"])
result = predictor.update(np.random.default_rng(3).normal(size=(4,1024)),energy=.1)
self.assertLess(result["confidence"],.34) # silence must reset confidence accumulation
predictor.reset()
self.assertEqual(len(predictor.frames),0)
with self.assertRaises(ValueError): predictor.update(np.zeros((4,192)))
def test_validation_threshold_fixed_for_test(self):
val = roc_metrics([.8,.9],[.1,.2,.3])
threshold = val["far05_threshold"]
test = roc_metrics([.25,.95],[.15,.35],threshold)
self.assertEqual(test["threshold"],threshold)
self.assertEqual(test["false_accept_rate"],.5)
self.assertEqual(test["false_reject_rate"],.5)
def test_centered_output_and_original_checkpoint_compatibility(self):
model = SpeakerPredictor("mlp",96,centered=True)
with torch.no_grad():
model.teacher_mean.copy_(torch.randn(192)*.03)
model.teacher_radius.fill_(.8)
embedding,_ = model(torch.randn(2,8,1024))
self.assertTrue(torch.allclose(embedding.norm(dim=-1),torch.ones(2),atol=1e-5))
original = {k:v for k,v in model.state_dict().items() if k not in ("teacher_mean","teacher_radius")}
load_state(SpeakerPredictor("mlp",96),original)
original.pop("embedding.weight")
with self.assertRaises(ValueError):load_state(SpeakerPredictor("mlp",96),original)
if __name__ == "__main__": unittest.main()