В этом примере вы обучаете три сверточные нейронные сети (CNNs) для выполнения верификации динамика и затем сравниваете производительности архитектур. Архитектуры всех трех CNN эквивалентны, за исключением первого сверточного слоя в каждом:
В первой архитектуре первый сверточный слой является «стандартным» сверточным слоем, реализованным с помощью convolution2dLayer
.
Во второй архитектуре первый сверточный слой представляет собой постоянную группу фильтров синуса, реализованную с использованием пользовательского слоя.
В третьей архитектуре первый сверточный слой является обучаемым sinc filterbank, реализованным с использованием пользовательского слоя. Эта архитектура упоминается как SincNet [1].
[1] показывает, что замена стандартного сверточного слоя слоем набора фильтров приводит к более быстрой сходимости обучения и более высокой точности. [1] также показывает, что обеспечение возможности изучения параметров банка фильтров приводит к дополнительному повышению эффективности.
Идентификация спикера является заметной исследовательской областью с различными приложениями, включая криминалистику и биометрическую аутентификацию. Многие системы идентификации диктора зависят от предварительно вычисленных функций, таких как i-векторы или MFCC, которые затем подаются в машинное обучение или нейронные сети для глубокого обучения для классификации. Другие речевые системы глубокого обучения обходят стадию редукции данных и подают аудиосигнал непосредственно в сеть. В таких сквозных системах сеть непосредственно изучает характеристики низкоуровневого аудиосигнала.
В этом примере вы сначала обучите традиционную сквозную идентификацию говорящего CNN. Полученные фильтры, как правило, имеют случайные формы, которые не соответствуют перцептивным доказательствам или знаниям о том, как работает человеческое ухо, особенно в сценариях, где объем обучающих данных ограничен [1]. Затем вы заменяете первый сверточный слой в сети пользовательским слоем sinc filterbank, который вводит структуру и ограничения, основанные на перцептивных доказательствах. Наконец, вы обучаете архитектуру SincNet, которая добавляет возможности обучения в параметры sinc filterbank.
Три архитектуры нейронных сетей, исследованные в примере, суммируются следующим образом:
Стандартная сверточная нейронная сеть - вход сигнал непосредственно соединяется с случайным образом инициализированным сверточным слоем, который пытается узнать функции и захватить характеристики из необработанного аудио систем координат.
ConstantSincLayer - форма входа волны свернута с набором функций sinc фиксированной ширины (полосно-пропускающие фильтры), равномерно разнесенных по шкале меля.
SincNetLayer - форма волны входа свернута с набором функций sinc, параметры которых выучены сетью. В архитектуре SincNet сеть настраивает параметры функции sinc во время обучения.
Этот пример определяет и обучает три нейронные сети, предложенные выше, и оценивает их эффективность на LibriSpeech Dataset [2].
В этом примере вы используете подмножество набора данных LibriSpeech Dataset [2]. LibriSpeech Dataset является большим корпусом считанной английской речи, выбранной с частотой 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 индексы = cellfun (@ (c) str2double (c) < 50, ADS.Labels);%#ok ADS = подмножество (ADS, индексы); 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
Сбросьте обучающий datastore.
reset(ADSTrain)
CNNs ожидают, что входы будут иметь согласованные размерности. Вы предварительно обработаете аудио путем удаления областей молчания и затем разбьете оставшуюся речь на 200 мс систем координат с перекрытием 40 мс.
Установите параметры для предварительной обработки.
frameDuration = 200e-3; overlapDuration = 40e-3; frameLength = floor(Fs*frameDuration); overlapLength = round(Fs*overlapDuration);
Используйте вспомогательную функцию, precrocessAudioData ,
для предварительной обработки обучающих и тестовых данных. XTrain
и XTest
содержат train и тестовые речевые системы координат, соответственно. YTrain
и YTest
содержат train и тестовые метки, соответственно.
[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 filterbank свертывает входные кадры с набором фиксированных полосно-пропускающих фильтров. Полосовые фильтры являются линейной комбинацией двух фильтров синуса во временном интервале. Частоты полосно-пропускающих фильтров разнесены линейно по шкале меля.
Реализация для слоя набора фильтров постоянного синуса может быть найдена в 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);
The 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] M. Ravanelli and Y. Bengio, «Steaker Recognition from Raw Waveform with SincNet», 2018 семинар по технологии разговорного языка IEEE (SLT), Афины, Греция, 2018, стр. 1021-1028, doi: 10 .11.11.09/SLLTT.2018.18.8.8.
[2] В. Панаетов, Г. Чен, Д. Пови и С. Худэнпур, «Librispeech: корпус ASR на основе аудиокниг общественного достояния», Международная конференция IEEE 2015 года по вопросам Акустики, Речи и Сигнала, Обрабатывающего (ICASSP), Брисбена, QLD, 2015, стр 5206-5210, doi: 10.1109/ICASSP.2015.7178964