exponenta event banner

Развертывание классификатора сигналов с использованием вейвлетов и глубокого обучения на Raspberry Pi

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

Предпосылки

Поддерживаемые версии библиотек и сведения о настройке переменных среды см. в разделе Предварительные условия для глубокого обучения с помощью кодера MATLAB (MATLAB Coder). Этот пример не поддерживается в MATLAB Online™.

Функциональные возможности сгенерированного кода

Основная функция в созданном исполняемом файле, processECGиспользует 65 536 выборок данных ЭКГ с одной точностью в качестве входных данных. Функция:

  1. Принимает CWT данных ЭКГ.

  2. Получают скалограмму из вейвлет-коэффициентов.

  3. Преобразует скалограмму в изображение RGB размерности 227-на-227-на-3. Это делает образ совместимым с сетевой архитектурой SqueeeNet.

  4. Выполняет прогнозирование для классификации изображения с помощью SqueeNet.

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

Создание объекта конфигурации создания кода

Создание объекта конфигурации создания кода для создания исполняемой программы. Укажите создание кода 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';

Прикрепление объекта конфигурации Deep Learning к объекту конфигурации создания кода

Установите DeepLearningConfig свойство объекта конфигурации генерации кода для объекта конфигурации глубокого обучения. Во время создания кода сделайте комментарии источника MATLAB видимыми в объекте конфигурации.

cfg.DeepLearningConfig = dlcfg;
cfg.MATLABSourceComments = 1;

Создание соединения с Raspberry Pi

Используйте функцию MATLAB Support Package for Raspberry Pi Support Package, raspi, чтобы создать соединение с Raspberry Pi. В следующем коде замените:

  • 'raspiname' с именем вашего Малинового Пи

  • 'pi' с именем пользователя

  • 'password' с вашим паролем

r = raspi('172.18.76.69','pi','raspberry');

Конфигурирование аппаратных параметров генерации кода для Raspberry Pi

Создать coder.Hardware объект для Raspberry Pi и присоедините его к объекту конфигурации генерации кода.

hw = coder.hardware('Raspberry Pi');
cfg.Hardware = hw;

Укажите папку сборки на Raspberry Pi.

buildDir = '~/remdirECG';
cfg.Hardware.BuildDir = buildDir;

Предоставить основной файл C++ для выполнения кода

Основной файл C++ считывает входные данные ЭКГ, вызывает processECG функция для выполнения предварительной обработки и глубокого обучения с использованием CNN на данных ЭКГ и отображает вероятность классификации.

Укажите основной файл в объекте конфигурации создания кода. Дополнительные сведения о создании и настройке main_ecg_raspi.cpp, см. Создание автономных исполняемых файлов C/C + + из кода MATLAB (кодер MATLAB).

cfg.CustomSource = 'main_ecg_raspi.cpp';

Создать исходный код C++ с помощью 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

Копировать входной файл в Raspberry Pi

Текстовый файл 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

Запустите исполняемую программу на 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
     '

Ссылки

  1. Баим, Д. С., В. С. Колуччи, Э. С. Монрад, Х. С. Смит, Р. Ф. Райт, А. Лануэ, Д. Ф. Готье, Б. Дж. Рансил, В. Гроссман и Э. Браунвальд. «Выживаемость пациентов с тяжелой застойной сердечной недостаточностью, получавших пероральный милринон». Журнал Американского колледжа кардиологов. Том 7, номер 3, 1986, стр. 661-670.

  2. Гольдбергер А. Л., Л. А. Н. Амарал, Л. Гласс, Ж. М. Хаусдорф, П. Ч. Иванов, Р. Г. Марк, Ж. Е. Миетус, Г. Б. Муди, К. -К. Пэн и Х. Э. Стэнли. «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.

  3. Муди, Г. Б. и Р. Г. Марк. «Влияние базы данных аритмии 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