主要内容

基于高斯混合模型的说话人验证

说话人验证或身份验证的任务是验证给定的语音片段是否属于给定的说话人。在说话人验证系统中,存在一组未知的所有其他说话人,因此将某个语音属于验证目标的可能性与不属于验证目标的可能性进行比较。这与说话人的情况形成对比识别任务,其中计算每个说话人的可能性,并比较这些可能性。说话人验证和说话人识别可以是文本相关的,也可以是文本无关的。在本例中,您使用高斯混合模型/通用背景模型(GMM-UBM)创建了一个文本相关的说话人验证系统。

GMM-UBM系统示意图如下所示:

执行说话人验证

为了激发这个例子,您将首先使用预先训练好的通用背景模型(UBM)执行说话人验证。该模型使用谷歌语音命令数据集中的单词“stop”进行训练[1].

垫文件,SpeakerFicationExampleData.mat,包括UBM,一个配置音频特征提取器对象,以及用于规范化特征的规范化因子。

负载SpeakerificationExampleData.matubmafe标准因子

登记

如果您想自己测试注册,请设置报名符合事实的。系统将提示您记录自己多次说“停止”。每次提示只说一次“停止”。增加记录次数应可提高验证准确性。

报名=错误的如果脐带=5.;身份证=“自我”;helperAddUser(afe.SampleRate、numToRecord、ID);终止

创建一个音频数据存储对象指向此示例中包含的五个音频文件,以及(如果您自己注册的话)刚刚录制的音频文件。此示例中包含的音频文件是内部创建的数据集的一部分,不用于训练UBM。

ads=音频数据存储(pwd);

本例中包含的文件由三个不同的说话者五次说出的“停止”一词组成:BFn(1),BHm(3) ,及帕拉尼姆(1) 。文件名的格式为SpeakerID_RecordingNumber。将数据存储标签设置为相应的扬声器ID。

[~,fileName]=cellfun(@(x)fileparts(x),ads.Files,“UniformOutput”、假);文件名=分裂(文件名,'_');speaker=strcat(文件名(:,1));ads.Labels=categorical(speaker);

在注册过程中使用所有来自您正在注册的演讲者的文件,但只保留一个文件。其余文件用于测试系统。

如果注册标签=ID;其他的注册标签=“BHm”终止forEnrollment=ads.Labels==注册标签;forEnrollment(find(forEnrollment==1,1))=false;adsEnroll=子集(ads,Forenroll);adsTest=子集(ads,~forEnrollment);

使用最大后验(MAP)适应来注册选择的说话者。您可以找到注册算法的详细信息在本例的后面部分.

speakerGMM=帮助人登记(ubm、afe、normFactors、ADSENTROL);

验证

对于测试集中的每个文件,使用似然比测试和阈值确定说话人是注册说话人还是冒名顶替者。

阈值=0.7; 重置(adsTest)虽然hasdata(adsTest)fprintf('要确认的标识:%s\n',enrollLabel)[音频数据,adsInfo]=读取(adsTest);fprintf(“|说话人身份:%s\n”,string(adsInfo.Label))verificationStatus=helperVerify(音频数据、afe、normFactors、speakerGMM、ubm、阈值);如果验证状态fprintf(“|已确认。\n”);其他的fprintf(“|骗子\不);终止终止
身份确认:BHm
|发言人身份:BFn
|冒名顶替者!
身份确认:BHm
|发言人身份:BHm
|确认。
身份确认:BHm
|发言人身份:RPalanim
|冒名顶替者!

该示例的其余部分详细介绍了UBM的创建和注册算法,然后使用常用的报告指标评估系统。

创建通用背景模型

本示例中使用的UBM是经过培训的[1]. 下载并提取数据集。

网址='https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz';downloadFolder=tempdir;datasetFolder=fullfile(downloadFolder,“google_speech”);如果~exist(datasetFolder,“dir”)disp('下载谷歌语音命令数据集(1.9 GB)…'解压(url, datasetFolder)终止

创建一个音频数据存储它指向数据集。使用文件夹名称作为标签。文件夹名称指示数据集中的单词。

ads=音频数据存储(数据集文件夹,“包含子文件夹”符合事实的“标签源”,“folderNames”);

子集数据集仅包含单词“stop”。

ads=子集(ads,ads.Labels==分类(“停下来”));

将标签设置为文件名中编码的唯一说话人ID。说话人ID有时以数字开头:添加“a”添加到所有ID以使名称更加友好。

[~,fileName]=cellfun(@(x)fileparts(x),ads.Files,“UniformOutput”、假);文件名=分裂(文件名,'_');演讲者= strcat (“a”,文件名(:,1));广告标签=分类(说话人);

创建三个数据存储:一个用于注册,一个用于评估验证系统,一个用于培训UBM。注册至少有三个话语的说话人。对于每个说话人,将其中两个话语放入注册集中。其他的将放入测试集中。测试集由所有具有数据集中有一个或多个话语。UBM训练集由剩余话语组成。

numSpeakersToEnroll=10;labelCount = countEachLabel(广告);forEnrollAndTestSet = labelCount {: 1} (labelCount {: 2} > = 3);forEnroll = forEnrollAndTestSet (randi([1,元素个数(forEnrollAndTestSet)], numSpeakersToEnroll, 1));tf = ismember (ads.Labels forEnroll);adsEnrollAndValidate =子集(广告、tf);adsEnroll = splitEachLabel (adsEnrollAndValidate 2);adsTest =子集(广告,ismember (ads.Labels forEnrollAndTestSet));adsTest =子集(adsTest ~ ismember (adsTest.Files adsEnroll.Files));forUBMTraining = ~(ismember(ads.Files,adsTest.Files) | ismember(ads.Files, adsenrollerfiles)); adsTrainUBM = subset(ads,forUBMTraining);

读取培训数据存储并侦听文件。重置数据存储。

[audioData,audioInfo]=读取(adsTrainUBM);fs=audioInfo.SampleRate;声音(audioData,fs)重置(adsTrainUBM)

特征提取

在本例的特征提取管道中,您:

  1. 使音频正常化

  2. 使用侦探讲话从音频中删除非语音区域的步骤

  3. 从音频中提取特征

  4. 规范化的特性

  5. 应用倒谱均值归一化

首先,创建一个音频特征提取器对象以提取MFCC。为帧指定40毫秒的持续时间和10毫秒的跃点。

窗口持续时间=0.04;hopDuration=0.01;windowSamples=圆形(windowDuration*fs);hopSamples=圆形(hopDuration*fs);重叠样本=窗口样本-hopSamples;afe=音频特征提取程序(...“SampleRate”,财政司司长,...“窗口”,hann(窗口样本,“周期性”),...“重叠长度”overlapSamples,......“mfcc”,对);

使音频正常化。

audioData=audioData./max(abs(audioData));

使用侦探讲话函数定位音频剪辑中的语音区域。调用侦探讲话没有任何输出参数来可视化检测到的语音区域。

detectSpeech(音频数据,fs);

呼叫侦探讲话再次。这次,返回语音区域的索引,并使用它们从音频剪辑中删除非语音区域。

idx = detectSpeech (audioData, fs);audioData = audioData (idx (1,1): idx(1、2);

呼叫提取音频特征提取器对象从音频数据中提取特征。从中输出的大小提取numHops-借-NUM特征.

特征=提取(afe,音频数据);[numHops,numFeatures]=大小(特征)
numHops=66
numFeatures=13

通过全局均值和方差对特征进行规范化。示例的下一部分将介绍如何计算全局均值和方差。现在,只需使用已加载的预先计算的均值和方差。

特征=(特征'-normFactors.Mean./normFactors.variation;

应用局部倒谱平均归一化。

特征=特征-平均值(特征,“全部”);

特征提取管道封装在helper函数中,辅助特征提取.

计算全局特征归一化因子

从数据集中提取所有特征。如果你有并行计算工具箱™, 确定数据集的最佳分区数,并将计算分散到可用的工作区。如果没有并行计算工具箱™, 使用单个分区。

featuresAll = {};如果~z~我是空的(“平行”) numPar = 18;其他的numPar=1;终止

使用辅助函数,辅助特征提取,从数据集中提取所有要素。正在调用辅助特征提取如果第三个参数为空,则执行中所述的特征提取步骤特征提取除了用全局均值和方差进行归一化。

帕弗ii=1:numPar adsPart=partition(ads,numPar,ii);featuresPart=单元格(0,numel(adsPart.Files));对于iii=1:numel(adsPart.Files)audioData=read(adsPart);featuresPart{iii}=helperFeatureExtraction(audioData,afe,[]);终止featuresAll=[featuresAll,featuresPart];终止
正在使用连接到并行池的“本地”配置文件启动并行池(parpool)(工作进程数:6)。
allFeatures=cat(2,featuresAll{:});

计算每个特征的平均值和方差。

标准因子。平均值=平均值(所有特征,2,“奥米南”);normalfactors.STD=STD(所有特征,[],2,“奥米南”);

初始化GMM

通用背景模型是高斯混合模型。定义混合中成分的数量。[2]对于与文本无关的系统,建议超过512。组件权重开始均匀分布。

numComponents=32; α=一(1,numComponents)/numComponents;

将随机初始化用于西格玛每个GMM组件的。创建一个结构来保存必要的UBM信息。

mu=randn(numFeatures,numComponents);sigma=rand(numFeatures,numComponents);ubm=struct(“成分比例”阿尔法“穆”,穆,“西格玛”,西格玛);

利用期望最大化训练UBM

将GMM拟合到训练集以创建UBM。使用期望最大化算法。

期望最大化算法是递归的。首先,定义停止标准。

maxIter=20;targetLog似然=0;tol=0.5;pastL=-inf;%前一个对数似然的初始化

在循环中,使用期望最大化算法训练UBM。

抽搐对于iter=1:maxIter%期望值N=零(1,numComponents);F=零(numFeatures、numComponents);S=零(numFeatures、numComponents);L=0;帕弗ii = 1:numPar adsPart = partition(adsTrainUBM,numPar,ii);虽然hasdata(adsPart) audioData = read(adsPart);%提取特征特征=辅助特征提取(音频数据、afe、标准因子);%计算后验对数似然对数似然=helpergmmlog似然(特征,ubm);%计算后验归一化概率logLikelihoodSum=helperLogSumExp(loglikelike);gamma=exp(对数似然-对数似然和)';%计算Baum-Welch统计量n=总和(伽马,1);f=特征*伽马;s=(特征。*特征)*伽马;%更新足够的话语统计数据N=N+N;F=F+F;S=S+S;%更新日志可能性L=L+总和(对数似然总和);终止终止%打印当前日志可能性,如果符合条件则停止。L=L/numel(adsTrainUBM.Files);fprintf('\滴定%d,对数似然= %0.3f\n',国际热核实验堆,L)如果L>目标似然度| | abs(pastL-L)打破其他的pastL=L;终止%最大化N = max (N, eps);于是。ComponentProportion = max (N / (N),每股收益);于是。ComponentProportion = ubm.ComponentProportion /笔(ubm.ComponentProportion);于是。亩= bsxfun(@rdivide,F,N); ubm.sigma = max(bsxfun(@rdivide,S,N) - ubm.mu.^2,eps);终止
迭代3,Log-likelihood = -522.670迭代4,Log-likelihood = -517.458迭代5,Log-likelihood = -514.852迭代10,Log-likelihood = -509.788,迭代11,Log-likelihood = -508.529,迭代12,Log-likelihood = -508.032
fprintf('UBM培训在%0.2f秒内完成。\n',toc)
UBM训练在32.31秒内完成。

注册:最大后验概率(MAP)估计

拥有通用背景模型后,您可以注册演讲者并根据演讲者调整UBM。[2]表明适应相关系数为16。相关系数控制将UBM的每个组件移动到说话人GMM的程度。

relevanceFactor=16;speakers=unique(adsEnroll.Labels);numSpeakers=numel(speakers);gmmCellArray=cell(numSpeakers,1);tic帕弗ii=1:numSpeakers%将数据存储子集设置为您正在调整的演讲者。adsTrainSubset=子集(adsnroll,adsnroll.Labels==说话人(ii));N=零(1,numComponents);F=零(numFeatures、numComponents);S=零(numFeatures、numComponents);虽然hasdata(adsTrainSubset) audioData = read(adsTrainSubset);特点= helperFeatureExtraction (audioData afe normFactors);[n、f、s、l] = helperExpectation(特性,于是);N=N+N;F=F+F;S=S+S;终止%确定最大似然gmm=helperMaximization(N,F,S);确定适应系数α=N./(N+相关因子);%调整手段gmm.mu=alpha.*gmm.mu+(1-alpha)。*ubm.mu;%调整方差gmm.sigma=alpha.*(S/N)+(1-alpha)。*(ubm.sigma+ubm.mu.^2)-gmm.mu.^2;gmm.sigma=最大值(gmm.sigma,每股收益);%调整重量gmm.componentproporty=alpha.*(N/和(N))+(1-α)。*ubm.componentproporty;gmm.componentproperty=gmm.componentproperty./sum(gmm.componentproperty);gmmCellArray{ii}=gmm;终止fprintf('注册在%0.2f秒内完成。\n',toc)
注册在0.27秒内完成。

出于记帐的目的,将GMM的单元格数组转换为结构,其中字段为speaker id,值为GMM结构。

对于i=1:numel(gmmCellArray)enrolledGMMs.(string(speakers(i))=gmmCellArray{i};终止

评价

说话人错误拒绝率

讲话者误拒率(FRR)是给定讲话者被错误拒绝的比率。使用已知的说话人集来确定一组阈值的说话人错误拒绝率。

演讲者=独特(adsEnroll.Labels);numSpeakers =元素个数(扬声器);llr =细胞(numSpeakers, 1);抽搐帕弗speakerIdx=1:numSpeakers localGMM=enrolledGMMs.(字符串(speakerIdx));adsTestSubset=subset(adsTest,adsTest.Labels==扬声器(speakerIdx));llrPerSpeaker=0(numel(adsTestSubset.Files),1);对于fileIdx=1:numel(adsTestSubset.Files)audioData=read(adsTestSubset);[x,numFrames]=helperFeatureExtraction(audioData,afe,normFactors);loglikelization=helpergmmloglization(x,localGMM);Lspeaker=helperLogSumExp(loglization);loglikelization=helpergmmloglization(x,ubm);Lubm=helperloglikelization;llrPerSpeaker(fileIdx)=平均值(中位数(Lspeaker-Lubm,3));终止llr{speakerIdx}=llrPerSpeaker;终止fprintf('以%0.2f秒计算的错误拒绝率。\n',toc)
在0.20秒内计算的错误拒绝率。

将错误拒绝率绘制为阈值的函数。

llr=cat(1,llr{:});阈值=-0.5:0.01:2.5;FRR=平均值(llr<阈值);绘图(阈值,FRR*100)标题(“错误拒绝率(FRR)”)xlabel(“门槛”)伊拉贝尔(“错误地拒绝(%)”网格)在…上

说话人虚假接受

speaker false acceptance rate(FAR)是不属于已注册说话人的话语被错误地接受为属于已注册说话人的速率。使用已知说话人集确定一组阈值的说话人FAR。使用与确定FRR相同的阈值集。

speakersTest=unique(adsTest.Labels);llr=单元(numSpeakers,1);抽搐帕弗speakerIdx=1:numel(speakers)localGMM=enrolledGMMs.(字符串(speakers(speakerIdx));adsTestSubset=subset(adsTest,adsTest.Labels~=speakers(speakerIdx));llrPerSpeaker=0(numel(adsTestSubset.Files),1);对于fileIdx=1:numel(adsTestSubset.Files)audioData=read(adsTestSubset);[x,numFrames]=helperFeatureExtraction(audioData,afe,normFactors);loglikelization=helpergmmloglization(x,localGMM);Lspeaker=helperLogSumExp(loglization);loglikelization=helpergmmloglization(x,ubm);Lubm=helperloglikelization;llrPerSpeaker(fileIdx)=平均值(中位数(Lspeaker-Lubm,3));终止llr{speakerIdx}=llrPerSpeaker;终止fprintf('FAR计算时间为%0.2f秒。\n',toc)
FAR计算时间为22.64秒。

根据阈值绘制距离。

llr=cat(1,llr{:});FAR=mean(llr>thresholds);plot(thresholds,FAR*100)标题(“错误接受率(FAR)”)xlabel(“门槛”)伊拉贝尔(“错误地拒绝(%)”网格)在…上

检测误差权衡(DET)

在说话人验证系统中移动阈值时,需要在FAR和FRR之间进行权衡。这称为检测错误权衡(DET),通常用于二进制分类问题。

x1=FAR*100;y1=FRR*100;绘制(x1,y1)网格在…上xlabel(“错误接受率(%)”)伊拉贝尔(“错误拒绝率(%)”)头衔(“检测误差折衷(DET)曲线”)

等错误率(EER)

要比较多个系统,您需要结合FAR和FRR性能的单个度量。为此,确定相等错误率(EER),这是FAR和FRR曲线相交的阈值。实际上,EER阈值可能不是最佳选择。例如,如果将说话人验证用作电汇多重认证方法的一部分,则FAR很可能比FRR更重要。

[~,EERThresholdIdx] = min(abs(FAR - FRR));EERThreshold =阈值(EERThresholdIdx);无论何时=意味着([(EERThresholdIdx), FRR (EERThresholdIdx)]);情节(阈值,“k”,...阈值,FRR,“b”,...EERThreshold,无论何时,“罗”,“MarkerFaceColor”,“r”)头衔(斯普林特)('等错误率= %0.2f,阈值= %0.2f',EER,EER)xlabel(“门槛”)伊拉贝尔(“错误率”)传说(“错误接受率(FAR)”,“错误拒绝率(FRR)”,“等错误率(EER)”网格)在…上

如果改变UBM培训的参数,考虑使用新的通用背景模型重新整理MAT文件,音频特征提取器,以及常模因素。

重新保存=错误的如果重新保存保存('SpeakerificationExampleData.mat',“于是”,“afe”,“正常因素”)终止

万博1manbetx辅助功能

将用户添加到数据集

作用helperAddUser(fs、numToRecord、ID)%创建音频设备读取器从音频设备读取设备阅读器=音频设备阅读器(“SampleRate”,fs);%初始化变量numRecordings=1;audioIn=[];%记录请求的号码虽然numRecordings<=numtorecords fprintf('说一次“停止”(记录%i的%i)…',numRecordings,numtorecording)tic虽然toc<2 audioIn=[audioIn;deviceReader()];终止fprintf(“完成。\ n”)idx=检测语音(音频输入,fs);如果isempty(idx)fprintf('未检测到语音。请再试一次。\n')其他的音频写入(sprintf)(“%s\u%i.flac”,ID,numRecordings),audioIn,fs)numRecordings=numRecordings+1;终止暂停(0.2)音频输入=[];终止%释放设备释放(deviceReader)终止

登记

作用speakerGMM=HelperRoll(ubm、afe、normFactors、adsEnroll)%初始化numComponents=numel(ubm.组件比例);numFeatures=大小(单位:μ,1);N=零(1,numComponents);F=零(numFeatures、numComponents);S=零(numFeatures、numComponents);NumFrames=0;虽然hasdata(adsEnroll)%从注册数据存储中读取audioData =阅读(adsEnroll);% 1. 提取特征并应用特征规范化[features,numFrames]=helperFeatureExtraction(音频数据、afe、标准因子);% 2. 计算后验概率。使用它来确定%足够的统计数据(计数、第一和第二时刻)[n,f,s]=帮助预期(特征,ubm);%3.更新足够的统计数据N=N+N;F=F+F;S=S+S;NumFrames=NumFrames+NumFrames;终止%创建最大化期望值的高斯混合模型speakerGMM=helperMaximization(N,F,S);%调整UBM以创建说话人模型。使用16的相关系数,%如[2]所提议的那样相关因子=16;确定适应系数α=N./(N+相关因子);%调整手段speakergm.mu=alpha.*speakergm.mu+(1-alpha)。*ubm.mu;%调整方差speakergm.sigma=alpha.*(S/N)+(1-alpha.*(ubm.sigma+ubm.mu.^2)-speakerGMM.mu.^2;speakergm.sigma=max(speakergm.sigma,eps);%调整重量speakergm.ComponentProportion=alpha.*(N/和(N))+(1-alpha)。*ubm.ComponentProportion;speakergm.ComponentProportion=speakergm.ComponentProportion./sum(speakergm.ComponentProportion);终止

验证

作用verificationStatus=helperVerify(音频数据、afe、normFactors、speakerGMM、ubm、阈值)%提取特征x = helperFeatureExtraction (audioData afe normFactors);%确定音频来自适应的GMM的日志可能性%演讲者post=helpergmmloglike(x,speakerGMM);Lspeaker=helperLogSumExp(post);%确定音频来自GMM的对数可能性适合所有人%演讲者帖子= helperGMMLogLikelihood (x,于是);Lubm = helperLogSumExp (post);%计算所有帧的比率。应用移动中值滤波器%删除异常值,然后取各帧的平均值llr=平均值(平均值(Lspeaker-Lubm,3));如果llr>阈值验证状态=真;其他的验证状态=假;终止终止

特征提取

作用[features,numFrames]=helperFeatureExtraction(音频数据、afe、标准因子)%正常化audioData=audioData/max(abs(audioData(:)));%防患于未然音频数据(isnan(音频数据))=0;%分离语音片段%本例中使用的数据集每个audioData有一个单词(如果更多)%如果检测到一个以上的语音段,只需使用最长的%检测到。idx=检测语音(音频数据,afe.采样器);如果大小(idx,1)>1[~,seg]=max(idx(:,2)-idx(:,1));其他的seg=1;终止音频数据=音频数据(idx(seg,1):idx(seg,2));%特征提取特点=提取(afe audioData);%功能正常化如果~isempty(normFactors) features = (features-normFactors. mean ')./normFactors. std ';终止特点=功能”;倒谱平均减法%(用于信道噪声)如果~isempty(normalfactors)特征=特征-平均值(特征,“全部”);终止numFrames=大小(特征,2);终止

对数和指数

作用y=helperLogSumExp(x)%计算日志和指数,同时避免溢出a=max(x,[],1);y=a+sum(exp(bsxfun(@减号,x,a)),1);终止

预料

作用[N,F,S,L]=帮助预期(特征,gmm)post=帮助预期(特征,gmm);%对帧上的可能性求和L=helperLogSumExp(post);%计算足够的统计数据伽马=经验值(L后)';N=总和(伽马,1);F=特征*伽马;S=(特征。*特征)*伽马;L=总和(L);终止

最大化

作用gmm=helperMaximization(N,F,S)N=max(N,eps);gmm.成分比例=最大值(N/总和(N),每股收益);gmm.mu=bsxfun(@rdivide,F,N);gmm.sigma=max(bsxfun(@rdivide,S,N)-gmm.mu.^2,eps);终止

高斯多分量混合对数似然

作用L=helpergmmloglikelike(x,gmm)xminusum=repmat(x,1,1,numel(gmm.ComponentProportion))-permute(gmm.mu,[1,3,2]);permuteSigma=permute(gmm.sigma,[1,3,2]);Lunweighted=-0.5*(总和(log(permuteSigma),1)+总和(bsxfun(@times,xMinusMu,(bsxfun,[rdivide 1,3,2]),1)+大小(gmm.mu 1)*对数,[2*permu温度,[1,2])));如果尺寸(温度,1)==1%如果只有一个帧,则后面的单例维度为%在排列中删除。这说明了边缘情况温度=温度';终止L=bsxfun(@plus,temp,log(gmm.ComponentProportion));终止

工具书类

[1] Warden P.“语音命令:单词语音识别的公共数据集”,2017年。可从https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz. 谷歌2017版权所有。Speech Commands数据集根据Creative Commons Attribute 4.0许可证获得许可,可在以下位置获得:https://creativecommons.org/licenses/by/4.0/legalcode.

雷诺兹,道格拉斯·A,托马斯·f·夸蒂里,罗伯特·b·邓恩。“使用自适应高斯混合模型的说话人验证”。数字信号处理10,第1-3号(2000):第19-41条。https://doi.org/10.1006/dspr.1999.0361.