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

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

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

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

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

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

load('commandNet.mat')

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

  • "да"

  • "нет"

  • "вниз"

  • "левый"

  • "право"

  • "на"

  • 'off'

  • остановка

  • "пойти"

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

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

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

 sound(x,fs)

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

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

auditorySpect = helperExtractAuditoryFeatures(x,fs);

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

command = classify(trainedNet,auditorySpect)
command = 

  categorical

     stop 

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

Вы теперь классифицируете слово ("игра"), которая не была включена в список команды, чтобы идентифицировать.

Загрузите речь, сигнализируют и слушают его.

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

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

auditorySpect = helperExtractAuditoryFeatures(x,fs);

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

command = classify(trainedNet,auditorySpect)
command = 

  categorical

     unknown 

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

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

x = 0.01 * randn(16e3,1);

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

auditorySpect = helperExtractAuditoryFeatures(x,fs);

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

command = classify(trainedNet,auditorySpect)
command = 

  categorical

     background 

Обнаружьте команды Используя передачу потокового аудио от микрофона

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

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

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

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

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

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

Загрузите и извлеките набор данных [1].

url = 'https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz';

downloadFolder = tempdir;
datasetFolder = fullfile(downloadFolder,'google_speech');

if ~exist(datasetFolder,'dir')
    disp('Downloading speech commands data set (1.5 GB)...')
    untar(url,datasetFolder)
end

Создайте audioDatastore это указывает на набор данных.

ads = audioDatastore(datasetFolder, ...
    'IncludeSubfolders',true, ...
    'FileExtensions','.wav', ...
    'LabelSource','foldernames')
ads = 

  audioDatastore with properties:

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

Выберите Words to Recognize

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

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

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

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

isCommand = ismember(ads.Labels,commands);
isUnknown = ~ismember(ads.Labels,[commands,"_background_noise_"]);

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

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

  11×2 table

     Label     Count
    _______    _____

    down       2359 
    go         2372 
    left       2353 
    no         2375 
    off        2357 
    on         2367 
    right      2367 
    stop       2380 
    unknown    8186 
    up         2375 
    yes        2377 

Разделение данных в обучение, валидацию и наборы тестов

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

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

Считайте список файлов валидации.

c = importdata(fullfile(datasetFolder,'validation_list.txt'));
filesValidation = string(c);

Считайте список тестовых файлов.

c = importdata(fullfile(datasetFolder,'testing_list.txt'));
filesTest = string(c);

Определите, какие файлы в datastore должны перейти к набору валидации и который должен перейти к набору тестов.

files = adsSubset.Files;
sf = split(files,filesep);
isValidation = ismember(sf(:,end-1) + "/" + sf(:,end),filesValidation);
isTest = ismember(sf(:,end-1) + "/" + sf(:,end),filesTest);

adsValidation = subset(adsSubset,isValidation);
adsTrain = subset(adsSubset,~isValidation & ~isTest);

Чтобы обучить сеть с набором данных в целом и достигнуть максимально возможной точности, установите 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);

Считайте файл из набора данных. Обучение сверточная нейронная сеть требует, чтобы вход был сопоставимым размером. Некоторые файлы в наборе данных меньше 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

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

Определите фактор денормализации, чтобы применяться.

unNorm = 2/(sum(afe.Window)^2);

Чтобы ускорить обработку, можно распределить извлечение признаков на нескольких рабочих, использующих 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 =

       25041

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

XTrain = XTrain/unNorm;
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 = XValidation/unNorm;
XValidation = log10(XValidation + epsil);

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

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_noise_ папка, чтобы создать выборки вторых клипов фонового шума. Создайте равное количество роликов фона из каждого файла фонового шума. Можно также создать собственные записи фонового шума и добавить их в _background_noise_ папка. Прежде, чем вычислить спектрограммы, функция перемасштабирует каждый аудиоклип с фактором, произведенным от логарифмического равномерного распределения в области значений, данной volumeRange.

adsBkg = subset(ads,ads.Labels=="_background_noise_");
 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 = Xbkg/unNorm;
Xbkg = log10(Xbkg + epsil);
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)];

Обучение сети

Задайте опции обучения. Используйте оптимизатор Адама с мини-пакетным размером 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.526%
Validation error: 5.1539%

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

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.7314 kB
Single-image prediction time on CPU: 3.1647 ms

Ссылки

[1] Начальник П. "Речевые Команды: общедоступный набор данных для распознавания речи однословного", 2017. Доступный от https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz. Авторское право Google 2017. Речевой Набор данных Команд лицензируется при Приписывании Creative Commons 4,0 лицензии, доступные здесь: https://creativecommons.org/licenses/by/4.0/legalcode.