exponenta event banner

Вейвлет-рассеяние времени с ускорением графического процессора - распознавание речевых цифр

В этом примере показано, как ускорить вычисление функций вейвлет-рассеяния с помощью gpuArray(Панель инструментов параллельных вычислений). Необходимо иметь Toolbox™ параллельных вычислений и поддерживаемый графический процессор. Дополнительные сведения см. в разделе Поддержка графического процессора по выпуску (Панель инструментов параллельных вычислений). В этом примере используется графический процессор NVIDIA Titan V с вычислительной способностью 7.0. Раздел примера, в котором вычисляется преобразование рассеяния, предоставляет возможность использовать графический процессор или центральный процессор, если вы хотите сравнить производительность графического процессора с производительностью центрального процессора.

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

Данные

Клонируйте или загрузите набор данных Free Spoken Digit (FSDD), доступный по адресу https://github.com/Jakobovski/free-spoken-digit-dataset. FSDD - это открытый набор данных, который со временем может расти. В этом примере используется версия, зафиксированная на 08/20/2020, которая состоит из 3000 записей английских цифр от 0 до 9, полученных из шести динамиков. Данные дискретизируются на частоте 8000 Гц.

Использовать audioDatastore управление доступом к данным и обеспечение произвольного разделения записей на обучающие и тестовые наборы. Установите location в расположение папки записей FSDD на компьютере. В этом примере данные хранятся в папке под tempdir.

location = fullfile(tempdir,'free-spoken-digit-dataset','recordings');
ads = audioDatastore(location);

Вспомогательная функция, helpergenLabels, определенный в конце этого примера, создает категориальный массив меток из файлов FSDD. Перечислите классы и количество примеров в каждом классе.

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 

Набор данных FSDD состоит из 10 сбалансированных классов по 300 записей в каждом. Записи в FSDD не имеют одинаковой продолжительности. Считывание файлов FSDD и построение гистограммы длин сигналов.

LenSig = zeros(numel(ads.Files),1);
nr = 1;
while hasdata(ads)
    digit = read(ads);
    LenSig(nr) = numel(digit);
    nr = nr+1;
end
reset(ads)
histogram(LenSig)
grid on
xlabel('Signal Length (Samples)')
ylabel('Frequency')

Гистограмма показывает, что распределение длин записи положительно искажено. Для классификации в этом примере используется общая длина сигнала 8192 выборки. Значение 8192, консервативный выбор, гарантирует, что усечение более длинных записей не влияет (отсекает) на речевое содержимое. Если длина сигнала превышает 8192 отсчетов или 1,024 секунды, запись усекается до 8192 отсчетов. Если длина сигнала меньше 8192 выборок, то сигнал симметрично предваряют и добавляют нули к длине 8192 выборок.

Вейвлет-рассеяние времени

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

sn = waveletScattering('SignalLength',8192,'InvarianceScale',0.22,...
    'SamplingFrequency',8000,'OversamplingFactor',2);

Настройка сети рассеяния приводит к 326 путям. Вы можете подтвердить это с помощью следующего кода.

[~,npaths] = paths(sn);
sum(npaths)
ans = 326

Разделение FSDD на учебные и тестовые наборы. Выделите 80% данных обучающему набору и сохраните 20% для тестового набора. Данные обучения предназначены для обучения классификатора на основе преобразования рассеяния. Тестовые данные предназначены для оценки способности модели обобщать невидимые данные.

rng default;
ads = shuffle(ads);
[adsTrain,adsTest] = splitEachLabel(ads,0.8);
summary(adsTrain.Labels)
     0      240 
     1      240 
     2      240 
     3      240 
     4      240 
     5      240 
     6      240 
     7      240 
     8      240 
     9      240 
summary(adsTest.Labels)
     0      60 
     1      60 
     2      60 
     3      60 
     4      60 
     5      60 
     6      60 
     7      60 
     8      60 
     9      60 

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

Xtrain = [];
scatds_Train = transform(adsTrain,@(x)helperReadSPData(x));
while hasdata(scatds_Train)
    smat = read(scatds_Train);
    Xtrain = cat(2,Xtrain,smat);
    
end

Повторите процесс для задержанного тестового набора. Полученная матрица равна 8192 на 600.

Xtest = [];
scatds_Test = transform(adsTest,@(x)helperReadSPData(x));
while hasdata(scatds_Test)
    smat = read(scatds_Test);
    Xtest = cat(2,Xtest,smat);
    
end

Примените преобразование рассеяния к обучающим и тестовым наборам. Перемещение наборов данных обучения и тестирования в графический процессор с помощью gpuArray. Использование gpuArray с графическим процессором NVIDIA с поддержкой CUDA обеспечивает значительное ускорение. С помощью этой сети рассеяния, размера партии и GPU реализация GPU вычисляет характеристики рассеяния приблизительно в 15 раз быстрее, чем версия CPU. Если использование графического процессора не требуется, установите useGPU кому false. Можно также чередовать значение useGPU сравнение производительности графического процессора с производительностью ЦП.

useGPU = true;
if useGPU
    Xtrain = gpuArray(Xtrain);
    Strain = sn.featureMatrix(Xtrain);
    Xtrain = gather(Xtrain);
    Xtest = gpuArray(Xtest);
    Stest = sn.featureMatrix(Xtest);
    Xtest = gather(Xtest);
else
    Strain = sn.featureMatrix(Xtrain);
    Stest = sn.featureMatrix(Xtest);
end

Получите характеристики рассеяния для обучающих и тестовых наборов.

TrainFeatures = Strain(2:end,:,:);
TrainFeatures = squeeze(mean(TrainFeatures,2))';
TestFeatures = Stest(2:end,:,:);
TestFeatures = squeeze(mean(TestFeatures,2))';

В этом примере используется классификатор вектора поддержки (SVM) с ядром квадратичного полинома. Подгоните модель SVM к элементам рассеяния.

template = templateSVM(...
    'KernelFunction', 'polynomial', ...
    'PolynomialOrder', 2, ...
    'KernelScale', 'auto', ...
    'BoxConstraint', 1, ...
    'Standardize', true);
classificationSVM = fitcecoc(...
    TrainFeatures, ...
    adsTrain.Labels, ...
    'Learners', template, ...
    'Coding', 'onevsone', ...
    'ClassNames', categorical({'0'; '1'; '2'; '3'; '4'; '5'; '6'; '7'; '8'; '9'}));

Используйте k-кратную перекрестную проверку, чтобы предсказать точность обобщения модели. Разбейте обучающий набор на пять групп для перекрестной проверки.

partitionedModel = crossval(classificationSVM, 'KFold', 5);
[validationPredictions, validationScores] = kfoldPredict(partitionedModel);
validationAccuracy = (1 - kfoldLoss(partitionedModel, 'LossFun', 'ClassifError'))*100
validationAccuracy = 97.2500

Оценочная точность обобщения составляет примерно 97%. Теперь используйте модель SVM для прогнозирования задержанного тестового набора.

predLabels = predict(classificationSVM,TestFeatures);
testAccuracy = sum(predLabels==adsTest.Labels)/numel(predLabels)*100
testAccuracy = 97

Точность также составляет приблизительно 97% в наборе испытаний с удержанием.

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

figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]);
ccscat = confusionchart(adsTest.Labels,predLabels);
ccscat.Title = 'Wavelet Scattering Classification';
ccscat.ColumnSummary = 'column-normalized';
ccscat.RowSummary = 'row-normalized';

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

reset(ads);
sig1 = helperReadSPData(read(ads));
scat1 = sn.featureMatrix(sig1);
scat1 = mean(scat1(2:end,:),2)';
plab1 = predict(classificationSVM,scat1);

Прочитайте следующую запись и спрогнозируйте цифру.

sig2 = helperReadSPData(read(ads));
scat2 = sn.featureMatrix(sig2);
scat2 = mean(scat2(2:end,:),2)';
plab2 = predict(classificationSVM,scat2);
t = 0:1/8000:(8192*1/8000)-1/8000;
plot(t,[sig1 sig2])
grid on
axis tight
legend(char(plab1),char(plab2))
title('Spoken Digit Prediction - GPU')

Приложение

В этом примере используются следующие вспомогательные функции.

helpergenLabels - создает метки на основе имен файлов в FSDD.

function Labels = helpergenLabels(ads)
% This function is only for use in Wavelet Toolbox examples. It may be
% changed or 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

helperReadSPData - гарантирует, что каждая запись в виде речевых цифр имеет длину 8192 образца.

function x = helperReadSPData(x)
% This function is only for use Wavelet Toolbox examples. 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 = single(x./max(abs(x)));

end

См. также

Связанные темы