Этот пример показов, как вы можете ускорить скалограмму расчета с помощью графических процессоров. Вычисленные скалограммы используются как входные функции в нейронных сетях глубокой свертки (CNN) для классификации ЭКГ и разговорных цифр.
Для использования графический процессор требуется Parallel Computing Toolbox™. Информацию о том, какие графические процессоры поддерживаются, см. в разделе Поддержка GPU Release (Parallel Computing Toolbox). Раздел аудио этого примера требует, чтобы Audio Toolbox™ использовала audio datastore и преобразованный datastore.
Самый эффективный способ вычисления скалограмм на графическом процессоре - использовать cwtfilterbank
. Шаги для вычисления скалограмм на графическом процессоре:
Конструкция cwtfilterbank
с требуемыми настройками свойств.
Переместите сигнал на графический процессор с помощью gpuArray
.
Используйте банк фильтров WT
метод для вычисления непрерывного вейвлет (CWT).
Первый раз вы используете WT
метод, cwtfilterbank
кэширует фильтры вейвлета на графическом процессоре. В результате существенная экономия времени в расчетах реализуется, когда вы получаете скалограммы нескольких сигналов, использующих одну и ту же группу фильтров и тот же тип данных. Ниже показан рекомендуемый рабочий процесс. В качестве примера используйте выборку гитарной музыки, содержащий 661 500 выборки.
[y,fs] = audioread('guitartune.wav'); plot(y) grid on
Поскольку большинство графических процессоров NVIDIA значительно эффективнее с одинарными, а не с двойной точностью данных, приведите сигнал к одинарной точности.
y = single(y);
Создайте банк фильтров, чтобы соответствовать длине сигнала и частоте дискретизации. Для глубокого обучения частота дискретизации обычно не требуется и, следовательно, может быть исключена.
fb = cwtfilterbank('SignalLength',length(y),'SamplingFrequency',fs);
Наконец, переместите сигнал на графический процессор, используя gpuArray
и вычислите CWT данных. Постройте график получившейся скалограммы.
[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 на GPU и CPU для того же сигнала. Указанное здесь время вычисления графического процессора получено с использованием NVIDIA Titan 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
Общим приложением CWT в глубоком обучении является использование скалограммы сигнала в качестве входного «изображения» для глубокого CNN. Это обязательно предписывает расчет нескольких скалограмм, по одному для каждого сигнала в наборах обучения, валидации и тестирования. Хотя графические процессоры часто используются для ускорения обучения и вывода в глубокой сети, также выгодно использовать графические процессоры для ускорения любой редукции данных или предварительной обработки данных, необходимой для повышения устойчивости глубокой сети.
Для иллюстрации этого в следующем разделе применяются вейвлет к классификации электрокардиограммы (ЭКГ) человека. Скалограммы используются с теми же данными, которые обрабатываются в Classify Time Series с использованием Wavelet Analysis и Глубокое Обучение. В этом примере передача обучения с помощью GoogLeNet и SqueezeNet использовалась для классификации форм волны ЭКГ в одну из трех категорий. Описание данных и способы их получения повторяются здесь для удобства.
Данные ЭКГ получены от трех групп людей: лиц с сердечной аритмией (АРР), лиц с застойным сердечным отказом (ХСН) и лиц с нормальными синусовыми ритмами (СМП). Всего существует 162 записи ЭКГ из трех баз данных PhysioNet: базы данных аритмии MIT-BIH [2] [3], базы данных нормального синусового ритма MIT-BIH [3] и базы данных застойной сердечной недостаточности BIDMC [1] Более конкретно, 96 записей от лиц с аритмией, 30 записей от лиц с застойным сердечным отказом и 36 записей от лиц с нормальными синусовыми ритмами. Цель состоит в том, чтобы обучить модель различать ARR, CHF и NSR.
Вы можете получить эти данные из репозитория MathWorks GitHub. Чтобы загрузить данные с сайта, нажмите Code
и выберите Download ZIP
. Сохраните файл physionet_ECG_data-main.zip
в папке, в которой у вас есть разрешение на запись. Инструкции для этого примера предполагают, что вы загрузили файл во временную директорию tempdir
, в MATLAB. Измените последующие инструкции для распаковки и загрузки данных, если вы решите загрузить данные в папку, отличную от tempdir
.
После загрузки данных с GitHub разархивируйте файл во временной директории.
unzip(fullfile(tempdir,'physionet_ECG_data-main.zip'),tempdir)
Unzipping создает папку physionet-ECG_data-main
во временной директории. Эта папка содержит текстовый файл README.md
и ECGData.zip
. The ECGData.zip
файл содержит
ECGData.mat
Modified_physionet_data.txt
License.txt
ECGData.mat
содержит данные, используемые в этом примере. Текстовый файл, Modified_physionet_data.txt
, требуется политикой копирования PhysioNet и предоставляет исходные атрибуты для данных, а также описание шагов предварительной обработки, применяемых к каждой записи ЭКГ.
Разархивирование ECGData.zip
в physionet-ECG_data-main
. Загрузите файл данных в рабочее рабочее пространство MATLAB.
unzip(fullfile(tempdir,'physionet_ECG_data-main','ECGData.zip'),... fullfile(tempdir,'physionet_ECG_data-main')) load(fullfile(tempdir,'physionet_ECG_data-main','ECGData.mat'))
ECGData
массив структур с двумя полями: Data
и Labels
. The Data
поле представляет собой 162 на 65536 матрицу, где каждая строка является дискретизацией записи ЭКГ в 128 герц. Labels
- массив ячеек 162 на 1 с диагностическими метками, по одному для каждой строки Data
. Три диагностические категории: 'ARR'
, 'CHF'
, и 'NSR'
. Используйте функцию helper, helperRandomSplit
, чтобы разделить данные на наборы обучения и валидации с 80% данных, выделенных для обучения и 20% для валидации. Преобразуйте метки диагностики ЭКГ в категории.
[trainData, validationData, trainLabels, validationLabels] = helperRandomSplit(80,ECGData); trainLabels = categorical(trainLabels); validationLabels = categorical(validationLabels);
В trainData
130 записей установите и 32 записи в
Data
валидации. По проекту обучающие данные содержат 80,25% (130/162) данных. Напомним, что класс ARR представляет 59,26% данных (96/162), класс CHF представляет 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
Вычислите скалограммы для наборов обучения и валидации. Задайте useGPU
на true
для использования графического процессора и false
для вычисления скалограмм на центральном процессоре. Чтобы уменьшить эффект больших входных матриц на CNN и создать больше примеров обучения и валидации, helperECGScalograms
разделяет каждую форму волны ЭКГ на четыре неперекрывающихся сегмента по 16384 выборки и вычисляет скалограммы для всех четырех сегментов. Реплицируйте метки так, чтобы они совпадали с расширенным набором данных. В этом случае получите оценку затраченного времени расчета.
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);
С графическим процессором Titan V 502 скалограммы были вычислены приблизительно за 4,2 секунды. Настройка useGPU
на false
и повторение вышеописанных расчетов демонстрирует скорость, полученную при помощи графический процессор. В этом случае для вычисления скалограмм с помощью центральный процессор потребовалось 33,3 секунды. Расчет графический процессор было более чем в 7 раз быстрее.
Повторите тот же процесс для данных валидации.
useGPU = true; Xvalid = helperECGScalograms(validationData,frameLength,useGPU);
Computing scalograms... ...done
validationLabels = repelem(validationLabels,4);
Затем создайте глубокий CNN, чтобы обработать как наборы обучения, так и наборы валидации. Используемая здесь простая сеть не оптимизирована. Этот CNN используется только для иллюстрации сквозного рабочего процесса для случаев, когда скалограммы помещаются в памяти.
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, показанным в Classify Time Series с использованием примера Wavelet Analysis и Глубокое Обучение. Кроме того, это намного более эффективное использование скалограммы, потому что в этом примере скалограммы должны были быть пересмотрены как изображения RGB, совместимые с SqueezeNet, сохранены на диск в соответствующем формате изображения, а затем переданы в глубокую сеть с помощью imageDatastore
.
В этом разделе показов, как ускорить скалограмму расчета используя графический процессор в преобразованном datastore рабочем процессе.
Клон или скачать бесплатный набор данных Spoken Digit (FSDD), доступный в https://github.com/Jakobovski/free-spoken-digit-dataset. FSDD является открытым набором данных, что означает, что он может расти с течением времени. Этот пример использует версию, зафиксированную на 01/29/2019, которая состоит из 2000 записей английских цифр от 0 до 9, полученных от четырех дикторов. Два носителя в этой версии являются носителями американского английского языка, а два носителя являются носителями английского языка с бельгийским французским и немецким акцентом. Данные отбираются с частотой дискретизации 8000 Гц.
Для других подходов к этому набору данных, включая вейвлет, смотрите Распознавание Разговорных Цифр с Вейвлет и Глубокое Обучение.
Использование 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
Сначала разделите 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 и преобразованные хранилища данных для обучающих и тестовых данных с помощью функции helper, helperDigitScalogram
. Преобразованный datastore преобразует каждую запись в сигнал длины 8192, вычисляет скалограмму на графическом процессоре и собирает данные обратно на центральный процессор.
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, чтобы обучаться с преобразованным datastore, adscTrain
. Как и в первом примере, сеть не оптимизирована. Цель точки - показать рабочий процесс с помощью скалограмм, вычисленных на графическом процессоре для данной , которой не помещаютси в память,.
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
в helperDigitScalogram
и используйте центральный процессор, чтобы получить скалограммы, время обучения значительно увеличивается. При этом наблюдалось увеличение с 25 минут и 10 секунд до 45 минут и 38 секунд.
Используйте обученную сеть, чтобы предсказать метки цифр для тестового набора.
Ypredicted = classify(trainedNet,adsSCTest,'ExecutionEnvironment','CPU'); cnnAccuracy = sum(Ypredicted == adsTest.Labels)/numel(Ypredicted)*100
cnnAccuracy = 96.2500
Время вывода с использованием графический процессор составило приблизительно 22 секунды. Используя центральный процессор, время вывода удвоилось до 45 секунд.
Эффективность обученной сети по тестовым данным близка к 96%. Это сопоставимо с эффективностью в распознавании разговорных цифр с вейвлет и глубоким обучением.
В этом примере показано, как использовать графический процессор для ускорения расчетов скалограммы. Пример представил оптимальный рабочий процесс для эффективного вычисления скалограмм как для данных в памяти, так и для данных , которых не помещаютсь в память,, считанных с диска с помощью преобразованных хранилищ данных.
Baim, D. S., В. С. Колуччи, Э. С. Монрэд, Х. С. Смит, Р. Ф. Райт, А. Лэноу, Д. Ф. Готье, Б. Дж. Рэнсил, В. Гроссман и Э. Браунвальд. «Выживание пациентов с тяжёлым застойным сердечным отказом, получавших пероральный милринон». Журнал Американского колледжа кардиологов. Том 7, № 3, 1986, стр. 661-670.
Гольдбергер А. Л., Л. А. Н. Амарал, Л. Гласс, Ж. М. Хаусдорф, П. Ч. Иванов, Р. Г. Марк, Ж. Э. Миетус, Г. Б. Муди, К.-К. Пэн и Х. Э. Стэнли. 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.
Moody, G. B., and R. G. Mark. «The влияния of the MIT-BIH Arrhythmia Database». IEEE Engineering in Medicine and Biology Magazine. Том 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