Этот пример показывает рабочий процесс для классификации сигналов электрокардиограммы человека (ЭКГ) с использованием непрерывного вейвлет-преобразования (CWT) и глубокой сверточной нейронной сети (CNN). В этом примере также приводится информация о том, как генерировать и развертывать код и CNN для прогнозирования на цели Raspberry Pi (устройство на базе ARM ®).
SqueeeNet - это глубокий CNN, изначально предназначенный для классификации изображений в 1000 категорий. В примере «Классифицировать временные ряды с использованием вейвлет-анализа и глубокого обучения» Squeez Net перепрофилируется для классификации форм сигналов ЭКГ на основе их скалограмм. Скалограмма является частотно-временным представлением сигнала и является абсолютным значением CWT сигнала. В этом примере мы повторно используем переподготовленный SqueeENet.
В этом примере используются данные ЭКГ из PhysioNet. Данные ЭКГ получены от трех групп людей: лиц с сердечной аритмией (ARR), лиц с застойной сердечной недостаточностью (CHF) и лиц с нормальными синусовыми ритмами (СМП). Набор данных включает 96 записей от лиц с ARR, 30 записей от лиц с CHF и 36 записей от лиц с NSR. Записи ЭКГ 162 из трех баз данных PhysioNet: базы данных аритмии MIT-BIH [2] [3], базы данных нормального синусового ритма MIT-BIH [3] и базы данных застойной сердечной недостаточности BIDMC [1] [3]. Сокращенные данные ЭКГ указанных выше ссылок можно загрузить из репозитория GitHub.
Процессор ARM, поддерживающий расширение NEON
Вычислительная библиотека ARM версии 19.05 (на целевом оборудовании ARM)
Переменные среды для компиляторов и библиотек
Пакет поддержки интерфейса кодера MATLAB для библиотек глубокого обучения
Поддерживаемые версии библиотек и сведения о настройке переменных среды см. в разделе Предварительные условия для глубокого обучения с помощью кодера MATLAB (MATLAB Coder). Этот пример не поддерживается в MATLAB Online™.
Основная функция в созданном исполняемом файле, processECGиспользует 65 536 выборок данных ЭКГ с одной точностью в качестве входных данных. Функция:
Принимает CWT данных ЭКГ.
Получают скалограмму из вейвлет-коэффициентов.
Преобразует скалограмму в изображение RGB размерности 227-на-227-на-3. Это делает образ совместимым с сетевой архитектурой SqueeeNet.
Выполняет прогнозирование для классификации изображения с помощью SqueeNet.
type processECGfunction [YPred] = processECG(input)
% processECG function - converts 1D ECG to image and predicts the syndrome
% of heart disease
%
% This function is only intended to support the example:
% Signal Classification Code Generation Using Wavelets and
% Deep Learning on Raspberry Pi. It may change or be removed in a
% future release.
% Copyright 2020 The MathWorks, Inc.
% colourmap for image transformation
persistent net jetdata;
if(isempty(jetdata))
jetdata = colourmap(128,class(input));
end
% Squeezenet trained network
if(isempty(net))
net = coder.loadDeepLearningNetwork('trainedNet.mat');
end
% Wavelet Transformation & Image conversion
cfs = ecg_to_Image(input);
image = ind2rgb(im2uint8(rescale(cfs)),single(jetdata));
image = im2uint8(imresize(image,[227,227]));
% figure
if isempty(coder.target)
imshow(image);
end
% Prediction
[YPred] = predict(net,image);
%% ECG to image conversion
function cfs = ecg_to_Image(input)
%Wavelet Transformation
persistent filterBank
[~,siglen] = size(input);
if isempty(filterBank)
filterBank = cwtfilterbank('SignalLength',siglen,'VoicesPerOctave',6);
end
%CWT conversion
cfs = abs(filterBank.wt(input));
end
%% Colourmap
function J = colourmap(m,class)
n = ceil(m/4);
u = [(1:1:n)/n ones(1,n-1) (n:-1:1)/n]';
g = ceil(n/2) - (mod(m,4)==1) + (1:length(u))';
r = g + n;
b = g - n;
r1 = r(r<=128);
g1 = g(g<=128);
b1 = b(b >0);
J = zeros(m,3);
J(r1,1) = u(1:length(r1));
J(g1,2) = u(1:length(g1));
J(b1,3) = u(end-length(b1)+1:end);
feval = str2func(class);
J = feval(J);
end
end
Создание объекта конфигурации создания кода для создания исполняемой программы. Укажите создание кода C++.
cfg = coder.config('exe'); cfg.TargetLang = 'C++';
Создать coder.ARMNEONConfig объект. Укажите ту же версию библиотеки вычислений ARM, что и в Raspberry Pi. Укажите архитектуру Raspberry Pi.
dlcfg = coder.DeepLearningConfig('arm-compute'); dlcfg.ArmComputeVersion = '19.05'; dlcfg.ArmArchitecture = 'armv7';
Установите DeepLearningConfig свойство объекта конфигурации генерации кода для объекта конфигурации глубокого обучения. Во время создания кода сделайте комментарии источника MATLAB видимыми в объекте конфигурации.
cfg.DeepLearningConfig = dlcfg; cfg.MATLABSourceComments = 1;
Используйте функцию MATLAB Support Package for Raspberry Pi Support Package, raspi, чтобы создать соединение с Raspberry Pi. В следующем коде замените:
'raspiname' с именем вашего Малинового Пи
'pi' с именем пользователя
'password' с вашим паролем
r = raspi('172.18.76.69','pi','raspberry');
Создать coder.Hardware объект для Raspberry Pi и присоедините его к объекту конфигурации генерации кода.
hw = coder.hardware('Raspberry Pi');
cfg.Hardware = hw;Укажите папку сборки на Raspberry Pi.
buildDir = '~/remdirECG';
cfg.Hardware.BuildDir = buildDir;Основной файл C++ считывает входные данные ЭКГ, вызывает processECG функция для выполнения предварительной обработки и глубокого обучения с использованием CNN на данных ЭКГ и отображает вероятность классификации.
Укажите основной файл в объекте конфигурации создания кода. Дополнительные сведения о создании и настройке main_ecg_raspi.cpp, см. Создание автономных исполняемых файлов C/C + + из кода MATLAB (кодер MATLAB).
cfg.CustomSource = 'main_ecg_raspi.cpp';codegenИспользуйте codegen для генерации кода C++. Когда codegen используется с пакетом поддержки MATLAB для аппаратных средств Raspberry Pi, исполняемый файл построен на плате Raspberry Pi.
Убедитесь, что установлены переменные среды ARM_COMPUTELIB и LD_LIBRARY_PATH на Малиновом Пи. См. раздел Предварительные условия для глубокого обучения с помощью кодера MATLAB (MATLAB Coder).
codegen -config cfg processECG -args {ones(1,65536,'single')} -d arm_compute
Deploying code. This may take a few minutes.
Для тестирования сгенерированного кода на Raspberry Pi скопируйте входной сигнал ЭКГ в каталог сгенерированного кода. Этот каталог можно найти вручную или с помощью raspi.utils.getRemoteBuildDirectory API. Эта функция перечисляет каталоги двоичных файлов, которые создаются с помощью codegen.
applicationDirPaths = raspi.utils.getRemoteBuildDirectory('applicationName','processECG')
applicationDirPaths=1×4 cell array
{1×1 struct} {1×1 struct} {1×1 struct} {1×1 struct}
Полный путь к удаленному каталогу построения получен из текущего рабочего каталога. Если вы не знаете, что applicationDirPaths содержит сгенерированный код, используйте функцию помощника helperFindTargetDir. В противном случае укажите соответствующий каталог.
directoryUnknown = true; if directoryUnknown targetDirPath = helperFindTargetDir(applicationDirPaths); else targetDirPath = applicationDirPaths{1}.directory; end
Текстовый файл input_ecg_raspi.csv содержит выборки ЭКГ репрезентативного сигнала ARR. Чтобы скопировать файл, необходимый для запуска исполняемой программы, используйте putFile, который поставляется с пакетом поддержки MATLAB для оборудования Raspberry Pi.
r.putFile('input_ecg_raspi.csv', targetDirPath);Для графического представления первые 1000 образцов могут быть нанесены на график с использованием этих шагов.
input = dlmread('input_ecg_raspi.csv'); plot(input(1:1000)) title('ARR Signal')

Запустите исполняемую программу на Raspberry Pi из MATLAB и направьте выходные данные обратно в MATLAB. Имя входного файла передается в качестве аргумента командной строки для исполняемого файла.
exeName = 'processECG.elf'; % executable name fileName = 'input_ecg_raspi.csv'; % Input ECG file that is pushed to target command = ['cd ' targetDirPath ';./' exeName ' ' fileName]; output = system(r,command)
output =
'Predicted Values on the Target Hardware
ARR CHF NSR
0.806078 0.193609 0.000313103
'
Баим, Д. С., В. С. Колуччи, Э. С. Монрад, Х. С. Смит, Р. Ф. Райт, А. Лануэ, Д. Ф. Готье, Б. Дж. Рансил, В. Гроссман и Э. Браунвальд. «Выживаемость пациентов с тяжелой застойной сердечной недостаточностью, получавших пероральный милринон». Журнал Американского колледжа кардиологов. Том 7, номер 3, 1986, стр. 661-670.
Гольдбергер А. Л., Л. А. Н. Амарал, Л. Гласс, Ж. М. Хаусдорф, П. Ч. Иванов, Р. Г. Марк, Ж. Е. Миетус, Г. Б. Муди, К. -К. Пэн и Х. Э. Стэнли. «PhysioBank, PhysioToolkit и PhysioNet: компоненты нового исследовательского ресурса для сложных физиологических сигналов». Циркуляция. Том 101, номер 23: e215-e220. [Электронные страницы тиража ;http://circ.ahajournals.org/content/101/23/e215.full]; 2000 (13 июня). дои: 10.1161/01.CIR.101.23.e215.
Муди, Г. Б. и Р. Г. Марк. «Влияние базы данных аритмии MIT-BIH». IEEE Engineering in Medicine and Biology Magazine. Том 20. Номер 3, май-июнь 2001 года, стр. 45-50. (PMID: 11446209)
helperFindTargetDir
function targetDir = helperFindTargetDir(dirPaths) % % This function is only intended to support wavelet deep learning examples. % It may change or be removed in a future release. % find pwd p = pwd; if ispc % replace blank spaces with underscores p = strrep(p,' ','_'); % split path into component folders pSplit = regexp(p,filesep,'split'); % Since Windows uses colons, remove any colons that occur for k=1:numel(pSplit) pSplit{k} = erase(pSplit{k},':'); end % now build the path using Linux file separation pLinux = ''; for k=1:numel(pSplit)-1 pLinux = [pLinux,pSplit{k},'/']; end pLinux = [pLinux,pSplit{end}]; else pLinux = p; end targetDir = ''; for k=1:numel(dirPaths) d = strfind(dirPaths{k}.directory,pLinux); if ~isempty(d) targetDir = dirPaths{k}.directory; break end end if numel(targetDir) == 0 disp('Target directory not found.'); end end