Распознавание разговорных цифр с помощью пользовательского слоя Log Spectrogram и глубокого обучения

Этот пример показов, как классифицировать разговорные цифры с помощью глубокой сверточной нейронной сети (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).

Архитектура глубокой сверточной нейронной сети (DCNN)

Можно использовать пользовательский слой так же, как и любой другой слой в 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