当前位置: 代码迷 >> 综合 >> 声纹识别:如何获取最佳效果的阈值(通过计算ERR)?
  详细解决方案

声纹识别:如何获取最佳效果的阈值(通过计算ERR)?

热度:31   发布时间:2023-12-15 05:23:09.0

文章目录

  • 1. 如何绘制 ROC 曲线
    • 1.1 What and Why
    • 1.2 How
      • 理论
  • 2. 如何绘制 ERR 曲线
    • what and why
    • how
  • 3. 代码实现
    • 基本代码介绍
    • 使用 [scikit-learn](https://blog.csdn.net/liuweiyuxiang/article/details/78475419)
    • 绘制 EER

摆在眼前的有几个问题:

1、声纹识别与人脸识别的阈值获取方式一致么?(ROC曲线 or ERR曲线?)
2、如何绘制 ROC 曲线?
3、如何绘制 ERR 曲线?

下面直接了当,进入主题。

1. 如何绘制 ROC 曲线

1.1 What and Why

  • ROC(Receiver Operating Characteristic)曲线全称是“受试者工作特征”。
  • 通常用来衡量一个二分类学习器的好坏:如果一个学习器的ROC曲线能将另一个学习器的ROC曲线完全包住,则说明该学习器的性能优于另一个学习器。

1.2 How

理论

前提知识:二分类问题、混淆矩阵、四个基础指标

ROC 曲线的横纵坐标分别是:

  • FPR(False Positive Rate)
  • TPR(True Positive Rate)

实际问题:一个模型一次只能产生一对(FPR, TPR),这只能绘制一个点,不足以绘制出一条曲线。

解决办法利用不同的阈值,产生不同的(FPR, TPR)对,从而绘制出 ROC 曲线。

对于许多学习器在判定二分类问题时是预测出一个对于真值的范围在[0.0, 1.0]之间的概率值,而判定是否为真值则看该概率值是否大于设定的阈值(Threshold)。例如如果阈值设定为0.5则所有概率值大于0.5的均为正例,其余为反例。

补充:

  • AUC(Area Under Curve)值:ROC曲线下(所覆盖的)面积。AUC值可以更直观的判断学习器的性能,AUC越大则性能越好。

小结:
可以看出,对于普通的二分类问题,其混淆矩阵的评价基准是“是否将正/负样本正确地判断为正/负样本”,而对于人脸识别和声纹识别的问题,并不是通过样本的正负(样本本身并没有正负一说)是否匹配成功来计算评价指标,而是通过一个**阈值(相似度分数)**直接判断互相的比对是否成功来计算评价指标。具体内容可以查看:人脸识别模型评价指标:完整梳理。
因此,对于人脸识别和声纹识别问题我们使用 ERR 曲线

注:很多人将人脸识别/声纹识别中的 FAR 和 FRR 等指标与基础二分类问题 FPR 和 FNR 等价来看,我这边觉得有问题,还是区分开来!!

2. 如何绘制 ERR 曲线

what and why

  • EER (Equal Error Rate) 表示等误率,指的是某一阈值下,FAR=FRR时,FAR或者FRR的值。
    这里有一个问题,阈值T指的是什么,分数?

how

3. 代码实现

基本代码介绍

from sklearn import metrics
from scipy import interpolate
from scipy.optimize import brentq
import matplotlib.pyplot as plt# given y_test (the actual labels), y_pred_class (predicted results), y_pred_prob (predicted probabilities)
y_test = [1, 0, 0, 1, 0, 0, 1, 1, 0, 0]                                                     # true values
y_pred_class = [0, 0, 0, 0, 0, 0, 0, 1, 0, 1]                                               # predicted values
y_pred_prob = [0.36752429, 0.28356344, 0.28895886, 0.4141062, 0.15896027, 0.17065156, \0.49889026, 0.51341541, 0.27678612, 0.67189438]                                   # predicted probabilities
y_test = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0]
y_test = y_test*5 + y_pred_class*4 + [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
y_pred_prob = y_pred_prob*10
y_pred_class = y_pred_class*10# confusion matrix
confusion = metrics.confusion_matrix(y_test, y_pred_class)
# TP TN FP FN
TP = confusion[1, 1]
TN = confusion[0, 0]
FP = confusion[0, 1]
FN = confusion[1, 0]# accuracy
ACC = (TP+TN) / float(TP+TN+FN+FP)
# ACC = metrics.accuracy_score(y_test, y_pred_class) another way# precision
PPV = TP / float(TP+FP)
# PPV = metrics.precision_score(y_test, y_pred_class)# TPR, sensitivity, recall
TPR = TP / float(TP+FN)
# TPR = metrics.recall_score(y_test, y_pred_class)# TNR, specificity
TNR = TN / float(TN+FP)# FPR
FPR = FP / float(TN+FP)
# FPR = 1 - TNR# F1 score
F1_score = (2*PPV*TPR) / (PPV+TPR)
# F1_score = metrics.f1_score(y_test, y_pred_class)# ROC
# IMPORTANT: first argument is true values, second argument is predicted probabilities
fpr, tpr, thresholds = metrics.roc_curve(y_test, y_pred_prob)
plt.plot(fpr, tpr, 'r')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.title('ROC curve')
plt.xlabel('FPR (False Positive Rate)')
plt.ylabel('TPR (True Positive Rate)')
plt.grid(True)
plt.show()
plt.savefig('ROC.png')# AUC
# IMPORTANT: first argument is true values, second argument is predicted probabilities
# AUC = metrics.roc_auc_score(y_test, y_pred_prob)
AUC = metrics.auc(fpr, tpr)
# # calculate cross-validated AUC
# from sklearn.cross_validation import cross_val_score
# mean_socre = cross_val_score(logreg, X, y, cv=10, scoring='roc_auc').mean()
# print(mean_socre)# EER
EER = brentq(lambda x: 1. - x - interpolate.interp1d(fpr, tpr)(x), 0., 1.)# TAR @ FAR = 0.1 / 0.01 / 0.001, FAR = FPR, TAR = TPR
TAR_FAR_E1 = brentq(lambda x: 0.1 - interpolate.interp1d(tpr, fpr)(x), 0., 1.)
TAR_FAR_E2 = brentq(lambda x: 0.01 - interpolate.interp1d(tpr, fpr)(x), 0., 1.)
TAR_FAR_E3 = brentq(lambda x: 0.001 - interpolate.interp1d(tpr, fpr)(x), 0., 1.)

使用 scikit-learn

绘制 EER

import numpy as np
import matplotlib.pyplot as plt
datas = np.array([[i*0.1,int((i*0.1>0.55)) or i*0.1 == 0.4 ]  for i in range(0,10)])
np.random.shuffle(datas)
print(datas)def get_far(labelFalse_predictTrue,labelTrue_predictTrue):far = labelFalse_predictTrue/(labelFalse_predictTrue+labelTrue_predictTrue)#错误接受率,错误接受的除以所有接受的return(far)def get_frr(labelTrue_predictFalse,labelFalse_predictFalse):frr = labelTrue_predictFalse/(labelTrue_predictFalse+labelFalse_predictFalse)#错误拒绝率,错误拒绝的除以所有拒绝的return(frr)pre_min,pre_max = np.min(datas[:,0]),np.max(datas[:,0])print(pre_min,pre_max)
step_len = (-pre_min+pre_max)/9thresholds = np.arange(pre_min,pre_max,step_len)
#thresholds = [0.45]scores = []
for t in thresholds:lf_pf = 0lf_pt = 0lt_pf = 0lt_pt = 0for i in range(len(datas)):pre = int(datas[i,0]>t)label = int(datas[i,1])print(pre,label)if(label==0 and pre==0):lf_pf += 1elif(label==0 and pre==1):lf_pt += 1elif(label==1 and pre==0):lt_pf += 1elif(label==1 and pre==1):lt_pt += 1far = get_far(lf_pt,lt_pt)frr = get_frr(lt_pf,lf_pf)scores.append([t,far,frr,abs(far-frr)])
scores = np.array(scores)
print(np.array(scores))plt.plot(scores[:,0],scores[:,1])
plt.plot(scores[:,0],scores[:,2])
#plt.plot(scores[:,0],scores[:,3])
plt.show()

另外一种计算方法:

错误接受率 (FAR), 错误拒绝率(FRR), 等错误率(EER)
这个类似:画EER曲线,声纹确认

参考:

  1. 如何绘制ROC曲线——简单、直观
  2. scikit-learn中评估分类器性能的度量,像混淆矩阵、ROC、AUC等
  3. 人脸识别数据集及评估协议(尚未完成)——值得好好看
  4. [深度基础]·EER计算画图——少见的靠谱:简洁明了,计算和绘制EER