Source code for hyperion.metrics.dcf

"""
 Copyright 2018 Johns Hopkins University  (Author: Jesus Villalba)
 Apache 2.0  (http://www.apache.org/licenses/LICENSE-2.0)
"""

import numpy as np

from .roc import compute_rocch, rocch2eer


[docs]def compute_dcf(p_miss, p_fa, prior, normalize=True): """Computes detection cost function DCF = prior*p_miss + (1-prior)*p_fa Args: p_miss: Vector of miss probabilities. p_fa: Vector of false alarm probabilities. prior: Target prior or vector of target priors. normalize: if true, return normalized DCF, else unnormalized. Returns: Matrix of DCF for each pair of (p_miss, p_fa) and each value of prior. [len(prior) x len(p_miss)] """ prior = np.asarray(prior) if prior.ndim == 1: prior = prior[:, None] dcf = prior * p_miss + (1 - prior) * p_fa if normalize: dcf /= np.minimum(prior, 1 - prior) return dcf
[docs]def compute_min_dcf(tar, non, prior, normalize=True): """Computes minimum DCF min_DCF = min_t prior*p_miss(t) + (1-prior)*p_fa(t) where t is the decission threshold. Args: tar: Target scores. non: Non-target scores. prior: Target prior or vector of target priors. normalize: if true, return normalized DCF, else unnormalized. Returns: Vector Minimum DCF for each prior. Vector of P_miss corresponding to each min DCF. Vector of P_fa corresponding to each min DCF. """ p_miss, p_fa = compute_rocch(tar, non) dcf = compute_dcf(p_miss, p_fa, prior, normalize) idx_min_dcf = np.argmin(dcf, axis=-1) if dcf.ndim == 1: min_dcf = dcf[idx_min_dcf] p_miss = p_miss[idx_min_dcf] p_fa = p_fa[idx_min_dcf] else: i1 = np.arange(dcf.shape[0]) min_dcf = dcf[i1, idx_min_dcf] p_miss = p_miss[idx_min_dcf] p_fa = p_fa[idx_min_dcf] return min_dcf, p_miss, p_fa
[docs]def compute_act_dcf(tar, non, prior, normalize=True): """Computes actual DCF by making decisions assuming that scores are calibrated to act as log-likelihood ratios. Args: tar: Target scores. non: Non-target scores. prior: Target prior or vector of target priors. normalize: if true, return normalized DCF, else unnormalized. Returns: Vector actual DCF for each prior. Vector of P_miss corresponding to each act DCF. Vector of P_fa corresponding to each act DCF. """ prior = np.asarray(prior) if prior.ndim == 1: assert np.all( prior == np.sort(prior, kind="mergesort") ), "priors must be in ascending order" else: prior = prior[None] num_priors = len(prior) ntar = len(tar) nnon = len(non) # thresholds t = -np.log(prior) + np.log(1 - prior) ttar = np.concatenate((t, tar)) ii = np.argsort(ttar, kind="mergesort") r = np.zeros((num_priors + ntar), dtype="int32") r[ii] = np.arange(1, num_priors + ntar + 1) r = r[:num_priors] n_miss = r - np.arange(num_priors, 0, -1) tnon = np.concatenate((t, non)) ii = np.argsort(tnon, kind="mergesort") r = np.zeros((num_priors + nnon), dtype="int32") r[ii] = np.arange(1, num_priors + nnon + 1) r = r[:num_priors] n_fa = nnon - r + np.arange(num_priors, 0, -1) # n_miss2 = np.zeros((num_priors,), dtype='int32') # n_fa2 = np.zeros((num_priors,), dtype='int32') # for i in range(len(t)): # n_miss2[i] = np.sum(tar<t[i]) # n_fa2[i] = np.sum(non>t[i]) # assert np.all(n_miss2 == n_miss) # assert np.all(n_fa2 == n_fa) # print(n_miss) # print(n_fa) p_miss = n_miss / ntar p_fa = n_fa / nnon act_dcf = prior * p_miss + (1 - prior) * p_fa if normalize: act_dcf /= np.minimum(prior, 1 - prior) if len(act_dcf) == 1: act_dcf = act_dcf[0] return act_dcf, p_miss, p_fa
[docs]def fast_eval_dcf_eer(tar, non, prior, normalize_dcf=True, return_probs=False): """Computes actual DCF, minimum DCF, EER and PRBE all togther Args: tar: Target scores. non: Non-target scores. prior: Target prior or vector of target priors. normalize_cdf: if true, return normalized DCF, else unnormalized. Returns: Vector Minimum DCF for each prior. Vector Actual DCF for each prior. EER value PREBP value """ p_miss, p_fa = compute_rocch(tar, non) eer = rocch2eer(p_miss, p_fa) N_miss = p_miss * len(tar) N_fa = p_fa * len(non) prbep = rocch2eer(N_miss, N_fa) dcf = compute_dcf(p_miss, p_fa, prior, normalize_dcf) min_dcf = np.min(dcf, axis=-1) act_dcf, act_pmiss, act_pfa = compute_act_dcf(tar, non, prior, normalize_dcf) if not return_probs: return min_dcf, act_dcf, eer, prbep idx = np.argmin(dcf, axis=-1) min_pmiss = p_miss[idx] min_pfa = p_fa[idx] return min_dcf, act_dcf, eer, prbep, min_pmiss, min_pfa, act_pmiss, act_pfa