主要内容

利用音高和MFCC识别说话人

这个例子演示了一种基于从录音语音中提取的特征来识别人的机器学习方法。用来训练分类器的特征是语音的浊音段的音调和梅尔频率倒谱系数(MFCC)。这是一种封闭集扬声器识别:将被测试扬声器的音频与所有可用的扬声器模型(有限集)进行比较,并返回最接近的匹配。

简介

本例中用于说话人识别的方法如图所示。

从10个扬声器的语音信号中提取基音和MFCC。这些特征被用来训练k -最近邻(KNN)分类器。然后,对新的需要分类的语音信号进行相同的特征提取。经过训练的KNN分类器预测10个说话者中哪一个最接近匹配。

用于分类的特征

本节讨论螺距、过零率、短时能量和MFCC。音高和MFCC是用来对说话者进行分类的两个特征。用过零率和短时能量来确定何时使用俯仰角特征。

球场

言语可以大致分为表达了而且无声的.在发声的情况下,来自肺部的空气被声带调节,产生准周期性的兴奋。产生的声音主要是由一个相对低频振荡,称为球场.在无声讲话的情况下,来自肺部的空气通过声道的狭窄处,变成了一种湍流的、类似噪音的兴奋。在语音的源-滤波器模型中,兴奋被称为源,声道被称为滤波器。源的特征化是语音系统特征化的重要组成部分。

作为浊音和浊音语音的一个例子,考虑单词“two”(/T UW/)的时域表示。辅音/T/(浊音)看起来像噪音,而元音/UW/(浊音)的特征是强基频。

[audioIn, fs] = audioread (“Counting-16-44p1-mono-15secs.wav”);twoStart = 110年e3;twoStop = 135年e3;audioIn = audioIn (twoStart: twoStop);timeVector = linspace (twoStart / fs, twoStop / fs,元素个数(audioIn));sound(audioIn,fs)图图(timeVector,audioIn)轴([(twoStart/fs) (twoStop/fs) -1]) ylabel(“振幅”)包含(“时间(s)”)标题(“话语——两个“

语音信号本质上是动态的,并随时间而变化。假设语音信号在短时间尺度上是静止的,它们的处理在20-40毫秒的窗口内完成。这个例子使用了一个30毫秒的窗口,重叠了25毫秒。使用球场函数来查看音高随时间的变化。

windowLength =圆(0.03 * fs);overlapLength =圆(0.025 * fs);f0 =音高(fs, audioIn WindowLength = WindowLength OverlapLength = OverlapLength范围= [50250]);图subplot(2,1,1) plot(timeVector,audioIn) axis([(110e3/fs) (135e3/fs) -1]) ylabel(“振幅”)包含(“时间(s)”)标题(“话语——两个“) subplot(2,1,2) timeVectorPitch = linspace(twoStart/fs,twoStop/fs,numel(f0));情节(timeVectorPitch f0,“*”轴([(110e3/fs) (135e3/fs) min(f0) max(f0)]) ylabel(“球场(Hz)”)包含(“时间(s)”)标题(“轮廓”

球场函数为每一帧估计一个音高值。然而,音高只是一个声源在浊语音区域的特征。区分沉默和说话最简单的方法是分析短时间能量。如果一帧中的能量超过了一个给定的阈值,您就将该帧声明为语音。

energyThreshold = 20;(段,~)=缓冲区(audioIn、windowLength overlapLength,“nodelay”);ste =总和((部分。*汉明(windowLength,“周期”)) ^ 2, 1);isSpeech = ste(:) > energyThreshold;

区分浊音和浊音最简单的方法是分析过零率。大量的过零意味着不存在显性的低频振荡。如果帧的过零率低于给定的阈值,则将其声明为语音。

zcrThreshold = 0.02;zcr = zerocrossrate (audioIn WindowLength = WindowLength OverlapLength = OverlapLength);isvocal = zcr < zcrThreshold;

结合isSpeech而且isVoiced确定一个帧是否包含浊音。

voicedSpeech = isSpeech & isvocal;

从音高估计和情节中删除不对应浊语音的区域。

f0 (~ voicedSpeech) =南;图subplot(2,1,1) plot(timeVector,audioIn)轴([(110e3/fs) (135e3/fs) -1])轴ylabel (“振幅”)包含(“时间(s)”)标题(“话语——两个“次要情节(2,1,2)情节(timeVectorPitch f0,“*”轴([(110e3/fs) (135e3/fs) min(f0) max(f0)]) ylabel(“球场(Hz)”)包含(“时间(s)”)标题(“轮廓”

mel频率倒谱系数(MFCC)

MFCC是从语音信号中提取的常用特征,用于识别任务。在语音源-滤波模型中,MFCC被理解为代表过滤器(声道)。声道的频率响应是相对平稳的,而浊音语音的来源可以建模为一个脉冲序列。结果是可以通过语音段的谱包络来估计声道。

MFCC的激励思想是基于对耳蜗的理解,将有关声道的信息(平滑频谱)压缩到少量的系数中。

虽然MFCC的计算没有硬性标准,但基本步骤由图表所示。

梅尔滤波器组对前10个三角形滤波器进行线性间隔,对其余滤波器进行对数间隔。单个波段的权重为均匀的能量。该图表示一个典型的梅尔滤波器组。

这个示例使用mfcc计算每个文件的MFCC。

数据集

本示例使用来自Mozilla的Common Voice数据集的一个子集[1].该数据集包含48千赫的受试者说短句的录音。本节中的helper函数组织下载的数据并返回一个audioDatastore对象。该数据集使用1.36 GB内存。

如果数据集不存在,请下载它并将其解压缩到其中tempdir

downloadFolder = matlab.internal.examples.downloadSupportFile (“音频”“commonvoice.zip”);dataFolder = tempdir;如果~ datasetExists (dataFolder) +(字符串“无法推进”)解压缩(downloadFolder dataFolder);结束

提取10位演讲者(5位女性和5位男性)的演讲文件,并将它们放入audioDatastore使用commonVoiceHelper函数。数据存储使您能够收集某种文件格式的必要文件并读取它们。打开此示例时,该函数放在当前文件夹中。

广告= commonVoiceHelper
ads = audioDatastore属性:Files:{'…\AppData\Local\Temp\commonvoice\train\clips\common_voice_en_116626.wav';’……\ AppData \当地\ Temp \无法推进\ \培训\剪辑common_voice_en_116631.wav”;’……\ AppData \当地\ Temp \无法推进\ \培训\剪辑common_voice_en_116643.wav”……{'C:\Users\jblock\AppData\Local\Temp\commonvoice\train\clips'}标签:[3;3;3.{} OutputDataType: 'double' SupportedOutputFormats: ["wav" "flac" "ogg" "opus" "mp4" "m4a"] DefaultOutputFormat: "wav"

splitEachLabel的函数audioDatastore将数据存储拆分为两个或多个数据存储。生成的数据存储具有来自每个标签的指定比例的音频文件。在本例中,数据存储被分成两个部分。每个标签的80%的数据用于训练,剩下的20%用于测试。的countEachLabel的方法audioDatastore用于计算每个标签的音频文件数量。在本例中,标签标识说话者。

[adsTrain, adsTest] = splitEachLabel(广告,0.8);

显示数据存储和列车数据存储中的扬声器数量。

adsTrain
adsTrain = audioDatastore属性:Files:{'…\AppData\Local\Temp\commonvoice\train\clips\common_voice_en_116626.wav';’……\ AppData \当地\ Temp \无法推进\ \培训\剪辑common_voice_en_116631.wav”;’……\ AppData \当地\ Temp \无法推进\ \培训\剪辑common_voice_en_116643.wav”……{'C:\Users\jblock\AppData\Local\Temp\commonvoice\train\clips'}标签:[3;3;3.{} OutputDataType: 'double' SupportedOutputFormats: ["wav" "flac" "ogg" "opus" "mp4" "m4a"] DefaultOutputFormat: "wav"
trainDatastoreCount = countEachLabel (adsTrain)
trainDatastoreCount =10×2表标签数_____ _____ 1 14 10 12 2 12 3 18 4 14 5 16 6 17 7 11 8 11 9 14

显示数据存储和测试数据存储中的扬声器数量。

adsTest
adsTest = audioDatastore属性:Files:{'…\AppData\Local\Temp\commonvoice\train\clips\common_voice_en_116761.wav';’……\ AppData \当地\ Temp \无法推进\ \培训\剪辑common_voice_en_116762.wav”;’……\ AppData \当地\ Temp \无法推进\ \培训\剪辑common_voice_en_116769.wav”……{'C:\Users\jblock\AppData\Local\Temp\commonvoice\train\clips'}标签:[3;3;3.{} OutputDataType: 'double' SupportedOutputFormats: ["wav" "flac" "ogg" "opus" "mp4" "m4a"] DefaultOutputFormat: "wav"
testDatastoreCount = countEachLabel (adsTest)
testDatastoreCount =10×2表标签数_____ _____ 1 4 10 3 2 3 3 4 4 4 4 5 4 6 4 7 3 8 3 9 4

要预览数据存储的内容,请读取示例文件并使用默认音频设备播放它。

[sampleTrain, dsInfo] =阅读(adsTrain);声音(sampleTrain dsInfo.SampleRate)

从train数据存储读取数据会推入读取指针,这样就可以遍历数据库。重置train数据存储,将读指针返回到下面特征提取的起始点。

重置(adsTrain)

特征提取

从训练数据存储中对应语音的每一帧中提取音调和MFCC特征。音频工具箱™提供audioFeatureExtractor这样你就可以快速有效地提取多个特征。配置一个audioFeatureExtractor提取螺距、短时能量、zcr和MFCC。

fs = dsInfo.SampleRate;windowLength =圆(0.03 * fs);overlapLength =圆(0.025 * fs);afe = audioFeatureExtractor (SampleRate = fs,...窗口=汉明(windowLength,“周期”), OverlapLength = OverlapLength,...zerocrossrate = true, shortTimeEnergy = true, = true, mfcc = true);

当你调用的提取函数时audioFeatureExtractor,所有特征被串联并返回到一个矩阵中。您可以使用info函数来确定矩阵的哪些列对应于哪些特征。

featureMap = info (afe)
featureMap =结构体字段:mfcc: [1 2 3 4 5 6 7 8 9 10 11 12 13] pitch: 14 zerocrossrate: 15 shortTimeEnergy: 16

从数据集中提取特征。

特点= [];标签= [];energyThreshold = 0.005;zcrThreshold = 0.2;keepLen =圆(长度(sampleTrain) / 3);hasdata(adsTrain) [audioIn,dsInfo] = read(adsTrain);使用每个记录的第一部分来加速代码。audioIn = audioIn (1: keepLen);audioIn壮举=提取(afe);isSpeech = feat(:, featumap . shorttimeenergy) > energyThreshold;isvocal = feat(:, featumap .zerocrossrate) < zcrThreshold;voicedSpeech = isSpeech & isvocal;壮举(~ voicedSpeech,:) = [];(的壮举:[featureMap.zerocrossrate featureMap.shortTimeEnergy]) = [];标签= repelem (dsInfo.Label、尺寸(功绩,1));特点=(功能;壮举);标签=(标签,标签);结束

Pitch和MFCC不在同一个音阶上。这将使分类器产生偏差。通过减去均值和除以标准差来归一化特征。

M =意味着(功能,1);S =性病(特性,[],1);特点= (features-M)。/ S;

训练一个分类器

现在您已经收集了所有10个扬声器的特征,可以基于它们训练分类器了。在本例中,使用k最近邻(KNN)分类器。KNN是一种自然适合于多类分类的分类技术。最近邻分类器的超参数包括最近邻的数量、用于计算到邻居的距离的距离度量以及距离度量的权重。选择超参数是为了优化测试集上的验证精度和性能。在这个例子中,邻居的数量被设置为5,选择的距离的度量是平方反加权欧氏距离。有关分类器的更多信息,请参见fitcknn(统计和机器学习工具箱)

训练分类器,打印交叉验证精度。crossval(统计和机器学习工具箱)而且kfoldLoss(统计和机器学习工具箱)用于计算KNN分类器的交叉验证精度。

指定所有的分类器选项并训练分类器。

trainedClassifier = fitcknn(特性、标签...距离=“欧几里得”...NumNeighbors = 5,...DistanceWeight =“squaredinverse”...规范= false,...一会=独特(标签);

执行交叉验证。

k = 5;组=标签;c = cvpartition(集团KFold = k);% 5倍分层交叉验证partitionedModel = crossval (trainedClassifier CVPartition = c);

计算验证精度。

validationAccuracy = 1 - kfoldLoss(partitionedModel,LossFun= .“ClassifError”);流('\n验证精度= %.2f%%\n', validationAccuracy * 100);
验证精度= 97.69%

想象困惑图表。

validationPredictions = kfoldPredict (partitionedModel);图(单位=“归一化”,Position=[0.4 0.4 0.4 0.4]“验证准确性”...ColumnSummary =“column-normalized”RowSummary =“row-normalized”);

你也可以使用分类学习者(统计和机器学习工具箱)应用程序尝试和比较各种分类器与您的功能表。

测试分类器

在本节中,您将使用来自10个说话者中的每个人的语音信号测试训练过的KNN分类器,看看它在使用未用于训练它的信号时表现如何。

读取文件,从测试集中提取特性,并规范化它们。

特点= [];标签= [];numVectorsPerFile = [];hasdata(adsTest) [audioIn,dsInfo] = read(adsTest);使用每个记录的相同的第一部分来加速代码。audioIn = audioIn (1: keepLen);audioIn壮举=提取(afe);isSpeech = feat(:, featumap . shorttimeenergy) > energyThreshold;isvocal = feat(:, featumap .zerocrossrate) < zcrThreshold;voicedSpeech = isSpeech & isvocal;壮举(~ voicedSpeech,:) = [];numVec =大小(功绩,1);(的壮举:[featureMap.zerocrossrate featureMap.shortTimeEnergy]) = [];标签= repelem (dsInfo.Label numVec);numVectorsPerFile = [numVectorsPerFile, numVec]; features = [features;feat]; labels = [labels,label];结束特点= (features-M)。/ S;

通过调用预测每一帧的标签(说话人)预测trainedClassifier

预测=预测(trainedClassifier、特点);预测=分类(string(预测);

想象困惑图表。

图(单位=“归一化”,Position=[0.4 0.4 0.4 0.4]) confusionchart(labels(:),预测,标题=测试精度(每帧)...ColumnSummary =“column-normalized”RowSummary =“row-normalized”);

对于一个给定的文件,对每一帧进行预测。确定每个文件的预测模式,然后绘制混淆图表。

r2 =预测(1:元素个数(adsTest.Files));idx = 1;ii = 1:numel(adast . files) r2(ii) = mode(预测(idx:idx+numVectorsPerFile(ii)-1));idx = idx + numVectorsPerFile(ii);结束图(单位=“归一化”,Position=[0.4 0.4 0.4 0.4])标签,r2,标题=“测试准确度(每个文件)”...ColumnSummary =“column-normalized”RowSummary =“row-normalized”);

对于测试中的所有文件,预测的扬声器与预期的扬声器相匹配。

参考文献

[1]Mozilla通用语音数据集

Baidu
map