Этот пример показывает рабочий процесс классификации сигналов электрокардиограммы (ЭКГ) человека с помощью Непрерывного Преобразования Вейвлета (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 processECG
function [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