В этом примере показано, как классифицировать произносимые цифры с помощью глубокой сверточной нейронной сети (CNN) и пользовательского слоя логарифмической спектрограммы. Пользовательский слой использует dlstft функция вычисления кратковременных преобразований Фурье способом, поддерживающим автоматическое обратное распространение.
Клонируйте или загрузите набор данных Free Spoken Digit Dataset (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 показывает, что общая длина 8192 семплов является подходящей для того, чтобы гарантировать, что не будет вырезано ни одной речевой цифры. Записи длиной более 8192 семплов усечены до 8192 семплов, в то время как записи с менее чем 8192 семплами симметрично дополнены длиной 8192. Вспомогательная функция helperReadSPData усекает или вставляет данные до 8192 выборок и нормализует каждую запись на ее максимальное значение. Исходный код для helperReadSPData перечислены в приложении. Эта вспомогательная функция применяется к каждой записи с помощью хранилища данных преобразования в сочетании с audioDatastore.
transTrain = transform(adsTrain,@(x,info)helperReadSPData(x,info),'IncludeInfo',true); transTest = transform(adsTest,@(x,info)helperReadSPData(x,info),'IncludeInfo',true);
Когда какая-либо обработка сигнала выполняется вне сети в качестве этапов предварительной обработки, существует большая вероятность того, что предсказания сети будут выполняться с другими настройками предварительной обработки, чем те, которые используются при обучении сети. Это может оказать значительное влияние на производительность сети, что обычно приводит к снижению производительности, чем ожидалось. Размещение спектрограммы или любых других вычислений предварительной обработки внутри сети в качестве уровня дает автономную модель и упрощает конвейер для развертывания. Это позволяет эффективно обучать, развертывать или совместно использовать сеть со всеми необходимыми операциями обработки сигналов. В этом примере операция обработки главного сигнала представляет собой вычисление спектрограммы. Способность вычислять спектрограмму внутри сети полезна как для вывода, так и когда пространство памяти устройства недостаточно для сохранения спектрограмм. Вычисление спектрограммы в сети требует только достаточного выделения памяти для текущей партии спектрограмм. Однако следует отметить, что это не оптимальный выбор с точки зрения скорости тренировок. Если у вас достаточно памяти, время обучения значительно сокращается за счет предварительного вычисления всех спектрограмм и хранения этих результатов. Затем для обучения сети считывайте «изображения» спектрограммы из хранилища вместо необработанного звука и вводите спектрограммы непосредственно в сеть. Следует отметить, что хотя это приводит к наиболее быстрому времени тренировки, возможность выполнения обработки сигнала внутри сети все еще имеет значительные преимущества по причинам, указанным выше.
При обучении глубоких сетей часто выгодно использовать логарифм представления сигнала, поскольку логарифм действует как динамический компрессор диапазона, повышая значения представления, которые имеют небольшие величины (амплитуды), но все еще несут важную информацию. В этом примере логарифмическая спектрограмма работает лучше, чем спектрограмма. Соответственно, этот пример создает пользовательский слой логарифмической спектрограммы и вставляет его в сеть после входного уровня. Дополнительные сведения о создании пользовательского слоя см. в разделе Определение пользовательских слоев глубокого обучения (панель инструментов глубокого обучения).
logSpectrogramLayer является слоем без обучаемых параметров, поэтому требуются только неизучиваемые свойства. Здесь единственными необходимыми свойствами являются свойства, необходимые для вычисления спектрограммы. Объявить их в properties раздел. В слое predict функция, 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 (панель инструментов глубокого обучения).
Пользовательский слой можно использовать так же, как и любой другой слой в инструментарии глубокого обучения. Создание небольшого DCNN в виде массива слоев, включающего пользовательский слой logSpectrogramLayer. Используйте уровни сверточной и пакетной нормализации и уменьшите значения карт элементов, используя уровни максимального объединения. Чтобы избежать переоборудования, добавьте небольшое количество отсева на вход последнего полностью подключенного слоя.
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 возможность асинхронной предварительной выборки и постановки данных в очередь для оптимизации производительности обучения. Фоновая диспетчеризация данных и использование графического процессора для обучения сети требуют Toolbox™ параллельных вычислений.
UsePrefetch =true; options = trainingOptions('adam', ... 'InitialLearnRate',1e-4, ... 'MaxEpochs',30, ... 'MiniBatchSize',50, ... 'Shuffle','every-epoch', ... 'DispatchInBackground',UsePrefetch,... 'Plots','training-progress',... "Verbose",false);
Обучение сети.
[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