Этот пример показывает рабочий процесс классификации сигналов электрокардиограммы (ЭКГ) человека с помощью Непрерывного Преобразования Вейвлета (CWT) и глубокой сверточной нейронной сети (CNN). Этот пример также предоставляет информацию о том, как сгенерировать и развернуть код и CNN для предсказания на целевой программе Raspberry Pi (устройство на базе ARM ®).
SqueezeNet - глубокий CNN, изначально разработанный для классификации изображений в 1000 категориях. В примере Classify Time Series Using Wavelet Analysis and Глубокое Обучение (Wavelet Toolbox), SqueezeNet переобучается, чтобы классифицировать формы волны ЭКГ на основе их скалограмм. Скалограмма является временно-частотным представлением сигнала и является абсолютным значением CWT сигнала. Переобученный SqueezeNet используется в этом примере.
В этом примере используются данные ЭКГ от PhysioNet. Данные ЭКГ получены от трех групп людей: лиц с сердечной аритмией (АРР), лиц с застойным сердечным отказом (ХСН) и лиц с нормальными синусовыми ритмами (СМП). Набор данных включает 96 записей от лиц с АРР, 30 записей от лиц с ХСН и 36 записей от лиц с СМП. 162 записи ЭКГ сделаны из трех баз данных PhysioNet: базы данных аритмии MIT-BIH [2] [3], базы данных нормального синусового ритма MIT-BIH [3] и базы данных застойного сердечного Отказа BIDMC [1] [3]. Укороченные данные ЭКГ вышеуказанных ссылок можно загрузить из репозитория GitHub.
Процессор ARM, поддерживающий расширение NEON
ARM Compute Library версии 19.05 (на целевом оборудовании ARM)
Переменные окружения для компиляторов и библиотек
Пакет поддержки MATLAB Coder Interface for Глубокое Обучение Libraries
Для поддерживаемых версий библиотек и для получения информации о настройке переменных окружения смотрите Необходимые условия для глубокого обучения с MATLAB Coder (MATLAB Coder). Этот пример не поддерживается в Online™ MATLAB.
Основная функция в сгенерированном исполняемом файле, processECG, использует 65 536 выборок данных ЭКГ с одной точностью в качестве входных данных. Функция:
Принимает CWT данных ECG.
Получает скалограмму из коэффициентов вейвлета.
Преобразует скалограмму в маг RGB размерности 227 227 3. Это делает изображение совместимым с сетевой архитектурой SqueezeNet.
Выполняет предсказание для классификации изображения с помощью SqueezeNet.
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
Создайте объект строения генерации кода для генерации исполняемой программы. Задайте генерацию кода С++.
cfg = coder.config('exe'); cfg.TargetLang = 'C++';
Создайте coder.ARMNEONConfig объект. Укажите ту же версию библиотеки ARM Compute, что и на Raspberry Pi. Задайте архитектуру Raspberry Pi.
dlcfg = coder.DeepLearningConfig('arm-compute'); dlcfg.ArmComputeVersion = '19.05'; dlcfg.ArmArchitecture = 'armv7';
Установите DeepLearningConfig свойство объекта строения генерации кода объекту строения глубокого обучения. Сделайте MATLAB Source Comments видимым в объекте строения во время генерации кода.
cfg.DeepLearningConfig = dlcfg; cfg.MATLABSourceComments = 1;
Используйте функцию MATLAB Поддержки Package for Raspberry Pi Поддержки Package, raspi, для создания соединения с Raspberry Pi. В следующем коде замените:
'raspiname' с именем вашего Raspberry Pi
'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++ считывает входные данные ECG, вызывает processECG функция для выполнения предварительной обработки и глубокого обучения с помощью CNN на данных ЭКГ и отображает вероятность классификации.
Укажите основной файл в объекте строения генерации кода. Для получения дополнительной информации о генерации и настройке main_ecg_raspi.cppСм. раздел «Генерация автономных исполняемых файлов C/C + + из кода MATLAB (MATLAB Coder)».
cfg.CustomSource = 'main_ecg_raspi.cpp';codegenИспользуйте codegen функция для генерации кода С++. Когда codegen используется с пакетом поддержки MATLAB для оборудования Raspberry Pi, исполняемый файл построен на плате Raspberry Pi.
Убедитесь, что задали переменные окружения ARM_COMPUTELIB и LD_LIBRARY_PATH на Raspberry Pi. Смотрите Необходимые условия глубокого обучения с MATLAB Coder (MATLAB Coder).
codegen -config cfg processECG -args {ones(1,65536,'single')} -d arm_compute
Deploying code. This may take a few minutes.
Чтобы протестировать сгенерированный код на Raspberry Pi, скопируйте входной сигнал ECG в директорию кода. Вы можете найти эту директорию вручную или с помощью 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 запись содержит сгенерированный код, используйте функцию helper 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
'
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)
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