Skip to content
Snippets Groups Projects
Commit 44c8b41e authored by Yannick DAYER's avatar Yannick DAYER
Browse files

Adding IVector high level methods

parent a736f9db
No related branches found
No related tags found
1 merge request!60Port of I-Vector to python
......@@ -2,15 +2,16 @@
# @author: Yannick Dayer <yannick.dayer@idiap.ch>
# @date: Fri 06 May 2022 14:18:25 UTC+02
import copy
import logging
from typing import List, Tuple
from typing import Any, Dict, List, Tuple
import numpy as np
from sklearn.base import BaseEstimator
from bob.learn.em import GMMMachine, GMMStats
from bob.learn.em import GMMMachine, GMMStats, linear_scoring
logger = logging.getLogger("__name__")
......@@ -93,7 +94,7 @@ def compute_tct_sigmac_inv(T: np.ndarray, sigma: np.ndarray) -> np.ndarray:
# Vectorized version:
# T.T (c,t,d) / sigma (c,1,d)
# TT_sigma_inv (c,t,d) = T.T (c,t,d) / sigma (c,1,d)
Tct_sigmacInv = T.transpose(0, 2, 1) / sigma[:, None, :]
# Tt_sigma_inv (c,t,d)
......@@ -244,8 +245,10 @@ class IVectorMachine(BaseEstimator):
self.dim_c = self.ubm.n_gaussians
self.dim_d = self.ubm.means.shape[-1]
self.T = np.zeros(shape=(self.dim_c, self.dim_d, self.dim_t))
self.sigma = np.zeros(shape=(self.dim_c, self.dim_d))
self.T = np.zeros(
shape=(self.dim_c, self.dim_d, self.dim_t)
) # TODO random ?
self.sigma = copy.deepcopy(self.ubm.variances)
def e_step(self, data: List[GMMStats]) -> IVectorStats:
"""Computes the expectation step of the e-m algorithm."""
......@@ -391,4 +394,52 @@ class IVectorMachine(BaseEstimator):
return self
def project(self, stats: GMMStats) -> IVectorStats:
if not isinstance(stats, GMMStats):
return [self.project(s) for s in stats] # TODO yes?
return forward(self.ubm.means, stats, self.T, self.sigma)
def transform(self, data: np.ndarray) -> List[IVectorStats]:
"""Transforms the data using the trained IVectorMachine.
Parameters
----------
data : np.ndarray
The data to transform.
Returns
-------
np.ndarray
The transformed data.
"""
stats = self.project(self.ubm.acc_stats(data))
return stats.t
def enroll(self, stats: List[GMMStats]) -> IVectorStats:
"""Enrolls a new speaker.
Parameters
----------
stats : List[GMMStats]
The GMM statistics of the speaker to enroll.
Returns
-------
IVectorStats
The IVector statistics of the speaker.
"""
return self.project(stats)
def score(self, model: IVectorStats, probes: List[GMMStats]) -> List[float]:
return linear_scoring(
model,
ubm=self.ubm,
test_stats=probes,
test_channel_offsets=0,
frame_length_normalization=True,
)
def _more_tags(self) -> Dict[str, Any]:
return {
"requires_fit": True,
"bob_fit_supports_dask_arrays": True,
}
......@@ -7,12 +7,27 @@ import numpy as np
from bob.learn.em import GMMMachine, GMMStats, IVectorMachine
def test_ivector_machine_base():
dim_c, dim_d, dim_t = 2, 3, 4
# Create the UBM and set its values manually
ubm = GMMMachine(n_gaussians=dim_c)
ubm.weights = np.array([0.4, 0.6], dtype=float)
ubm.means = np.array([[1, 7, 4], [4, 5, 3]], dtype=float)
ubm.variances = np.array([[0.5, 1.0, 1.5], [1.0, 1.5, 2.0]], dtype=float)
machine = IVectorMachine(ubm=ubm, dim_t=dim_t)
assert hasattr(machine, "ubm")
assert hasattr(machine, "T")
assert hasattr(machine, "sigma")
assert machine.T.shape == (dim_c, dim_d, dim_t), machine.T.shape
assert machine.sigma.shape == (dim_c, dim_d), machine.sigma.shape
np.testing.assert_equal(machine.sigma, ubm.variances)
def test_ivector_machine_projection():
# Preset IVector Machine parameters
t = np.array(
[[1, 2], [4, 1], [0, 3], [5, 8], [7, 10], [11, 1]], dtype=float
)
sigma = np.array([1, 2, 1, 3, 2, 4], dtype=float)
# Create the UBM and set its values manually
ubm = GMMMachine(n_gaussians=2)
......@@ -20,24 +35,82 @@ def test_ivector_machine_projection():
ubm.means = np.array([[1, 7, 4], [4, 5, 3]], dtype=float)
ubm.variances = np.array([[0.5, 1.0, 1.5], [1.0, 1.5, 2.0]], dtype=float)
# Manually create a feature projected on the UBM
machine = IVectorMachine(ubm=ubm, dim_t=2)
machine.T = np.array(
[[[1, 2], [4, 1], [0, 3]], [[5, 8], [7, 10], [11, 1]]], dtype=float
)
machine.sigma = np.array([[1, 2, 1], [3, 2, 4]], dtype=float)
# Manually create a feature (usually projected with the UBM)
gmm_projection = GMMStats(ubm.n_gaussians, ubm.means.shape[-1])
gmm_projection.t = 1
gmm_projection.n = np.array([0.4, 0.6], dtype=float)
gmm_projection.sum_px = np.array([[1, 2, 3], [2, 4, 3]], dtype=float)
gmm_projection.sum_pxx = np.array([[10, 20, 30], [40, 50, 60]], dtype=float)
machine = IVectorMachine(ubm=ubm, dim_t=2)
machine.t = t
machine.sigma = sigma
# Reference from C++ implementation
ivector_projection_ref = np.array([-0.04213415, 0.21463343])
ivector_projection = machine.project(gmm_projection)
np.testing.assert_almost_equal(
ivector_projection_ref, ivector_projection, decimal=5
ivector_projection_ref, ivector_projection, decimal=7
)
def test_ivector_machine_transformer():
ubm = GMMMachine(n_gaussians=2)
ubm.means = np.array([[1, 7, 4], [4, 5, 3]], dtype=float)
ubm.variances = np.array([[0.5, 1.0, 1.5], [1.0, 1.5, 2.0]], dtype=float)
machine = IVectorMachine(ubm=ubm, dim_t=2)
assert hasattr(machine, "fit")
assert hasattr(machine, "transform")
assert hasattr(machine, "enroll")
assert hasattr(machine, "score")
transformed = machine.transform([np.ndarray([1, 2, 3])])[0]
assert isinstance(transformed, IVectorMachine)
nij_sigma_wij2_ref = np.array([[0.5, 1.0, 1.5], [1.0, 1.5, 2.0]]) # TODO
nij_ref = np.array([[1, 2, 3], [4, 5, 6]])
fnorm_sigma_wij_ref = np.array([[0.5, 1.0, 1.5], [1.0, 1.5, 2.0]]) # TODO
snormij_ref = np.array([[1, 2, 3], [4, 5, 6]])
np.testing.assert_almost_equal(
transformed.acc_nij_sigma_wij2, nij_sigma_wij2_ref
)
np.testing.assert_almost_equal(transformed.acc_nij, nij_ref)
np.testing.assert_almost_equal(
transformed.acc_fnorm_sigma_wij, fnorm_sigma_wij_ref
)
np.testing.assert_almost_equal(transformed.acc_snormij, snormij_ref)
def test_ivector_machine_training():
assert False, "Not implemented"
# Define GMMStats
gs1 = GMMStats(n_gaussians=2, n_features=3)
gs1.log_likelihood = -3
gs1.t = 1
gs1.n = np.array([0.4, 0.6], dtype=float)
gs1.sum_px = np.array([[1.0, 2.0, 3.0], [2.0, 4.0, 3.0]], dtype=float)
gs1.sum_pxx = np.array(
[[10.0, 20.0, 30.0], [40.0, 50.0, 60.0]], dtype=float
)
gs2 = GMMStats(n_gaussians=2, n_features=3)
gs2.log_likelihood = -4
gs2.t = 1
gs2.n = np.array([0.2, 0.8], dtype=float)
gs2.sum_px = np.array([[2.0, 1.0, 3.0], [3.0, 4.1, 3.2]], dtype=float)
gs2.sum_pxx = np.array(
[[12.0, 15.0, 25.0], [39.0, 51.0, 62.0]], dtype=float
)
data = [gs1, gs2]
# Define the ubm
ubm = GMMMachine(n_gaussians=3)
ubm.means = np.array([[1, 2, 3], [6, 7, 8], [10, 11, 12]])
ubm.variances = np.ones((3, 3))
machine = IVectorMachine(ubm=ubm, dim_t=2)
machine.fit(data)
assert False, "TODO: add tests (with projection)"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment