Идентификация динамика Используя подачу и MFCC

Этот пример демонстрирует подход машинного обучения, чтобы идентифицировать людей на основе функций, извлеченных из записанной речи. Функциями, использованными, чтобы обучить классификатор, является подача речевых сегментов речи и коэффициентов кепстра mel-частоты (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')

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')

Коэффициенты кепстра Mel-частоты (MFCC)

MFCC являются популярными функциями, извлеченными из речевых сигналов для использования в задачах распознавания. В модели фильтра источника речи MFCC, как изучают, представляют фильтр (речевой тракт). Частотная характеристика речевого тракта относительно является гладкой, тогда как источник речевой речи может быть смоделирован, когда импульс обучается. Результат состоит в том, что речевой тракт может быть оценен спектральным конвертом речевого сегмента.

Идея мотивации MFCC состоит в том, чтобы сжать информацию о речевом тракте (сглаживавший спектр) в небольшое количество коэффициентов на основе понимания улитки уха.

Несмотря на то, что нет никакого твердого стандарта для вычисления MFCC, основные шаги обрисованы в общих чертах схемой.

mel filterbank линейно располагает первые 10 треугольных фильтров с интервалами и логарифмически располагает остающиеся фильтры с интервалами. Отдельные полосы взвешиваются для даже энергии. График представляет типичный mel filterbank.

Этот пример использует mfcc вычислить MFCC для каждого файла.

Набор данных

Этот пример использует Базу данных переписи (также известный как Базу данных AN4) от CMU Robust Speech Recognition Group [1]. Набор данных содержит записи участников эксперимента и участниц эксперимента, произносящих слова и числа. Функция помощника в этом разделе загружает его для вас и преобразует необработанные файлы в FLAC. Речевые файлы разделены в подкаталоги на основе меток, соответствующих динамикам. Если вы не можете загрузить его, можно загрузить таблицу функций от HelperAN4TrainingFeatures.mat и перейдите непосредственно к разделу Training a Classifier. Функции были извлечены из того же набора данных.

Загрузите и извлеките речевые файлы для 10 динамиков (5 розеток и 5 штекеров) во временную директорию с помощью HelperAN4Download функция.

dataDir = HelperAN4Download;
Downloading AN4 dataset... done.
Reducing dataset to 5 females and 5 males... done.

Создайте audioDatastore объект управлять этой базой данных для обучения. Datastore позволяет вам собирать необходимые файлы формата файла и читать их.

ads = audioDatastore(dataDir,'IncludeSubfolders',true, ...
    'FileExtensions','.flac', ...
    'LabelSource','foldernames')
ads = 
  audioDatastore with properties:

                       Files: {
                              ' ...\bhemmat\AppData\Local\Temp\an4\wav\flacData\fejs\an36-fejs-b.flac';
                              ' ...\bhemmat\AppData\Local\Temp\an4\wav\flacData\fejs\an37-fejs-b.flac';
                              ' ...\bhemmat\AppData\Local\Temp\an4\wav\flacData\fejs\an38-fejs-b.flac'
                               ... and 122 more
                              }
                     Folders: {
                              'C:\Users\bhemmat\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"

splitEachLabel функция audioDatastore разделяет datastore в два или больше хранилища данных. Получившиеся хранилища данных имеют заданную пропорцию звуковых файлов от каждой метки. В этом примере datastore разделен в две части. 80% данных для каждой метки используются в обучении, и остающиеся 20% используются в тестировании. countEachLabel метод audioDatastore используется, чтобы считать количество звуковых файлов на метку. В этом примере метка идентифицирует динамик.

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

Отобразите datastore и количество динамиков в обучать datastore.

adsTrain
adsTrain = 
  audioDatastore with properties:

                       Files: {
                              ' ...\bhemmat\AppData\Local\Temp\an4\wav\flacData\fejs\an36-fejs-b.flac';
                              ' ...\bhemmat\AppData\Local\Temp\an4\wav\flacData\fejs\an37-fejs-b.flac';
                              ' ...\bhemmat\AppData\Local\Temp\an4\wav\flacData\fejs\an38-fejs-b.flac'
                               ... and 94 more
                              }
                     Folders: {
                              'C:\Users\bhemmat\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: {
                              ' ...\bhemmat\AppData\Local\Temp\an4\wav\flacData\fejs\cen6-fejs-b.flac';
                              ' ...\bhemmat\AppData\Local\Temp\an4\wav\flacData\fejs\cen7-fejs-b.flac';
                              ' ...\bhemmat\AppData\Local\Temp\an4\wav\flacData\fejs\cen8-fejs-b.flac'
                               ... and 25 more
                              }
                     Folders: {
                              'C:\Users\bhemmat\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)

Чтение от обучать datastore продвигает указатель чтения так, чтобы можно было выполнить итерации через базу данных. Сбросьте обучать 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,'WindowLength',windowLength,'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.

Обучите классификатор и распечатайте точность перекрестной проверки. crossval и kfoldLoss используются для расчета точность перекрестной проверки в классификаторе 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.57%

Визуализируйте график беспорядка.

validationPredictions = kfoldPredict(partitionedModel);
figure
cm = confusionchart(labels,validationPredictions,'title','Validation Accuracy');
cm.ColumnSummary = 'column-normalized';
cm.RowSummary = 'row-normalized';

Можно также использовать Приложение Classification Learner, чтобы испытать и сравнить различные классификаторы с вашей таблицей функций.

Тестирование классификатора

В этом разделе вы тестируете обученный классификатор KNN с речевыми сигналами от каждого из 10 докладчиков, чтобы видеть, как хорошо это ведет себя с сигналами, которые не использовались, чтобы обучить его.

Считайте файлы, извлеките функции из набора тестов и нормируйте их.

features = [];
labels = [];
numVectorsPerFile = [];
while hasdata(adsTest)
    [audioIn,dsInfo] = read(adsTest);
    
    melC = mfcc(audioIn,fs,'WindowLength',windowLength,'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 - Аудио Базы данных". Полученный доступ 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.