В этом примере вы обучаете три сверточные нейронные сети (CNN) выполнять верификацию динамика, а затем сравниваете производительность архитектур. Все архитектуры трех CNN эквивалентны, за исключением первого сверточного уровня в каждом:
В первой архитектуре первый сверточный слой является «стандартным» сверточным слоем, реализованным с использованием convolution2dLayer.
Во второй архитектуре первый сверточный слой представляет собой постоянный набор фильтров sinc, реализованный с использованием пользовательского слоя.
В третьей архитектуре первый сверточный уровень представляет собой обучаемый набор фильтров sinc, реализованный с использованием пользовательского уровня. Эта архитектура называется SincNet [1].
[1] показывает, что замена стандартного сверточного слоя слоем набора фильтров приводит к более быстрой конвергенции обучения и более высокой точности. [1] также показывает, что обеспечение обучаемости параметров банка фильтров дает дополнительный прирост производительности.
Идентификация спикера является важной областью исследований с различными приложениями, включая криминалистику и биометрическую аутентификацию. Многие системы идентификации говорящих зависят от предварительно вычисленных признаков, таких как i-векторы или MFCC, которые затем подаются в сети машинного обучения или глубокого обучения для классификации. Другие речевые системы глубокого обучения обходят этап извлечения признаков и подают звуковой сигнал непосредственно в сеть. В таких сквозных системах сеть непосредственно изучает характеристики низкоуровневого звукового сигнала.
В этом примере сначала обучается традиционная сквозная идентификация динамика CNN. Полученные фильтры имеют тенденцию иметь случайные формы, которые не соответствуют восприятию или знанию того, как работает человеческое ухо, особенно в сценариях, где объем обучающих данных ограничен [1]. Затем необходимо заменить первый сверточный слой в сети пользовательским слоем sinc filterbank, который вводит структуру и ограничения на основе данных восприятия. Наконец, вы обучаете архитектуру SincNet, которая добавляет обучаемость к параметрам sinc filterbank.
Три архитектуры нейронных сетей, исследованные в примере, суммируются следующим образом:
Стандартная сверточная нейронная сеть - входной сигнал непосредственно соединен со случайно инициализированным сверточным слоем, который пытается изучить особенности и захватить характеристики из необработанных аудиокадров.
ConstantSincLayer - входной сигнал свернут с набором функций sinc фиксированной ширины (полосовых фильтров), равномерно разнесенных по шкале mel.
SincNetLayer - входной сигнал свернут с набором sinc-функций, параметры которых распознаются сетью. В архитектуре SincNet сеть настраивает параметры функций sinc во время обучения.
Этот пример определяет и обучает три нейронные сети, предложенные выше, и оценивает их производительность в наборе данных LibriSpeech [2].
В этом примере используется подмножество набора данных LibriSpeech [2]. Набор данных LibriSpeech представляет собой большой корпус считанной английской речи, дискретизированной на частоте 16 кГц. Данные получены из аудиокниг, считанных из проекта LibriVox.
downloadDatasetFolder = tempdir; filename = "train-clean-100.tar.gz"; url = "http://www.openSLR.org/resources/12/" + filename; datasetFolder = fullfile(downloadDatasetFolder,"LibriSpeech","train-clean-100"); if ~isfolder(datasetFolder) gunzip(url,downloadDatasetFolder); unzippedFile = fullfile(downloadDatasetFolder,filename); untar(unzippedFile{1}(1:end-3),downloadDatasetFolder); end
Создание audioDatastore объект для доступа к аудиоданным LibriSpeech.
ADS = audioDatastore(datasetFolder,'IncludeSubfolders',1);Извлеките метку динамика из пути к файлу.
ADS.Labels = extractBetween(ADS.Files,fullfile(datasetFolder,filesep),filesep);
Полное dev-train-100 набор данных составляет около 6 ГБ данных. Для обучения сети с данными от всех 251 динамиков установите reduceDataset кому false. Чтобы быстро запустить этот пример с данными только из шести динамиков, установите reduceDataset кому true.
reducedDataSet =false; if reducedDataSet indices = cellfun(@(c)str2double(c)<50,ADS.Labels); %#ok ADS = subset(ADS,indices); end ADS = splitEachLabel(ADS,0.1);
Разделите аудиофайлы на обучающие и тестовые данные. 80% аудиофайлов назначены обучающему набору, а 20% - тестовому набору.
[ADSTrain,ADSTest] = splitEachLabel(ADS,0.8);
Постройте график одного из аудиофайлов и прослушайте его.
[audioIn,dsInfo] = read(ADSTrain); Fs = dsInfo.SampleRate; sound(audioIn,Fs) t = (1/Fs)*(0:length(audioIn)-1); plot(t,audioIn) title("Audio Sample") xlabel("Time (s)") ylabel("Amplitude") grid on

Сбросьте хранилище данных обучения.
reset(ADSTrain)
CNN ожидают, что входные данные будут иметь согласованные размеры. Вы будете предварительно обрабатывать звук, удаляя области молчания и затем разбивая оставшуюся речь на кадры 200 мс с перекрытием 40 мс.
Задайте параметры для предварительной обработки.
frameDuration = 200e-3; overlapDuration = 40e-3; frameLength = floor(Fs*frameDuration); overlapLength = round(Fs*overlapDuration);
Используйте вспомогательную функцию preprocessAudioData, для предварительной обработки обучающих и тестовых данных. XTrain и XTest содержат речевой кадр канала и тестовый речевой кадр соответственно. YTrain и YTest содержат метки канала и теста соответственно.
[XTrain,YTrain] = preprocessAudioData(ADSTrain,frameLength,overlapLength,Fs);
Starting parallel pool (parpool) using the 'local' profile ... Connected to the parallel pool (number of workers: 6).
[XTest,YTest] = preprocessAudioData(ADSTest,frameLength,overlapLength,Fs);
Стандарт CNN основан на архитектуре нейронной сети в [1].
numFilters = 80;
filterLength = 251;
numSpeakers = numel(unique(ADS.Labels));
layers = [
imageInputLayer([1 frameLength 1])
% First convolutional layer
convolution2dLayer([1 filterLength],numFilters)
batchNormalizationLayer
leakyReluLayer(0.2)
maxPooling2dLayer([1 3])
% This layer is followed by 2 convolutional layers
convolution2dLayer([1 5],60)
batchNormalizationLayer
leakyReluLayer(0.2)
maxPooling2dLayer([1 3])
convolution2dLayer([1 5],60)
batchNormalizationLayer
leakyReluLayer(0.2)
maxPooling2dLayer([1 3])
% This is followed by 3 fully-connected layers
fullyConnectedLayer(256)
batchNormalizationLayer
leakyReluLayer(0.2)
fullyConnectedLayer(256)
batchNormalizationLayer
leakyReluLayer(0.2)
fullyConnectedLayer(256)
batchNormalizationLayer
leakyReluLayer(0.2)
fullyConnectedLayer(numSpeakers)
softmaxLayer
classificationLayer];Анализ слоев нейронной сети с помощью analyzeNetwork функция
analyzeNetwork(layers)
Обучение нейронной сети в течение 15 эпох с использованием adam оптимизация. Перетасуйте тренировочные данные перед каждой эпохой. Варианты обучения нейронной сети устанавливаются с помощью trainingOptions. Используйте данные теста в качестве данных проверки для наблюдения за улучшением производительности сети по мере прохождения обучения.
numEpochs = 15; miniBatchSize = 128; validationFrequency = floor(numel(YTrain)/miniBatchSize); options = trainingOptions("adam", ... "Shuffle","every-epoch", ... "MiniBatchSize",miniBatchSize, ... "Plots","training-progress", ... "Verbose",false,"MaxEpochs",numEpochs, ... "ValidationData",{XTest,categorical(YTest)}, ... "ValidationFrequency",validationFrequency);
Для обучения сети звоните trainNetwork.
[convNet,convNetInfo] = trainNetwork(XTrain,YTrain,layers,options);

Постройте график частотной характеристики по величине девяти фильтров, полученных из стандартной сети CNN. Форма этих фильтров не интуитивна и не соответствует восприятию. В следующем разделе рассматривается эффект использования ограниченных форм фильтра.
F = squeeze(convNet.Layers(2,1).Weights); H = zeros(size(F)); Freq = zeros(size(F)); for ii = 1:size(F,2) [h,f] = freqz(F(:,ii),1,251,Fs); H(:,ii) = abs(h); Freq(:,ii) = f; end idx = linspace(1,size(F,2),9); idx = round(idx); figure for jj = 1:9 subplot(3,3,jj) plot(Freq(:,idx(jj)),H(:,idx(jj))) sgtitle("Frequency Response of Learned Standard CNN Filters") xlabel("Frequency (Hz)") end

В этом разделе вы заменяете первый сверточный слой в стандартном CNN постоянным слоем sinc filterbank. Слой набора постоянных синк-фильтров свертывает входные кадры с набором фиксированных полосовых фильтров. Полосовые фильтры представляют собой линейную комбинацию двух sinc-фильтров во временной области. Частоты полосовых фильтров линейно разнесены по шкале mel.
Реализацию для постоянного уровня набора фильтров sinc можно найти в constantSincLayer.m (прилагается к этому примеру). Определение параметров для ConstantSincLayer. Используйте 80 фильтров и длину фильтра 251.
numFilters = 80;
filterLength = 251;
numChannels = 1;
name = 'constant_sinc';Измените первый сверточный уровень со стандартного CNN на ConstantSincLayer и сохранить остальные слои неизменными.
cSL = constantSincLayer(numFilters,filterLength,Fs,numChannels,name)
cSL =
constantSincLayer with properties:
Name: 'constant_sinc'
NumFilters: 80
SampleRate: 16000
FilterLength: 251
NumChannels: []
Filters: [1×251×1×80 single]
MinimumFrequency: 50
MinimumBandwidth: 50
StartFrequencies: [1×80 double]
Bandwidths: [1×80 double]
Show all properties
layers(2) = cSL;
Обучение сети с помощью trainNetwork функция. Используйте те же параметры обучения, которые были определены ранее.
[constSincNet,constSincInfo] = trainNetwork(XTrain,YTrain,layers,options);

plotNFilters способ отображает амплитудную частотную характеристику n фильтры с равномерно разнесенными индексами фильтров. Постройте график частотной характеристики девяти фильтров в ConstantSincLayer.
figure n = 9; plotNFilters(constSincNet.Layers(2),n)

В этом разделе в качестве первого сверточного уровня сети используется обучаемый уровень SincNet. Уровень SincNet свертывает входные кадры с набором полосовых фильтров. Полоса пропускания и начальные частоты фильтров SincNet инициализируются как равномерно разнесенные в шкале mel. Уровень SincNet пытается узнать лучшие параметры для этих полосовых фильтров в рамках нейронной сети.
Реализацию для уровня набора фильтров SincNet можно найти в sincNetLayer.m (прилагается к этому примеру). Определение параметров для SincNetLayer. Используйте 80 фильтров и длину фильтра 251.
numFilters = 80;
filterLength = 251;
numChannels = 1;
name = 'sinc';Замените ConstantSincLayer из предыдущей сети с SincNetLayer. Этот новый уровень имеет два обучаемых параметра: FilterFrequencies и FilterBandwidths.
sNL = sincNetLayer(numFilters,filterLength,Fs,numChannels,name)
sNL =
sincNetLayer with properties:
Name: 'sinc'
NumFilters: 80
SampleRate: 16000
FilterLength: 251
NumChannels: []
Window: [1×251 double]
TimeStamps: [1×251 double]
MinimumFrequency: 50
MinimumBandwidth: 50
Learnable Parameters
FilterFrequencies: [1×80 double]
FilterBandwidths: [1×80 double]
Show all properties
layers(2) = sNL;
Обучение сети с помощью trainNetwork функция. Используйте те же параметры обучения, которые были определены ранее.
[sincNet,sincNetInfo] = trainNetwork(XTrain,YTrain,layers,options);

Используйте plotNFilters способ SincNetLayer визуализировать амплитудную частотную характеристику девяти фильтров с равномерно разнесенными индексами, изученными SincNet.
figure plotNFilters(sincNet.Layers(2),9)

Таблица суммирует точность кадра для всех трех нейронных сетей.
NetworkType = {'Standard CNN','Constant Sinc Layer','SincNet Layer'}';
Accuracy = [convNetInfo.FinalValidationAccuracy;constSincInfo.FinalValidationAccuracy;sincNetInfo.FinalValidationAccuracy];
resultsSummary = table(NetworkType,Accuracy)resultsSummary=3×2 table
NetworkType Accuracy
_______________________ ________
{'Standard CNN' } 72.97
{'Constant Sinc Layer'} 74.902
{'SincNet Layer' } 78.062
Постройте график точности тестового набора относительно числа эпох, чтобы увидеть, насколько хорошо учатся сети по мере увеличения числа эпох. SincNet превосходит ConstantSincLayer сеть, особенно на ранних этапах обучения. Это показывает, что обновление параметров полосовых фильтров в рамках нейронной сети приводит к более быстрой сходимости. Такое поведение наблюдается только тогда, когда набор данных достаточно велик, поэтому его можно не видеть, когда reduceDataSet имеет значение true.
epoch = linspace(0,numEpochs,numel(sincNetInfo.ValidationAccuracy(~isnan(sincNetInfo.ValidationAccuracy)))); epoch = [epoch,numEpochs]; sinc_valAcc = [sincNetInfo.ValidationAccuracy(~isnan(sincNetInfo.ValidationAccuracy)),... sincNetInfo.FinalValidationAccuracy]; const_sinc_valAcc = [constSincInfo.ValidationAccuracy(~isnan(constSincInfo.ValidationAccuracy)),... constSincInfo.FinalValidationAccuracy]; conv_valAcc = [convNetInfo.ValidationAccuracy(~isnan(convNetInfo.ValidationAccuracy)),... convNetInfo.FinalValidationAccuracy]; figure plot(epoch,sinc_valAcc,'-*','MarkerSize',4) hold on plot(epoch,const_sinc_valAcc,'-*','MarkerSize',4) plot(epoch,conv_valAcc,'-*','MarkerSize',4) ylabel('Frame-Level Accuracy (Test Set)') xlabel('Epoch') xlim([0 numEpochs+0.3]) title('Frame-Level Accuracy Versus Epoch') legend("sincNet","constantSincLayer","conv2dLayer","Location","southeast") grid on

На приведенном выше рисунке конечная точность кадра немного отличается от точности кадра, вычисленной в последней итерации. Во время обучения уровни нормализации партий выполняют нормализацию по мини-пакетам. Однако в конце обучения уровни пакетной нормализации нормализуются по всем учебным данным, что приводит к незначительному изменению производительности.
function [X,Y] = preprocessAudioData(ADS,SL,OL,Fs) if ~isempty(ver('parallel')) pool = gcp; numPar = numpartitions(ADS,pool); else numPar = 1; end parfor ii = 1:numPar X = zeros(1,SL,1,0); Y = zeros(0); subADS = partition(ADS,numPar,ii); while hasdata(subADS) [audioIn,dsInfo] = read(subADS); speechIdx = detectSpeech(audioIn,Fs); numChunks = size(speechIdx,1); audioData = zeros(1,SL,1,0); for chunk = 1:numChunks % Remove trail end audio audio_chunk = audioIn(speechIdx(chunk,1):speechIdx(chunk,2)); audio_chunk = buffer(audio_chunk,SL,OL); q = size(audio_chunk,2); % Split audio into 200 ms chunks audio_chunk = reshape(audio_chunk,1,SL,1,q); % Concatenate with existing audio audioData = cat(4,audioData,audio_chunk); end audioLabel = str2double(dsInfo.Label{1}); % Generate labels for training and testing by replecating matrix audioLabelsTrain = repmat(audioLabel,1,size(audioData,4)); % Add data points for current speaker to existing data X = cat(4,X,audioData); Y = cat(2,Y,audioLabelsTrain); end XC{ii} = X; YC{ii} = Y; end X = cat(4,XC{:}); Y = cat(2,YC{:}); Y = categorical(Y); end
[1] М. Раванелли и Я. Бенгио, «Распознавание спикера по необработанной волнообразной форме с SincNet», Семинар по технологиям разговорного языка IEEE (SLT) 2018, Афины, Греция, 2018, стр. 1021-1028, doi: 10.1109/SLT.2018.8639585.
[2] В. Панаетов, Г. Чен, Д. Пови и С. Худэнпур, «Librispeech: корпус ASR на основе аудиокниг общественного достояния», Международная конференция IEEE 2015 года по вопросам Акустики, Речи и Сигнала, Обрабатывающего (ICASSP), Брисбена, QLD, 2015, стр 5206-5210, doi: 10.1109/ICASSP.2015.7178964