File size: 1,792 Bytes
245922c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
"""Compare two voices with TitaNet.mlpackage (macOS, Python 3.9+).

    pip install coremltools kaldi-native-fbank soundfile numpy
    python example.py a.wav b.wav

The WAV files must be mono 16 kHz. Prints the cosine similarity of the two
speaker embeddings.
"""

import sys

import coremltools as ct
import kaldi_native_fbank as knf
import numpy as np
import soundfile as sf


def features(samples: np.ndarray) -> np.ndarray:
    """The features sherpa-onnx feeds TitaNet-L, shaped (1, 80, T)."""
    o = knf.FbankOptions()
    o.frame_opts.samp_freq = 16000
    o.frame_opts.frame_length_ms = 25
    o.frame_opts.frame_shift_ms = 10
    o.frame_opts.snip_edges = True
    o.frame_opts.dither = 0
    o.frame_opts.remove_dc_offset = False
    o.frame_opts.preemph_coeff = 0.97
    o.frame_opts.window_type = "hann"
    o.mel_opts.num_bins = 80
    o.mel_opts.low_freq = 0
    o.mel_opts.high_freq = -400  # 7600 Hz
    o.mel_opts.is_librosa = True
    fbank = knf.OnlineFbank(o)
    fbank.accept_waveform(16000, samples.tolist())
    fbank.input_finished()
    f = np.array([fbank.get_frame(i) for i in range(fbank.num_frames_ready)], dtype=np.float32)
    f = (f - f.mean(0)) / (f.std(0) + 1e-5)  # per-bin, population std
    return f.T[None].copy()


def embed(model: ct.models.MLModel, path: str) -> np.ndarray:
    samples, rate = sf.read(path, dtype="float32")
    assert rate == 16000 and samples.ndim == 1, "expected mono 16 kHz audio"
    return model.predict({"features": features(samples)})["embedding"][0]


if __name__ == "__main__":
    model = ct.models.MLModel("TitaNet.mlpackage", compute_units=ct.ComputeUnit.CPU_AND_GPU)
    a, b = embed(model, sys.argv[1]), embed(model, sys.argv[2])
    print(f"cosine similarity: {a @ b / np.linalg.norm(a) / np.linalg.norm(b):.3f}")