В этом примере показано, как обнаруживать области речи в среде с низким уровнем сигнала к шуму с помощью глубокого обучения. В примере используется набор данных речевых команд для обучения сети двунаправленной долговременной памяти (BiLSTM) обнаружению речевой активности.
Обнаружение речевой активности является важным компонентом многих аудиосистем, таких как автоматическое распознавание речи и распознавание динамиков. Обнаружение речевой активности может быть особенно сложным в ситуациях с низким уровнем сигнала к шуму (SNR), когда речь блокируется шумом.
В этом примере используются сети долговременной кратковременной памяти (LSTM), которые являются типом рецидивирующей нейронной сети (RNN), хорошо подходящей для изучения последовательности и данных временных рядов. Сеть LSTM может изучать долгосрочные зависимости между временными шагами последовательности. Уровень LSTM (lstmLayer (Deep Learning Toolbox)) может смотреть на временную последовательность в прямом направлении, в то время как двунаправленный уровень LSTM (bilstmLayer (Deep Learning Toolbox)) может смотреть на временную последовательность как в прямом, так и в обратном направлениях. В этом примере используется двунаправленный уровень LSTM.
Этот пример обучает двунаправленную сеть LSTM обнаружению речевой активности с характерными последовательностями спектральных характеристик и метрикой гармонического отношения.
В сценариях с высоким SNR традиционные алгоритмы обнаружения речи работают адекватно. Чтение в аудиофайле, состоящем из слов, произнесенных с паузами между ними. Выполните повторную выборку звука до 16 кГц. Слушайте звук.
fs = 16e3;
[speech,fileFs] = audioread('Counting-16-44p1-mono-15secs.wav');
speech = resample(speech,fs,fileFs);
speech = speech/max(abs(speech));
sound(speech,fs)Используйте detectSpeech функция для определения местоположения областей речи. detectSpeech функция правильно идентифицирует все области речи.
win = hamming(50e-3 * fs,'periodic'); detectSpeech(speech,fs,'Window',win)

Повреждение звукового сигнала с шумом стиральной машины при SNR -20 дБ. Прослушать поврежденный звук.
[noise,fileFs] = audioread('WashingMachine-16-8-mono-200secs.mp3');
noise = resample(noise,fs,fileFs);
SNR = -20;
noiseGain = 10^(-SNR/20) * norm(speech) / norm(noise);
noisySpeech = speech + noiseGain*noise(1:numel(speech));
noisySpeech = noisySpeech./max(abs(noisySpeech));
sound(noisySpeech,fs)Звонить detectSpeech на шумном звуковом сигнале. Функция не может обнаружить речевые области при очень низком SNR.
detectSpeech(noisySpeech,fs,'Window',win)
Загрузка и загрузка предварительно обученной сети и сконфигурированной сети audioFeatureExtractor объект. Сеть была обучена обнаружению речи в средах с низким SNR с учетом функций, выводимых из audioFeatureExtractor объект.
url = 'http://ssd.mathworks.com/supportfiles/audio/VoiceActivityDetection.zip'; downloadNetFolder = tempdir; netFolder = fullfile(downloadNetFolder,'VoiceActivityDetection'); if ~exist(netFolder,'dir') disp('Downloading pretrained network (1 file - 8 MB) ...') unzip(url,downloadNetFolder) end load(fullfile(netFolder,'voiceActivityDetectionExample.mat'));
speechDetectNet
speechDetectNet =
SeriesNetwork with properties:
Layers: [6×1 nnet.cnn.layer.Layer]
InputNames: {'sequenceinput'}
OutputNames: {'classoutput'}
afe
afe =
audioFeatureExtractor with properties:
Properties
Window: [256×1 double]
OverlapLength: 128
SampleRate: 16000
FFTLength: []
SpectralDescriptorInput: 'linearSpectrum'
Enabled Features
spectralCentroid, spectralCrest, spectralEntropy, spectralFlux, spectralKurtosis, spectralRolloffPoint
spectralSkewness, spectralSlope, harmonicRatio
Disabled Features
linearSpectrum, melSpectrum, barkSpectrum, erbSpectrum, mfcc, mfccDelta
mfccDeltaDelta, gtcc, gtccDelta, gtccDeltaDelta, spectralDecrease, spectralFlatness
spectralSpread, pitch
To extract a feature, set the corresponding property to true.
For example, obj.mfcc = true, adds mfcc to the list of enabled features.
Извлеките элементы из речевых данных, а затем нормализуйте их. Сориентируйте элементы так, чтобы время проходило по столбцам.
features = extract(afe,noisySpeech); features = (features - mean(features,1)) ./ std(features,[],1); features = features';
Передайте признаки через сеть обнаружения речи, чтобы классифицировать каждый вектор признаков как принадлежащий к кадру речи или нет.
decisionsCategorical = classify(speechDetectNet,features);
Каждое решение соответствует окну анализа, проанализированному audioFeatureExtractor. Реплицируйте решения таким образом, чтобы они находились в однозначном соответствии с выборками звука. Постройте график речи, шумной речи и решений VAD.
decisionsWindow = 1.2*(double(decisionsCategorical)-1); decisionsSample = [repelem(decisionsWindow(1),numel(afe.Window)), ... repelem(decisionsWindow(2:end),numel(afe.Window)-afe.OverlapLength)]; t = (0:numel(decisionsSample)-1)/afe.SampleRate; plot(t,noisySpeech(1:numel(t)), ... t,speech(1:numel(t)), ... t,decisionsSample); xlabel('Time (s)') ylabel('Amplitude') legend('Noisy Speech','Speech','VAD','Location','southwest')

Можно также использовать обученную сеть VAD в потоковом контексте. Для моделирования потоковой среды сначала сохраните речевые и шумовые сигналы в виде WAV-файлов. Для моделирования потокового ввода следует считывать кадры из файлов и смешивать их в требуемом SNR.
audiowrite('Speech.wav',speech,fs) audiowrite('Noise.wav',noise,fs)
Чтобы применить сеть VAD к потоковому звуку, необходимо обменяться между задержкой и точностью. Определите параметры для обнаружения потоковой голосовой активности в демонстрации шума. Можно задать длительность теста, длину последовательности, подаваемой в сеть, длину перехода последовательности, и SNR для тестирования. Обычно увеличение длины последовательности увеличивает точность, но также увеличивает отставание. Можно также выбрать сигнал, выводимый на устройство, в качестве исходного сигнала или шумного сигнала.
testDuration =20; sequenceLength =
400; sequenceHop =
20; SNR =
-20; noiseGain = 10^(-SNR/20) * norm(speech) / norm(noise); signalToListenTo =
"noisy";
Вызовите функцию поддержки потоковой демонстрации для наблюдения за производительностью сети VAD в потоковом аудио. Параметры, заданные с помощью элементов управления в реальном времени, не прерывают пример потоковой передачи. После завершения потоковой демонстрации можно изменить параметры демонстрации, а затем запустить потоковую демонстрацию еще раз. Код потоковой демонстрации можно найти в разделе Вспомогательные функции.
helperStreamingDemo(speechDetectNet,afe, ... 'Speech.wav','Noise.wav', ... testDuration,sequenceLength,sequenceHop,signalToListenTo,noiseGain);
Остальная часть примера проходит обучение и оценку сети VAD.
Обучение:
Создание audioDatastore указывает на файлы звуковой речи, используемые для обучения сети LSTM.
Создание обучающего сигнала, состоящего из речевых сегментов, разделенных сегментами тишины различной длительности.
Повреждение речевого сигнала плюс сигнал молчания с шумом стиральной машины (SNR = -10 дБ).
Извлекают из шумного сигнала характерные последовательности, состоящие из спектральных характеристик и гармонического отношения.
Обучение сети LSTM с использованием последовательностей функций для идентификации областей речевой активности.
Прогноз:
Создание audioDatastore речевых файлов, используемых для тестирования обучаемой сети, и создания тестового сигнала, состоящего из речи, разделенной сегментами тишины.
Испортить тестовый сигнал шумом стиральной машины (SNR = -10 дБ).
Извлеките последовательности признаков из шумного тестового сигнала.
Определите области речевой активности, пройдя тестирование через обученную сеть.
Сравните точность сети с базовой линией речевой активности из тестового сигнала «сигнал плюс тишина».
Вот эскиз тренировочного процесса.

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

Загрузите и извлеките набор данных речевых команд Google [1].
url = 'https://ssd.mathworks.com/supportfiles/audio/google_speech.zip'; downloadFolder = tempdir; datasetFolder = fullfile(downloadFolder,'google_speech'); if ~exist(datasetFolder,'dir') disp('Downloading Google speech commands data set (1.9 GB)...') unzip(url,downloadFolder) end
Downloading Google speech commands data set (1.9 GB)...
Создание audioDatastore указывает на набор данных обучения.
adsTrain = audioDatastore(fullfile(datasetFolder, 'train'), "Includesubfolders",true);
Создание audioDatastore указывает на набор данных проверки.
adsValidation = audioDatastore(fullfile(datasetFolder, 'validation'), "Includesubfolders",true);
Чтение содержимого аудиофайла с помощью read. Получить частоту выборки из adsInfo структура.
[data,adsInfo] = read(adsTrain); Fs = adsInfo.SampleRate;
Прослушивание звукового сигнала с помощью команды sound.
sound(data,Fs)
Постройте график звукового сигнала.
timeVector = (1/Fs) * (0:numel(data)-1); plot(timeVector,data) ylabel("Amplitude") xlabel("Time (s)") title("Sample Audio") grid on

Сигнал имеет неречевые части (тишина, фоновый шум и т.д.), которые не содержат полезной речевой информации. Этот пример удаляет молчание с помощью detectSpeech функция.
Извлеките полезную часть данных. Определите периодическое окно Хэмминга 50 мс для анализа. Звонить detectSpeech без выходных аргументов для построения графика обнаруженных речевых областей. Звонить detectSpeech для возврата индексов обнаруженной речи. Изолировать обнаруженные речевые области и затем использовать sound для прослушивания звука.
win = hamming(50e-3 * Fs,'periodic'); detectSpeech(data,Fs,'Window',win);

speechIndices = detectSpeech(data,Fs,'Window',win);
sound(data(speechIndices(1,1):speechIndices(1,2)),Fs) detectSpeech функция возвращает индексы, которые плотно окружают обнаруженную область речи. Эмпирически было определено, что для этого примера расширение индексов обнаруженной речи на пять кадров с каждой стороны увеличило производительность конечной модели. Увеличьте речевые индексы на пять кадров, а затем прослушайте речь.
speechIndices(1,1) = max(speechIndices(1,1) - 5*numel(win),1); speechIndices(1,2) = min(speechIndices(1,2) + 5*numel(win),numel(data)); sound(data(speechIndices(1,1):speechIndices(1,2)),Fs)
Сбросьте хранилище данных обучения и перетасуйте порядок файлов в хранилищах данных.
reset(adsTrain) adsTrain = shuffle(adsTrain); adsValidation = shuffle(adsValidation);
detectSpeech функция вычисляет основанные на статистике пороги для определения речевых областей. Вы можете пропустить расчет порога и ускорить detectSpeech путем непосредственного задания пороговых значений. Для определения пороговых значений для набора данных вызовите detectSpeech при выборке файлов и получении вычисляемых пороговых значений. Возьмем среднее пороговых значений.
TM = []; for index1 = 1:500 data = read(adsTrain); [~,T] = detectSpeech(data,Fs,'Window',win); TM = [TM;T]; end T = mean(TM); reset(adsTrain)
Создание 1000-секундного обучающего сигнала путем объединения нескольких речевых файлов из набора обучающих данных. Использовать detectSpeech для удаления нежелательных частей каждого файла. Вставка случайного периода молчания между речевыми сегментами.
Предварительно распределите обучающий сигнал.
duration = 2000*Fs; audioTraining = zeros(duration,1);
Предварительно назначьте маску обучения голосовым действиям. Значения 1 в маске соответствуют выборкам, расположенным в зонах с речевой активностью. Значения 0 соответствуют областям без речевой активности.
maskTraining = zeros(duration,1);
Укажите максимальную продолжительность сегмента молчания, равную 2 секундам.
maxSilenceSegment = 2;
Создание обучающего сигнала путем вызова read в хранилище данных в цикле.
numSamples = 1; while numSamples < duration data = read(adsTrain); data = data ./ max(abs(data)); % Normalize amplitude % Determine regions of speech idx = detectSpeech(data,Fs,'Window',win,'Thresholds',T); % If a region of speech is detected if ~isempty(idx) % Extend the indices by five frames idx(1,1) = max(1,idx(1,1) - 5*numel(win)); idx(1,2) = min(length(data),idx(1,2) + 5*numel(win)); % Isolate the speech data = data(idx(1,1):idx(1,2)); % Write speech segment to training signal audioTraining(numSamples:numSamples+numel(data)-1) = data; % Set VAD baseline maskTraining(numSamples:numSamples+numel(data)-1) = true; % Random silence period numSilenceSamples = randi(maxSilenceSegment*Fs,1,1); numSamples = numSamples + numel(data) + numSilenceSamples; end end
Визуализируйте 10-секундную часть обучающего сигнала. Постройте график базовой маски голосовой активности.
figure range = 1:10*Fs; plot((1/Fs)*(range-1),audioTraining(range)); hold on plot((1/Fs)*(range-1),maskTraining(range)); grid on lines = findall(gcf,"Type","Line"); lines(1).LineWidth = 2; xlabel("Time (s)") legend("Signal","Speech Region") title("Training Signal (first 10 seconds)");

Прослушайте первые 10 секунд обучающего сигнала.
sound(audioTraining(range),Fs);
Искажение обучающего сигнала с помощью шума стиральной машины путем добавления шума стиральной машины к речевому сигналу таким образом, чтобы отношение сигнал/шум составляло -10 дБ.
Считайте шум 8 кГц и преобразуйте его в 16 кГц.
noise = audioread("WashingMachine-16-8-mono-1000secs.mp3");
noise = resample(noise,2,1);Поврежденный тренировочный сигнал с шумом.
audioTraining = audioTraining(1:numel(noise)); SNR = -10; noise = 10^(-SNR/20) * noise * norm(audioTraining) / norm(noise); audioTrainingNoisy = audioTraining + noise; audioTrainingNoisy = audioTrainingNoisy / max(abs(audioTrainingNoisy));
Визуализируйте 10-секундную часть шумного обучающего сигнала. Постройте график базовой маски голосовой активности.
figure plot((1/Fs)*(range-1),audioTrainingNoisy(range)); hold on plot((1/Fs)*(range-1),maskTraining(range)); grid on lines = findall(gcf,"Type","Line"); lines(1).LineWidth = 2; xlabel("Time (s)") legend("Noisy Signal","Speech Area") title("Training Signal (first 10 seconds)");

Прослушайте первые 10 секунд шумного обучающего сигнала.
sound(audioTrainingNoisy(range),Fs)
Обратите внимание, что базовая маска речевой активности была получена с помощью сигнала бесшумной речи плюс тишина. Убедитесь, что используется detectSpeech сигнал с искаженным шумом не дает хороших результатов.
speechIndices = detectSpeech(audioTrainingNoisy,Fs,'Window',win); speechIndices(:,1) = max(1,speechIndices(:,1) - 5*numel(win)); speechIndices(:,2) = min(numel(audioTrainingNoisy),speechIndices(:,2) + 5*numel(win)); noisyMask = zeros(size(audioTrainingNoisy)); for ii = 1:size(speechIndices) noisyMask(speechIndices(ii,1):speechIndices(ii,2)) = 1; end
Визуализируйте 10-секундную часть шумного обучающего сигнала. Постройте график маски речевой активности, полученной при анализе шумного сигнала.
figure plot((1/Fs)*(range-1),audioTrainingNoisy(range)); hold on plot((1/Fs)*(range-1),noisyMask(range)); grid on lines = findall(gcf,"Type","Line"); lines(1).LineWidth = 2; xlabel("Time (s)") legend("Noisy Signal","Mask from Noisy Signal") title("Training Signal (first 10 seconds)");

Создайте 200-секундный шумный речевой сигнал для проверки подлинности обученной сети. Используйте хранилище данных проверки. Обратите внимание, что хранилища данных проверки и обучения имеют разных докладчиков.
Предварительно назначьте сигнал проверки и маску проверки. Эта маска используется для оценки точности обученной сети.
duration = 200*Fs; audioValidation = zeros(duration,1); maskValidation = zeros(duration,1);
Создание сигнала проверки путем вызова read в хранилище данных в цикле.
numSamples = 1; while numSamples < duration data = read(adsValidation); data = data ./ max(abs(data)); % Normalize amplitude % Determine regions of speech idx = detectSpeech(data,Fs,'Window',win,'Thresholds',T); % If a region of speech is detected if ~isempty(idx) % Extend the indices by five frames idx(1,1) = max(1,idx(1,1) - 5*numel(win)); idx(1,2) = min(length(data),idx(1,2) + 5*numel(win)); % Isolate the speech data = data(idx(1,1):idx(1,2)); % Write speech segment to training signal audioValidation(numSamples:numSamples+numel(data)-1) = data; % Set VAD Baseline maskValidation(numSamples:numSamples+numel(data)-1) = true; % Random silence period numSilenceSamples = randi(maxSilenceSegment*Fs,1,1); numSamples = numSamples + numel(data) + numSilenceSamples; end end
Искажение сигнала проверки подлинности с помощью шума стиральной машины путем добавления шума стиральной машины к речевому сигналу таким образом, чтобы отношение сигнал/шум составляло -10 дБ. Используйте другой файл шума для сигнала проверки подлинности, чем для обучающего сигнала.
noise = audioread("WashingMachine-16-8-mono-200secs.mp3");
noise = resample(noise,2,1);
noise = noise(1:duration);
audioValidation = audioValidation(1:numel(noise));
noise = 10^(-SNR/20) * noise * norm(audioValidation) / norm(noise);
audioValidationNoisy = audioValidation + noise;
audioValidationNoisy = audioValidationNoisy / max(abs(audioValidationNoisy));В этом примере выполняется обучение сети LSTM с использованием следующих функций:
В этом примере используется audioFeatureExtractor для создания оптимального трубопровода извлечения элемента для набора элементов. Создание audioFeatureExtractor объект для извлечения набора элементов. Используйте 256-точечное окно Ганна с 50% перекрытием.
afe = audioFeatureExtractor('SampleRate',Fs, ... 'Window',hann(256,"Periodic"), ... 'OverlapLength',128, ... ... 'spectralCentroid',true, ... 'spectralCrest',true, ... 'spectralEntropy',true, ... 'spectralFlux',true, ... 'spectralKurtosis',true, ... 'spectralRolloffPoint',true, ... 'spectralSkewness',true, ... 'spectralSlope',true, ... 'harmonicRatio',true); featuresTraining = extract(afe,audioTrainingNoisy);
Отображение размеров матрицы элементов. Первое измерение соответствует количеству окон, в которые был разбит сигнал (оно зависит от длины окна и длины перекрытия). Второй размер - это количество элементов, используемых в этом примере.
[numWindows,numFeatures] = size(featuresTraining)
numWindows = 125009
numFeatures = 9
В классификационных приложениях рекомендуется нормализовать все элементы так, чтобы они имели нулевое среднее и единичное стандартное отклонение.
Вычислите среднее значение и стандартное отклонение для каждого коэффициента и используйте их для нормализации данных.
M = mean(featuresTraining,1); S = std(featuresTraining,[],1); featuresTraining = (featuresTraining - M) ./ S;
Извлеките элементы из сигнала проверки с помощью того же процесса.
featuresValidation = extract(afe,audioValidationNoisy); featuresValidation = (featuresValidation - mean(featuresValidation,1)) ./ std(featuresValidation,[],1);
Каждая функция соответствует 128 выборкам данных (длина транзитного участка). Для каждого транзитного участка установите ожидаемое значение «голос/нет голоса» в режим базовых значений маски, соответствующих этим 128 выборкам. Преобразуйте голосовую маску в категориальную.
windowLength = numel(afe.Window); hopLength = windowLength - afe.OverlapLength; range = (hopLength) * (1:size(featuresTraining,1)) + hopLength; maskMode = zeros(size(range)); for index = 1:numel(range) maskMode(index) = mode(maskTraining( (index-1)*hopLength+1:(index-1)*hopLength+windowLength )); end maskTraining = maskMode.'; maskTrainingCat = categorical(maskTraining);
Выполните то же самое для маски проверки.
range = (hopLength) * (1:size(featuresValidation,1)) + hopLength; maskMode = zeros(size(range)); for index = 1:numel(range) maskMode(index) = mode(maskValidation( (index-1)*hopLength+1:(index-1)*hopLength+windowLength )); end maskValidation = maskMode.'; maskValidationCat = categorical(maskValidation);
Разделите обучающие признаки и маску на последовательности длиной 800, с 75% перекрытием между последовательными последовательностями.
sequenceLength = 800; sequenceOverlap = round(0.75*sequenceLength); trainFeatureCell = helperFeatureVector2Sequence(featuresTraining',sequenceLength,sequenceOverlap); trainLabelCell = helperFeatureVector2Sequence(maskTrainingCat',sequenceLength,sequenceOverlap);
Сети LSTM могут изучать долгосрочные зависимости между временными шагами данных последовательности. В этом примере используется двунаправленный уровень LSTM bilstmLayer (Deep Learning Toolbox) для просмотра последовательности в прямом и обратном направлениях.
Укажите входной размер, который будет последовательностью длины 9 (количество элементов). Укажите скрытый двунаправленный уровень LSTM с размером вывода 200 и выведите последовательность. Эта команда дает команду двунаправленному уровню LSTM отобразить входной временной ряд в 200 признаков, которые передаются на следующий уровень. Затем укажите двунаправленный уровень LSTM с размером вывода 200 и выведите последний элемент последовательности. Эта команда дает команду двунаправленному уровню LSTM преобразовать его вход в 200 функций, а затем подготавливает выход для полностью подключенного уровня. Наконец, укажите два класса, включив полностью подключенный слой размера 2, за которым следуют слой softmax и слой классификации.
layers = [ ... sequenceInputLayer( size(featuresValidation,2) ) bilstmLayer(200,"OutputMode","sequence") bilstmLayer(200,"OutputMode","sequence") fullyConnectedLayer(2) softmaxLayer classificationLayer ];
Затем укажите параметры обучения для классификатора. Набор MaxEpochs кому 20 так, что сеть 20 проходит через обучающие данные. Набор MiniBatchSize кому 64 чтобы сеть просматривала 64 обучающих сигнала одновременно. Набор Plots кому "training-progress" для создания графиков, показывающих ход обучения по мере увеличения числа итераций. Набор Verbose кому false для отключения печати выходных данных таблицы, соответствующих данным, отображаемым на графике. Набор Shuffle кому "every-epoch" перетасовать тренировочную последовательность в начале каждой эпохи. Набор LearnRateSchedule кому "piecewise" снижать скорость обучения на заданный коэффициент (0,1) каждый раз, когда проходит определенное количество эпох (10). Набор ValidationData к предикторам и целям проверки.
В этом примере используется решатель ADAM. ADAM работает лучше с рецидивирующими нейронными сетями (RNN), такими как LSTM, чем стохастический градиентный спуск по умолчанию с решателем импульса (SGDM).
maxEpochs = 20; miniBatchSize = 64; options = trainingOptions("adam", ... "MaxEpochs",maxEpochs, ... "MiniBatchSize",miniBatchSize, ... "Shuffle","every-epoch", ... "Verbose",0, ... "SequenceLength",sequenceLength, ... "ValidationFrequency",floor(numel(trainFeatureCell)/miniBatchSize), ... "ValidationData",{featuresValidation.',maskValidationCat.'}, ... "Plots","training-progress", ... "LearnRateSchedule","piecewise", ... "LearnRateDropFactor",0.1, ... "LearnRateDropPeriod",5);
Обучение сети LSTM с использованием указанных вариантов обучения и архитектуры уровня с помощью trainNetwork. Поскольку тренировочный набор большой, тренировочный процесс может занять несколько минут.
doTraining = true; if doTraining [speechDetectNet,netInfo] = trainNetwork(trainFeatureCell,trainLabelCell,layers,options); fprintf("Validation accuracy: %f percent.\n", netInfo.FinalValidationAccuracy); else load speechDetectNet end
Validation accuracy: 91.320312 percent.
Оценка речевой активности в сигнале проверки подлинности с использованием обученной сети. Преобразование расчетной маски VAD из категориальной в двойную.
EstimatedVADMask = classify(speechDetectNet,featuresValidation.'); EstimatedVADMask = double(EstimatedVADMask); EstimatedVADMask = EstimatedVADMask.' - 1;
Вычислите и постройте график матрицы путаницы проверки на основе векторов фактических и оценочных меток.
figure cm = confusionchart(maskValidation,EstimatedVADMask,"title","Validation Accuracy"); cm.ColumnSummary = "column-normalized"; cm.RowSummary = "row-normalized";

При изменении параметров сети или трубопровода извлечения элементов рекомендуется повторно сохранить MAT-файл в новой сети и audioFeatureExtractor объект.
resaveNetwork =false; if resaveNetwork save('Audio_VoiceActivityDetectionExample.mat','speechDetectNet','afe'); end
function [sequences,sequencePerFile] = helperFeatureVector2Sequence(features,featureVectorsPerSequence,featureVectorOverlap) if featureVectorsPerSequence <= featureVectorOverlap error('The number of overlapping feature vectors must be less than the number of feature vectors per sequence.') end if ~iscell(features) features = {features}; end hopLength = featureVectorsPerSequence - featureVectorOverlap; idx1 = 1; sequences = {}; sequencePerFile = cell(numel(features),1); for ii = 1:numel(features) sequencePerFile{ii} = floor((size(features{ii},2) - featureVectorsPerSequence)/hopLength) + 1; idx2 = 1; for j = 1:sequencePerFile{ii} sequences{idx1,1} = features{ii}(:,idx2:idx2 + featureVectorsPerSequence - 1); %#ok<AGROW> idx1 = idx1 + 1; idx2 = idx2 + hopLength; end end end
function helperStreamingDemo(speechDetectNet,afe,cleanSpeech,noise,testDuration,sequenceLength,sequenceHop,signalToListenTo,noiseGain)Создать dsp.AudioFileReader объекты для считывания из речевых и шумовых файлов покадрово.
speechReader = dsp.AudioFileReader(cleanSpeech,'PlayCount',inf); noiseReader = dsp.AudioFileReader(noise,'PlayCount',inf); fs = speechReader.SampleRate;
Создать dsp.MovingStandardDeviation объект и dsp.MovingAverage объект. Они используются для определения стандартного отклонения и среднего значения звуковых функций для нормализации. Со временем статистика должна улучшаться.
movSTD = dsp.MovingStandardDeviation('Method','Exponential weighting','ForgettingFactor',1); movMean = dsp.MovingAverage('Method','Exponential weighting','ForgettingFactor',1);
Создать три dsp.AsyncBuffer объекты. Один для буферизации входного звука, один для буферизации извлеченных элементов и один для буферизации выходного буфера. Выходной буфер необходим только для визуализации решений в реальном времени.
audioInBuffer = dsp.AsyncBuffer;
featureBuffer = dsp.AsyncBuffer;
audioOutBuffer = dsp.AsyncBuffer;Для звуковых буферов выполняется буферизация как исходного чистого речевого сигнала, так и шумного сигнала. Вы будете воспроизводить только указанные signalToListenTo. Преобразовать signalToListenTo переменная для канала, который вы хотите прослушать.
channelToListenTo = 1;
if strcmp(signalToListenTo,"clean")
channelToListenTo = 2;
endСоздайте область времени для визуализации исходного речевого сигнала, шумного сигнала, к которому применяется сеть, и выходного сигнала решения из сети.
scope = timescope('SampleRate',fs, ... 'TimeSpanSource','property', ... 'TimeSpan',3, ... 'BufferLength',fs*3*3, ... 'YLimits',[-1 1], ... 'TimeSpanOverrunAction','Scroll', ... 'ShowGrid',true, ... 'NumInputPorts',3, ... 'LayoutDimensions',[3,1], ... 'Title','Noisy Speech'); scope.ActiveDisplay = 2; scope.Title = 'Clean Speech (Original)'; scope.YLimits = [-1 1]; scope.ActiveDisplay = 3; scope.Title = 'Detected Speech'; scope.YLimits = [-1 1];
Создание audioDeviceWriter объект для воспроизведения оригинального или шумного звука с динамиков.
deviceWriter = audioDeviceWriter('SampleRate',fs);Инициализация переменных, используемых в цикле.
windowLength = numel(afe.Window);
hopLength = windowLength - afe.OverlapLength;
myMax = 0;
audioBufferInitialized = false;
featureBufferInitialized = false;Запустите потоковую демонстрацию.
tic
while toc < testDuration
% Read a frame of the speech signal and a frame of the noise signal
speechIn = speechReader();
noiseIn = noiseReader();
% Mix the speech and noise at the specified SNR
noisyAudio = speechIn + noiseGain*noiseIn;
% Update a running max for normalization
myMax = max(myMax,max(abs(noisyAudio)));
% Write the noisy audio and speech to buffers
write(audioInBuffer,[noisyAudio,speechIn]);
% If enough samples are buffered,
% mark the audio buffer as initialized and push the read pointer
% for the audio buffer up a window length.
if audioInBuffer.NumUnreadSamples >= windowLength && ~audioBufferInitialized
audioBufferInitialized = true;
read(audioInBuffer,windowLength);
end
% If enough samples are in the audio buffer to calculate a feature
% vector, read the samples, normalize them, extract the feature vectors, and write
% the latest feature vector to the features buffer.
while (audioInBuffer.NumUnreadSamples >= hopLength) && audioBufferInitialized
x = read(audioInBuffer,windowLength + hopLength,windowLength);
write(audioOutBuffer,x(end-hopLength+1:end,:));
noisyAudio = x(:,1);
noisyAudio = noisyAudio/myMax;
features = extract(afe,noisyAudio);
write(featureBuffer,features(2,:));
end
% If enough feature vectors are buffered, mark the feature buffer
% as initialized and push the read pointer for the feature buffer
% and the audio output buffer (so that they are in sync).
if featureBuffer.NumUnreadSamples >= (sequenceLength + sequenceHop) && ~featureBufferInitialized
featureBufferInitialized = true;
read(featureBuffer,sequenceLength - sequenceHop);
read(audioOutBuffer,(sequenceLength - sequenceHop)*windowLength);
end
while featureBuffer.NumUnreadSamples >= sequenceHop && featureBufferInitialized
features = read(featureBuffer,sequenceLength,sequenceLength - sequenceHop);
features(isnan(features)) = 0;
% Use only the new features to update the
% standard deviation and mean. Normalize the features.
localSTD = movSTD(features(end-sequenceHop+1:end,:));
localMean = movMean(features(end-sequenceHop+1:end,:));
features = (features - localMean(end,:)) ./ localSTD(end,:);
decision = classify(speechDetectNet,features');
decision = decision(end-sequenceHop+1:end);
decision = double(decision)' - 1;
decision = repelem(decision,hopLength);
audioHop = read(audioOutBuffer,sequenceHop*hopLength);
% Listen to the speech or speech+noise
deviceWriter(audioHop(:,channelToListenTo));
% Visualize the speech+noise, the original speech, and the
% voice activity detection.
scope(audioHop(:,1),audioHop(:,2),audioHop(:,1).*decision)
end
end
release(deviceWriter)
release(audioInBuffer)
release(audioOutBuffer)
release(featureBuffer)
release(movSTD)
release(movMean)
release(scope)
end[1] Уорден П. «Речевые команды: публичный набор данных для однословного распознавания речи», 2017. Доступно в https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz. Авторское право Google 2017. Набор данных речевых команд лицензирован по лицензии Creative Commons Attribution 4.0