Этот пример показов, как классифицировать разговорные цифры с помощью глубокой сверточной нейронной сети (CNN) и пользовательского слоя журнала спектрограммы. Пользовательский слой использует dlstft
функция для вычисления краткосрочных преобразований Фурье способом, который поддерживает автоматическое распространение назад.
Клон или скачать бесплатный набор данных Spoken Digit (FSDD), доступный в https://github.com/Jakobovski/free-spoken-digit-dataset. FSDD является открытым набором данных, что означает, что он может расти с течением времени. Этот пример использует версию, совершенную 12 августа 2020 года, которая состоит из 3000 записей на английском языке цифр от 0 до 9, полученных от шести дикторов. Каждая цифра произносится 50 раз каждым диктором. Данные отбираются с частотой дискретизации 8000 Гц.
Использование audioDatastore
для управления доступом к данным. Установите location
Свойство в расположение папки записей FSDD на вашем компьютере. В этом примере используется базовая папка, возвращенная MATLAB tempdir
команда.
pathToRecordingsFolder = fullfile(tempdir,'free-spoken-digit-dataset','recordings'); location = pathToRecordingsFolder; ads = audioDatastore(location);
Функция помощника helpergenLabels
создает категориальный массив меток из файлов FSDD. Исходный код для helpergenLabels
приведено в приложении. Перечислите классы и количество примеров в каждом классе.
ads.Labels = helpergenLabels(ads); summary(ads.Labels)
0 300 1 300 2 300 3 300 4 300 5 300 6 300 7 300 8 300 9 300
Извлеките четыре аудио файлов, соответствующих разным цифрам. Использование stft
построить их спектрограммы в децибелах. Различия в формантной структуре высказываний различимы в спектрограмме. Это делает спектрограмму разумным представлением сигнала для обучения, чтобы различать цифры в глубокой сети.
adsSample = subset(ads,[1,301,601,901]); SampleRate = 8000; for i = 1:4 [audioSamples,info] = read(adsSample); subplot(2,2,i) stft(audioSamples,SampleRate,'FrequencyRange','onesided'); title('Digit: '+string(info.Label)) end
Разделите FSDD на обучающие и тестовые наборы с сохранением равных пропорций меток в каждом подмножестве. Для воспроизводимых результатов установите генератор случайных чисел на его значение по умолчанию. Восемьдесят процентов, или 2400 записей, используются для обучения. Оставшиеся 600 записей, 20% от общего числа, удерживаются для проверки.
rng default;
ads = shuffle(ads);
[adsTrain,adsTest] = splitEachLabel(ads,0.8);
Подтвердите, что как обучающий, так и тестовый наборы содержат правильные пропорции каждого класса.
disp(countEachLabel(adsTrain))
Label Count _____ _____ 0 240 1 240 2 240 3 240 4 240 5 240 6 240 7 240 8 240 9 240
disp(countEachLabel(adsTest))
Label Count _____ _____ 0 60 1 60 2 60 3 60 4 60 5 60 6 60 7 60 8 60 9 60
Записи в FSDD не имеют равномерной длины в выборках. Чтобы использовать спектрограмму в качестве представления сигнала в глубокой сети, требуется равномерная входная длина. Анализ аудиозаписей в этой версии FSDD показывает, что общая длина 8192 выборки является подходящим для обеспечения того, чтобы никакая разговорная цифра не была обрезана. Записи, больше 8192 сэмпла в длину, усечены до 8192 сэмплов, в то время как записи с менее чем 8192 выборки симметрично заполнены до длины 8192 выборок Функция помощника helperReadSPData
обрезает или заполняет данные до 8192 выборок и нормализует каждую запись по ее максимальному значению. Исходный код для helperReadSPData
приведено в приложении. Эта вспомогательная функция применяется к каждой записи при помощи хранилища datastore преобразования в сочетании с audioDatastore
.
transTrain = transform(adsTrain,@(x,info)helperReadSPData(x,info),'IncludeInfo',true); transTest = transform(adsTest,@(x,info)helperReadSPData(x,info),'IncludeInfo',true);
Когда любая обработка сигналов выполняется вне сети в качестве шагов предварительной обработки, существует большая вероятность того, что предсказания сети выполняются с различными настройками предварительной обработки, чем те, которые используются в сетевом обучении. Это может оказать значительное влияние на эффективность сети, обычно приводя к снижению эффективности, чем ожидалось. Размещение спектрограммы или любых других предварительных расчетов внутри сети в качестве слоя дает вам автономную модель и упрощает конвейер для развертывания. Это позволяет вам эффективно обучать, развертывать или совместно использовать свою сеть со всеми необходимыми операциями обработки сигналов. В этом примере основной операцией обработки сигналов является расчет спектрограммы. Возможность вычислить спектрограмму внутри сети полезна как для вывода, так и когда пространство в памяти устройства недостаточно для сохранения спектрограмм. Вычисление спектрограммы в сети требует только достаточного выделения памяти для текущего пакета спектрограмм. Однако следует отметить, что это не оптимальный выбор с точки зрения скорости обучения. Если у вас достаточно памяти, время обучения значительно сокращается путем предварительного вычисления всех спектрограмм и хранения этих результатов. Затем, чтобы обучить сеть, считывайте «изображения» спектрограммы из хранилища вместо необработанного аудио и вводите спектрограммы непосредственно в сети. Обратите внимание, что, хотя это приводит к наиболее быстрому времени обучения, способность выполнять обработку сигналов внутри сети все еще имеет значительные преимущества по указанным выше причинам.
В обучении глубоких сетей часто выгодно использовать логарифм представления сигнала, потому что логарифм действует как динамический компрессор области значений, увеличивая значения представления, которые имеют малые величины (амплитуды), но все еще несут важную информацию. В этом примере логарифмическая спектрограмма работает лучше, чем спектрограмма. Соответственно, этот пример создает пользовательский слой журнала спектрограммы и вставляет его в сеть после слоя входа. Дополнительные сведения о создании пользовательского слоя см. в разделе «Определение пользовательских слоев глубокого обучения» (Deep Learning Toolbox).
logSpectrogramLayer
является слоем без настраиваемых параметров, поэтому необходимы только невразучиваемые свойства. Здесь единственными необходимыми свойствами являются свойства, необходимые для расчета спектрограммы. Объявите их в properties
раздел. В predict
слоя function, the
dlarray
-поддерживаемая краткосрочная функция преобразования Фурье dlstft
используется для вычисления спектрограммы. Для получения дополнительной информации о dlstft
и эти параметры, относятся к dlstft
документация. Создайте функцию, которая создает слой и инициализирует свойства слоя. Задайте любые переменные, необходимые для создания слоя в качестве входов для функции конструктора.
classdef logSpectrogramLayer < nnet.layer.Layer properties % (Optional) Layer properties. % Spectral window Window % Number of overlapped smaples OverlapLength % Number of DFT points FFTLength % Signal Length SignalLength end method function layer = logSpectrogramLayer(sigLength,NVargs) arguments sigLength {mustBeNumeric} NVargs.Window {mustBeFloat,mustBeNonempty,mustBeFinite,mustBeReal,mustBeVector}= hann(128,'periodic') NVargs.OverlapLength {mustBeNumeric} = 96 NVargs.FFTLength {mustBeNumeric} = 128 NVargs.Name string = "logspec" end layer.Type = 'logSpectrogram'; layer.Name = NVargs.Name; layer.SignalLength = sigLength; layer.Window = NVargs.Window; layer.OverlapLength = NVargs.OverlapLength; layer.FFTLength = NVargs.FFTLength; end ... end
Как упоминалось выше, пользовательский слой использует dlstft
для получения STFT и затем вычисляет логарифм квадратной величины STFT, чтобы получить логарифмические спектрограммы. Можно также удалить log
функция, если вы хотите или добавляете любую другую поддерживаемую dlarray функцию, чтобы настроить выход. Можно копировать logSpectrogramLayer.m
в другую папку, если вы хотите экспериментировать с различными выходами от функции предсказания. Рекомендуется сохранить пользовательский слой под другим именем, чтобы предотвратить любые конфликты с версией, используемой в этом примере.
function Z = predict(layer, X) % Forward input data through the layer at prediction time and % output the result. % % Inputs: % layer - Layer to forward propagate through % X - Input data, specified as a 1-by-1-by-C-by-N % dlarray, where N is the mini-batch size. % Outputs: % Z - Output of layer forward function returned as % an sz(1)-by-sz(2)-by-sz(3)-by-N dlarray, % where sz is the layer output size and N is % the mini-batch size. % Use dlstft to compute short-time Fourier transform. % Specify the data format as SSCB to match the output of % imageInputLayer. X = squeeze(X); [YR,YI] = dlstft(X,'Window',layer.Window,... 'FFTLength',layer.FFTLength,'OverlapLength',layer.OverlapLength,... 'DataFormat','TBC'); % This code is needed to handle the fact that 2D convolutional % DAG networks expect SSCB YR = permute(YR,[1 4 2 3]); YI = permute(YI,[1 4 2 3]); % Take the logarithmic squared magnitude of short-time Fourier % transform. Z = log(YR.^2 + YI.^2); end
Поскольку logSpectrogramLayer использует тот же прямой проход для обучения и предсказания (вывод), только predict
функция необходима, и нет forward
функция обязательна. Кроме того, потому что predict
функция использует dlstft
, который поддерживает dlarray
дифференциация в обратном распространении может быть выполнена автоматически. Это означает, что вы не должны писать backward
функция. Это является значительным преимуществом при написании пользовательского слоя, поддерживающего dlarray
. Список функций, поддерживающих dlarray
объекты, см. Список функций с поддержкой dlarray (Deep Learning Toolbox).
Можно использовать пользовательский слой так же, как и любой другой слой в Deep Learning Toolbox. Создайте небольшой DCNN как массив слоев, который включает пользовательский слой logSpectrogramLayer
. Используйте сверточные и пакетные слои нормализации и downsample карты признаков с помощью максимальных слоев объединения. Чтобы защитить от сверхподбора кривой, добавьте небольшое количество выпадения на вход последнего полностью подключенного слоя.
sigLength = 8192; dropoutProb = 0.2; numF = 12; layers = [ imageInputLayer([sigLength 1]) logSpectrogramLayer(sigLength,'Window',hamming(1280),'FFTLength',1280,... 'OverlapLength',900) convolution2dLayer(5,numF,'Padding','same') batchNormalizationLayer reluLayer maxPooling2dLayer(3,'Stride',2,'Padding','same') convolution2dLayer(3,2*numF,'Padding','same') batchNormalizationLayer reluLayer maxPooling2dLayer(3,'Stride',2,'Padding','same') convolution2dLayer(3,4*numF,'Padding','same') batchNormalizationLayer reluLayer maxPooling2dLayer(3,'Stride',2,'Padding','same') convolution2dLayer(3,4*numF,'Padding','same') batchNormalizationLayer reluLayer convolution2dLayer(3,4*numF,'Padding','same') batchNormalizationLayer reluLayer maxPooling2dLayer(2) dropoutLayer(dropoutProb) fullyConnectedLayer(numel(categories(ads.Labels))) softmaxLayer classificationLayer('Classes',categories(ads.Labels)); ];
Установите гиперпараметры, которые будут использоваться при обучении сети. Используйте мини-пакет размером 50
и скорость обучения в 1e-4
. Задайте оптимизацию Адама. Задайте UsePrefetch
на true
обеспечение возможности асинхронной предварительной выборки и постановки данных в постановку в очередь для оптимизации производительности обучения. Фоновая отправка данных и использование графический процессор для обучения сети требует Parallel Computing Toolbox™.
UsePrefetch = true; опции = trainingOptions ('adam', ... 'InitialLearnRate', 1e-4, ... 'MaxEpochs',30, ... 'MiniBatchSize',50, ... 'Shuffle','every-epoch', ... 'DispatchInBackground', UsePrefetch,... 'Plots','training-progress',... "Verbose", ложный);
Обучите сеть.
[trainedNet,trainInfo] = trainNetwork(transTrain,layers,options);
Используйте обученную сеть, чтобы предсказать метки цифр для тестового набора. Вычислите точность предсказания.
[YPred,probs] = classify(trainedNet,transTest); cnnAccuracy = sum(YPred==adsTest.Labels)/numel(YPred)*100
cnnAccuracy = 97
Суммируйте эффективность обученной сети на тестовом наборе с графиком неточностей. Отображение точности и отзыва для каждого класса с помощью сводных данных по столбцам и строкам. Таблица в нижней части графика неточностей показывает значения точности. Таблица справа от графика неточностей показывает значения отзыва.
figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]); ccDCNN = confusionchart(adsTest.Labels,YPred); ccDCNN.Title = 'Confusion Chart for DCNN'; ccDCNN.ColumnSummary = 'column-normalized'; ccDCNN.RowSummary = 'row-normalized';
В этом примере показано, как создать пользовательский слой спектрограммы с помощью dlstft
. Использование функциональности, поддерживающей dlarray
пример продемонстрировал, как встраивать операции обработки сигналов в сеть таким образом, чтобы поддерживать обратное распространение и использование графических процессоров.
function Labels = helpergenLabels(ads) % This function is only for use in the "Spoken Digit Recognition with % Custom Log Spectrogram Layer and Deep Learning" example. It may change or % be removed in a future release. tmp = cell(numel(ads.Files),1); expression = "[0-9]+_"; for nf = 1:numel(ads.Files) idx = regexp(ads.Files{nf},expression); tmp{nf} = ads.Files{nf}(idx); end Labels = categorical(tmp); end
function [out,info] = helperReadSPData(x,info) % This function is only for use in the "Spoken Digit Recognition with % Custom Log Spectrogram Layer and Deep Learning" example. It may change or % be removed in a future release. N = numel(x); if N > 8192 x = x(1:8192); elseif N < 8192 pad = 8192-N; prepad = floor(pad/2); postpad = ceil(pad/2); x = [zeros(prepad,1) ; x ; zeros(postpad,1)]; end x = x./max(abs(x)); out = {x./max(abs(x)),info.Label}; end