Этот пример демонстрирует подход машинного обучения для идентификации людей на основе функций, извлеченных из записанной речи. Функциями, используемыми для обучения классификатора, являются тангаж озвученных сегментов речи и коэффициенты mel frequency cepstrum (MFCC). Это идентификация динамика с закрытой установкой: аудио тестируемого динамика сравнивается со всеми доступными моделями динамика (конечный набор) и возвращается ближайшее соответствие.
Подход, используемый в этом примере для идентификации динамика, показан на схеме.
Тангаж и MFCC извлекаются из речевых сигналов, записанных для 10 динамиков. Эти функции используются для обучения классификатора K-ближайших соседей (KNN). Затем новые речевые сигналы, которые нужно классифицировать, проходят через ту же редукцию данных. Обученный классификатор KNN предсказывает, какой из 10 динамиков является ближайшим соответствием.
В этом разделе рассматриваются тангаж и MFCC, две функции, которые используются для классификации динамиков.
Тангаж
Речь может быть широко классифицирована как озвученная и незаявленная. В случае голосовой речи воздух из легких модулируется голосовыми связками и приводит к квазипериодическому возбуждению. В полученном звуке преобладают относительно низкочастотные колебания, называемые тангажем. В случае невокализованной речи воздух из легких проходит через сужение в голосовом тракте и становится турбулентным, шумоподобным возбуждением. В модели речи «источник-фильтр» возбуждение упоминается как источник, а голосовой тракт упоминается как фильтр. Характеристика источника является важной частью характеристики речевой системы.
В качестве примера звонкой и негласной речи рассмотрим представление слова «два» во временной области (/T UW/). Согласный/T/( негласная речь) выглядит как шум, в то время как гласный/UW/( голосовая речь) характеризуется сильной основной частотой.
[audioIn, fs] = audioread('Counting-16-44p1-mono-15secs.wav'); twoStart = 110e3; twoStop = 135e3; audioIn = audioIn(twoStart:twoStop); timeVector = linspace((twoStart/fs),(twoStop/fs),numel(audioIn)); sound(audioIn,fs) figure plot(timeVector,audioIn) axis([(twoStart/fs) (twoStop/fs) -1 1]) ylabel('Amplitude') xlabel('Time (s)') title('Utterance - Two')
Речевой сигнал имеет динамический характер и изменяется с течением времени. Принято, что речевые сигналы являются стационарными по коротким временным шкалам, и их обработка осуществляется в окнах 20-40 мс. Этот пример использует окно 30 мс с перекрытием 25 мс. Используйте pitch
функция, чтобы увидеть, как тангаж изменяется с течением времени.
windowLength = round(0.03*fs); overlapLength = round(0.025*fs); f0 = pitch(audioIn,fs,'WindowLength',windowLength,'OverlapLength',overlapLength,'Range',[50,250]); figure subplot(2,1,1) plot(timeVector,audioIn) axis([(110e3/fs) (135e3/fs) -1 1]) ylabel('Amplitude') xlabel('Time (s)') title('Utterance - Two') subplot(2,1,2) timeVectorPitch = linspace((twoStart/fs),(twoStop/fs),numel(f0)); plot(timeVectorPitch,f0,'*') axis([(110e3/fs) (135e3/fs) min(f0) max(f0)]) ylabel('Pitch (Hz)') xlabel('Time (s)') title('Pitch Contour')
The pitch
функция оценивает значение тангажа для каждой системы координат. Однако тангаж характерен только для источника в областях голосовой речи. Самым простым методом различения тишины и речи является анализ краткосрочной степени. Если степень в системе координат выше заданного порога, вы объявляете систему координат речевым.
pwrThreshold = -20;
[segments,~] = buffer(audioIn,windowLength,overlapLength,'nodelay');
pwr = pow2db(var(segments));
isSpeech = (pwr > pwrThreshold);
Самым простым методом различения голосовой и невокализированной речи является анализ нулевой скорости пересечения. Большое количество пересечений нуля подразумевает, что нет доминирующего низкочастотного колебания. Если нулевая скорость пересечения для системы координат ниже заданного порога, вы объявляете ее как озвученную.
zcrThreshold = 300;
zeroLoc = (audioIn==0);
crossedZero = logical([0;diff(sign(audioIn))]);
crossedZero(zeroLoc) = false;
[crossedZeroBuffered,~] = buffer(crossedZero,windowLength,overlapLength,'nodelay');
zcr = (sum(crossedZeroBuffered,1)*fs)/(2*windowLength);
isVoiced = (zcr < zcrThreshold);
Объедините isSpeech
и isVoiced
для определения, содержит ли система координат голосовую речь.
voicedSpeech = isSpeech & isVoiced;
Удалите области, которые не соответствуют озвученной речи, из оценки тангажа и графика.
f0(~voicedSpeech) = NaN; figure subplot(2,1,1) plot(timeVector,audioIn) axis([(110e3/fs) (135e3/fs) -1 1]) axis tight ylabel('Amplitude') xlabel('Time (s)') title('Utterance - Two') subplot(2,1,2) plot(timeVectorPitch,f0,'*') axis([(110e3/fs) (135e3/fs) min(f0) max(f0)]) ylabel('Pitch (Hz)') xlabel('Time (s)') title('Pitch Contour')
Коэффициенты Мел-частоты Cepstrum (MFCC)
MFCC являются популярными функциями, извлеченными из речевых сигналов для использования в задачах распознавания. В модели речи «источник-фильтр» MFCC понимается как представление фильтра (голосового тракта). Частотная характеристика голосового тракта относительно гладка, в то время как источник голосовой речи может быть смоделирован как импульсный train. Результатом является то, что голосовой тракт может быть оценен спектральной огибающей речевого сегмента.
Мотивирующая идея MFCC состоит в том, чтобы сжать информацию о голосовом тракте (сглаженный спектр) в небольшое количество коэффициентов, основанных на понимании улитки.
Несмотря на отсутствие жесткого стандарта для вычисления MFCC, основные шаги описаны на схеме.
mel filterbank линейно разделяет первые 10 треугольных фильтров и логарифмически разделяет оставшиеся фильтры. Отдельные полосы взвешены для четной энергии. График представляет типичный mel filterbank.
Этот пример использует mfcc
вычислить MFCC для каждого файла.
Этот пример использует базу данных переписи населения (также известную как AN4 Database) из группы распознавания робастной речи CMU [1]. Набор данных содержит записи мужских и женских субъектов, говорящих слова и цифры. Функция helper в этом разделе загружает ее для вас и преобразует необработанные файлы в FLAC. Речевые файлы разделяются на подкаталоги на основе меток, соответствующих динамикам. Если вы не можете загрузить его, можно загрузить таблицу функций из HelperAN4TrainingFeatures.mat
и переходите непосредственно к разделу «Обучение классификатора». Функции были извлечены из того же набора данных.
Загрузите и извлечите файлы речи для 10 динамиков (5 женских и 5 мужских) во временную директорию с помощью HelperAN4Download
функция.
dataDir = HelperAN4Download;
Создайте audioDatastore
объект для управления этой базой данных для обучения. datastore позволяет собирать необходимые файлы формата файла и читать их.
ads = audioDatastore(dataDir,'IncludeSubfolders',true, ... 'FileExtensions','.flac', ... 'LabelSource','foldernames')
ads = audioDatastore with properties: Files: { ' ...\scrawfor\AppData\Local\Temp\an4\wav\flacData\fejs\an36-fejs-b.flac'; ' ...\scrawfor\AppData\Local\Temp\an4\wav\flacData\fejs\an37-fejs-b.flac'; ' ...\scrawfor\AppData\Local\Temp\an4\wav\flacData\fejs\an38-fejs-b.flac' ... and 122 more } Folders: { 'C:\Users\scrawfor\AppData\Local\Temp\an4\wav\flacData' } Labels: [fejs; fejs; fejs ... and 122 more categorical] AlternateFileSystemRoots: {} OutputDataType: 'double' SupportedOutputFormats: ["wav" "flac" "ogg" "mp4" "m4a"] DefaultOutputFormat: "wav"
The splitEachLabel
функция audioDatastore
разделяет datastore на два или более хранилищ данных. Получившиеся хранилища данных имеют заданную долю аудио файлов от каждой метки. В этом примере datastore разделяется на две части. 80% данных для каждой метки используется для обучения, а оставшиеся 20% используются для проверки. The countEachLabel
метод audioDatastore
используется для подсчета количества аудио файлов на метку. В этом примере метка идентифицирует динамик.
[adsTrain, adsTest] = splitEachLabel(ads,0.8);
Отобразите datastore и количество динамиков в train.
adsTrain
adsTrain = audioDatastore with properties: Files: { ' ...\scrawfor\AppData\Local\Temp\an4\wav\flacData\fejs\an36-fejs-b.flac'; ' ...\scrawfor\AppData\Local\Temp\an4\wav\flacData\fejs\an37-fejs-b.flac'; ' ...\scrawfor\AppData\Local\Temp\an4\wav\flacData\fejs\an38-fejs-b.flac' ... and 94 more } Folders: { 'C:\Users\scrawfor\AppData\Local\Temp\an4\wav\flacData' } Labels: [fejs; fejs; fejs ... and 94 more categorical] AlternateFileSystemRoots: {} OutputDataType: 'double' SupportedOutputFormats: ["wav" "flac" "ogg" "mp4" "m4a"] DefaultOutputFormat: "wav"
trainDatastoreCount = countEachLabel(adsTrain)
trainDatastoreCount=10×2 table
Label Count
_____ _____
fejs 10
fmjd 10
fsrb 10
ftmj 10
fwxs 10
mcen 10
mrcb 10
msjm 10
msjr 10
msmn 7
Отобразите datastore и количество динамиков в тестовом datastore.
adsTest
adsTest = audioDatastore with properties: Files: { ' ...\scrawfor\AppData\Local\Temp\an4\wav\flacData\fejs\cen6-fejs-b.flac'; ' ...\scrawfor\AppData\Local\Temp\an4\wav\flacData\fejs\cen7-fejs-b.flac'; ' ...\scrawfor\AppData\Local\Temp\an4\wav\flacData\fejs\cen8-fejs-b.flac' ... and 25 more } Folders: { 'C:\Users\scrawfor\AppData\Local\Temp\an4\wav\flacData' } Labels: [fejs; fejs; fejs ... and 25 more categorical] AlternateFileSystemRoots: {} OutputDataType: 'double' SupportedOutputFormats: ["wav" "flac" "ogg" "mp4" "m4a"] DefaultOutputFormat: "wav"
testDatastoreCount = countEachLabel(adsTest)
testDatastoreCount=10×2 table
Label Count
_____ _____
fejs 3
fmjd 3
fsrb 3
ftmj 3
fwxs 2
mcen 3
mrcb 3
msjm 3
msjr 3
msmn 2
Чтобы предворительно просмотреть содержимое datastore, прочтите образец файла и воспроизведите его с помощью аудио устройства по умолчанию.
[sampleTrain, dsInfo] = read(adsTrain); sound(sampleTrain,dsInfo.SampleRate)
Чтение из train datastore перемещает указатель на чтение так, чтобы можно было выполнить итерацию через базу данных. Сбросьте train datastore, чтобы вернуть указатель на чтение в начало для следующей редукции данных.
reset(adsTrain)
Извлеките функции тангажа и MFCC из каждой системы координат, который соответствует озвученной речи в обучающем datastore. Вспомогательная функция isVoicedSpeech выполняет обнаружение голоса, изложенное в описании редукции данных тангажа.
fs = dsInfo.SampleRate; windowLength = round(0.03*fs); overlapLength = round(0.025*fs); features = []; labels = []; while hasdata(adsTrain) [audioIn,dsInfo] = read(adsTrain); melC = mfcc(audioIn,fs,'Window',hamming(windowLength,'periodic'),'OverlapLength',overlapLength); f0 = pitch(audioIn,fs,'WindowLength',windowLength,'OverlapLength',overlapLength); feat = [melC,f0]; voicedSpeech = isVoicedSpeech(audioIn,fs,windowLength,overlapLength); feat(~voicedSpeech,:) = []; label = repelem(dsInfo.Label,size(feat,1)); features = [features;feat]; labels = [labels,label]; end
Тангаж и MFCC не имеют одинаковых шкал. Это приведет к смещению классификатора. Нормализуйте функции путем вычитания среднего и деления стандартного отклонения.
M = mean(features,1); S = std(features,[],1); features = (features-M)./S;
Теперь, когда вы собрали функции для всех 10 динамиков, можно обучить классификатор на их основе. В этом примере вы используете классификатор K-ближайших соседей (KNN). KNN является классификационным методом, естественно подходящим для многоклассовой классификации. Гиперпараметры для ближайшего соседнего классификатора включают количество ближайших соседей, метрику расстояния, используемую для вычисления расстояния до соседей, и вес метрики расстояния. Гиперпараметры выбираются для оптимизации точности валидации и эффективности на тестовом наборе. В этом примере количество соседей устанавливается равным 5, и метрика для выбранного расстояния является квадратным-обратным взвешенным Евклидовым расстоянием. Для получения дополнительной информации о классификаторе см. fitcknn
(Statistics and Machine Learning Toolbox).
Обучите классификатор и распечатайте точность перекрестной проверки. crossval
(Statistics and Machine Learning Toolbox) и kfoldLoss
(Statistics and Machine Learning Toolbox) используются для вычисления точности перекрестной валидации классификатора KNN.
Задайте все опции классификатора и обучите классификатор.
trainedClassifier = fitcknn( ... features, ... labels, ... 'Distance','euclidean', ... 'NumNeighbors',5, ... 'DistanceWeight','squaredinverse', ... 'Standardize',false, ... 'ClassNames',unique(labels));
Выполните перекрестную валидацию.
k = 5; group = labels; c = cvpartition(group,'KFold',k); % 5-fold stratified cross validation partitionedModel = crossval(trainedClassifier,'CVPartition',c);
Вычислите точность валидации.
validationAccuracy = 1 - kfoldLoss(partitionedModel,'LossFun','ClassifError'); fprintf('\nValidation accuracy = %.2f%%\n', validationAccuracy*100);
Validation accuracy = 97.64%
Визуализируйте график неточностей.
validationPredictions = kfoldPredict(partitionedModel); figure cm = confusionchart(labels,validationPredictions,'title','Validation Accuracy'); cm.ColumnSummary = 'column-normalized'; cm.RowSummary = 'row-normalized';
Вы также можете использовать Приложение Classification Learner (Statistics and Machine Learning Toolbox), чтобы попробовать и сравнить различные классификаторы с вашей таблицей функций.
В этом разделе вы тестируете обученный классификатор KNN с речевыми сигналами от каждого из 10 динамиков, чтобы увидеть, насколько хорошо он ведет себя с сигналами, которые не использовались для его обучения.
Чтение файлов, извлечение функций из тестового набора и их нормализация.
features = []; labels = []; numVectorsPerFile = []; while hasdata(adsTest) [audioIn,dsInfo] = read(adsTest); melC = mfcc(audioIn,fs,'Window',hamming(windowLength,'periodic'),'OverlapLength',overlapLength); f0 = pitch(audioIn,fs,'WindowLength',windowLength,'OverlapLength',overlapLength); feat = [melC,f0]; voicedSpeech = isVoicedSpeech(audioIn,fs,windowLength,overlapLength); feat(~voicedSpeech,:) = []; numVec = size(feat,1); label = repelem(dsInfo.Label,numVec); numVectorsPerFile = [numVectorsPerFile,numVec]; features = [features;feat]; labels = [labels,label]; end features = (features-M)./S;
Спрогнозируйте метку (динамик) для каждой системы координат путем вызова predict
на trainedClassifier
.
prediction = predict(trainedClassifier,features); prediction = categorical(string(prediction));
Визуализируйте график неточностей.
figure('Units','normalized','Position',[0.4 0.4 0.4 0.4]) cm = confusionchart(labels,prediction,'title','Test Accuracy (Per Frame)'); cm.ColumnSummary = 'column-normalized'; cm.RowSummary = 'row-normalized';
Для данного файла делаются предсказания для каждой системы координат. Определите режим предсказаний для каждого файла и затем постройте график неточностей.
r2 = prediction(1:numel(adsTest.Files)); idx = 1; for ii = 1:numel(adsTest.Files) r2(ii) = mode(prediction(idx:idx+numVectorsPerFile(ii)-1)); idx = idx + numVectorsPerFile(ii); end figure('Units','normalized','Position',[0.4 0.4 0.4 0.4]) cm = confusionchart(adsTest.Labels,r2,'title','Test Accuracy (Per File)'); cm.ColumnSummary = 'column-normalized'; cm.RowSummary = 'row-normalized';
Предсказанные динамики соответствуют ожидаемым динамикам для всех тестируемых файлов.
Эксперимент повторяли с использованием внутреннего набора данных. Набор данных состоит из 20 дикторов, каждый из которых говорит несколько предложений из гарвардского списка предложений [2]. Для 20 динамиков точность валидации 89%.
function voicedSpeech = isVoicedSpeech(x,fs,windowLength,overlapLength) pwrThreshold = -40; [segments,~] = buffer(x,windowLength,overlapLength,'nodelay'); pwr = pow2db(var(segments)); isSpeech = (pwr > pwrThreshold); zcrThreshold = 1000; zeroLoc = (x==0); crossedZero = logical([0;diff(sign(x))]); crossedZero(zeroLoc) = false; [crossedZeroBuffered,~] = buffer(crossedZero,windowLength,overlapLength,'nodelay'); zcr = (sum(crossedZeroBuffered,1)*fs)/(2*windowLength); isVoiced = (zcr < zcrThreshold); voicedSpeech = isSpeech & isVoiced; end
[1] «CMU Sphinx Group - Audio Databases». Доступ к 19 декабря 2019 года. http://www.speech.cs.cmu.edu/databases/an4/.
[2] «Гарвардские предложения». Википедия, 27 августа 2019 года. Википедия, https://en.wikipedia.org/w/index.php?title=Harvard_sentences&oldid=912785385.