Ускорение графического процессора Scalograms для глубокого обучения

В этом примере показано, как можно ускорить scalogram расчет с помощью графических процессоров. Вычисленные scalograms используются в качестве входных функций к глубоким нейронным сетям свертки (CNN) для ECG и разговорной классификации цифр.

У вас должен быть CUDA-поддерживающий NVIDIA, графический процессор с вычисляет возможность 3.0 или выше. Смотрите Поддержку графического процессора Релизом (Parallel Computing Toolbox) для деталей. Аудио раздел этого примера требует, чтобы Audio Toolbox™ использовал аудио datastore и преобразованный datastore.

Расчет Scalogram Используя графический процессор

Самый эффективный способ вычислить scalograms на графическом процессоре состоит в том, чтобы использовать cwtfilterbank. Шаги, чтобы вычислить scalograms на графическом процессоре:

  1. Создайте cwtfilterbank с желаемыми настройками свойства.

  2. Переместите сигнал в графический процессор с помощью gpuArray.

  3. Используйте набор фильтров WT метод, чтобы вычислить непрерывный вейвлет преобразовывает (CWT).

В первый раз вы используете WT метод, cwtfilterbank кэширует фильтры вейвлета на графическом процессоре. В результате существенная экономия времени в расчете понята, когда вы получаете scalograms нескольких сигналов с помощью того же набора фильтров и того же типа данных. Следующее демонстрирует рекомендуемый рабочий процесс. Как пример, используйте выборку музыки гитары, содержащей 661 500 выборок.

[y,fs] = audioread('guitartune.wav');
plot(y)
grid on

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

y = single(y);

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

fb = cwtfilterbank('SignalLength',length(y),'SamplingFrequency',fs);

Наконец переместите сигнал в графический процессор с помощью gpuArray и вычислите CWT данных. Постройте получившийся scalogram.

[cfs,f] = fb.wt(gpuArray(y));
t = 0:1/fs:(length(y)*1/fs)-1/fs;
imagesc(t,f,abs(cfs))
axis xy
ylabel('Hz')
xlabel('Seconds')

Используйте gather принести коэффициенты CWT и любые другие выходные параметры назад к центральному процессору.

cfs = gather(cfs);
f = gather(f);

Продемонстрировать КПД, полученный в использовании графического процессора, время расчет CWT на графическом процессоре и центральном процессоре для того же сигнала. Графический процессор вычисляет времена, о которых сообщают, здесь получены с помощью Титана NVIDIA V с вычислить возможностью 7,0.

ygpu = gpuArray(y);
fgpu = @()fb.wt(ygpu);
Tgpu = gputimeit(fgpu)
Tgpu = 0.2658

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

fcpu = @()fb.wt(y);
Tcpu = timeit(fcpu)
Tcpu = 3.7088
Tcpu/Tgpu
ans = 13.9533

Scalograms в глубоком обучении

Распространенное приложение CWT в глубоком обучении должно использовать scalogram сигнала как вход "изображение" к глубокому CNN. Это обязательно передает под мандат расчет нескольких scalograms, один для каждого сигнала в обучении, валидации и наборах тестов. В то время как графические процессоры часто используются, чтобы ускорить обучение и вывод в глубокой сети, это также выгодно, чтобы использовать графические процессоры, чтобы ускорить любое извлечение признаков, или предварительная обработка данных должна была сделать глубокую сеть более устойчивой.

Чтобы проиллюстрировать это, следующий раздел применяет вейвлет scalograms к человеческой электрокардиограмме (ECG) классификация. Scalograms используются с теми же данными, обработанными в, Классифицируют Временные ряды Используя Анализ Вейвлета и Глубокое обучение. В том примере передача обучения с GoogLeNet и SqueezeNet использовалась, чтобы классифицировать формы волны ECG в одну из трех категорий. Описание данных и как получить, это повторяется здесь для удобства.

Описание данных о ECG и загрузка

Данные о ECG получены из трех групп людей: люди с сердечной аритмией (ARR), люди с застойной сердечной недостаточностью (CHF) и люди с нормальными ритмами пазухи (NSR). Всего от трех Физиосетевых баз данных существует 162 записи ECG: База данных Аритмии MIT-BIH [2] [3], MIT-BIH Нормальная База данных Ритма Пазухи [3] и База данных Застойной сердечной недостаточности BIDMC [1] [3]. А именно, 96 записей от людей с аритмией, 30 записей от людей с застойной сердечной недостаточностью и 36 записей от людей с нормальными ритмами пазухи. Цель состоит в том, чтобы обучить модель различать ARR, швейцарский франк и NSR.

Можно получить эти данные из репозитория MathWorks GitHub. Чтобы загрузить данные из веб-сайта, нажмите Clone or download и выберите Download ZIP. Сохраните файл physionet_ECG_data-master.zip в папке, где у вас есть разрешение записи. Инструкции для этого примера принимают, что вы загрузили файл на свою временную директорию, tempdir, в MATLAB. Измените последующие инструкции для того, чтобы разархивировать и загрузить данные, если вы принимаете решение загрузить данные в папке, отличающейся от tempdir. Если вы знакомы с Git, можно загрузить последнюю версию инструментов (Git) и получить данные из системной командной строки с помощью git clone https://github.com/mathworks/physionet_ECG_data/.

После загрузки данных GitHub разархивируйте файл в своей временной директории.

unzip(fullfile(tempdir,'physionet_ECG_data-master.zip'),tempdir)

Разархивация создает папку physionet-ECG_data-master в вашей временной директории. Эта папка содержит текстовый файл README.md и ECGData.zip. ECGData.zip файл содержит

  • ECGData.mat

  • Modified_physionet_data.txt

  • License.txt

ECGData.mat содержит данные, используемые в этом примере. Текстовый файл, Modified_physionet_data.txt, требуется копированием PhysioNet политики и обеспечивает исходные приписывания для данных, а также описание шагов предварительной обработки применилось к каждой записи ECG.

Разархивируйте ECGData.zip в physionet-ECG_data-master. Загрузите файл данных в свое рабочее пространство MATLAB.

unzip(fullfile(tempdir,'physionet_ECG_data-master','ECGData.zip'),...
    fullfile(tempdir,'physionet_ECG_data-master'))
load(fullfile(tempdir,'physionet_ECG_data-master','ECGData.mat'))

ECGData массив структур с двумя полями: Data и Labels. Data поле 162 65536 матрица, где каждая строка является записью ECG, произведенной на уровне 128 герц. Labels 162 1 массив ячеек диагностических меток, один для каждой строки Data. Три диагностических категории: 'ARR', 'CHF', и 'NSR'. Используйте функцию помощника, helperRandomSplit, разделять данные в обучение и валидацию устанавливает с 80% данных, выделенных для обучения и 20% для валидации. Преобразуйте метки диагностики ECG в categoricals.

[trainData, validationData, trainLabels, validationLabels] = helperRandomSplit(80,ECGData);
trainLabels = categorical(trainLabels);
validationLabels = categorical(validationLabels);

В trainData существует 130 записей установите и 32 записи в validationData. Проектом обучающие данные содержат 80,25% (130/162) данных. Вспомните, что класс ARR представляет 59,26% данных (96/162), класс швейцарского франка представляет 18,52% (30/162), и класс NSR представляет 22,22% (36/162). Исследуйте процент каждого класса в наборах обучающих данных и наборах тестов. Проценты в каждом сопоставимы с полными процентами класса в наборе данных.

Ctrain = countcats(trainLabels)./numel(trainLabels).*100
Ctrain = 3×1

   59.2308
   18.4615
   22.3077

Cvalid = countcats(validationLabels)./numel(validationLabels).*100
Cvalid = 3×1

   59.3750
   18.7500
   21.8750

Scalograms с глубоким CNN — данные о ECG

Расчет Scalogram на графическом процессоре

Вычислите scalograms и для наборов обучения и для валидации. Установите useGPU к true использовать графический процессор и false вычислить scalograms на центральном процессоре. Смягчить последствие больших входных матриц на CNN и создать больше примеров обучения и валидации, helperECGScalograms разделения каждая форма волны ECG в четыре неперекрывающихся сегмента 16 384 выборок каждый и вычисляют scalograms для всех четырех сегментов. Реплицируйте метки, чтобы совпадать с расширенным набором данных. В этом случае получите оценку израсходованного времени вычисления.

frameLength = 16384;
useGPU = true;
tic;
Xtrain = helperECGScalograms(trainData,frameLength,useGPU);
Computing scalograms...
Processed 50 files out of 130
Processed 100 files out of 130
...done
T = toc;
sprintf('Elapsed time is %1.2f seconds',T)
ans = 
'Elapsed time is 4.22 seconds'
trainLabels = repelem(trainLabels,4);

С Титаном V графических процессоров 502 scalograms были вычислены приблизительно за 4,2 секунды. Установка useGPU к false и повторение вышеупомянутого расчета демонстрирует скорость, полученную при помощи графического процессора. В этом случае использование центрального процессора потребовало, чтобы 33,3 секунды вычислили scalograms. Расчет графического процессора был больше чем в 7 раз быстрее.

Повторите тот же процесс для данных о валидации.

useGPU = true;
Xvalid = helperECGScalograms(validationData,frameLength,useGPU);
Computing scalograms...
...done
validationLabels = repelem(validationLabels,4);

Затем настройте глубокий CNN, чтобы обработать и наборы обучения и валидации. Простая сеть, используемая здесь, не оптимизирована. Этот CNN только используется, чтобы проиллюстрировать сквозной рабочий процесс для случаев, где scalograms умещаются в памяти.

sz = size(Xtrain);
specSize = sz(1:2);
imageSize = [specSize 1];
dropoutProb = 0.3;

layers = [
    imageInputLayer(imageSize)
    
    convolution2dLayer(3,12,'Padding','same')
    batchNormalizationLayer
    reluLayer
    
    maxPooling2dLayer(2,'Stride',2)
    
   
    convolution2dLayer(3,20,'Padding','same')
    batchNormalizationLayer
    reluLayer
    
    maxPooling2dLayer(2,'Stride',2)
    
   
    
    convolution2dLayer(3,32,'Padding','same')
    batchNormalizationLayer
    reluLayer
    dropoutLayer(dropoutProb)
    fullyConnectedLayer(3)
    softmaxLayer
    classificationLayer];

Используйте следующие опции обучения.

options = trainingOptions('sgdm',...
    'InitialLearnRate', 1e-4,...
    'LearnRateDropPeriod',18,...
    'MiniBatchSize', 20,...
    'MaxEpochs',25,...
    'L2Regularization',1e-1,...
    'Plots', 'training-progress',...
    'Verbose',false,...
    'Shuffle','every-epoch',...
    'ExecutionEnvironment','auto',...
    'ValidationData',{Xvalid,validationLabels});

Обучите сеть и измерьте ошибку валидации.

trainNetwork(Xtrain,trainLabels,layers,options);

Даже при том, что простой CNN, используемый здесь, не оптимизирован, точность валидации последовательно находится в высоких 80 к низкой 90-процентной области значений. Это сопоставимо с точностью валидации, достигнутой с более мощным и оптимизированным SqueezeNet, показанным в, Классифицируют Временные ряды Используя пример Анализа и Глубокого обучения Вейвлета. Далее, это - намного более эффективное использование scalogram, потому что в том примере scalograms должен был быть перемасштабирован, когда RGB отображает совместимый с SqueezeNet, сохраненным на диск в соответствующем формате изображения, и затем питаемым глубокую сеть с помощью imageDatastore.

Разговорное Распознавание Цифры — Вычисление графического процессора с помощью Datastore Преобразования

Этот раздел показывает, как ускорить scalogram расчет с помощью графического процессора в преобразованном рабочем процессе datastore.

Данные

Клонируйте или загрузите Свободный разговорный набор данных цифры (FSDD), доступный в https://github.com/Jakobovski/free-spoken-digit-dataset. FSDD является открытым набором данных, что означает, что это может расти в зависимости от времени. Этот пример использует версию, фиксировавшую 01/29/2019, который состоит из 2 000 записей английских цифр 0 через 9 полученных от четырех докладчиков. Два из докладчиков в этой версии являются носителями американского варианта английского языка, и два докладчика являются ненативными докладчиками английского языка с французским Бельгии и немецким диакритическим знаком. Данные производятся на уровне 8 000 Гц.

Для других подходов к этому набору данных включая рассеивание вейвлета смотрите Разговорное Распознавание Цифры с Рассеиванием Вейвлета и Глубоким обучением.

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

pathToRecordingsFolder = '/home/user/free-spoken-digit-dataset/recordings';
location = pathToRecordingsFolder;

Укажите audioDatastore к тому местоположению.

ads = audioDatastore(location);

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

ads.Labels = helpergenLabels(ads);
summary(ads.Labels)
     0      200 
     1      200 
     2      200 
     3      200 
     4      200 
     5      200 
     6      200 
     7      200 
     8      200 
     9      200 

Преобразованный Datastore

Сначала разделите FSDD в наборы обучающих данных и наборы тестов. Выделите 80% данных к набору обучающих данных и сохраните 20% для набора тестов.

rng default;
ads = shuffle(ads);
[adsTrain,adsTest] = splitEachLabel(ads,0.8);
countEachLabel(adsTrain)
ans=10×2 table
    Label    Count
    _____    _____

      0       160 
      1       160 
      2       160 
      3       160 
      4       160 
      5       160 
      6       160 
      7       160 
      8       160 
      9       160 

Затем создайте набор фильтров CWT и преобразованные хранилища данных и для обучения и для тестовых данных с помощью функции помощника, helperDigitScalogram. Преобразованный datastore преобразует каждую запись в сигнал длины 8192, вычисляет scalogram на графическом процессоре и собирает данные назад на центральный процессор.

reset(gpuDevice(1))
fb = cwtfilterbank('SignalLength',8192);
adsSCTrain = transform(adsTrain,@(audio,info)helperDigitScalogram(audio,info,fb),'IncludeInfo',true);
adsSCTest = transform(adsTest,@(audio,info)helperDigitScalogram(audio,info,fb),'IncludeInfo',true);

Глубокий CNN

Создайте глубокий CNN, чтобы обучаться с преобразованным datastore, adscTrain. Как в первом примере, не оптимизирована сеть. Точка должна показать рабочий процесс с помощью scalograms вычисленный на графическом процессоре для данных, которые не помещаются в память.

numClasses = 10;

dropoutProb = 0.2;
numF = 12;
layers = [
    imageInputLayer([101 8192 1])

    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(numClasses)
    softmaxLayer
    classificationLayer('Classes',categories(ads.Labels));
   ]; 

Установите опции обучения для сети.

miniBatchSize = 25;
options = trainingOptions('adam', ...
    'InitialLearnRate',1e-4, ...
    'MaxEpochs',30, ...
    'MiniBatchSize',miniBatchSize, ...
    'Shuffle','every-epoch', ...
    'Plots', 'training-progress',...
    'Verbose',false,...
    'ExecutionEnvironment','gpu');

Обучите сеть.

trainedNet = trainNetwork(adsSCTrain,layers,options);

В этом экземпляре обучение было завершено за 25 минут и 10 секунд. Если вы комментируете вызов gpuArray in helperDigitScalogram и используйте центральный процессор, чтобы получить scalograms, учебное время значительно увеличивается. В этом случае увеличение с 25 минут и 10 секунд к 45 минутам и 38 секунд наблюдалось.

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

Ypredicted = classify(trainedNet,adsSCTest,'ExecutionEnvironment','CPU');
cnnAccuracy = sum(Ypredicted == adsTest.Labels)/numel(Ypredicted)*100
cnnAccuracy = 96.2500

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

Эффективность обучивших сеть на тестовых данных близко к 96%. Это сопоставимо с эффективностью в Разговорном Распознавании Цифры с Рассеиванием Вейвлета и Глубоким обучением.

Сводные данные

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

Ссылки

  1. Baim, D. S. В. С. Колуччи, Э. С. Монрэд, Х. С. Смит, Р. Ф. Райт, А. Лэноу, Д. Ф. Готье, Б. Дж. Рэнсил, В. Гроссман и Э. Бронвалд. "Выживание пациентов с тяжелой застойной сердечной недостаточностью отнеслось с устным milrinone". Журнал американского Колледжа Кардиологии. Издание 7, Номер 3, 1986, стр 661–670.

  2. Голдбергер А. Л., Л. А. Н. Амарал, L. Стекло, Дж. М. Гаусдорф, P. Ch. Иванов, Р. Г. Марк, Дж. Э. Митус, Г. Б. Муди, C.-K. Пенг и Х. Э. Стэнли. "PhysioBank, PhysioToolkit и PhysioNet: Компоненты Нового Ресурса Исследования для Комплексных Физиологических Сигналов". Циркуляция. Издание 101, Номер 23: e215–e220. [Циркуляция Электронные Страницы; http://circ.ahajournals.org/content/101/23/e215.full]; 2000 (13 июня). doi: 10.1161/01. CIR.101.23.e215.

  3. Капризный, G. B. и Р. Г. Марк. "Удар Базы данных Аритмии MIT-BIH". Разработка IEEE в Журнале Медицины и Биологии. Издание 20. Номер 3, мочь-июнь 2001, стр 45–50. (PMID: 11446209)

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
function X = helperECGScalograms(data,window,useGPU)

disp("Computing scalograms...");
Nsig = size(data,1);
Nsamp = size(data,2);
Nsegment = Nsamp/window;

fb = cwtfilterbank('SignalLength',window,'Voices',10);
Ns = length(fb.Scales);
X = zeros([Ns,window,1,Nsig*Nsegment],'single');
start = 0;
if useGPU
    data = gpuArray(single(data'));
else
    data = single(data');
end
for ii = 1:Nsig
    ts = data(:,ii);
    ts = reshape(ts,window,Nsegment);
    ts = (ts-mean(ts))./max(abs(ts));
    
    for kk = 1:size(ts,2)
        cfs = fb.wt(ts(:,kk));
        X(:,:,1,kk+start) = gather(abs(cfs));
        
    end
    start = start+Nsegment;
    
    if mod(ii,50) == 0
        disp("Processed " + ii + " files out of " + Nsig)
    end
    
end

disp("...done");
data = gather(data);

end
function [x,info] = helperReadSPData(x,info)
% 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 = x./max(abs(x));

end
function [dataout,info] = helperDigitScalogram(audioin,info,fb)
audioin = single(audioin);
audioin = gpuArray(audioin);
audioin = helperReadSPData(audioin);
cfs = gather(abs(fb.wt(audioin)));
audioin = gather(audioin);
dataout = {cfs,info.Label};
end