主要内容

说话人识别使用x-vectors

说话人识别的答案”说话的是谁?”的问题。说话人识别通常分为两个任务:演讲者识别演讲者验证。在说话人识别,演讲者被认为通过比较他们的演讲闭集的模板。在议长验证,演讲者是被比较的可能性演讲属于一个特定的演讲者与预定的阈值。传统的机器学习方法在这些任务在理想条件下表现良好。例如说话人识别使用传统的机器学习方法,明白了说话者识别使用沥青和MFCC(音频工具箱)演讲者验证使用i-Vectors(音频工具箱)。音频工具箱™提供ivectorSystem(音频工具箱)封装能力训练的一个矢量i系统,招收扬声器或其他音频标签,评估系统决定阈值,并确定或验证使用者或其他音频标签。

在不利的情况下,深度学习的方法x-vectors已被证明为许多场景和应用程序实现先进的结果[1]。i-vectors向量x系统是一个进化的最初的任务开发验证。

在这个例子中,您将开发一个向量x系统。首先,你训练一个时滞神经网络(TDNN)进行识别。然后火车x-vector-based议长的传统的后端验证系统:LDA投影矩阵和PLDA模型。然后执行议长验证使用TDNN和后端降维和得分。向量x系统后端,或分类器,是一样的矢量i系统的开发。在后台的详细信息,请参见演讲者验证使用i-Vectors(音频工具箱)ivectorSystem(音频工具箱)

演讲者Diarization使用x-vectors(音频工具箱),你使用向量x系统执行议长diarization训练在这个例子。演讲者diarization回答一个问题,“谁说当?”。

在这个例子中,你会发现生活控制可调参数。改变控制不重新运行的例子。如果你改变一个控制,您必须重新运行的例子。

数据集管理

这个示例使用LibriSpeech数据集的一个子集[2]。LibriSpeech数据集是一个大型语料库的读英语演讲在16岁千赫采样。数据来源于有声读物读LibriVox项目。下载100小时LibriSpeech训练数据的子集,清洁发展,和干净的测试集。

dataFolder = tempdir;datasetTrain = fullfile (dataFolder,“LibriSpeech”,“培训-清洗- 100”);如果~ datasetExists (datasetTrain)文件名=“火车——清洁- 100. tar.gz”;url =“http://www.openSLR.org/resources/12/”+文件名;gunzip (url, dataFolder);unzippedFile = fullfile (dataFolder,文件名);解压(unzippedFile {1} (1: end-3) dataFolder);结束datasetDev = fullfile (dataFolder,“LibriSpeech”,“dev-clean”);如果~ datasetExists (datasetDev)文件名=“dev-clean.tar.gz”;url =“http://www.openSLR.org/resources/12/”+文件名;gunzip (url, dataFolder);unzippedFile = fullfile (dataFolder,文件名);解压(unzippedFile {1} (1: end-3) dataFolder);结束数据集= fullfile (dataFolder,“LibriSpeech”,“清洁测试”);如果~ datasetExists(集)文件名=“test-clean.tar.gz”;url =“http://www.openSLR.org/resources/12/”+文件名;gunzip (url, dataFolder);unzippedFile = fullfile (dataFolder,文件名);解压(unzippedFile {1} (1: end-3) dataFolder);结束

创建audioDatastore(音频工具箱)指向的对象数据。演讲者标签编码的文件名。将数据存储到火车,验证集和测试集。您将使用这些集训练、验证和测试TDNN。

adsTrain = audioDatastore (datasetTrain IncludeSubfolders = true);adsTrain。标签=分类(extractBetween (adsTrain.Files fullfile (datasetTrain filesep) filesep));adsDev = audioDatastore (datasetDev IncludeSubfolders = true);adsDev。标签=分类(extractBetween (adsDev.Files fullfile (datasetDev filesep) filesep));adsEvaluate = audioDatastore(数据集,IncludeSubfolders = true);adsEvaluate。标签=分类(extractBetween (adsEvaluate.Files fullfile(数据集,filesep) filesep));

分离audioDatastore对象分为五组:

  • adsTrain——包含TDNN和后端分类器的训练集。

  • adsValidation——包含验证组评估TDNN培训进展。

  • adsTest——包含测试集来评估TDNN议长识别的性能。

  • adsEnroll——包含招生组评估检测误差向量x的权衡扬声器系统验证。

  • adsDET——包含评价组用于确定检测误差向量x的权衡扬声器系统验证。

[adsTrain, adsValidation adsTest] = splitEachLabel (adsTrain, 0.8, 0.1, 0.1,“随机”);[adsEnroll, adsLeftover] = splitEachLabel (adsEvaluate 3“随机”);adsDET = audioDatastore ([adsLeftover.Files; adsDev.Files]);adsDET。标签= [adsLeftover.Labels; adsDev.Labels];

你可以减少训练和检测错误权衡这个示例中所使用的数据集来加速运行时性能为代价的。一般来说,减少数据集开发和调试是一个很好的实践。

speedupExample =;如果speedupExample adsTrain = splitEachLabel (adsTrain 5);adsValidation = splitEachLabel (adsValidation 2);adsDET = splitEachLabel (adsDET 5);结束

特征提取

创建一个audioFeatureExtractor(音频工具箱)对象提取30 MFCCs 30 ms损害10 ms跳窗户。数据集是16 kHz的采样率。

fs = 16 e3;windowDuration =0.03;hopDuration =0.01;windowSamples =圆(windowDuration * fs);hopSamples =圆(hopDuration * fs);overlapSamples = windowSamples - hopSamples;numCoeffs =30.;afe = audioFeatureExtractor (SampleRate = fs,窗口=损害(windowSamples,“周期”),OverlapLength = overlapSamples,mfcc = true);setExtractorParameters (afe“mfcc”,NumCoeffs = NumCoeffs)

创建一个预处理适用于音频转换数据存储和输出特性。支持函数金宝app,xVectorPreprocess,执行语音检测,提取特征区域的演讲。当参数被设置为言论,检测区域连接在一起。

adsTrainTransform =变换(adsTrain @ (x) xVectorPreprocess (x, afe段= false, MinimumDuration = 0.5));特点=预览(adsTrainTransform)
特点=1×1单元阵列{30×363单}

在一个循环,从训练集提取所有功能。如果你有并行计算工具箱™,然后计算分布在多个工人。

numPar = numpartitions (adsTrain);特点=细胞(1、numPar);parfor2 = 1:numPar adsPart =分区(adsTrainTransform、numPar ii);N =元素个数(adsPart.UnderlyingDatastores {1} .Files);f =细胞(1,N);jj = 1: N f {jj} =阅读(adsPart);结束功能{2}=猫(2 f {:});结束

连接的特性,然后拯救地球结构的平均值和标准偏差。您将使用这些因素规范化的特点。

特点=猫(2,特征{:});特点=猫(2,特征{:});因素=结构(“的意思是”,意味着(功能,2),“性病”性病(特性、0 2));清晰的特性f

创建一个新的变换为训练集数据存储,这一次指定和归一化因素作为真正的。现在,特点是标准化的全球平均值和标准偏差,然后文件级别的意思。个人演讲地区检测到不连接。输出是一个表第一个变量包含特征矩阵和第二个变量包含标签。

adsTrainTransform =变换(adsTrain @ (x, myInfo) xVectorPreprocess (x, afe myInfo,= = true,因素因素,MinimumDuration = 0.5),IncludeInfo = true);featuresTable =预览(adsTrainTransform)
featuresTable =3×2表特性标签售予______ 1034{30×142单}{30×64单}1034{30×157单}1034

应用相同的转换来验证、测试入学,侦破集。

adsValidationTransform =变换(adsValidation @ (x, myInfo) xVectorPreprocess (x, afe myInfo,= = true,因素因素,MinimumDuration = 0.5),IncludeInfo = true);adsTestTransform =变换(adsTest @ (x, myInfo) xVectorPreprocess (x, afe myInfo,= = true,因素因素,MinimumDuration = 0.5),IncludeInfo = true);adsEnrollTransform =变换(adsEnroll @ (x, myInfo) xVectorPreprocess (x, afe myInfo,= = true,因素因素,MinimumDuration = 0.5),IncludeInfo = true);adsDETTransform =变换(adsDET @ (x, myInfo) xVectorPreprocess (x, afe myInfo,= = true,因素因素,MinimumDuration = 0.5),IncludeInfo = true);

x矢量特征提取模型

在本例中,您定义了向量x功能器模型[1]一层图和训练它使用自定义训练循环。这种模式允许您进行预处理mini-batches和修剪的序列长度一致。

表总结了体系结构的网络中描述[1]在这个例子中并实施。T是帧总数(随着时间的推移,特征向量)音频信号。N是类的数量在训练集(扬声器)。

定义网络。你可以改变模型大小增加或减少numFilters参数。

numFilters =512年;dropProb = 0.2;numClasses =元素个数(独特(adsTrain.Labels));层= [sequenceInputLayer (Name = afe.FeatureVectorLength最小长度= 15日“输入”)convolution1dLayer (5 numFilters DilationFactor = 1,名字=“conv_1”)batchNormalizationLayer (Name =“BN_1”)dropoutLayer (dropProb Name =“drop_1”)reluLayer (Name =“act_1”)convolution1dLayer (3 numFilters DilationFactor = 2, Name =“conv_2”)batchNormalizationLayer (Name =“BN_2”)dropoutLayer (dropProb Name =“drop_2”)reluLayer (Name =“act_2”)convolution1dLayer (3 numFilters DilationFactor = 3 =“conv_3”)batchNormalizationLayer (Name =“BN_3”)dropoutLayer (dropProb Name =“drop_3”)reluLayer (Name =“act_3”)convolution1dLayer (1 numFilters DilationFactor = 1,名字=“conv_4”)batchNormalizationLayer (Name =“BN_4”)dropoutLayer (dropProb Name =“drop_4”)reluLayer (Name =“act_4”1500年)convolution1dLayer (1, DilationFactor = 1,名字=“conv_5”)batchNormalizationLayer (Name =“BN_5”)dropoutLayer (dropProb Name =“drop_5”)reluLayer (Name =“act_5”)statisticsPooling1dLayer (Name =“statistics_pooling”)fullyConnectedLayer (numFilters Name =“fc_1”)batchNormalizationLayer (Name =“BN_6”)dropoutLayer (dropProb Name =“drop_6”)reluLayer (Name =“act_6”)fullyConnectedLayer (numFilters Name =“fc_2”)batchNormalizationLayer (Name =“BN_7”)dropoutLayer (dropProb Name =“drop_7”)reluLayer (Name =“act_7”)fullyConnectedLayer (numClasses Name =“fc_3”)softmaxLayer (Name =“softmax”));dlnet = dlnetwork (layerGraph(层));

的模型需要统计池被实现为一个自定义图层放置在当前文件夹当你打开这个例子。显示自定义层的内容。

类型(“statisticsPooling1dLayer.m”)
classdef statisticsPooling1dLayer < nnet.layer。层& nnet.layer。Formattable %这个类只有在这个例子中使用。它可能改变或%在将来发布的版本中移除。方法函数= statisticsPooling1dLayer(选项)参数的选择。Name = "这结束。= options.Name名称;结束函数X =预测(~,X) X = dlarray (stripdims([意味着(X, 3); std (X 0 3)]),“CB”);结束函数X =前进(~,X) X = X + 0.0001 *兰德(大小(X),“单”);X = dlarray (stripdims([意味着(X, 3); std (X 0 3)]),“CB”);结束结束结束

火车模型

使用minibatchqueue创建一个mini-batch队列训练数据。mini-batch大小设置为适合您的硬件。

miniBatchSize =256年;兆贝可= minibatchqueue (adsTrainTransform,MiniBatchSize = MiniBatchSize,MiniBatchFormat = [“施”,”“),MiniBatchFcn = @preprocessMiniBatch,OutputEnvironment =“汽车”);

设置数量的训练时期,最初的学习速率,学习速率下降时期,学习速度下降因子,每个时代的验证。

numEpochs =5;learnRate =0.001;gradDecay = 0.5;sqGradDecay = 0.999;trailingAvg = [];trailingAvgSq = [];LearnRateDropPeriod =2;LearnRateDropFactor =0.1;

显示培训进展,支持对象初始化金宝appprogressPlotter。支持对象金宝app,progressPlotter,被放置在当前文件夹当你打开这个例子。

训练循环运行。

类=独特(adsTrain.Labels);页= progressPlotter (string(类));迭代= 0;时代= 1:numEpochs%洗牌mini-batch队列洗牌(兆贝可)hasdata(兆贝可)%更新迭代计数器迭代=迭代+ 1;%得到mini-batch mini-batch队列[dlX Y] =下一个(兆贝可);%评估模型梯度、州和使用dlfeval和modelGradients损失函数(渐变,dlnet。损失,预测]= dlfeval (@modelGradients, dlnet dlX Y);%更新使用亚当优化网络参数[dlnet, trailingAvg trailingAvgSq] = adamupdate (dlnet、渐变trailingAvg trailingAvgSq,迭代,learnRate、gradDecay sqGradDecay eps (“单身”));%更新培训进展阴谋updateTrainingProgress (pp、时代=时代,迭代=迭代,LearnRate = LearnRate =预测,预测目标= Y,损失=损失)结束%通过模型通过验证数据[predictionValidation, labelsValidation] = predictBatch (dlnet adsValidationTransform);predictionValidation = onehotdecode (predictionValidation字符串(类),1);%更新培训进展情节与验证的结果updateValidation (pp、迭代=迭代预测= predictionValidation目标= labelsValidation)%更新学习速率如果快速眼动(时代,LearnRateDropPeriod) = = 0 learnRate = learnRate * LearnRateDropFactor;结束结束

评估TDNN说话人识别精度使用了测试集。支持函数,金宝apppredictBatch,对预测计算并行计算工具箱™。解码的预测,然后计算出预测精度。

[predictionTest,目标]= predictBatch (dlnet adsTestTransform);predictionTest = onehotdecode (predictionTest字符串(类),1);精度=意味着(目标(:)= = predictionTest (:))
精度= 0.9460

训练向量x系统后端

演讲者向量x系统验证,TDNN你训练用于输出一个嵌入层。嵌入的输出层(“fc_1”在这个例子中)是“x-vectors”一个向量x系统。

后端(或分类)的一个向量x系统是一样的一个矢量i系统的后端。在算法的详细信息,请参见ivectorSystem(音频工具箱)演讲者验证使用i-Vectors(音频工具箱)

从火车提取x-vectors集。

[xvecsTrain, labelsTrain] = predictBatch (dlnet adsTrainTransform,输出=“fc_1”);

创建一个线性判别分析(LDA)投影矩阵,以减少x-vectors的维度。LDA试图最小化之间的内部类方差和方差最大化扬声器。

numEigenvectors =150年;projMat = helperTrainProjectionMatrix (xvecsTrain labelsTrain numEigenvectors);

应用LDA x-vectors投影矩阵。

xvecsTrainP = projMat * xvecsTrain;

火车G-PLDA模型进行评分。

numIterations =3;numDimensions =150年;plda = helperTrainPLDA (xvecsTrainP labelsTrain、numIterations numDimensions);

评估向量x系统

发言者验证系统验证,他们声称是。扬声器可以验证之前,他们必须进入系统。登记在系统意味着系统有一个演讲者的模板向量x表示。

登记人

提取x-vectors伸出的数据集,adsEnroll

[xvecsEnroll, labelsEnroll] = predictBatch (dlnet adsEnrollTransform,输出=“fc_1”);

应用LDA x-vectors投影矩阵。

xvecsEnrollP = projMat * xvecsEnroll;

为每个演讲者创建模板x-vectors x-vectors的平均个人扬声器在登记文件。

uniqueLabels =独特(labelsEnroll);enrollmentTable = cell2table(细胞(0,2),VariableNames = [“xvector”,“NumSamples”]);2 = 1:元素个数(uniqueLabels) idx = uniqueLabels (ii) = = labelsEnroll;wLocalMean =意味着(xvecsEnrollP (:, idx), 2);localTable =表({wLocalMean}, (sum (idx)),VariableNames = [“xvector”,“NumSamples”),RowNames =字符串(uniqueLabels (ii)));enrollmentTable = [enrollmentTable; localTable];% #好< AGROW >结束

演讲者验证系统需要设置一个阈值,平衡误接受的概率的概率(FA)和一个错误的拒绝(FR),根据您的应用程序的要求。确定阈值,满足您FA / FR需求,评估系统的检测误差权衡。

[xvecsDET, labelsDET] = predictBatch (dlnet adsDETTransform,输出=“fc_1”);xvecsDETP = projMat * xvecsDET;detTable = helperDetectionErrorTradeoff (xvecsDETP labelsDET、enrollmentTable plda);

阴谋的结果检测错误权衡评价PLDA得分和余弦相似度得分(CSS)。

图绘制(detTable.PLDA.Threshold detTable.PLDA.FAR,detTable.PLDA.Threshold detTable.PLDA.FRR)曾经= helperEqualErrorRate (detTable.PLDA);标题([“议长验证”,“检测错误权衡”,“PLDA得分”,“平等错误率= "+曾经]);包含(“阈值”)ylabel (“出错率”)传说([“远”,“FRR”])

图绘制(detTable.CSS.Threshold detTable.CSS.FAR,detTable.CSS.Threshold detTable.CSS.FRR)曾经= helperEqualErrorRate (detTable.CSS);标题([“议长验证”,“检测错误权衡”,“余弦相似性得分”,“平等错误率= "+曾经]);包含(“阈值”)ylabel (“出错率”)传说([“远”,“FRR”])

引用

[1]斯奈德,大卫,et al。“x-vectors:健壮款嵌入的说话人识别。”2018年IEEE国际会议音响、演讲和信号处理(ICASSP),2018岁的IEEE 5329 - 33页。DOI.org (Crossref),doi: 10.1109 / ICASSP.2018.8461375。

[2]诉Panayotov g·陈,d . Povey和s . Khudanpur”Librispeech:一种基于公共领域的ASR语料库有声书本,“2015年IEEE国际会议音响、演讲和信号处理(ICASSP),布里斯班昆士兰,2015年,页。5206 - 5210 . doi: 10.1109 / ICASSP.2015.7178964

金宝app支持功能

特征提取和标准化

函数(输出,myInfo) = xVectorPreprocess (afe audioData, myInfo, nvargs)%这个函数只在本例中使用。它可能改变或%在将来发布的版本中移除。参数audioData afe myInfo = [] nvargs。= []nvargs因素。部分= true;nvargs。MinimumDuration = 1;nvargs。使用GPU = false;结束%如果请求在GPU如果nvargs。使用GPU audioData = gpuArray(audioData);结束%的规模audioData = audioData / max (abs (audioData (:)));%防止nanaudioData (isnan (audioData)) = 0;%确定地区的言论mergeDur = 0.2;%秒idx = detectSpeech (audioData afe.SampleRate MergeDistance = afe.SampleRate * mergeDur);%如果区域小于MinimumDuration秒,放弃。如果nvargs。段idxToRemove = (idx(:,2)-idx(:,1))结束%提取特征numSegments =大小(idx, 1);特点=细胞(numSegments, 1);2 = 1:numSegments temp =(单(提取(afe, audioData (idx (2, 1): idx (2, 2))))) ';如果isempty(临时)temp = 0(30日15日“单身”);结束{二}= temp;特性结束%标准化特性如果~ isempty (nvargs.Factors)特性= cellfun (@ (x) (x-nvargs.Factors.Mean)。/ nvargs.Factors.STD,特性,UniformOutput = false);结束% Cepstral意味着减法(信道噪声)如果~ isempty (nvargs.Factors) fileMean =意味着(猫(2,特性{:}),“所有”);特点= cellfun (@ (x) x - fileMean,特性,UniformOutput = false);结束如果~ nvargs。段特点={cat(2,features{:})};结束如果isempty (myInfo)输出=功能;其他的标签= repelem (myInfo.Label元素个数(特性),1);输出=表(特性、标签);结束结束

计算模型梯度和更新状态

函数[梯度、州损失,YPred] = modelGradients (dlnet, X, Y)%这个函数只在本例中使用。它可能改变或%在将来发布的版本中移除。向前(YPred、州)= (dlnet X);损失= crossentropy (YPred Y);梯度= dlgradient(损失、dlnet.Learnables);损失=双(收集(extractdata(损失)));结束

预处理Mini-Batch

函数(序列、标签)= preprocessMiniBatch(序列、标签)%这个函数只在本例中使用。它可能改变或%在将来发布的版本中移除。trimDimension = 2;长度= cellfun (@ (x)大小(x, trimDimension)序列);最小长度= min(长度);序列= cellfun (@ (x) randomTruncate (x, trimDimension最小长度),序列,UniformOutput = false);序列=猫(3序列{});标签=猫({}):2、标签;= onehotencode标签(标签,1);标签(isnan(标签))= 0;结束

随机截断音频信号到指定长度

函数y = randomTruncate (x,昏暗,最小长度)%这个函数只在本例中使用。它可能改变或%在将来发布的版本中移除。N =大小(x,昏暗的);如果N >最小长度开始= randperm (N-minLength, 1);如果昏暗的= = 1 y = x(启动:启动+ minLength-1:);elseif昏暗的= = 2 y = x(:开始:开始+ minLength-1);结束其他的y = x;结束结束

预测批

函数[xvecs、标签]= predictBatch (dlnet ds, nvargs)参数dlnet ds nvargs。输出= [];结束如果~ isempty(版本(“平行”)池=质量;numPartition = numpartitions (ds、池);其他的numPartition = 1;结束xvecs = [];标签= [];输出= nvargs.Outputs;parforpartitionIndex = 1: numPartition dsPart =分区(ds, numPartition partitionIndex);partitionFeatures = [];partitionLabels = [];hasdata (dsPart) atable =阅读(dsPart);F = atable.features;L = atable.labels;kk = 1:元素个数(左)如果isempty(输出)f =收集(extractdata(预测(dlnet, (dlarray (f {kk},“施”)))));其他的f =收集(extractdata(预测(dlnet (dlarray (f {kk},“施”)),输出=输出)));结束l = l(乐);partitionFeatures = [partitionFeatures f];partitionLabels = [partitionLabels l];结束结束xvecs = [xvecs, partitionFeatures];标签=(标签,partitionLabels);结束结束