Определение ключевого слова в шуме Используя MFCC и сети LSTM

В этом примере показано, как идентифицировать ключевое слово в шумной речи с помощью нейронной сети для глубокого обучения. В частности, пример использует сеть Bidirectional Long Short-Term Memory (BiLSTM) и mel-частоту cepstral коэффициенты (MFCC).

Введение

Ключевое слово, определяющее (KWS), является важной составляющей речи - помогают технологиям, где пользователь говорит предопределенное ключевое слово с пробуждением система прежде, чем говорить полную команду или запрос к устройству.

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

Этот пример использует сети долгой краткосрочной памяти (LSTM), которые являются типом рекуррентной нейронной сети (RNN), подходящей, чтобы изучить данные timeseries и последовательность. Сеть LSTM может изучить долгосрочные зависимости между временными шагами последовательности. Слой LSTM (lstmLayer) может посмотреть в то время последовательность в прямом направлении, в то время как двунаправленный слой LSTM (bilstmLayer) может посмотреть в то время последовательность и во вперед и в обратные направления. Этот пример использует двунаправленный слой LSTM.

Пример использует google Speech Commands Dataset, чтобы обучить модель глубокого обучения. Чтобы запустить пример, необходимо сначала загрузить набор данных. Если вы не хотите загружать набор данных или обучать сеть, то можно загрузить предварительно обученную сеть путем открытия этого примера в MATLAB® и ввода load("KWSNet.mat") в командной строке.

Сводные данные в качестве примера

Пример проходит следующие шаги:

  1. Смотрите базовую линию определения ключевого слова "золотого стандарта" на сигнале валидации.

  2. Создайте учебное произнесение из бесшумного набора данных.

  3. Обучите ключевое слово, определяющее сеть LSTM с помощью последовательностей MFCC, извлеченных из того произнесения.

  4. Проверяйте сетевую точность путем сравнения базовой линии валидации с выходом сети, когда применено сигнал валидации.

  5. Проверяйте сетевую точность на сигнал валидации, поврежденный шумом.

  6. Увеличьте обучающий набор данных путем введения шума к речевым данным с помощью audioDataAugmenter.

  7. Переобучите сеть с увеличенным набором данных.

  8. Проверьте, что переобученная сеть теперь дает к более высокой точности, когда применено шумный сигнал валидации.

Смотрите сигнал валидации

В этом примере ключевым словом, чтобы определить является YES.

Вы используете демонстрационный речевой сигнал подтвердить сеть KWS. Сигнал валидации состоит 34 секунды речи с ключевым словом YES, появляющийся периодически.

Загрузите сигнал валидации.

[audioIn,fs] = audioread('KeywordSpeech-16-16-mono-34secs.flac');

Слушайте сигнал.

sound(audioIn,fs)

Визуализируйте сигнал.

t = (1/fs) * (0:length(audioIn)-1);
plot(t,audioIn);
grid on;
xlabel('Time (s)')
title('Validation Speech Signal')

Смотрите базовую линию KWS

Загрузите базовую линию KWS. Эта базовая линия была получена с помощью speech2text: Создайте ключевое слово, определяющее маску Используя Audio Labeler.

load('KWSBaseline.mat','KWSBaseline')

Базовая линия является логическим вектором той же длины как звуковой сигнал валидации. Сегменты в audioIn где ключевое слово произнесено, установлены в одного в KWSBaseline.

Визуализируйте речевой сигнал наряду с базовой линией KWS.

h = figure;
plot(t,audioIn)
grid on
xlabel('Time (s)')
hold on
plot(t,KWSBaseline)
legend('Speech','KWS Baseline','Location','southeast')
l = findall(h,'type','line');
l(1).LineWidth = 2;
title("Validation Signal")

Слушайте речевые сегменты, идентифицированные как ключевые слова.

sound(audioIn(KWSBaseline),fs)

Цель сети, которую вы обучаете, состоит в том, чтобы вывести маску KWS нулей и единиц как эта базовая линия.

Загрузите речевой набор данных команд

Загрузите обучающий набор данных с Речевого Набора данных Команд и извлеките загруженные файлы. Установите datafolder к местоположению данных. Используйте audioDatastore создать datastore, который содержит имена файлов. Используйте имена папок в качестве источника метки.

datafolder = PathToDatabase;
ads = audioDatastore(datafolder,'LabelSource','foldername','Includesubfolders',true);

Набор данных содержит файлы фонового шума, которые не используются в этом примере. Используйте subset создать новый datastore, который не имеет файлов фонового шума.

isBackNoise = ismember(ads.Labels,"_background_noise_");
ads = subset(ads,~isBackNoise);

Набор данных имеет приблизительно 65 000 одного второго длинного произнесения 30 коротких слов (включая ключевое слово YES). Получите отказ распределения слова в datastore.

countEachLabel(ads)
ans =

  30×2 table

    Label     Count
    ______    _____

    bed       1713 
    bird      1731 
    cat       1733 
    dog       1746 
    down      2359 
    eight     2352 
    five      2357 
    four      2372 
    go        2372 
    happy     1742 
    house     1750 
    left      2353 
    marvin    1746 
    nine      2364 
    no        2375 
    off       2357 
    on        2367 
    one       2370 
    right     2367 
    seven     2377 
    sheila    1734 
    six       2369 
    stop      2380 
    three     2356 
    tree      1733 
    two       2373 
    up        2375 
    wow       1745 
    yes       2377 
    zero      2376 

Разделите ads в два хранилища данных: первый datastore содержит файлы, соответствующие ключевому слову. Второй datastore содержит все другие слова.

keyword     = 'yes';
isKeyword   = ismember(ads.Labels,keyword);
ads_keyword = subset(ads,isKeyword);
ads_other   = subset(ads,~isKeyword);

Получите отказ распределения слова в каждом datastore.

countEachLabel(ads_keyword)
countEachLabel(ads_other)
ans =

  1×2 table

    Label    Count
    _____    _____

     yes     2377 


ans =

  29×2 table

    Label     Count
    ______    _____

    bed       1713 
    bird      1731 
    cat       1733 
    dog       1746 
    down      2359 
    eight     2352 
    five      2357 
    four      2372 
    go        2372 
    happy     1742 
    house     1750 
    left      2353 
    marvin    1746 
    nine      2364 
    no        2375 
    off       2357 
    on        2367 
    one       2370 
    right     2367 
    seven     2377 
    sheila    1734 
    six       2369 
    stop      2380 
    three     2356 
    tree      1733 
    two       2373 
    up        2375 
    wow       1745 
    zero      2376 

Создайте учебные предложения и метки

Учебные хранилища данных содержат вторые речевые сигналы, где одно слово произнесено. Вы создадите более комплексное учебное речевое произнесение, которое содержит смесь ключевого слова наряду с другими словами.

Вот пример созданного произнесения. Считайте одно ключевое слово из datastore ключевого слова и нормируйте его, чтобы иметь максимальное значение одного.

yes = read(ads_keyword);
yes = yes / max(abs(yes));

Сигнал имеет неречевые фрагменты (тишина, фоновый шум, и т.д.), которые не содержат полезную информацию о речи. Этот пример удаляет тишину с помощью простого подхода пороговой обработки, идентичного тому, используемому в, Классифицируют Пол Используя Сети LSTM.

Получите запуск и индексы конца полезного фрагмента сигнала.

[~,~,startIndex,endIndex] = HelperGetSpeechSegments(yes,fs);

Случайным образом выберите количество слов, чтобы использовать в синтезируемом учебном предложении. Используйте максимум 10 слов.

numWords = randi([0 10]);

Случайным образом выберите местоположение, в котором происходит ключевое слово.

keywordLocation = randi([1 numWords+1]);

Считайте желаемое количество произнесения неключевого слова и создайте учебное предложение и маску.

sentence = [];
mask = [];
for index = 1:numWords+1
    if index == keywordLocation
        sentence = [sentence;yes]; %#ok
        newMask = zeros(size(yes));
        newMask(startIndex:endIndex) = 1;
        mask = [mask;newMask]; %#ok
    else
        other = read(ads_other);
        other = other ./ max(abs(other));
        sentence = [sentence;other]; %#ok
        mask = [mask;zeros(size(other))]; %#ok
    end
end

Постройте учебное предложение наряду с маской.

figure
t  = (1/fs) * (0:length(sentence)-1);
h = figure;
plot(t,sentence)
grid on
hold on
plot(t,mask)
xlabel('Time (s)')
legend('Training Signal' , 'Mask','Location','southeast')
l = findall(h,'type','line');
l(1).LineWidth = 2;
title("Example Utterance")

Слушайте учебное предложение.

sound(sentence,fs)

Выделить признаки

Этот пример обучает нейронную сеть для глубокого обучения с помощью 42 коэффициентов MFCC (14 MFCC, 14 дельт и 14 коэффициентов дельты дельты).

Задайте параметры, требуемые для экстракции MFCC.

WindowLength = 512;
OverlapLength = 384;

Извлеките функции MFCC.

[coeffs,delta,deltaDelta] = mfcc(sentence,fs,'WindowLength',WindowLength,'OverlapLength',OverlapLength);

Конкатенация коэффициентов в одну матрицу функции.

featureMatrix = [coeffs delta deltaDelta];
size(featureMatrix)
ans =

        1113          42

Обратите внимание на то, что вы вычисляете MFCC путем скольжения окна через вход, таким образом, матрица функции короче, чем входной речевой сигнал. Каждая строка в featureMatrix соответствует 128 выборкам от речевого сигнала (WindowLength-OverlapLength).

Вычислите маску той же длины как featureMatrix.

HopLength = WindowLength - OverlapLength;
range = (HopLength) * (1:size(coeffs,1)) + HopLength;
featureMask  = zeros(size(range));
for index = 1:numel(range)
    featureMask(index) = mode(mask( (index-1)*HopLength+1:(index-1)*HopLength+WindowLength ));
end

Извлеките функции из обучающего набора данных

Синтез предложения и извлечение признаков для целого обучающего набора данных могут быть довольно длительными. Чтобы ускорить обработку, если у вас есть Parallel Computing Toolbox™, делят учебный datastore и процесс каждый раздел на отдельном рабочем.

Выберите много разделов datastore.

numPartitions = 6;

Инициализируйте массивы ячеек для матриц функции и масок.

TrainingFeatures  = {};
TrainingMasks = {};

Выполните синтез предложения, извлечение признаков и создание маски с помощью parfor.

tic
parfor ii = 1:numPartitions

    subads_keyword = partition(ads_keyword,numPartitions,ii);
    subads_other   = partition(ads_other,numPartitions,ii);

    count = 1;
    localFeatures = cell(length(subads_keyword.Files),1);
    localMasks    = cell(length(subads_keyword.Files),1);

    while hasdata(subads_keyword)

        % Create a training sentence
        [sentence,mask] = synthesizeSentence(subads_keyword,subads_other,fs);

        % Compute mfcc features
        [coeffs,delta,deltaDelta] = mfcc(sentence,fs,'WindowLength',WindowLength,'OverlapLength',OverlapLength);
        featureMatrix = [coeffs delta deltaDelta];
        featureMatrix(~isfinite(featureMatrix)) = 0;

        % Create mask
        hopLength = WindowLength - OverlapLength;
        range     = (hopLength) * (1:size(coeffs,1)) + hopLength;
        featureMask  = zeros(size(range));
        for index = 1:numel(range)
            featureMask(index) = mode(mask( (index-1)*hopLength+1:(index-1)*hopLength+WindowLength ));
        end

        localFeatures{count} = featureMatrix;
        catVect              = categorical(featureMask);
        catVect              = addcats(catVect,{'1'});
        localMasks{count}    = catVect;

        count = count + 1;

    end

    TrainingFeatures = [TrainingFeatures;localFeatures];
    TrainingMasks    = [TrainingMasks;localMasks];

end
fprintf('Training feature extraction took %f seconds.\n',toc)
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 6).
Training feature extraction took 114.697514 seconds.

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

sampleFeature = TrainingFeatures{1};
numFeatures = size(sampleFeature,2);
featuresMatrix = cat(1,TrainingFeatures{:});
M = mean(featuresMatrix);
S = std(featuresMatrix);
for index = 1:length(TrainingFeatures)
    f = TrainingFeatures{index};
    f = (f - M) ./ S;
    TrainingFeatures{index} = f.'; %#ok
end

Извлеките функции валидации

Извлеките функции MFCC из сигнала валидации.

[coeffs,delta,deltaDelta] = mfcc(audioIn,fs,'WindowLength',WindowLength,'OverlapLength',OverlapLength);
featureMatrix = [coeffs,delta,deltaDelta];
featureMatrix(~isfinite(featureMatrix)) = 0;

Нормируйте функции валидации.

FeaturesValidationClean = (featureMatrix - M)./S;
range = (HopLength) * (1:size(FeaturesValidationClean,1)) + HopLength;

Создайте валидацию маска KWS.

featureMask  = zeros(size(range));
for index = 1:numel(range)
    featureMask(index) = mode(KWSBaseline( (index-1)*HopLength+1:(index-1)*HopLength+WindowLength ));
end
BaselineV = categorical(featureMask);

Задайте сетевую архитектуру LSTM

Сети LSTM могут изучить долгосрочные зависимости между временными шагами данных о последовательности. Этот пример использует двунаправленный слой LSTM bilstmLayer смотреть на последовательность и во вперед и в обратные направления.

Задайте входной размер, чтобы быть последовательностями размера numFeatures. Задайте два скрытых двунаправленных слоя LSTM с выходным размером 150 и выведите последовательность. Эта команда дает двунаправленному слою LSTM команду сопоставлять входные временные ряды в 150 функций, которые передаются следующему слою. Задайте два класса включением полносвязного слоя размера 2, сопровождаемый softmax слоем и слоем классификации.

layers = [ ...
    sequenceInputLayer(numFeatures)
    bilstmLayer(150,"OutputMode","sequence")
    bilstmLayer(150,"OutputMode","sequence")
    fullyConnectedLayer(2)
    softmaxLayer
    classificationLayer
    ];

Задайте опции обучения

Задайте опции обучения для классификатора. Установите MaxEpochs к 10 так, чтобы сеть сделала 10, проходит через обучающие данные. Установите MiniBatchSize к 64 так, чтобы сеть посмотрела на 64 учебных сигнала за один раз. Установите Plots к "training-progress" сгенерировать графики, которые показывают процесс обучения количеством увеличений итераций. Установите Verbose к false отключить печать таблицы выход, который соответствует данным, показанным в графике. Установите Shuffle к "every-epoch" переставить обучающую последовательность в начале каждой эпохи. Установите LearnRateSchedule к "piecewise" чтобы уменьшить темп обучения заданным фактором (0.1) каждый раз, определенное число эпох (4) передало. Установите ValidationData к предикторам валидации и целям.

Этот пример использует адаптивную оценку момента (ADAM) решатель. ADAM выполняет лучше с рекуррентными нейронными сетями (RNNs) как LSTMs, чем стохастический градиентный спуск по умолчанию с импульсом (SGDM) решатель.

maxEpochs     = 10;
miniBatchSize = 64;
options = trainingOptions("adam", ...
    "InitialLearnRate",1e-4,...
    "MaxEpochs",maxEpochs, ...
    "MiniBatchSize",miniBatchSize, ...
    "Shuffle","every-epoch",...
    "Verbose",false, ...
    "ValidationFrequency",floor(numel(TrainingFeatures)/miniBatchSize),...
    "ValidationData",{FeaturesValidationClean.',BaselineV},...
    "Plots","training-progress",...
    "LearnRateSchedule","piecewise",...
    "LearnRateDropFactor",0.1, ...
    "LearnRateDropPeriod",5);

Обучите сеть LSTM

Обучите сеть LSTM с заданными опциями обучения и архитектурой слоя с помощью trainNetwork. Поскольку набор обучающих данных является большим, учебный процесс может занять несколько минут.

doTraining = true;
if doTraining
    [keywordNetNoAugmentation,info] = trainNetwork(TrainingFeatures,TrainingMasks,layers,options);
    fprintf("Validation accuracy: %f percent.\n" , info.ValidationAccuracy(end));
else
    load('keywordNetNoAugmentation.mat','keywordNetNoAugmentation','M','S');%#ok
end
Validation accuracy: 89.470030 percent.

Проверяйте сетевую точность на бесшумный сигнал валидации

Оцените маску KWS для сигнала валидации использование обучившего сеть.

v = classify(keywordNetNoAugmentation , FeaturesValidationClean.');

Вычислите и постройте матрицу беспорядка валидации от векторов фактических и предполагаемых меток.

figure
cm = confusionchart(BaselineV,v,"title","Validation Accuracy");
cm.ColumnSummary = "column-normalized";
cm.RowSummary = "row-normalized";

Преобразуйте сетевой выход от категориального, чтобы удвоиться.

v = double(v) - 1;
v = repmat(v,HopLength,1);
v = v(:);

Слушайте области ключевого слова, идентифицированные сетью.

sound(audioIn(logical(v)),fs)

Визуализируйте предполагаемые и ожидаемые маски KWS.

baseline = double(BaselineV) - 1;
baseline = repmat(baseline,HopLength,1);
baseline = baseline(:);

t  = (1/fs) * (0:length(v)-1);
h = figure;
plot(t,audioIn(1:length(v)))
grid on
hold on
plot(t,v)
plot(t,0.8 * baseline)
xlabel('Time (s)')
legend('Training Signal','Network Mask','Baseline Mask','Location','southeast')
l = findall(h,'type','line');
l(1).LineWidth = 2;
l(2).LineWidth = 2;
title('Results for Noise-Free Speech')

Проверяйте сетевую точность на шумный сигнал валидации

Вы будете теперь проверять сетевую точность на шумный речевой сигнал. Сигнал с шумом был получен путем повреждения чистого сигнала валидации аддитивным белым Гауссовым шумом.

Загрузите сигнал с шумом.

[audioInNoisy,fs] = audioread('NoisyKeywordSpeech-16-16-mono-34secs.flac');
sound(audioInNoisy,fs)

Визуализируйте сигнал.

figure
t = (1/fs) * (0:length(audioInNoisy)-1);
plot(t,audioInNoisy);
grid on;
xlabel('Time (s)')
title('Noisy Validation Speech Signal')

Извлеките матрицу функции из сигнала с шумом.

[coeffs,delta,deltaDelta] = mfcc(audioInNoisy,fs,'WindowLength',WindowLength,'OverlapLength',OverlapLength);
featureMatrixV = [coeffs,delta,deltaDelta];
featureMatrixV(~isfinite(featureMatrixV)) = 0;
FeaturesValidationNoisy = (featureMatrixV - M)./S;

Передайте матрицу функции сети.

v   = classify(keywordNetNoAugmentation,FeaturesValidationNoisy.');

Сравните сетевой выход с базовой линией. Обратите внимание на то, что точность ниже, чем та, которую вы получили для чистого сигнала.

figure
cm = confusionchart(BaselineV,v,"title","Validation Accuracy - Noisy Speech");
cm.ColumnSummary = "column-normalized";
cm.RowSummary = "row-normalized";

Преобразуйте сетевой выход от категориального, чтобы удвоиться.

 v = double(v) - 1;
 v = repmat(v,HopLength,1);
 v = v(:);

Слушайте области ключевого слова, идентифицированные сетью.

sound(audioIn(logical(v)),fs)

Визуализируйте предполагаемые и базовые маски.

t  = (1/fs) * (0:length(v)-1);
h = figure;
plot(t,audioInNoisy(1:length(v)))
grid on
hold on
plot(t,v)
plot(t,0.8 * baseline)
xlabel('Time (s)')
legend('Training Signal','Network Mask','Baseline Mask','Location','southeast')
l = findall(h,'type','line');
l(1).LineWidth = 2;
l(2).LineWidth = 2;
title('Results for Noisy Speech - No Data Augmentation')

Выполните увеличение данных

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

Используйте audioDataAugmenter увеличивать ваш набор данных.

ada = audioDataAugmenter('TimeStretchProbability',0,...
                         'PitchShiftProbability',0,...
                         'VolumeControlProbability',0,...
                         'TimeShiftProbability',0,...
                         'SNRRange',[-1 1],...
                         'AddNoiseProbability',.85);

С этими настройками, audioDataAugmenter возразите повреждает входной звуковой сигнал с белым гауссовым шумом с вероятностью 85%. ОСШ случайным образом выбран из области значений [-1 1] (в дБ). Существует 15%-я вероятность, что увеличение не изменяет ваш входной сигнал.

Как пример, передайте звуковой сигнал увеличению.

reset(ads_keyword)
x = read(ads_keyword);
data = augment(ada,x,fs)
data =

  1×2 table

         Audio          AugmentationInfo
    ________________    ________________

    {16000×1 double}      [1×1 struct]  

Смотрите AugmentationInfo переменная в data проверять, как сигнал был изменен.

data.AugmentationInfo
ans = 

  struct with fields:

    SNR: 0.5247

Сбросьте хранилища данных.

reset(ads_keyword)
reset(ads_other)

Инициализируйте ячейки маски и функция.

TrainingFeatures = {};
TrainingMasks = {};

Выполните извлечение признаков снова. Каждый сигнал повреждается шумом с вероятностью 85%, таким образом, ваш увеличенный набор данных имеет приблизительно 85%-е зашумленные данные и 15%-е бесшумные данные.

tic
parfor ii = 1:numPartitions

    subads_keyword = partition(ads_keyword,numPartitions,ii);
    subads_other   = partition(ads_other,numPartitions,ii);

    count = 1;
    localFeatures = cell(length(subads_keyword.Files),1);
    localMasks    = cell(length(subads_keyword.Files),1);

    while hasdata(subads_keyword)

        [sentence,mask] = synthesizeSentence(subads_keyword,subads_other,fs);

        % Corrupt with noise
        augmentedData = augment(ada,sentence,fs);
        sentence      = augmentedData.Audio{1};

        % Compute mfcc features
        [coeffs,delta,deltaDelta] = mfcc(sentence,fs,'WindowLength',WindowLength,'OverlapLength',OverlapLength);
        featureMatrix = [coeffs delta deltaDelta];
        featureMatrix(~isfinite(featureMatrix)) = 0;

        hopLength = WindowLength - OverlapLength;
        range     = (hopLength) * (1:size(coeffs,1)) + hopLength;
        featureMask  = zeros(size(range));
        for index = 1:numel(range)
            featureMask(index) = mode(mask( (index-1)*hopLength+1:(index-1)*hopLength+WindowLength ));
        end

        localFeatures{count} = featureMatrix;
        catVect              = categorical(featureMask);
        catVect              = addcats(catVect,{'1'});
        localMasks{count}    = catVect;

        count = count + 1;

    end

    TrainingFeatures = [TrainingFeatures;localFeatures];
    TrainingMasks    = [TrainingMasks;localMasks];

end
fprintf('Training feature extraction took %f seconds.\n',toc)
Training feature extraction took 61.492070 seconds.

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

sampleFeature = TrainingFeatures{1};
numFeatures = size(sampleFeature,2);
featuresMatrix = cat(1,TrainingFeatures{:});
M = mean(featuresMatrix);
S = std(featuresMatrix);
for index = 1:length(TrainingFeatures)
    f = TrainingFeatures{index};
    f = (f - M) ./ S;
    TrainingFeatures{index} = f.'; %#ok
end

Нормируйте функции валидации с новыми значениями среднего и стандартного отклонения.

FeaturesValidationNoisy = (featureMatrixV - M)./S;

Переобучите сеть с увеличенным набором данных

Воссоздайте опции обучения. Используйте шумные базовые функции и маску для валидации.

options = trainingOptions("adam", ...
     "InitialLearnRate",1e-4,...
    "MaxEpochs",maxEpochs, ...
    "MiniBatchSize",miniBatchSize, ...
    "Shuffle","every-epoch",...
    "Verbose",false, ...
    "ValidationFrequency",floor(numel(TrainingFeatures)/miniBatchSize),...
    "ValidationData",{FeaturesValidationNoisy.',BaselineV},...
    "Plots","training-progress",...
    "LearnRateSchedule","piecewise",...
    "LearnRateDropFactor",0.1, ...
    "LearnRateDropPeriod",5);

Обучите сеть.

if doTraining
    [KWSNet,info] = trainNetwork(TrainingFeatures,TrainingMasks,layers,options);
else
    load('KWSNet.mat','KWSNet');%#ok
end

Проверьте сетевую точность на сигнале валидации.

v = classify(KWSNet,FeaturesValidationNoisy.');

Сравните предполагаемые и ожидаемые маски KWS.

figure
cm = confusionchart(BaselineV,v,"title","Validation Accuracy with Data Augmentation");
cm.ColumnSummary = "column-normalized";
cm.RowSummary = "row-normalized";

Слушайте идентифицированные области ключевого слова.

 v = double(v) - 1;
 v = repmat(v,HopLength,1);
 v = v(:);
sound(audioIn(logical(v)),fs)

Визуализируйте предполагаемые и ожидаемые маски.

h = figure;
plot(t,audioInNoisy(1:length(v)))
grid on
hold on
plot(t,v)
plot(t,.8 * baseline)
xlabel('Time (s)')
legend('Training Signal' , 'Network Mask','Baseline Mask','Location','southeast')
l = findall(h,'type','line');
l(1).LineWidth = 2;
l(2).LineWidth = 2;
title('Results for Noisy Speech - With Data Augmentation')