日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从说话人识别demo开始学习kaldi--(7)EER的计算

發布時間:2024/1/18 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从说话人识别demo开始学习kaldi--(7)EER的计算 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考這里:
https://blog.csdn.net/zjm750617105/article/details/52558779

我的1.txt長這個樣子:(可參考local/prepare_for_eer.py,但我是用excel弄出來的,哈哈),一共14232行。這是整合真實值與打分得到的文件。。

5.1663/target -32.37284/nontarget -38.94157/nontarget -58.89211/nontarget -69.29233/nontarget

下面先用kaldi的方法計算一下eer:

def read_file(filepath):with open(filepath, 'r') as f:lines = f.readlines()return linesscore_path = r"E:\share_with_ubuntu\aishell-v1\1.txt" score_lines = read_file(score_path) target_scores = [] nontarget_scores = [] for line in score_lines:splits = line.strip().split('/')if splits[1] == 'target':target_scores.append(eval(splits[0]))else:nontarget_scores.append(eval(splits[0])) print(len(target_scores),len(nontarget_scores))

結果:

7116 135204

kaldi中對于閾值的選擇是對target_scores的每一個分數進行迭代,也就是把每一個target_scores中的分數都當做閾值來算一遍。

但是也有文章說,直接在target_scores的最小值和最大值之間取10000個點,把每一個點都當做閾值進行迭代。

設一萬個點的可以參考下面:
https://blog.csdn.net/zjm750617105/article/details/60503253
(這里面是對all_scores而不是target_scores分10000個點,到底應該對什么分一萬個點呢?我實驗了兩種,一是對all_scores分一萬個點,二是對target_scores分一萬個點,但結果幾乎是一樣的。是真的沒有區別還是只是對我的數據沒有區別?)

通過對nist,det curve工具(https://www.nist.gov/itl/iad/mig/tools)
的分析得知,nist給的工具中使用的是對all_scores劃分閾值,有多少點就有多少待選的閾值。

#從小到大排序 target_scores = sorted(target_scores) nontarget_scores = sorted(nontarget_scores)# 下面是kaldi中compute-eer的方法 target_size = len(target_scores) target_position = 0 for target_position in range(target_size):nontarget_size = len(nontarget_scores)nontarget_n = nontarget_size * target_position * 1.0 / target_sizenontarget_position = int(nontarget_size - 1 - nontarget_n)if nontarget_position < 0:nontarget_position = 0if nontarget_scores[nontarget_position] < target_scores[target_position]:print ("nontarget_scores[nontarget_position] is", nontarget_position, nontarget_scores[nontarget_position])print ("target_scores[target_position] is", target_position, target_scores[target_position])breakthreshold = target_scores[target_position] print ("threshold is --> ", threshold) eer = target_position * 1.0 / target_size print ("eer is --> ", eer)

結果:

nontarget_scores[nontarget_position] is 133246 -13.30128 target_scores[target_position] is 103 -13.16873 threshold is --> -13.16873 eer is --> 0.01447442383361439

但是我不太理解上面的方法,根據下面kaldi中的注釋,我們來自己寫一下python代碼。
ComputeEer computes the Equal Error Rate (EER) for the given scores
and returns it as a proportion beween 0 and 1.
If we set the threshold at x, then the target error-rate is the
proportion of target_scores below x; and the non-target error-rate
is the proportion of non-target scores above x. We seek a
threshold x for which these error rates are the same; this
error rate is the EER.
We compute this by iterating over the positions in target_scores: 0, 1, 2,
and so on, and for each position consider whether the cutoff could be here.
For each of these position we compute the corresponding position in
nontarget_scores where the cutoff would be if the EER were the same.
For instance, if the vectors had the same length, this would be position
length() - 1, length() - 2, and so on. As soon as the value at that
position in nontarget_scores at that position is less than the value from target_scores, we have our EER.

這里再來明確一下FR和FA的定義:
FR = 所有真正例中被判為負例的數目 / 所有真正例的數目。即miss,未命中。
FA = 所有真負例中被判為正例的數目 / 所有真負例的數目。即fa,false-alarm,假警報。

閾值一旦設定,所有小于閾值的都被預測為負例,所有大于閾值的都被預測為正例
這里(真實值中)所有正例的數目就是7116,所有負例的數目就是135204
由于FR和FA不可能完全相等,下面計算他們差的絕對值的最小值。
(或者用插值的方法來求FR和FA完全相等的地方。插值是離散函數逼近的重要方法,利用它可通過函數在有限個點處的取值狀況,估算出函數在其他點處的近似值。 from scipy.interpolate import interp1d)

def count_xiaoyu_x(list1,x): # 要求list1是從小到大排列的num =0for i in range(len(list1)):if (list1[i]<x):num+=1else:breakreturn numdef count_dayu_x(list1,x): # 要求list1是從小到大排列的num =0length = len(list1)for i in range(length):if (list1[length-i-1]>x):num+=1else:breakreturn numfr_list = [] fa_list = [] cha_list = [] for position in range(7116):FR = count_xiaoyu_x(target_scores,target_scores[position])/7116FA = count_dayu_x(nontarget_scores,target_scores[position])/135204cha = abs(FR-FA)fr_list.append(FR)fa_list.append(FA)cha_list.append(cha)a = min(cha_list) b = cha_list.index(a) print(target_scores[b],fr_list[b],fa_list[b],'%.10f'%a)

結果:

-13.22655 0.01433389544688027 0.014363480370403242 0.0000295849

這里發現與kaldi的結果不太一樣,剛好是kaldi結果的上一個點
這個cha的變化趨勢是怎樣的呢,是不是只有一個最低點呢,畫個圖看看

import numpy as np import matplotlib.pyplot as pltfig, ax = plt.subplots() plt.xlabel('threshhold') plt.ylabel('cha') ax.set_xlim([min(target_scores), max(target_scores)]) ax.set_ylim([min(cha_list), max(cha_list)])plt.plot(target_scores,cha_list,'.',label=" cha with threshold")plt.legend(loc='upper right') plt.show()


確實只有一個最低點,下面這個才是kaldi的結果

print(target_scores[b+1],fr_list[b+1],fa_list[b+1],'%.10f'%cha_list[b+1])

結果:

-13.16873 0.01447442383361439 0.014274725599834325 0.0001996982

比較兩個cha,0.0000295849和0.0001996982,我的結果確實更小一些呢。

現在來畫fa和fr隨閾值變化的曲線,最好能從曲線上就找到FR和FA離的最近的兩個點

#!coding=utf-8 import numpy as np import matplotlib.pyplot as pltfig, ax = plt.subplots() plt.title(" curve") plt.xlabel('threshhold') plt.ylabel('y') ax.set_xlim([min(target_scores), max(target_scores)]) ax.set_ylim([0, 1])plt.plot(target_scores,fr_list,'.',label=" FR with threshold") plt.plot(target_scores,fa_list,'.',label=" FA with threshold")plt.legend(loc='upper right') plt.show()


上面的圖太不清楚了,怎么能從圖上就找到這個交點呢,更改刻度再畫一次

a=[] b=[] c=[]for i in range(len(target_scores)):if((-20<target_scores[i]) & (target_scores[i]<-10)):a.append(target_scores[i])b.append(fr_list[i])c.append(fa_list[i]) print(len(a),len(b),len(c))import numpy as np import matplotlib.pyplot as pltfig, ax = plt.subplots() plt.title(" curve") plt.xlabel('threshhold') plt.ylabel('y') ax.set_xlim([-20, -10]) ax.set_ylim([0, 0.1])plt.plot(a,b,'.',label="curve of FR with threshold") plt.plot(a,c,'.',label="curve of FA with threshold")plt.legend(loc='upper right') plt.show()

結果:

# 再畫一次 a=[] b=[] c=[]for i in range(len(target_scores)):if((-14<target_scores[i]) & (target_scores[i]<-12)):a.append(target_scores[i])b.append(fr_list[i])c.append(fa_list[i])print(len(a),len(b),len(c))plt.title(" curve") plt.xlabel('threshhold') plt.ylabel('y') ax.set_xlim([-14, -12]) ax.set_ylim([0, 0.04])plt.plot(a,b,'.',label="curve of FR with threshold") plt.plot(a,c,'.',label="curve of FA with threshold")plt.legend(loc='upper right') plt.show() # 這時有38個點,還是不太清楚

# 再畫一次 a=[] b=[] c=[]for i in range(len(target_scores)):if((-13.5<target_scores[i]) & (target_scores[i]<-13)):a.append(target_scores[i])b.append(fr_list[i])c.append(fa_list[i])print(len(a),len(b),len(c))plt.title(" curve") plt.xlabel('threshhold') plt.ylabel('y') ax.set_xlim([-13.5, -13]) ax.set_ylim([0.013, 0.016])plt.plot(a,b,'.',label="curve of FR with threshold") plt.plot(a,c,'.',label="curve of FA with threshold")plt.legend(loc='upper right') plt.show()


這時只有6個點,可以很清楚的看到第4個點,黃色和藍色是離的最近的

print(a[3],b[3],c[3]) # 打印出來的閾值,fr,fa和我們上面的計算結果是一樣的

結果:

-13.22655 0.01433389544688027 0.014363480370403242

果然和我上面的結果是一樣的。

下面畫DET曲線,橫軸是fa,縱軸是fr

# 先來看下坐標范圍 print(min(fa_list),max(fa_list)) print(min(fr_list),max(fr_list)) print(len(fa_list),len(fr_list)) 0.0 0.07365906334132126 0.0 0.9998594716132658 7116 7116 # 下面畫DET曲線,橫軸是fa,縱軸是fr plt.xlabel('fa') plt.ylabel('fr') ax.set_xlim([0, max(fa_list)]) ax.set_ylim([0, max(fr_list)])plt.plot(fa_list,fr_list,'.',label="curve of DET")plt.legend(loc='upper right') plt.show()


怎么把我們找到的eer的值標記上去呢
參考:python顯示圖上每個點的坐標:https://zhidao.baidu.com/question/1388281986500209380.html
參考:Python:給圖形中添加文本注釋(text函數):https://blog.csdn.net/weixin_38725737/article/details/82664096

# 怎么把我們找到的eer的值標記上去呢 # 參考:python顯示圖上每個點的坐標:https://zhidao.baidu.com/question/1388281986500209380.html # 參考:Python:給圖形中添加文本注釋(text函數):https://blog.csdn.net/weixin_38725737/article/details/82664096plt.xlabel('fa') plt.ylabel('fr') ax.set_xlim([0, max(fa_list)]) ax.set_ylim([0, max(fr_list)])plt.plot(fa_list,fr_list,'.',label="curve of DET") plt.text(0.01, 0.2, "EER=0.01433", size = 15, alpha = 0.7)plt.legend(loc='upper right') plt.show()

但是下面這個曲線與y=x的交點處橫坐標,明顯小于0.01啊,為什么呢,難道是因為7116個點太密了?

那再放大一點看細節

m=[] n=[]for i in range(len(fa_list)):if((0<fa_list[i]) & (fa_list[i]<0.002)):m.append(fa_list[i])n.append(fr_list[i])print(len(m),len(n))plt.title(" curve") plt.xlabel('fa') plt.ylabel('fr') ax.set_xlim([0,0.002]) ax.set_ylim([0,0.2])plt.plot(m,n,'.',label="curve of DET")plt.legend(loc='upper right') plt.show()


還是這樣啊,為什么呢?難道是我畫DET曲線的方法不對?

2019.12.16增加:
原來是我的刻度問題,現在把x軸和y軸的刻度弄一樣,再畫一下:

import numpy as np import matplotlib.pyplot as plt # 下面畫DET曲線,橫軸是fa,縱軸是fr plt.xlabel('fa') plt.ylabel('fr') #ax.set_xlim([0, 0.08]) #ax.set_ylim([0, 0.08]) plt.xlim(0,0.08) plt.ylim(0,0.08)plt.plot(fa_list,fr_list,'.',label="curve of DET")plt.legend(loc='upper right') plt.show()

結果:

這下,曲線與對角線y=x的交點有點像在x=0.0143的位置了吧,又有一個新問題了,為啥它畫出來不是正方形的圖片,怎么是個長方形的?

本頁有一個問題沒解決:
1.如何理解kaldi中的方法?

------------------2020-11-26–附上另一種計算方法-------------------

def compute_det_curve(target_scores, nontarget_scores):n_scores = target_scores.size + nontarget_scores.sizeall_scores = np.concatenate((target_scores, nontarget_scores))labels = np.concatenate((np.ones(target_scores.size), np.zeros(nontarget_scores.size)))# Sort labels based on scoresindices = np.argsort(all_scores, kind='mergesort') # 返回排序后數組的原索引值labels = labels[indices] # 對all_scores從小到大排序后,里面的score就亂了,label也需要重新調整# Compute false rejection and false acceptance ratestar_trial_sums = np.cumsum(labels)# 求累計和# 所有真正例的數目# 所有真負例的數目# FR = 所有真正例中被判為負例的數目 / 所有真正例的數目。即miss,未命中。# FA = 所有真負例中被判為正例的數目 / 所有真負例的數目。即fa,false-alarm,假警報。# 有多少分數,就有多少個閾值,有了閾值之后,小于它的,都被判為負例,所有大于它的,都被判為正例# 也就是,閾值位置之前,有多少個1,就是所有真正例中被判為負例的數目# 閾值位置之后,有多少個0,就是所有真負例中被判為正例的數目# 假如閾值選定的是第三個score,位置參數是2,那么在labels[2]之前有幾個1呢,通過tar_trial_sums[2]-1=2,我們知道,有2個1# 在labels[2]之后有幾個0呢,nontarget_trial_sums[2]=155,告訴我們有155個0nontarget_trial_sums = nontarget_scores.size - (np.arange(1, n_scores + 1) - tar_trial_sums)frr = np.concatenate((np.atleast_1d(0), tar_trial_sums / target_scores.size)) # false rejection ratesfar = np.concatenate((np.atleast_1d(1), nontarget_trial_sums / nontarget_scores.size)) # false acceptance ratesthresholds = np.concatenate((np.atleast_1d(all_scores[indices[0]] - 0.001), all_scores[indices])) # Thresholds are the sorted scoresreturn frr, far, thresholdsdef compute_eer(target_scores, nontarget_scores):""" Returns equal error rate (EER) and the corresponding threshold. """frr, far, thresholds = compute_det_curve(target_scores, nontarget_scores)abs_diffs = np.abs(frr - far) # 求差的最小值,即找離的最近的兩個點min_index = np.argmin(abs_diffs) # 求最小值所在的位置eer = np.mean((frr[min_index], far[min_index])) # 求均值return eer, thresholds[min_index]

---------------------2020.12.1-------------------------------

from scipy.optimize import brentq from scipy.interpolate import interp1d from sklearn.metrics import roc_curve, confusion_matrix# EER reference: https://yangcha.github.io/EER-ROC/def compute_eer(y_true, y_pred):fpr, tpr, _ = roc_curve(y_true, y_pred, pos_label=1)eer = brentq(lambda x : 1. - x - interp1d(fpr, tpr)(x), 0., 1)return 100. * eerdef compute_confuse(y_true, y_pred):return confusion_matrix(y_true, y_pred)

總結

以上是生活随笔為你收集整理的从说话人识别demo开始学习kaldi--(7)EER的计算的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。