Распознание речевых команд с использованием глубокого обучения

Этот пример показывает, как обучить модель глубокого обучения, которая обнаруживает наличие речевых команд в аудио. Пример использует набор данных речевых команд [1], чтобы обучить сверточную нейронную сеть распознавать данный набор команд.

Чтобы обучить сеть с нуля, необходимо сначала загрузить набор данных. Если вы не хотите загружать набор данных или обучать сеть, то можно загрузить предварительно обученную сеть, предоставленную этим примером, и выполнить следующие два раздела примера: Распознавать команды с предварительно обученной сетью и Обнаруживать команды с использованием передачи потокового аудио из микрофона.

Распознавание команд с предварительно обученной сетью

Прежде чем подробно войти в процесс обучения, вы будете использовать предварительно обученную сеть распознавания речи для идентификации речевых команд.

Загрузите предварительно обученную сеть.

load('commandNet.mat')

Сеть обучена распознавать следующие речевые команды:

  • «да»

  • «нет»

  • вверх

  • «вниз»

  • «слева»

  • правильно

  • «on»

  • «off»

  • Стоп

  • «перейти»

Загрузите короткий речевой сигнал, где человек говорит «стоп».

 [x,fs] = audioread('stop_command.flac');

Послушайте команду.

 sound(x,fs)

Предварительно обученная сеть принимает спектрограммы на основе слуха в качестве входов. Сначала вы преобразуете форму речевого сигнала в спектрограмму на основе слуха.

Используйте функцию extractAuditoryFeature для вычисления слуховой спектрограммы. Подробные сведения о редукции данных будут рассмотрены позже в примере.

auditorySpect = helperExtractAuditoryFeatures(x,fs);

Классифицируйте команду на основе ее слуховой спектрограммы.

command = classify(trainedNet,auditorySpect)
command = 

  categorical

     stop 

Сеть обучена классифицировать слова, не принадлежащие этому набору, как «неизвестные».

Теперь вы классифицируете слово («play»), которое не было включено в список команд для идентификации.

Загрузите речевой сигнал и прослушайте его.

x = audioread('play_command.flac');
sound(x,fs)

Вычислите слуховую спектрограмму.

auditorySpect = helperExtractAuditoryFeatures(x,fs);

Классифицируйте сигнал.

command = classify(trainedNet,auditorySpect)
command = 

  categorical

     unknown 

Сеть обучена классифицировать фоновый шум как «фон».

Создайте сигнал на одну секунду, состоящий из случайного шума.

x = pinknoise(16e3);

Вычислите слуховую спектрограмму.

auditorySpect = helperExtractAuditoryFeatures(x,fs);

Классифицируйте фоновый шум.

command = classify(trainedNet,auditorySpect)
command = 

  categorical

     background 

Обнаружение команд, использующих передачу потокового аудио с микрофона

Протестируйте предварительно обученную сеть обнаружения команд на передаче потокового аудио с микрофона. Попробуйте сказать одну из команд, например, да, нет, или остановить. Затем попробуйте сказать одно из неизвестных слов, таких как Марвин, Шейла, кровать, дом, кошка, птица или любое число от нуля до девяти.

Укажите частоту классификации в Гц и создайте аудио устройство считыватель, который может считать аудио с вашего микрофона.

classificationRate = 20;
adr = audioDeviceReader('SampleRate',fs,'SamplesPerFrame',floor(fs/classificationRate));

Инициализируйте буфер для аудио. Извлеките классификационные метки сети. Инициализируйте буферы в полсекунды для меток и классификационных вероятностей передачи потокового аудио. Используйте эти буферы, чтобы сравнить результаты классификации за более длительный период времени и по этому сборке 'agreement' over когда команда обнаружена. Задайте пороги для логики принятия решений.

audioBuffer = dsp.AsyncBuffer(fs);

labels = trainedNet.Layers(end).Classes;
YBuffer(1:classificationRate/2) = categorical("background");

probBuffer = zeros([numel(labels),classificationRate/2]);

countThreshold = ceil(classificationRate*0.2);
probThreshold = 0.7;

Создайте рисунок и обнаружите команды, пока существует созданный рисунок. Чтобы запустить цикл бесконечно, установите timeLimit на Inf. Чтобы остановить живое обнаружение, просто закройте рисунок.

h = figure('Units','normalized','Position',[0.2 0.1 0.6 0.8]);

timeLimit = 20;

tic
while ishandle(h) && toc < timeLimit

    % Extract audio samples from the audio device and add the samples to
    % the buffer.
    x = adr();
    write(audioBuffer,x);
    y = read(audioBuffer,fs,fs-adr.SamplesPerFrame);

    spec = helperExtractAuditoryFeatures(y,fs);

    % Classify the current spectrogram, save the label to the label buffer,
    % and save the predicted probabilities to the probability buffer.
    [YPredicted,probs] = classify(trainedNet,spec,'ExecutionEnvironment','cpu');
    YBuffer = [YBuffer(2:end),YPredicted];
    probBuffer = [probBuffer(:,2:end),probs(:)];

    % Plot the current waveform and spectrogram.
    subplot(2,1,1)
    plot(y)
    axis tight
    ylim([-1,1])

    subplot(2,1,2)
    pcolor(spec')
    caxis([-4 2.6445])
    shading flat

    % Now do the actual command detection by performing a very simple
    % thresholding operation. Declare a detection and display it in the
    % figure title if all of the following hold: 1) The most common label
    % is not background. 2) At least countThreshold of the latest frame
    % labels agree. 3) The maximum probability of the predicted label is at
    % least probThreshold. Otherwise, do not declare a detection.
    [YMode,count] = mode(YBuffer);

    maxProb = max(probBuffer(labels == YMode,:));
    subplot(2,1,1)
    if YMode == "background" || count < countThreshold || maxProb < probThreshold
        title(" ")
    else
        title(string(YMode),'FontSize',20)
    end

    drawnow
end

Загрузка набора данных речевых команд

Этот пример использует набор данных Google Speech Commands Dataset [1]. Загрузите набор данных и распакуйте загруженный файл. Установите PathToDatabase в местоположение данных.

url = 'https://ssd.mathworks.com/supportfiles/audio/google_speech.zip';
downloadFolder = tempdir;
dataFolder = fullfile(downloadFolder,'google_speech');

if ~exist(dataFolder,'dir')
    disp('Downloading data set (1.4 GB) ...')
    unzip(url,downloadFolder)
end

Создайте Training Datastore

Создайте audioDatastore это указывает на обучающие данные набор.

ads = audioDatastore(fullfile(dataFolder, 'train'), ...
    'IncludeSubfolders',true, ...
    'FileExtensions','.wav', ...
    'LabelSource','foldernames')
ads = 

  audioDatastore with properties:

                       Files: {
                              ' ...\AppData\Local\Temp\google_speech\train\bed\00176480_nohash_0.wav';
                              ' ...\AppData\Local\Temp\google_speech\train\bed\004ae714_nohash_0.wav';
                              ' ...\AppData\Local\Temp\google_speech\train\bed\004ae714_nohash_1.wav'
                               ... and 51085 more
                              }
                     Folders: {
                              'C:\Users\jibrahim\AppData\Local\Temp\google_speech\train'
                              }
                      Labels: [bed; bed; bed ... and 51085 more categorical]
    AlternateFileSystemRoots: {}
              OutputDataType: 'double'
      SupportedOutputFormats: ["wav"    "flac"    "ogg"    "mp4"    "m4a"]
         DefaultOutputFormat: "wav"

Выбор слов для распознавания

Задайте слова, которые вы хотите, чтобы ваша модель распознавала как команды. Пометьте все слова, которые не являются командами, как unknown. Маркировка слов, которые не являются командами, как unknown создает группу слов, которая аппроксимирует распределение всех слов, кроме команд. Сеть использует эту группу, чтобы узнать различие между командами и всеми другими словами.

Чтобы уменьшить классовый дисбаланс между известными и неизвестными словами и ускорить обработку, включите только часть неизвестных слов в набор обучающих данных.

Использование subset чтобы создать datastore, который содержит только команды и подмножество неизвестных слов. Подсчитайте количество примеров, принадлежащих каждой категории.

commands = categorical(["yes","no","up","down","left","right","on","off","stop","go"]);

isCommand = ismember(ads.Labels,commands);
isUnknown = ~isCommand;

includeFraction = 0.2;
mask = rand(numel(ads.Labels),1) < includeFraction;
isUnknown = isUnknown & mask;
ads.Labels(isUnknown) = categorical("unknown");

adsTrain = subset(ads,isCommand|isUnknown);
countEachLabel(adsTrain)
ans =

  11×2 table

     Label     Count
    _______    _____

    down       1842 
    go         1861 
    left       1839 
    no         1853 
    off        1839 
    on         1864 
    right      1852 
    stop       1885 
    unknown    6483 
    up         1843 
    yes        1860 

Создайте хранилище Datastore валидации

Создайте audioDatastore это указывает на набор данных валидации. Выполните те же шаги, которые используются для создания обучающего datastore.

ads = audioDatastore(fullfile(dataFolder, 'validation'), ...
    'IncludeSubfolders',true, ...
    'FileExtensions','.wav', ...
    'LabelSource','foldernames')

isCommand = ismember(ads.Labels,commands);
isUnknown = ~isCommand;

includeFraction = 0.2;
mask = rand(numel(ads.Labels),1) < includeFraction;
isUnknown = isUnknown & mask;
ads.Labels(isUnknown) = categorical("unknown");

adsValidation = subset(ads,isCommand|isUnknown);
countEachLabel(adsValidation)
ads = 

  audioDatastore with properties:

                       Files: {
                              ' ...\AppData\Local\Temp\google_speech\validation\bed\026290a7_nohash_0.wav';
                              ' ...\AppData\Local\Temp\google_speech\validation\bed\060cd039_nohash_0.wav';
                              ' ...\AppData\Local\Temp\google_speech\validation\bed\060cd039_nohash_1.wav'
                               ... and 6795 more
                              }
                     Folders: {
                              'C:\Users\jibrahim\AppData\Local\Temp\google_speech\validation'
                              }
                      Labels: [bed; bed; bed ... and 6795 more categorical]
    AlternateFileSystemRoots: {}
              OutputDataType: 'double'
      SupportedOutputFormats: ["wav"    "flac"    "ogg"    "mp4"    "m4a"]
         DefaultOutputFormat: "wav"


ans =

  11×2 table

     Label     Count
    _______    _____

    down        264 
    go          260 
    left        247 
    no          270 
    off         256 
    on          257 
    right       256 
    stop        246 
    unknown     850 
    up          260 
    yes         261 

Чтобы обучить сеть со набором данных в целом и достичь максимально возможной точности, установите reduceDataset на false. Чтобы запустить этот пример быстро, установите reduceDataset на true.

reduceDataset = false;
if reduceDataset
    numUniqueLabels = numel(unique(adsTrain.Labels));
    % Reduce the dataset by a factor of 20
    adsTrain = splitEachLabel(adsTrain,round(numel(adsTrain.Files) / numUniqueLabels / 20));
    adsValidation = splitEachLabel(adsValidation,round(numel(adsValidation.Files) / numUniqueLabels / 20));
end

Вычисление слуховых спектрограмм

Чтобы подготовить данные для эффективного обучения сверточной нейронной сети, преобразуйте формы речи в спектрограммы на основе слуха.

Задайте параметры редукции данных. segmentDuration - длительность каждого речевого клипа (в секундах). frameDuration - длительность каждой системы координат для вычисления спектра. hopDuration - временной шаг между каждым спектром. numBands количество фильтров в слуховой спектрограмме.

Создайте audioFeatureExtractor объект для выполнения редукции данных.

fs = 16e3; % Known sample rate of the data set.

segmentDuration = 1;
frameDuration = 0.025;
hopDuration = 0.010;

segmentSamples = round(segmentDuration*fs);
frameSamples = round(frameDuration*fs);
hopSamples = round(hopDuration*fs);
overlapSamples = frameSamples - hopSamples;

FFTLength = 512;
numBands = 50;

afe = audioFeatureExtractor( ...
    'SampleRate',fs, ...
    'FFTLength',FFTLength, ...
    'Window',hann(frameSamples,'periodic'), ...
    'OverlapLength',overlapSamples, ...
    'barkSpectrum',true);
setExtractorParams(afe,'barkSpectrum','NumBands',numBands,'WindowNormalization',false);

Считайте файл из набора данных. Настройка сверточной нейронной сети требует, чтобы вход был допустимым размером. Некоторые файлы в наборе данных имеют длину менее 1 секунды. Примените заполнение нуля к передней и задней частотам аудиосигнала так, чтобы он имел длину segmentSamples.

x = read(adsTrain);

numSamples = size(x,1);

numToPadFront = floor( (segmentSamples - numSamples)/2 );
numToPadBack = ceil( (segmentSamples - numSamples)/2 );

xPadded = [zeros(numToPadFront,1,'like',x);x;zeros(numToPadBack,1,'like',x)];

Чтобы извлечь аудио функции, вызовите extract. Выходные выходы - спектр Корка со временем между строками.

features = extract(afe,xPadded);
[numHops,numFeatures] = size(features)
numHops =

    98


numFeatures =

    50

В этом примере вы постпроцессируете слуховую спектрограмму путем применения логарифма. Взятие журнала малых чисел может привести к ошибке округления.

Чтобы ускорить обработку, можно распределить редукцию данных между несколькими работниками с помощью parfor.

Во-первых, определите количество разделов для набора данных. Если у вас нет Parallel Computing Toolbox™, используйте один раздел.

if ~isempty(ver('parallel')) && ~reduceDataset
    pool = gcp;
    numPar = numpartitions(adsTrain,pool);
else
    numPar = 1;
end

Для каждого раздела считайте из datastore, обнулите сигнал и затем извлеките функции.

parfor ii = 1:numPar
    subds = partition(adsTrain,numPar,ii);
    XTrain = zeros(numHops,numBands,1,numel(subds.Files));
    for idx = 1:numel(subds.Files)
        x = read(subds);
        xPadded = [zeros(floor((segmentSamples-size(x,1))/2),1);x;zeros(ceil((segmentSamples-size(x,1))/2),1)];
        XTrain(:,:,:,idx) = extract(afe,xPadded);
    end
    XTrainC{ii} = XTrain;
end

Преобразуйте выход в 4-мерный массив со слуховыми спектрограммами по четвертой размерности.

XTrain = cat(4,XTrainC{:});

[numHops,numBands,numChannels,numSpec] = size(XTrain)
numHops =

    98


numBands =

    50


numChannels =

     1


numSpec =

       25021

Масштабируйте функции по степени окна, а затем берите журнал. Чтобы получить данные с более плавным распределением, примите логарифм спектрограмм с помощью небольшого смещения.

epsil = 1e-6;
XTrain = log10(XTrain + epsil);

Выполните шаги редукции данных, описанные выше, к набору валидации.

if ~isempty(ver('parallel'))
    pool = gcp;
    numPar = numpartitions(adsValidation,pool);
else
    numPar = 1;
end
parfor ii = 1:numPar
    subds = partition(adsValidation,numPar,ii);
    XValidation = zeros(numHops,numBands,1,numel(subds.Files));
    for idx = 1:numel(subds.Files)
        x = read(subds);
        xPadded = [zeros(floor((segmentSamples-size(x,1))/2),1);x;zeros(ceil((segmentSamples-size(x,1))/2),1)];
        XValidation(:,:,:,idx) = extract(afe,xPadded);
    end
    XValidationC{ii} = XValidation;
end
XValidation = cat(4,XValidationC{:});
XValidation = log10(XValidation + epsil);

Изолируйте метки train и валидации. Удалите пустые категории.

YTrain = removecats(adsTrain.Labels);
YValidation = removecats(adsValidation.Labels);

Визуализация данных

Постройте графики форм волны и слуховых спектрограмм нескольких обучающих выборок. Воспроизведение соответствующих аудиоклипов.

specMin = min(XTrain,[],'all');
specMax = max(XTrain,[],'all');
idx = randperm(numel(adsTrain.Files),3);
figure('Units','normalized','Position',[0.2 0.2 0.6 0.6]);
for i = 1:3
    [x,fs] = audioread(adsTrain.Files{idx(i)});
    subplot(2,3,i)
    plot(x)
    axis tight
    title(string(adsTrain.Labels(idx(i))))

    subplot(2,3,i+3)
    spect = (XTrain(:,:,1,idx(i))');
    pcolor(spect)
    caxis([specMin specMax])
    shading flat

    sound(x,fs)
    pause(2)
end

Добавьте фоновые данные шума

Сеть должна быть способна не только распознавать различные разговорные слова, но и обнаруживать, содержит ли вход тишину или фоновый шум.

Используйте аудио файлов в _background_ папку для создания выборок односекундных клипов фонового шума. Создайте равное количество фоновых клипов из каждого файла фонового шума. Можно также создать собственные записи фонового шума и добавить их в _background_ папку. Перед вычислением спектрограмм функция пересматривает каждый аудиоклип с фактором, выбранным из логарифмического распределения в области значений, заданной volumeRange.

adsBkg = audioDatastore(fullfile(dataFolder, 'background'))
numBkgClips = 4000;
if reduceDataset
    numBkgClips = numBkgClips/20;
end
volumeRange = log10([1e-4,1]);

numBkgFiles = numel(adsBkg.Files);
numClipsPerFile = histcounts(1:numBkgClips,linspace(1,numBkgClips,numBkgFiles+1));
Xbkg = zeros(size(XTrain,1),size(XTrain,2),1,numBkgClips,'single');
bkgAll = readall(adsBkg);
ind = 1;

for count = 1:numBkgFiles
    bkg = bkgAll{count};
    idxStart = randi(numel(bkg)-fs,numClipsPerFile(count),1);
    idxEnd = idxStart+fs-1;
    gain = 10.^((volumeRange(2)-volumeRange(1))*rand(numClipsPerFile(count),1) + volumeRange(1));
    for j = 1:numClipsPerFile(count)

        x = bkg(idxStart(j):idxEnd(j))*gain(j);

        x = max(min(x,1),-1);

        Xbkg(:,:,:,ind) = extract(afe,x);

        if mod(ind,1000)==0
            disp("Processed " + string(ind) + " background clips out of " + string(numBkgClips))
        end
        ind = ind + 1;
    end
end
Xbkg = log10(Xbkg + epsil);
adsBkg = 

  audioDatastore with properties:

                       Files: {
                              ' ...\AppData\Local\Temp\google_speech\background\doing_the_dishes.wav';
                              ' ...\AppData\Local\Temp\google_speech\background\dude_miaowing.wav';
                              ' ...\AppData\Local\Temp\google_speech\background\exercise_bike.wav'
                               ... and 3 more
                              }
                     Folders: {
                              'C:\Users\jibrahim\AppData\Local\Temp\google_speech\background'
                              }
    AlternateFileSystemRoots: {}
              OutputDataType: 'double'
                      Labels: {}
      SupportedOutputFormats: ["wav"    "flac"    "ogg"    "mp4"    "m4a"]
         DefaultOutputFormat: "wav"

Processed 1000 background clips out of 4000
Processed 2000 background clips out of 4000
Processed 3000 background clips out of 4000
Processed 4000 background clips out of 4000

Разделите спектрограммы фонового шума между наборами для обучения, валидации и тестирования. Потому что _background_noise_ папка содержит только около пяти с половиной минут фонового шума, фоновые выборки в различных наборах данных сильно коррелируют. Чтобы увеличить изменение фонового шума, можно создать собственные файлы фона и добавить их в папку. Чтобы повысить робастность сети до шума, можно также попробовать смешать фоновый шум в речевые файлы.

numTrainBkg = floor(0.85*numBkgClips);
numValidationBkg = floor(0.15*numBkgClips);

XTrain(:,:,:,end+1:end+numTrainBkg) = Xbkg(:,:,:,1:numTrainBkg);
YTrain(end+1:end+numTrainBkg) = "background";

XValidation(:,:,:,end+1:end+numValidationBkg) = Xbkg(:,:,:,numTrainBkg+1:end);
YValidation(end+1:end+numValidationBkg) = "background";

Постройте график распределения различных меток классов в наборах обучения и валидации.

figure('Units','normalized','Position',[0.2 0.2 0.5 0.5])

subplot(2,1,1)
histogram(YTrain)
title("Training Label Distribution")

subplot(2,1,2)
histogram(YValidation)
title("Validation Label Distribution")

Определите архитектуру нейронной сети

Создайте простую сетевую архитектуру как массив слоев. Используйте сверточные и пакетные слои нормализации и понижающее отображение карты признаков «пространственно» (то есть по времени и частоте) с помощью максимальных слоев объединения. Добавьте конечный слой максимального объединения, который объединяет входную карту функций глобально с течением времени. Это обеспечивает (приблизительную) инвариацию преобразования времени в вход спектрограммах, позволяя сети выполнять ту же классификацию независимо от точного положения речи во времени. Глобальное объединение также значительно уменьшает количество параметров в конечном полносвязном слое. Чтобы уменьшить возможность запоминания сетью специфических функций обучающих данных, добавьте небольшое количество отсева на вход к последнему полностью подключенному слою.

Сеть небольшая, так как она имеет всего пять сверточных слоев с небольшим количеством фильтров. numF управляет количеством фильтров в сверточных слоях. Чтобы увеличить точность сети, попробуйте увеличить глубину сети, добавив одинаковые блоки сверточных, нормализации партии . и слоев ReLU. Можно также попробовать увеличить количество сверточных фильтров путем увеличения numF.

Используйте взвешенные потери классификации перекрестной энтропии. weightedClassificationLayer(classWeights) создает пользовательский слой классификации, который вычисляет потери перекрестной энтропии с наблюдениями, взвешенными по classWeights. Задайте веса классов в том же порядке, в котором появляются классы categories(YTrain). Чтобы задать каждому классу равный общий вес при потере, используйте веса классов, которые обратно пропорциональны количеству примеров обучения в каждом классе. При использовании оптимизатора Адама для обучения сети алгоритм настройки не зависит от общей нормализации весов классов.

classWeights = 1./countcats(YTrain);
classWeights = classWeights'/mean(classWeights);
numClasses = numel(categories(YTrain));

timePoolSize = ceil(numHops/8);

dropoutProb = 0.2;
numF = 12;
layers = [
    imageInputLayer([numHops numBands])

    convolution2dLayer(3,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([timePoolSize,1])

    dropoutLayer(dropoutProb)
    fullyConnectedLayer(numClasses)
    softmaxLayer
    weightedClassificationLayer(classWeights)];

Обучите сеть

Задайте опции обучения. Используйте оптимизатор Adam с мини-пакетом размером 128. Обучите 25 эпох и уменьшите скорость обучения в 10 раз после 20 эпох.

miniBatchSize = 128;
validationFrequency = floor(numel(YTrain)/miniBatchSize);
options = trainingOptions('adam', ...
    'InitialLearnRate',3e-4, ...
    'MaxEpochs',25, ...
    'MiniBatchSize',miniBatchSize, ...
    'Shuffle','every-epoch', ...
    'Plots','training-progress', ...
    'Verbose',false, ...
    'ValidationData',{XValidation,YValidation}, ...
    'ValidationFrequency',validationFrequency, ...
    'LearnRateSchedule','piecewise', ...
    'LearnRateDropFactor',0.1, ...
    'LearnRateDropPeriod',20);

Обучите сеть. Если у вас нет графический процессор, то обучение сети может занять время.

trainedNet = trainNetwork(XTrain,YTrain,layers,options);

Оценка обученной сети

Вычислите окончательную точность сети на набор обучающих данных (без увеличения данных) и наборе валидации. Сеть очень точна на этом наборе данных. Однако обучение, валидация и тестовые данные все имеют аналогичные распределения, которые не обязательно отражают реальные окружения. Это ограничение особенно относится к unknown категория, которая содержит высказывания лишь небольшого числа слов.

if reduceDataset
    load('commandNet.mat','trainedNet');
end
YValPred = classify(trainedNet,XValidation);
validationError = mean(YValPred ~= YValidation);
YTrainPred = classify(trainedNet,XTrain);
trainError = mean(YTrainPred ~= YTrain);
disp("Training error: " + trainError*100 + "%")
disp("Validation error: " + validationError*100 + "%")
Training error: 1.907%
Validation error: 5.5376%

Постройте график матрицы неточностей. Отображение точности и отзыва для каждого класса с помощью сводных данных по столбцам и строкам. Отсортируйте классы матрицы неточностей. Самая большая путаница между неизвестными словами и командами, вверх и назад, вниз и нет, и идти и нет.

figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]);
cm = confusionchart(YValidation,YValPred);
cm.Title = 'Confusion Matrix for Validation Data';
cm.ColumnSummary = 'column-normalized';
cm.RowSummary = 'row-normalized';
sortClasses(cm, [commands,"unknown","background"])

При работе с приложениями с ограниченными аппаратными ресурсами, такими как мобильные приложения, учитывайте ограничения на доступную память и вычислительные ресурсы. Вычислите общий размер сети в килобайтах и протестируйте ее скорость предсказания при использовании центральный процессор. Время предсказания является временем для классификации одного входного изображения. Если вы вводите несколько изображений в сеть, они могут быть классифицированы одновременно, что приводит к более короткому времени предсказания на изображение. Однако при классификации передачи потокового аудио наиболее актуальным является время предсказания с одним изображением.

info = whos('trainedNet');
disp("Network size: " + info.bytes/1024 + " kB")

for i = 1:100
    x = randn([numHops,numBands]);
    tic
    [YPredicted,probs] = classify(trainedNet,x,"ExecutionEnvironment",'cpu');
    time(i) = toc;
end
disp("Single-image prediction time on CPU: " + mean(time(11:end))*1000 + " ms")
Network size: 286.7402 kB
Single-image prediction time on CPU: 2.5119 ms

Ссылки

[1] Warden P. «Speech Commands: A public dataset for single-word speech recognition», 2017. Доступно из https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz. Копирайт Google 2017. Набор данных Speech Commands лицензирован по лицензии Creative Commons Attribution 4.0, доступной здесь: https://creativecommons.org/licenses/by/4.0/legalcode.