主要内容

使用自定义SincNet层和深度学习的说话人识别

在这个例子中,你训练三个卷积神经网络(cnn)来执行说话者验证,然后比较架构的性能。这三个cnn的架构除了第一个卷积层之外都是等效的:

  1. 在第一种架构中,第一个卷积层是一个“标准”卷积层,使用convolution2dLayer

  2. 在第二种架构中,第一个卷积层是一个常量sinc滤波器组,使用自定义层实现。

  3. 在第三种架构中,第一个卷积层是一个可训练的sinc滤波器组,使用自定义层实现。这种体系结构被称为SincNet[1]

[1]结果表明,用滤波器组层代替标准卷积层可以获得更快的训练收敛速度和更高的准确率。[1]还表明,使滤波器组的参数可学习产生额外的性能收益。

简介

说话人识别是一个突出的研究领域,具有各种应用,包括法医学和生物特征认证。许多说话人识别系统依赖于预先计算的特征,如i向量或mfc,然后将其输入机器学习或深度学习网络进行分类。其他深度学习语音系统绕过特征提取阶段,直接将音频信号馈送到网络。在这种端到端系统中,网络直接学习低电平音频信号特征。

在本例中,首先训练一个传统的端到端说话者识别CNN。学习到的过滤器往往具有随机形状,不符合感知证据或人耳工作方式的知识,特别是在训练数据量有限的情况下[1].然后用自定义sinc滤波器组层替换网络中的第一个卷积层,该层引入了基于感知证据的结构和约束。最后,训练SincNet体系结构,这为sinc过滤器组参数增加了可学习性。

本例中探索的三种神经网络架构总结如下:

  1. 标准卷积神经网络-输入波形直接连接到一个随机初始化的卷积层,该层试图从原始音频帧中学习特征和捕获特征。

  2. ConstantSincLayer输入波形与一组固定宽度的sinc函数(带通滤波器)在mel尺度上等距卷积。

  3. SincNetLayer-输入波形与一组sinc函数卷积,这些函数的参数由网络学习。在SincNet体系结构中,网络在训练时调整sinc函数的参数。

这个例子定义和训练了上面提出的三个神经网络,并评估了它们在LibriSpeech数据集上的性能[2]

数据集

下载数据集

在本例中,您使用LibriSpeech数据集的一个子集[2].LibriSpeech数据集是一个以16khz采样的大型英语语音阅读语料库。这些数据来源于LibriVox项目中阅读的有声读物。

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

创建一个audioDatastore对象访问LibriSpeech音频数据。

ads = audioDatastore(dataset, inclesubfolders =true);

从文件路径中提取扬声器标签。

ads.Labels = categorical(extractBetween(ads.Files,fullfile(dataset,filesep),filesep));

完整的dev -培训- 100dataset大约是6gb的数据。要快速运行此示例,请设置speedupExample真正的

speedupExample =如果speedupExample allSpeakers = unique(ads.Labels);subsetSpeakers = allSpeakers(1:50);ads =子集(ads,ismember(ads. labels,subsetSpeakers));ads.Labels = removecats(ads.Labels);结束ads = splitEachLabel(ads,0.1);

将音频文件拆分为训练数据和测试数据。80%的音频文件分配给训练集,20%分配给测试集。

[adsTrain,adsTest] = splitEachLabel(ads,0.8);

语音信号样本

画出其中一个音频文件并听一听。

[audioIn,dsInfo] = read(adsTrain);Fs = dsInfo.SampleRate;sound(audioIn,Fs) t = (1/Fs)*(0:length(audioIn)-1);情节(t, audioIn)标题(“音频样本”)包含(“时间(s)”) ylabel (“振幅”网格)

重置训练数据存储。

重置(adsTrain)

数据预处理

cnn期望输入具有一致的维度。您将通过去除静默区域来预处理音频,然后将剩余的语音分解为200 ms帧,其中有40 ms重叠。

设置预处理参数。

frameDuration = 200e-3;overlapDuration = 40e-3;frameLength = floor(Fs*frameDuration);overlapLength = round(Fs*overlapDuration);

利用支撑函数,金宝apppreprocessAudioData,对训练数据和测试数据进行预处理。在音频数据存储上定义一个转换来执行预处理,然后使用readall对整个数据集进行预处理,并将预处理过的数据放入内存中。如果您有并行计算工具箱™,您可以将计算负载分散到各个工作人员。XTrain而且XTest分别包含训练和测试语音帧。TTrain而且tt分别包含列车和测试标签。

pFlag = ~isempty(ver(“平行”));adsTrainTransform = transform(adsTrain,@(x){preprocessAudioData(x,frameLength,overlapLength,Fs)});XTrain = readall(adsTrainTransform,UseParallel=pFlag);

复制标签,以便每个200毫秒的块都有相应的标签。

chunksPerFile = cellfun(@(x)size(x,4),XTrain);TTrain = repelem(adsTrain.Labels,chunksPerFile,1);

将训练集连接到一个数组中。

XTrain = cat(4,XTrain{:});

对测试集执行相同的预处理步骤。

adsTestTransform = transform(adsTest,@(x){preprocessAudioData(x,frameLength,overlapLength,Fs)});XTest = readall(adsTestTransform,UseParallel=true);chunksPerFile = cellfun(@(x)size(x,4),XTest);TTest = repelem(adste . labels,chunksPerFile,1);XTest = cat(4,XTest{:});

标准的美国有线电视新闻网

定义层

标准CNN的灵感来自于[1]

numFilters = 80;filterLength = 251;numSpeakers = nummel(唯一的(removecats(ads.Labels)));图层= [imageInputLayer([1 frameLength 1])第一卷积层convolution2dLayer([1 filterLength],numFilters) batchNormalizationLayer leakyReluLayer(0.2) maxPooling2dLayer([1 3])这一层后面是2个卷积层convolution2dLayer([1 5],60) batchNormalizationLayer leakyReluLayer(0.2) maxPooling2dLayer([1 3]) convolution2dLayer([1 5],60) batchNormalizationLayer leakyReluLayer(0.2) maxPooling2dLayer([1 3])接下来是3个完全连接的层fullyConnectedLayer(256) batchNormalizationLayer leakyReluLayer(0.2) fullyConnectedLayer(256) batchNormalizationLayer leakyReluLayer(0.2) fullyConnectedLayer(256) fullyConnectedLayer(0.2) fullyConnectedLayer(numSpeakers) softmaxLayer classificationLayer];

分析神经网络的层次analyzeNetwork函数

analyzeNetwork(层)

列车网络的

训练神经网络15个纪元亚当优化。在每个纪元之前对训练数据进行洗牌。神经网络的训练选项设置使用trainingOptions.使用测试数据作为验证数据,观察网络性能如何随着训练的进行而提高。

numEpochs = 15;miniBatchSize = 128;validationFrequency = floor(数字(TTrain)/miniBatchSize);选项= trainingOptions(“亚当”...洗牌=“every-epoch”...MiniBatchSize = MiniBatchSize,...情节=“训练进步”...Verbose = false, MaxEpochs = numEpochs,...ValidationData = {XTest,直言(tt)},...ValidationFrequency = ValidationFrequency);

要训练网络,请呼叫trainNetwork

[convNet,convNetInfo] = trainNetwork(XTrain,TTrain,layers,options);

检测第一卷积层的频率响应

绘制从标准CNN网络中学到的9个滤波器的幅值频率响应。这些过滤器的形状不是直观的,也不对应于感性的知识。下一节将探讨使用约束过滤器形状的效果。

F =挤压(convNet.Layers(2,1).Weights);H = 0(大小(F));频率=零(大小(F));2 = 1:尺寸(F, 2) [h F] = freqz (F(:,(二),1251年,Fs);H(:,ii) = abs(H);频率(:,ii) = f;结束idx = linspace(1,size(F,2),9);Idx = round(Idx);数字jj = 1:9次要情节(3,3,jj)情节(频率(:,idx (jj)), H (:, idx (jj))) sgtitle (学习标准CNN滤波器的频率响应)包含(“频率(赫兹)”结束

常量Sinc滤波器组

在本节中,将标准CNN中的第一个卷积层替换为常数sinc滤波器组层。常数sinc滤波器组层将输入帧与一组固定带通滤波器进行卷积。带通滤波器是两个正弦滤波器在时域上的线性组合。带通滤波器的频率在mel尺度上线性间隔。

定义层

常量sinc滤波器组层的实现可以在constantSincLayer.m文件(附在本例中)。为ConstantSincLayer.使用80个滤镜,滤镜长度为251。

numFilters = 80;filterLength = 251;numChannels = 1;name =“constant_sinc”

将第一个卷积层从标准CNN改为ConstantSincLayer保持其他图层不变。

cSL = constantSincLayer(numFilters,filterLength,Fs,numChannels,name)
cSL = constantSincLayer with properties: Name: 'constant_sinc' NumFilters: 80 SampleRate: 16000 FilterLength: 251 NumChannels: [] Filters: [1×251×1×80 single] MinimumFrequency: 50 MinimumBandwidth: 50 StartFrequencies:[0.0019 0.0032 0.0047 0.0062 0.0078 0.0094 0.0111 0.0128 0.0145 0.0164 0.0183 0.0202 0.0222 0.0243 0.0264 0.0286 0.0309 0.0332 0.0356 0.0381 0.0488 0.0517 0.0547 0.0578 0.0610 0.0643 0.0677 0.0712 0.0748…][0.0028 0.0030 0.0031 0.0032 0.0033 0.0034 0.0035 0.0036 0.0038 0.0039 0.0041 0.0042 0.0043 0.0045 0.0046 0.0047 0.0049 0.0051 0.0052 0.0055 0.0057 0.0059 0.0061 0.0063 0.0065 0.0067 0.0069 0.0071 0.0073 0.0075…]状态参数无属性。显示所有属性
layers(2) = cSL;

列车网络的

训练网络使用trainNetwork函数。使用之前定义的相同的训练选项。

[constSincNet,constSincInfo] = trainNetwork(XTrain,TTrain,layers,options);

检测第一卷积层的频率响应

plotNFilters方法绘制的幅值频率响应n具有等间隔过滤器索引的过滤器。图中9个滤波器的幅值频率响应ConstantSincLayer

图n = 9;plotNFilters (constSincNet.Layers (2), n)

SincNet

在本节中,您将使用一个可训练的SincNet层作为网络中的第一个卷积层。SincNet层将输入帧与一组带通滤波器进行卷积。SincNet滤波器的带宽和初始频率在mel尺度上被初始化为等间隔。SincNet层试图在神经网络框架内为这些带通滤波器学习更好的参数。

定义层

中可以找到SincNet层过滤器库层的实现sincNetLayer.m文件(附在本例中)。为SincNetLayer.使用80个滤镜,滤镜长度为251。

numFilters = 80;filterLength = 251;numChannels = 1;name =“sinc”

取代ConstantSincLayer从以前的网络与SincNetLayer.这个新层有两个可学习的参数:FilterFrequencies而且FilterBandwidths

sNL = sincNetLayer(numFilters,filterLength,Fs,numChannels,name)
sNL = sincNetLayer with properties: Name: 'sinc' NumFilters: 80 SampleRate: 16000 FilterLength: 251 NumChannels: [] Window:[0.0800 0.0801 0.0806 0.0813 0.0823 0.0836 0.0852 0.0871 0.0893 0.0917 0.0945 0.0975 0.1008 0.1043 0.1082 0.1123 0.1167 0.1214 0.1263 0.1369 0.1426 0.1547 0.1612 0.1679 0.1819 0.1893 0.1969 0.2047 0.2127…][-0.0078 -0.0077 -0.0077 -0.0076 -0.0076 -0.0075 -0.0074 -0.0074 -0.0073 -0.0073 -0.0072 -0.0071 -0.0071 -0.0070 -0.0069 -0.0069 -0.0068 -0.0067 -0.0067 -0.0066 -0.0066 -0.0065 -0.0064 -0.0064 -0.0064 -0.0063 -0.0063 -0.0062 -0.0061…][0.0019 0.0032 0.0047 0.0062 0.0078 0.0094 0.0111 0.0128 0.0145 0.0164 0.0183 0.0202 0.0222 0.0243 0.0264 0.0286 0.0309 0.0332 0.0356 0.0381 0.0407 0.0433 0.0460 0.0488 0.0517 0.0547 0.0578 0.0610 0.0643 0.0677 0.0712 0.0748…]filterbandwidth:[0.0028 0.0030 0.0031 0.0032 0.0033 0.0034 0.0035 0.0036 0.0038 0.0039 0.0041 0.0042 0.0043 0.0045 0.0046 0.0047 0.0049 0.0051 0.0052 0.0055 0.0057 0.0059 0.0061 0.0063 0.0065 0.0067 0.0069 0.0071 0.0073 0.0075…]状态参数无属性。显示所有属性
layers(2) = sNL;

列车网络的

训练网络使用trainNetwork函数。使用之前定义的相同的训练选项。

[sincNet,sincNetInfo] = trainNetwork(XTrain,TTrain,layers,options);

检测第一卷积层的频率响应

使用plotNFilters的方法SincNetLayer以可视化SincNet学习的九个具有等间隔指数的滤波器的幅度频响。

图plotNFilters (sincNet.Layers (2), 9)

结果总结

精度

表格总结了所有三个神经网络的帧精度。

网络类型= [“标准CNN”“恒Sinc层”“SincNet层”];精度= [convNetInfo.FinalValidationAccuracy;constSincInfo.FinalValidationAccuracy;sincNetInfo.FinalValidationAccuracy];resultsSummary = table(网络类型,准确度)
resultsSummary =3×2表NetworkType准确性  _____________________ ________ " 标准的美国有线电视新闻网“75.455”“71.202”常数Sinc层SincNet 78.395层”

与epoch相关的性能

将测试集上的准确性与epoch数绘制在一起,看看随着epoch数的增加,网络的学习情况如何。SincNet的性能优于ConstantSincLayer建立人际关系网,尤其是在培训的早期阶段。这表明,在神经网络框架内更新带通滤波器的参数会导致更快的收敛。只有当数据集足够大时才会观察到这种行为,因此在其他情况下可能看不到这种行为speedupExample设置为真正的

epoch = linspace(0,numEpochs, nummel (sincNetInfo.ValidationAccuracy(~isnan(sincNetInfo.ValidationAccuracy))));epoch = [epoch,numEpochs];sinc_valAcc = [sincNetInfo.ValidationAccuracy(~isnan(sincNetInfo.ValidationAccuracy))),...sincNetInfo.FinalValidationAccuracy];const_sinc_valAcc = [constSincInfo.ValidationAccuracy(~isnan(constSincInfo.ValidationAccuracy))),...constSincInfo.FinalValidationAccuracy];conv_valAcc = [convNetInfo.ValidationAccuracy(~isnan(convNetInfo.ValidationAccuracy)),...convNetInfo.FinalValidationAccuracy];图绘制(sinc_valAcc时代,“- *”MarkerSize = 4)情节(const_sinc_valAcc时代,“- *”MarkerSize = 4)情节(conv_valAcc时代,“- *”MarkerSize = 4) ylabel (帧级精度(测试集))包含(“时代”xlim([0 numEpochs+0.3]) title(“帧级精度与纪元”)传说(“sincNet”“constantSincLayer”“conv2dLayer”位置=“东南”网格)

在上图中,最终的帧精度与上次迭代中计算的帧精度略有不同。在训练时,批归一化层在小批上执行归一化。然而,在训练结束时,批归一层对整个训练数据进行归一化,这导致性能略有变化。

金宝app支持功能

函数xp = preprocessAudioData(x,frameLength,overlapLength,Fs) speechIdx = detectSpeech(x,Fs);xp = 0 (1,frameLength,1,0);ii = 1:size(speechIdx,1)%分离语音段audioChunk = x(speechIdx(ii,1):speechIdx(ii,2));分成200毫秒的小块audioChunk = buffer(audioChunk,frameLength,overlapLength);audioChunk =重塑(audioChunk,1,frameLength,1,size(audioChunk,2));连接现有音频xp = cat(4,xp,audioChunk);结束结束

参考文献

[1] M. Ravanelli和Y. Bengio,“使用SincNet从原始波形识别说话人”,2018 IEEE口语技术研讨会(SLT),希腊雅典,2018,pp. 1021-1028, doi: 10.1109/SLT.2018.8639585。

[2] V. Panayotov, G. Chen, D. Povey和S. Khudanpur,“Librispeech:基于公共领域有声书的ASR语料库,”2015 IEEE声学、语音与信号处理国际会议(ICASSP)中国农业科学,2015,pp. 5206-5210, doi: 10.1109/ICASSP.2015.7178964