예제 #1
0
def gaussian_backend_test(test_ss, params, diag=False, compute_llr=True):
    """
    Process data through a Gaussian-Backend which parameters (mean and variance)
    have been estimated using Gaussian_Backend_Train.
    
    If compute_llr is set to true, return the log-likelihood ratio, if not,
    return rthe log-likelihood on each Gaussian distrbution. Default is True.
    
    :param test_ss: a StatServer which stat1 are vectors to classify
    :param params: Gaussian Backend parameters, a tupple of mean, covariance
        and constante computed with Gaussian_Backend_Train
    :param diag: boolean, if true: use the diagonal version of the covariance
        matrix, if not the full version
    :param compute_llr: boolean, if true, return the log-likelihood ratio, if not,
    return rthe log-likelihood on each Gaussian distrbution.
    """
    gb_mean, gb_sigma, gb_cst = params

    scores = Scores()
    scores.modelset = gb_mean.modelset
    scores.segset = test_ss.segset
    scores.scoremat = numpy.ones(
        (gb_mean.modelset.shape[0], test_ss.segset.shape[0]))
    scores.scoremask = numpy.ones(scores.scoremat.shape, dtype='bool')

    if diag:
        gb_gmm = Mixture()
        gb_gmm.w = numpy.ones(gb_mean.modelset.shape[0],
                              dtype='float') / gb_mean.modelset.shape[0]
        gb_gmm.mu = gb_mean.stat1
        if gb_sigma.ndim == 2:
            gb_gmm.invcov = numpy.tile(1 / numpy.diag(gb_sigma),
                                       (gb_mean.modelset.shape[0], 1))
        elif gb_sigma.ndim == 2:
            gb_gmm.invcov = numpy.tile(1. / gb_sigma,
                                       (gb_mean.modelset.shape[0], 1))
        gb_gmm._compute_all()

        scores.scoremat = gb_gmm.compute_log_posterior_probabilities(
            test_ss.stat1).T

    else:
        assert gb_sigma.ndim == 2
        scores.scoremat *= gb_cst

        inv_sigma = numpy.linalg.inv(gb_sigma)

        # Compute scores for all trials per language
        for lang in range(gb_mean.modelset.shape[0]):
            scores.scoremat[lang, :] -= 0.5 * (gb_mean.stat1[lang, :].dot(
                inv_sigma).dot(gb_mean.stat1[lang, :].T) - 2 * numpy.sum(
                    test_ss.stat1.dot(inv_sigma) * gb_mean.stat1[lang, :],
                    axis=1) + numpy.sum(
                        test_ss.stat1.dot(inv_sigma) * test_ss.stat1, axis=1))

    if compute_llr:
        scores.scoremat = compute_log_likelihood_ratio(scores.scoremat)

    assert scores.validate()
    return scores
예제 #2
0
 def score_plda(self, model_iv):
     try:
         distance = model_iv.score_plda_slow()
         distance.write(self.score_fn)
         scores = Scores(scores_file_name=self.score_fn)
         return scores
     except Exception as e:
         traceback.print_exc()
예제 #3
0
def two_covariance_scoring(enroll, test, ndx, W, B, check_missing=True):
    """Compute the 2-covariance scores between to sets of vectors. The list of 
    trials to perform is given in an Ndx object. Within and between class 
    co-variance matrices have to be pre-computed.
    
    :param enroll: a StatServer in which stat1 are i-vectors
    :param test: a StatServer in which stat1 are i-vectors
    :param ndx: an Ndx object defining the list of trials to perform
    :param W: the within-class co-variance matrix to consider
    :param B: the between-class co-variance matrix to consider
    :param check_missing: boolean, default is True, set to False not to check missing models
      
    :return: a score object
    """
    assert isinstance(enroll,
                      StatServer), 'First parameter should be a directory'
    assert isinstance(test,
                      StatServer), 'Second parameter should be a StatServer'
    assert isinstance(ndx, Ndx), 'Third parameter should be an Ndx'
    assert enroll.stat1.shape[1] == test.stat1.shape[
        1], 'I-vectors dimension mismatch'
    assert enroll.stat1.shape[1] == W.shape[
        0], 'I-vectors and co-variance matrix dimension mismatch'
    assert enroll.stat1.shape[1] == B.shape[
        0], 'I-vectors and co-variance matrix dimension mismatch'

    # If models are not unique, compute the mean per model, display a warning
    if not numpy.unique(enroll.modelset).shape == enroll.modelset.shape:
        logging.warning("Enrollment models are not unique, average i-vectors")
        enroll = enroll.mean_stat_per_model()

    # Remove missing models and test segments
    if check_missing:
        clean_ndx = _check_missing_model(enroll, test, ndx)
    else:
        clean_ndx = ndx

    # Two covariance scoring scoring
    S = numpy.zeros((enroll.modelset.shape[0], test.segset.shape[0]))
    iW = scipy.linalg.inv(W)
    iB = scipy.linalg.inv(B)

    G = reduce(numpy.dot, [iW, scipy.linalg.inv(iB + 2 * iW), iW])
    H = reduce(numpy.dot, [iW, scipy.linalg.inv(iB + iW), iW])

    s2 = numpy.sum(numpy.dot(enroll.stat1, H) * enroll.stat1, axis=1)
    s3 = numpy.sum(numpy.dot(test.stat1, H) * test.stat1, axis=1)

    for ii in range(enroll.modelset.shape[0]):
        A = enroll.stat1[ii, :] + test.stat1
        s1 = numpy.sum(numpy.dot(A, G) * A, axis=1)
        S[ii, :] = s1 - s3 - s2[ii]

    score = Scores()
    score.scoremat = S
    score.modelset = clean_ndx.modelset
    score.segset = clean_ndx.segset
    score.scoremask = clean_ndx.trialmask
    return score
def svm_scoring(svm_filename_structure, test_sv, ndx, num_thread=1):
    """Compute scores for SVM verification on multiple threads
    (two classes only as implementeed at the moment)
    
    :param svm_filename_structure: structure of the filename where to load the SVM models
    :param test_sv: StatServer object of super-vectors. stat0 are set to 1 and stat1
          are the super-vector to classify
    :param ndx: Ndx object of the trials to perform
    :param num_thread: number of thread to launch in parallel
    
    :return: a Score object.
    """
    # Remove missing models and test segments
    existing_models, model_idx = sidekit.sv_utils.check_file_list(
        ndx.modelset, svm_filename_structure)
    clean_ndx = ndx.filter(existing_models, test_sv.segset, True)

    score = Scores()
    score.scoremat = numpy.zeros(clean_ndx.trialmask.shape)
    score.modelset = clean_ndx.modelset
    score.segset = clean_ndx.segset
    score.scoremask = clean_ndx.trialmask

    tmp = multiprocessing.Array(ctypes.c_double, score.scoremat.size)
    score.scoremat = numpy.ctypeslib.as_array(tmp.get_obj())
    score.scoremat = score.scoremat.reshape(score.modelset.shape[0],
                                            score.segset.shape[0])

    # Split the list of segment to process for multi-threading
    los = numpy.array_split(numpy.arange(clean_ndx.segset.shape[0]),
                            num_thread)

    jobs = []
    for idx in los:
        p = multiprocessing.Process(target=svm_scoring_singleThread,
                                    args=(svm_filename_structure, test_sv,
                                          clean_ndx, score, idx))
        jobs.append(p)
        p.start()
    for p in jobs:
        p.join()

    return score
예제 #5
0
def cosine_scoring(enroll, test, ndx, wccn=None, check_missing=True):
    """Compute the cosine similarities between to sets of vectors. The list of 
    trials to perform is given in an Ndx object.
    
    :param enroll: a StatServer in which stat1 are i-vectors
    :param test: a StatServer in which stat1 are i-vectors
    :param ndx: an Ndx object defining the list of trials to perform
    :param wccn: numpy.ndarray, if provided, the i-vectors are normalized by using a Within Class Covariance Matrix
    :param check_missing: boolean, if True, check that all models and segments exist
    
    :return: a score object
    """
    assert isinstance(enroll,
                      StatServer), 'First parameter should be a StatServer'
    assert isinstance(test,
                      StatServer), 'Second parameter should be a StatServer'
    assert isinstance(ndx, Ndx), 'Third parameter should be an Ndx'
    enroll_copy = copy.deepcopy(enroll)
    test_copy = copy.deepcopy(test)

    # If models are not unique, compute the mean per model, display a warning
    #if not numpy.unique(enroll_copy.modelset).shape == enroll_copy.modelset.shape:
    #    logging.warning("Enrollment models are not unique, average i-vectors")
    #    enroll_copy = enroll_copy.mean_stat_per_model()

    # Remove missing models and test segments
    if check_missing:
        clean_ndx = _check_missing_model(enroll_copy, test_copy, ndx)
    else:
        clean_ndx = ndx

    if wccn is not None:
        enroll_copy.rotate_stat1(wccn)
        if enroll_copy != test_copy:
            test_copy.rotate_stat1(wccn)

    # Cosine scoring
    enroll_copy.norm_stat1()
    if enroll_copy != test_copy:
        test_copy.norm_stat1()
    s = numpy.dot(enroll_copy.stat1, test_copy.stat1.transpose())

    score = Scores()
    score.scoremat = s
    score.modelset = clean_ndx.modelset
    score.segset = clean_ndx.segset
    score.scoremask = clean_ndx.trialmask
    return score
예제 #6
0
def mahalanobis_scoring(enroll, test, ndx, m, check_missing=True):
    """Compute the mahalanobis distance between to sets of vectors. The list of 
    trials to perform is given in an Ndx object.
    
    :param enroll: a StatServer in which stat1 are i-vectors
    :param test: a StatServer in which stat1 are i-vectors
    :param ndx: an Ndx object defining the list of trials to perform
    :param m: mahalanobis matrix as a ndarray
    :param check_missing: boolean, default is True, set to False not to check missing models
    
    :return: a score object
    """
    assert isinstance(enroll,
                      StatServer), 'First parameter should be a StatServer'
    assert isinstance(test,
                      StatServer), 'Second parameter should be a StatServer'
    assert isinstance(ndx, Ndx), 'Third parameter should be an Ndx'
    assert enroll.stat1.shape[1] == test.stat1.shape[
        1], 'I-vectors dimension mismatch'
    assert enroll.stat1.shape[1] == m.shape[
        0], 'I-vectors and Mahalanobis matrix dimension mismatch'

    # If models are not unique, compute the mean per model, display a warning
    if not numpy.unique(enroll.modelset).shape == enroll.modelset.shape:
        logging.warning("Enrollment models are not unique, average i-vectors")
        enroll = enroll.mean_stat_per_model()

    # Remove missing models and test segments
    if check_missing:
        clean_ndx = _check_missing_model(enroll, test, ndx)
    else:
        clean_ndx = ndx

    # Mahalanobis scoring
    s = numpy.zeros((enroll.modelset.shape[0], test.segset.shape[0]))
    for i in range(enroll.modelset.shape[0]):
        diff = enroll.stat1[i, :] - test.stat1
        s[i, :] = -0.5 * numpy.sum(numpy.dot(diff, m) * diff, axis=1)

    score = Scores()
    score.scoremat = s
    score.modelset = clean_ndx.modelset
    score.segset = clean_ndx.segset
    score.scoremask = clean_ndx.trialmask
    return score
def PLDA_scoring_uncertainty(enroll,
                             test,
                             ndx,
                             mu,
                             F,
                             Sigma,
                             p_known=0.0,
                             scaling_factor=1.,
                             test_uncertainty=None,
                             Vtrans=None,
                             check_missing=True):
    """

    :param enroll:
    :param test:
    :param ndx:
    :param mu:
    :param F:
    :param Sigma:
    :param p_known:
    :param scaling_factor:
    :param test_uncertainty:
    :param Vtrans:
    :param check_missing:
    :return:
    """
    assert isinstance(enroll, StatServer), 'First parameter should be a StatServer'
    assert isinstance(test, StatServer), 'Second parameter should be a StatServer'
    assert isinstance(ndx, Ndx), 'Third parameter should be an Ndx'
    assert enroll.stat1.shape[1] == test.stat1.shape[1], 'I-vectors dimension mismatch'
    assert enroll.stat1.shape[1] == F.shape[0], 'I-vectors and co-variance matrix dimension mismatch'
    assert enroll.stat1.shape[1] == G.shape[0], 'I-vectors and co-variance matrix dimension mismatch'

    enroll_ctr = copy.deepcopy(enroll)
    test_ctr = copy.deepcopy(test)

    # Remove missing models and test segments
    if check_missing:
        clean_ndx = _check_missing_model(enroll_ctr, test_ctr, ndx)
    else:
        clean_ndx = ndx

    # Center the i-vectors around the PLDA mean
    enroll_ctr.center_stat1(mu)
    test_ctr.center_stat1(mu)

    # Align StatServers to match the clean_ndx
    enroll_ctr.align_models_average(clean_ndx.modelset)
    test_ctr.align_segments(clean_ndx.segset)

    # Compute constant component of the PLDA distribution
    scoremat = numpy.zeros((enroll_ctr.stat1.shape[0], test_ctr.stat1.shape[0]), dtype='float')
    invSigma = scipy.linalg.inv(Sigma)

    K1 = scipy.linalg.inv(numpy.eye(F.shape[1]) + F.T.dot(invSigma * scaling_factor).dot(F))

    FK1Ft = F.dot(K1).dot(F.T)
    Xtilda_e = FK1Ft.dot(invSigma * scaling_factor).dot(enroll_ctr.stat1.T).T

    for t in range(test_ctr.stat1.shape[0]):
        xt = test_ctr.stat1[t,:]
        Pr = numpy.eye(F.shape[1]) - numpy.outer(test.stat1[t, :],test.stat1[t, :])
        Cunc = Pr.dot(Vtrans.transpose()).dot(numpy.diag(test_uncertainty[t, :]).dot(Vtrans)).dot(Pr)
        prec_den = scipy.linalg.inv(F.dot(F.T) + Sigma + Cunc)

        denom = -0.5 * xt.dot(prec_den).dot(xt) +0.5 * numpy.linalg.slogdet(prec_den)[1]
        prec_num = scipy.linalg.inv(FK1Ft+Sigma+Cunc)
        Xec = Xtilda_e - xt
        numer = -0.5 * numpy.einsum('ij, ji->i', Xec.dot(prec_num), Xec.T) + 0.5 * numpy.linalg.slogdet(prec_num)[1]
        scoremat[:, t] = scaling_factor * (numer - denom)

    # Compute verification scores
    score = Scores()
    score.modelset = clean_ndx.modelset
    score.segset = clean_ndx.segset
    score.scoremask = clean_ndx.trialmask

    score.scoremat = scoremat

    # Case of open-set identification, we compute the log-likelihood
    # by taking into account the probability of having a known impostor
    # or an out-of set class
    if p_known != 0:
        N = score.scoremat.shape[0]
        open_set_scores = numpy.empty(score.scoremat.shape)
        tmp = numpy.exp(score.scoremat)
        for ii in range(N):
            # open-set term
            open_set_scores[ii, :] = score.scoremat[ii, :] \
                - numpy.log(p_known * tmp[~(numpy.arange(N) == ii)].sum(axis=0) / (N - 1) + (1 - p_known))
        score.scoremat = open_set_scores

    return score
def fast_PLDA_scoring(enroll,
                      test,
                      ndx,
                      mu,
                      F,
                      Sigma,
                      test_uncertainty=None,
                      Vtrans=None,
                      p_known=0.0,
                      scaling_factor=1.,
                      check_missing=True):
    """Compute the PLDA scores between to sets of vectors. The list of
    trials to perform is given in an Ndx object. PLDA matrices have to be
    pre-computed. i-vectors are supposed to be whitened before.

    :param enroll: a StatServer in which stat1 are i-vectors
    :param test: a StatServer in which stat1 are i-vectors
    :param ndx: an Ndx object defining the list of trials to perform
    :param mu: the mean vector of the PLDA gaussian
    :param F: the between-class co-variance matrix of the PLDA
    :param Sigma: the residual covariance matrix
    :param p_known: probability of having a known speaker for open-set
        identification case (=1 for the verification task and =0 for the
        closed-set case)
    :param check_missing: boolean, if True, check that all models and segments exist

    :return: a score object
    """
    # assert isinstance(enroll, StatServer), 'First parameter should be a StatServer'
    # assert isinstance(test, StatServer), 'Second parameter should be a StatServer'
    # assert isinstance(ndx, Ndx), 'Third parameter should be an Ndx'
    # assert enroll.stat1.shape[1] == test.stat1.shape[1], 'I-vectors dimension mismatch'
    # assert enroll.stat1.shape[1] == F.shape[0], 'I-vectors and co-variance matrix dimension mismatch'
    # assert enroll.stat1.shape[1] == G.shape[0], 'I-vectors and co-variance matrix dimension mismatch'

    enroll_ctr = copy.deepcopy(enroll)
    test_ctr = copy.deepcopy(test)

    # If models are not unique, compute the mean per model, display a warning
    if not numpy.unique(enroll_ctr.modelset).shape == enroll_ctr.modelset.shape:
        logging.warning("Enrollment models are not unique, average i-vectors")
        enroll_ctr = enroll_ctr.mean_stat_per_model()

    # Remove missing models and test segments
    if check_missing:
        clean_ndx = _check_missing_model(enroll_ctr, test_ctr, ndx)
    else:
        clean_ndx = ndx

    # Center the i-vectors around the PLDA mean
    enroll_ctr.center_stat1(mu)
    test_ctr.center_stat1(mu)

    # If models are not unique, compute the mean per model, display a warning
    if not numpy.unique(enroll_ctr.modelset).shape == enroll_ctr.modelset.shape:
        logging.warning("Enrollment models are not unique, average i-vectors")
        enroll_ctr = enroll_ctr.mean_stat_per_model()

    # Compute constant component of the PLDA distribution
    invSigma = scipy.linalg.inv(Sigma)
    I_spk = numpy.eye(F.shape[1], dtype='float')

    K = F.T.dot(invSigma * scaling_factor).dot(F)
    K1 = scipy.linalg.inv(K + I_spk)
    K2 = scipy.linalg.inv(2 * K + I_spk)

    # Compute the Gaussian distribution constant
    alpha1 = numpy.linalg.slogdet(K1)[1]
    alpha2 = numpy.linalg.slogdet(K2)[1]
    plda_cst = alpha2 / 2.0 - alpha1

    # Compute intermediate matrices
    Sigma_ac = numpy.dot(F, F.T)
    Sigma_tot = Sigma_ac + Sigma
    Sigma_tot_inv = scipy.linalg.inv(Sigma_tot)

    Tmp = numpy.linalg.inv(Sigma_tot - Sigma_ac.dot(Sigma_tot_inv).dot(Sigma_ac))
    Phi = Sigma_tot_inv - Tmp
    Psi = Sigma_tot_inv.dot(Sigma_ac).dot(Tmp)

    # Compute the different parts of PLDA score
    model_part = 0.5 * numpy.einsum('ij, ji->i', enroll_ctr.stat1.dot(Phi), enroll_ctr.stat1.T)
    seg_part = 0.5 * numpy.einsum('ij, ji->i', test_ctr.stat1.dot(Phi), test_ctr.stat1.T)

    # Compute verification scores
    score = Scores()
    score.modelset = clean_ndx.modelset
    score.segset = clean_ndx.segset
    score.scoremask = clean_ndx.trialmask

    score.scoremat = model_part[:, numpy.newaxis] + seg_part + plda_cst
    score.scoremat += enroll_ctr.stat1.dot(Psi).dot(test_ctr.stat1.T)
    score.scoremat *= scaling_factor

    # Case of open-set identification, we compute the log-likelihood
    # by taking into account the probability of having a known impostor
    # or an out-of set class
    if p_known != 0:
        N = score.scoremat.shape[0]
        open_set_scores = numpy.empty(score.scoremat.shape)
        tmp = numpy.exp(score.scoremat)
        for ii in range(N):
            # open-set term
            open_set_scores[ii, :] = score.scoremat[ii, :] \
                - numpy.log(p_known * tmp[~(numpy.arange(N) == ii)].sum(axis=0) / (N - 1) + (1 - p_known))
        score.scoremat = open_set_scores

    return score
def full_PLDA_scoring(enroll, test, ndx, mu, F, G, Sigma, p_known=0.0, scaling_factor=1., check_missing=True):
    """Compute PLDA scoring

    :param enroll: a StatServer in which stat1 are i-vectors
    :param test: a StatServer in which stat1 are i-vectors
    :param ndx: an Ndx object defining the list of trials to perform
    :param mu: the mean vector of the PLDA gaussian
    :param F: the between-class co-variance matrix of the PLDA
    :param G: the within-class co-variance matrix of the PLDA
    :param Sigma: the residual covariance matrix
    :param p_known: probability of having a known speaker for open-set
        identification case (=1 for the verification task and =0 for the
        closed-set case)
    :param check_missing: boolean, default is True, set to False not to check missing models

    """

    enroll_copy = copy.deepcopy(enroll)
    test_copy = copy.deepcopy(test)

    # If models are not unique, compute the mean per model, display a warning
    # if not numpy.unique(enroll_copy.modelset).shape == enroll_copy.modelset.shape:
    #    logging.warning("Enrollment models are not unique, average i-vectors")
    #    enroll_copy = enroll_copy.mean_stat_per_model()

    # Remove missing models and test segments
    if check_missing:
        clean_ndx = _check_missing_model(enroll_copy, test_copy, ndx)
    else:
        clean_ndx = ndx

    # Center the i-vectors around the PLDA mean
    enroll_copy.center_stat1(mu)
    test_copy.center_stat1(mu)

    # Compute temporary matrices
    invSigma = scipy.linalg.inv(Sigma)
    I_iv = numpy.eye(mu.shape[0], dtype='float')
    I_ch = numpy.eye(G.shape[1], dtype='float')
    I_spk = numpy.eye(F.shape[1], dtype='float')
    A = numpy.linalg.inv(G.T.dot(invSigma * scaling_factor).dot(G) + I_ch)  # keep numpy as interface are different
    B = F.T.dot(invSigma * scaling_factor).dot(I_iv - G.dot(A).dot(G.T).dot(invSigma * scaling_factor))
    K = B.dot(F)
    K1 = scipy.linalg.inv(K + I_spk)
    K2 = scipy.linalg.inv(2 * K + I_spk)

    # Compute the Gaussian distribution constant
    alpha1 = numpy.linalg.slogdet(K1)[1]
    alpha2 = numpy.linalg.slogdet(K2)[1]
    constant = alpha2 / 2.0 - alpha1

    # Compute verification scores
    score = Scores()
    score.scoremat = numpy.zeros(clean_ndx.trialmask.shape)
    score.modelset = clean_ndx.modelset
    score.segset = clean_ndx.segset
    score.scoremask = clean_ndx.trialmask

    # Project data in the space that maximizes the speaker separability
    test_tmp = B.dot(test_copy.stat1.T)
    enroll_tmp = B.dot(enroll_copy.stat1.T)

    # score qui ne dépend que du segment
    tmp1 = test_tmp.T.dot(K1)

    # Compute the part of the score that is only dependent on the test segment
    S1 = numpy.empty(test_copy.segset.shape[0])
    for seg_idx in range(test_copy.segset.shape[0]):
        S1[seg_idx] = tmp1[seg_idx, :].dot(test_tmp[:, seg_idx])/2.

    # Compute the part of the score that depends only on the model (S2) and on both model and test segment
    S2 = numpy.empty(enroll_copy.modelset.shape[0])

    for model_idx in range(enroll_copy.modelset.shape[0]):
        mod_plus_test_seg = test_tmp + numpy.atleast_2d(enroll_tmp[:, model_idx]).T
        tmp2 = mod_plus_test_seg.T.dot(K2)

        S2[model_idx] = enroll_tmp[:, model_idx].dot(K1).dot(enroll_tmp[:, model_idx])/2.
        score.scoremat[model_idx, :] = numpy.einsum("ij, ji->i", tmp2, mod_plus_test_seg)/2.

    score.scoremat += constant - (S1 + S2[:, numpy.newaxis])
    score.scoremat *= scaling_factor

    # Case of open-set identification, we compute the log-likelihood
    # by taking into account the probability of having a known impostor
    # or an out-of set class
    if p_known != 0:
        N = score.scoremat.shape[0]
        open_set_scores = numpy.empty(score.scoremat.shape)
        tmp = numpy.exp(score.scoremat)
        for ii in range(N):
            # open-set term
            open_set_scores[ii, :] = score.scoremat[ii, :] \
                - numpy.log(p_known * tmp[~(numpy.arange(N) == ii)].sum(axis=0) / (N - 1) + (1 - p_known))
        score.scoremat = open_set_scores

    return score
예제 #10
0
def gmm_scoring(ubm, enroll, ndx, feature_server, num_thread=1):
    """Compute log-likelihood ratios for sequences of acoustic feature 
    frames between a Universal Background Model (UBM) and a list of 
    Gaussian Mixture Models (GMMs) which only mean vectors differ 
    from the UBM.
    
    :param ubm: a Mixture object used to compute the denominator of the 
        likelihood ratios
    :param enroll: a StatServer object which stat1 attribute contains 
        mean super-vectors of the GMMs to use to compute the numerator 
        of the likelihood ratios.
    :param ndx: an Ndx object which define the list of trials to compute
    :param feature_server: a FeatureServer object to load the features
    :param num_thread: number of thread to launch in parallel
    
    :return: a Score object.
    
    """
    assert isinstance(ubm, Mixture), 'First parameter should be a Mixture'
    assert isinstance(enroll,
                      StatServer), 'Second parameter should be a StatServer'
    assert isinstance(ndx, Ndx), 'Third parameter should be a Ndx'
    assert isinstance(
        feature_server,
        FeaturesServer), 'Fourth parameter should be a FeatureServer'

    # Remove missing models and test segments
    if feature_server.features_extractor is None:
        existing_test_seg, test_seg_idx = sidekit.sv_utils.check_file_list(
            ndx.segset, feature_server.feature_filename_structure)
        clean_ndx = ndx.filter(enroll.modelset, existing_test_seg, True)
    elif feature_server.features_extractor.audio_filename_structure is not None:
        existing_test_seg, test_seg_idx = \
            sidekit.sv_utils.check_file_list(ndx.segset, feature_server.features_extractor.audio_filename_structure)
        clean_ndx = ndx.filter(enroll.modelset, existing_test_seg, True)
    else:
        clean_ndx = ndx

    s = numpy.zeros(clean_ndx.trialmask.shape)
    dims = s.shape
    with warnings.catch_warnings():
        warnings.simplefilter('ignore', RuntimeWarning)
        tmp_stat1 = multiprocessing.Array(ctypes.c_double, s.size)
        s = numpy.ctypeslib.as_array(tmp_stat1.get_obj())
        s = s.reshape(dims)

    # Split the list of segment to process for multi-threading
    los = numpy.array_split(numpy.arange(clean_ndx.segset.shape[0]),
                            num_thread)
    jobs = []
    for idx in los:
        p = multiprocessing.Process(target=gmm_scoring_singleThread,
                                    args=(ubm, enroll, ndx, feature_server, s,
                                          idx))
        jobs.append(p)
        p.start()
    for p in jobs:
        p.join()

    score = Scores()
    score.scoremat = s
    score.modelset = clean_ndx.modelset
    score.segset = clean_ndx.segset
    score.scoremask = clean_ndx.trialmask
    return score
예제 #11
0
def cosine_scoring(enroll,
                   test,
                   ndx,
                   wccn=None,
                   check_missing=True,
                   device=None):
    """Compute the cosine similarities between to sets of vectors. The list of 
    trials to perform is given in an Ndx object.
    
    :param enroll: a StatServer in which stat1 are i-vectors
    :param test: a StatServer in which stat1 are i-vectors
    :param ndx: an Ndx object defining the list of trials to perform
    :param wccn: numpy.ndarray, if provided, the i-vectors are normalized by using a Within Class Covariance Matrix
    :param check_missing: boolean, if True, check that all models and segments exist
    
    :return: a score object
    """
    assert isinstance(enroll,
                      StatServer), 'First parameter should be a StatServer'
    assert isinstance(test,
                      StatServer), 'Second parameter should be a StatServer'
    assert isinstance(ndx, Ndx), 'Third parameter should be an Ndx'
    enroll_copy = copy.deepcopy(enroll)
    test_copy = copy.deepcopy(test)

    # If models are not unique, compute the mean per model, display a warning
    #if not numpy.unique(enroll_copy.modelset).shape == enroll_copy.modelset.shape:
    #    logging.warning("Enrollment models are not unique, average i-vectors")
    #    enroll_copy = enroll_copy.mean_stat_per_model()

    # Remove missing models and test segments
    if check_missing:
        clean_ndx = _check_missing_model(enroll_copy, test_copy, ndx)
    else:
        clean_ndx = ndx

    if wccn is not None:
        enroll_copy.rotate_stat1(wccn)
        if enroll_copy != test_copy:
            test_copy.rotate_stat1(wccn)

    # Cosine scoring
    enroll_copy.norm_stat1()
    if enroll_copy != test_copy:
        test_copy.norm_stat1()
    s_size_in_bytes = enroll_copy.stat1.shape[0] * test_copy.stat1.shape[0] * 4
    if device == None:
        device = torch.device("cuda:0" if torch.cuda.is_available()
                              and s_size_in_bytes < 3e9 else "cpu")
    else:
        device = device if torch.cuda.is_available(
        ) and s_size_in_bytes < 3e9 else torch.device("cpu")

    score = Scores()
    score.scoremat = torch.einsum(
        'ij,kj',
        torch.FloatTensor(enroll_copy.stat1).to(device),
        torch.FloatTensor(test_copy.stat1).to(device)).cpu().numpy()
    score.modelset = clean_ndx.modelset
    score.segset = clean_ndx.segset
    score.scoremask = clean_ndx.trialmask
    return score
예제 #12
0
def jfa_scoring(ubm,
                enroll,
                test,
                ndx,
                mean,
                sigma,
                V,
                U,
                D,
                batch_size=100,
                num_thread=1,
                check_missing=True):
    """Compute a verification score as a channel point estimate 
    of the log-likelihood ratio. Detail of this scoring can be found in 
    [Glembeck09].
    
    [Glembek09] Ondrej Glembek, Lukas Burget, Najim Dehak, Niko Brummer, 
    and Patrick Kenny, "Comparison of scoring methods used in speaker 
    recognition with joint factor analysis." 
    in Acoustics, Speech and Signal Processing, 2009. ICASSP 2009. 
    IEEE International Conference on. IEEE, 2009.

    Note that input statistics should not be whitened as
        it is done within this function.
    
    :param ubm: the Mixture object used to compute sufficient statistics
    :param enroll: a StatServer object which contains zero- and first-order
        statistics.
    :param test: a StatServer object which contains zero- and first-order
        statistics.
    :param ndx: an Ndx object which trial mask will be copied into the output
        Scores object
    :param mean: mean vector of the JFA model
    :param sigma: residual covariance vector of the JFA model
    :param V: between class covariance matrix of the JFA model
    :param U: within class covariance matrix of the JFA model
    :param D: MAP covariance matrix for the JFA model
    :param batch_size: size of the batch to reduce memory footprint
    :param num_thread: number of parallel process to run
    :param check_missing: boolean, if True, check that all model exist

    :return: a Scores object
    """
    assert isinstance(ubm, Mixture), '1st parameter must be a Mixture'
    assert isinstance(enroll, StatServer), '2nd parameter must be a StatServer'
    assert isinstance(test, StatServer), '3rd parameter must be a StatServer'
    assert isinstance(ndx, Ndx), '4th parameter shomustuld be a Ndx'

    # Remove missing models and test segments
    if check_missing:
        clean_ndx = _check_missing_model(enroll, test, ndx)
    else:
        clean_ndx = ndx

    print("taille de clean_ndx.trial_mask = {}".format(
        clean_ndx.trialmask.shape))

    # Sum enrolment statistics per model in case of multi-session
    enroll = enroll.sum_stat_per_model()[0]

    # Whiten enroll and test statistics
    enroll.whiten_stat1(ubm.get_mean_super_vector(),
                        ubm.get_invcov_super_vector())
    test.whiten_stat1(ubm.get_mean_super_vector(),
                      ubm.get_invcov_super_vector())

    # Estimate Vy and DZ from the enrollment
    trn_y, trn_x, trn_z = enroll.estimate_hidden(mean,
                                                 sigma,
                                                 V,
                                                 U,
                                                 D,
                                                 batch_size=batch_size,
                                                 num_thread=num_thread)
    M = ((trn_y.stat1.dot(V.T)) + (trn_z.stat1 * D))

    # Estimate Ux from the test
    tmp = copy.deepcopy(test)
    test_y, test_x, test_z = tmp.estimate_hidden(mean, sigma, None, U, None,
                                                 batch_size, num_thread)

    # remove Ux weighted from the test statistics
    Ux = copy.deepcopy(test)
    Ux.stat1 = test_x.stat1.dot(U.T)
    test = test.subtract_weighted_stat1(Ux)

    # sum zero-order statistics for each test segment
    test_stat0_sum = test.stat0.sum(axis=1)

    # Compute score as the dot product of the enrollment supervector and the first
    # order statistics divided by the sum of the zero-order stats
    scores = Scores()
    scores.modelset = enroll.modelset
    scores.segset = test.segset
    scores.scoremask = clean_ndx.trialmask
    scores.scoremat = M.dot((test.stat1 / test_stat0_sum[:, None]).T)

    return scores