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

Этот пример показывает, как сгенерировать и развернуть исполняемый файл CUDA ®, который классифицирует сигналы электрокардиограммы (ЭКГ) человека, используя функции, извлеченные непрерывным вейвлет (CWT) и предварительно обученной сверточной нейронной сетью (CNN).

SqueezeNet - глубокий CNN, изначально разработанный для классификации изображений в 1000 категориях. Мы повторно используем сетевую архитектуру CNN, чтобы классифицировать сигналы ЭКГ на основе их скалограмм. Скалограмма является абсолютным значением CWT сигнала. После обучения SqueezeNet для классификации сигналов ECG, вы создаете исполняемый файл CUDA, который генерирует скалограмму сигнала ECG, а затем использует CNN для классификации сигнала. Исполняемый файл и CNN оба развертываются на оборудовании NVIDIA.

Этот пример использует те же данные, что и в Classify Time Series Using Wavelet Analysis and Глубокое Обучение (Wavelet Toolbox). В этом примере передача обучения с помощью 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'.

Редукция данных

После загрузки данных необходимо сгенерировать скалограммы сигналов. Скалограммы являются «входными» изображениями для CNN.

Чтобы хранить скалограммы каждой категории, сначала создайте директорию данных ECG 'data' внутри tempdir. Затем создайте три подкаталога в 'data' названы в честь каждой категории ЭКГ. Функция помощника helperCreateECGDirectories делает это для вас. helperCreateECGDirectories принимает ECGData, имя директории данных ECG и имя родительской директории в качестве входных параметров. Можно заменить tempdir с другой директорией, в котором у вас есть разрешение на запись. Исходный код для этой вспомогательной функции можно найти в разделе Вспомогательные функции в конце этого примера.

parentDir = tempdir;
dataDir = 'data';
helperCreateECGDirectories(ECGData,parentDir,dataDir)

После создания папок создайте скалограммы сигналов ECG в виде изображений RGB и запишите их в соответствующий подкаталог в dataDir. Чтобы создать скалограммы, сначала предварительно вычислите банк фильтров CWT. Предварительное вычисление группы фильтров является предпочтительным способом при получении CWT многих сигналов с использованием тех же параметров. Функция помощника helperCreateRGBfromTF делает это. Исходный код для этой вспомогательной функции находится в разделе Вспомогательные функции в конце этого примера. Для совместимости с архитектурой SqueezeNet каждый образ RGB представляет собой массив размера 227 227 3.

helperCreateRGBfromTF(ECGData,parentDir,dataDir)

Разделите набор данных на данные обучения и валидации

Загрузите скалограммные изображения как image datastore. The imageDatastore функция автоматически помечает изображения на основе имен папок и сохраняет данные как ImageDatastore объект. image datastore позволяет вам хранить большие данные об изображениях, включая данные, которые не помещаются в памяти, и эффективно считывать пакеты изображений при обучении CNN.

allImages = imageDatastore(fullfile(tempdir,dataDir),...
    'IncludeSubfolders',true,...
    'LabelSource','foldernames');

Случайным образом разделите изображения на две группы: одну для обучения и другую для валидации. Используйте 80% изображений для обучения и оставшуюся часть для валидации. В целях воспроизводимости мы устанавливаем случайное начальное значение на значение по умолчанию.

rng default
[imgsTrain,imgsValidation] = splitEachLabel(allImages,0.8,'randomized');
disp(['Number of training images: ',num2str(numel(imgsTrain.Files))]);
Number of training images: 130
disp(['Number of validation images: ',num2str(numel(imgsValidation.Files))]);
Number of validation images: 32

SqueezeNet

SqueezeNet является предварительно обученным CNN, который может классифицировать изображения в 1000 категорий. Вам необходимо переобучить SqueezeNet для нашей задачи классификации ЭКГ. Перед переобучением вы изменяете несколько слои сети и настраиваете различные опции обучения. После завершения переобучения вы сохраняете CNN в .mat файл. Исполняемый файл CUDA будет использовать .mat файл.

Укажите пробный индекс эксперимента и директорию результатов. При необходимости создайте директорию.

trial = 1;
ResultDir = 'results';
if ~exist(ResultDir,'dir')
    mkdir(ResultDir)
end
MatFile = fullfile(ResultDir,sprintf('SqueezeNet_Trial%d.mat',trial));

Загрузка SqeezeNet. Извлеките график слоев и проверьте последние пять слоев.

sqz = squeezenet;
lgraph = layerGraph(sqz);
lgraph.Layers(end-4:end)
ans = 
  5×1 Layer array with layers:

     1   'conv10'                            Convolution              1000 1×1×512 convolutions with stride [1  1] and padding [0  0  0  0]
     2   'relu_conv10'                       ReLU                     ReLU
     3   'pool10'                            Global Average Pooling   Global average pooling
     4   'prob'                              Softmax                  softmax
     5   'ClassificationLayer_predictions'   Classification Output    crossentropyex with 'tench' and 999 other classes

Чтобы переобучить SqueezeNet, чтобы классифицировать три класса сигналов ECG, замените 'conv10' слой с новым сверточным слоем с количеством фильтров, равным количеству классов ЭКГ. Замените слой классификации новым слоем без меток классов.

numClasses = numel(categories(imgsTrain.Labels));
new_conv10_WeightLearnRateFactor = 1;
new_conv10_BiasLearnRateFactor = 1;
newConvLayer = convolution2dLayer(1,numClasses,...
        'Name','new_conv10',...
        'WeightLearnRateFactor',new_conv10_WeightLearnRateFactor,...
        'BiasLearnRateFactor',new_conv10_BiasLearnRateFactor);
lgraph = replaceLayer(lgraph,'conv10',newConvLayer);
newClassLayer = classificationLayer('Name','new_classoutput');
lgraph = replaceLayer(lgraph,'ClassificationLayer_predictions',newClassLayer);
lgraph.Layers(end-4:end)
ans = 
  5×1 Layer array with layers:

     1   'new_conv10'        Convolution              3 1×1 convolutions with stride [1  1] and padding [0  0  0  0]
     2   'relu_conv10'       ReLU                     ReLU
     3   'pool10'            Global Average Pooling   Global average pooling
     4   'prob'              Softmax                  softmax
     5   'new_classoutput'   Classification Output    crossentropyex

Создайте набор опций обучения для использования с SqueezeNet.

OptimSolver = 'sgdm';
MiniBatchSize = 15;
MaxEpochs = 20;
InitialLearnRate = 1e-4;
Momentum = 0.9;
ExecutionEnvironment = 'cpu';

options = trainingOptions(OptimSolver,...
    'MiniBatchSize',MiniBatchSize,...
    'MaxEpochs',MaxEpochs,...
    'InitialLearnRate',InitialLearnRate,...
    'ValidationData',imgsValidation,...
    'ValidationFrequency',10,...
    'ExecutionEnvironment',ExecutionEnvironment,...
    'Momentum',Momentum);

Сохраните все параметры в структуре. Обученная сеть и структура будут позже сохранены в .mat файл.

TrialParameter.new_conv10_WeightLearnRateFactor = new_conv10_WeightLearnRateFactor;
TrialParameter.new_conv10_BiasLearnRateFactor = new_conv10_BiasLearnRateFactor;
TrialParameter.OptimSolver = OptimSolver;
TrialParameter.MiniBatchSize = MiniBatchSize;
TrialParameter.MaxEpochs = MaxEpochs;
TrialParameter.InitialLearnRate = InitialLearnRate;
TrialParameter.Momentum = Momentum;
TrialParameter.ExecutionEnvironment = ExecutionEnvironment;

Установите значение по умолчанию для случайного начального числа и обучите сеть. Сохраните обученную сеть, пробные параметры, время запуска обучения и datastore, содержащее изображения для валидации. Процесс обучения обычно занимает 1-5 минут на настольном центральном процессоре. Если вы хотите использовать обученный CNN из предыдущего испытания, установите trial на индекс число судебных разбирательств и LoadModel на true.

LoadModel = false;
if ~LoadModel
    rng default
    tic;
    trainedModel = trainNetwork(imgsTrain,lgraph,options);
    trainingTime = toc;
    fprintf('Total training time: %.2e sec\n',trainingTime);
    save(MatFile,'TrialParameter','trainedModel','trainingTime','imgsValidation');
else
    disp('Load ML model from the file')
    load(MatFile,'trainedModel','imgsValidation');
end
Initializing input data normalization.
|======================================================================================================================|
|  Epoch  |  Iteration  |  Time Elapsed  |  Mini-batch  |  Validation  |  Mini-batch  |  Validation  |  Base Learning  |
|         |             |   (hh:mm:ss)   |   Accuracy   |   Accuracy   |     Loss     |     Loss     |      Rate       |
|======================================================================================================================|
|       1 |           1 |       00:00:02 |       26.67% |       25.00% |       4.1769 |       2.9883 |      1.0000e-04 |
|       2 |          10 |       00:00:12 |       73.33% |       59.38% |       0.9877 |       1.1559 |      1.0000e-04 |
|       3 |          20 |       00:00:21 |       60.00% |       56.25% |       0.9164 |       0.9182 |      1.0000e-04 |
|       4 |          30 |       00:00:31 |       86.67% |       68.75% |       0.6698 |       0.7883 |      1.0000e-04 |
|       5 |          40 |       00:00:40 |       66.67% |       68.75% |       0.9053 |       0.7489 |      1.0000e-04 |
|       7 |          50 |       00:00:50 |       80.00% |       78.13% |       0.5422 |       0.6781 |      1.0000e-04 |
|       8 |          60 |       00:00:59 |      100.00% |       81.25% |       0.4187 |       0.6124 |      1.0000e-04 |
|       9 |          70 |       00:01:08 |       93.33% |       84.38% |       0.3561 |       0.5471 |      1.0000e-04 |
|      10 |          80 |       00:01:18 |       73.33% |       84.38% |       0.5141 |       0.4765 |      1.0000e-04 |
|      12 |          90 |       00:01:27 |       86.67% |       84.38% |       0.4220 |       0.4038 |      1.0000e-04 |
|      13 |         100 |       00:01:36 |       93.33% |       90.63% |       0.1923 |       0.3476 |      1.0000e-04 |
|      14 |         110 |       00:01:46 |      100.00% |       90.63% |       0.1472 |       0.3125 |      1.0000e-04 |
|      15 |         120 |       00:01:55 |      100.00% |       93.75% |       0.0791 |       0.2777 |      1.0000e-04 |
|      17 |         130 |       00:02:04 |       86.67% |       93.75% |       0.2486 |       0.2833 |      1.0000e-04 |
|      18 |         140 |       00:02:14 |      100.00% |       93.75% |       0.0386 |       0.2288 |      1.0000e-04 |
|      19 |         150 |       00:02:23 |      100.00% |       93.75% |       0.0487 |       0.2397 |      1.0000e-04 |
|      20 |         160 |       00:02:32 |      100.00% |       93.75% |       0.0224 |       0.2041 |      1.0000e-04 |
|======================================================================================================================|
Total training time: 1.61e+02 sec

Сохраните только обученную сеть в отдельном .mat файл. Этот файл будет использоваться исполняемым файлом CUDA.

ModelFile = fullfile(ResultDir,sprintf('SqueezeNet_Trial%d.mat',trial));
OutMatFile = fullfile('ecg_model.mat');

data = load(ModelFile,'trainedModel');
net = data.trainedModel;
save(OutMatFile,'net');

Используйте обученную сеть для предсказания классов для набора валидации.

[YPred, probs] = classify(trainedModel,imgsValidation);
accuracy = mean(YPred==imgsValidation.Labels)
accuracy = 0.9375

Результирующая эффективность обученной сети на наборе валидации с графика путаницы. Отображение точности и отзыва для каждого класса с помощью сводных данных по столбцам и строкам. Сохраните рисунок. Таблица в нижней части графика неточностей показывает значения точности. Таблица справа от графика неточностей показывает значения отзыва.

figure
confusionMat = confusionmat(imgsValidation.Labels,YPred);
confusionchart(imgsValidation.Labels,YPred, ...
    'Title',sprintf('Confusion Matrix on Validation (overall accuracy: %.4f)',accuracy),...
    'ColumnSummary','column-normalized','RowSummary','row-normalized');

AccFigFile = fullfile(ResultDir,sprintf('SqueezeNet_ValidationAccuracy_Trial%d.fig',trial));
saveas(gcf,AccFigFile);

Отображение размера обученной сети.

info = whos('trainedModel');
ModelMemSize = info.bytes/1024;
fprintf('Trained network size: %g kB\n',ModelMemSize)
Trained network size: 2981.55 kB

Определите среднее время, необходимое сети для классификации изображения.

NumTestForPredTime = 20;
TrialParameter.NumTestForPredTime = NumTestForPredTime;

fprintf('Test prediction time (number of tests: %d)... ',NumTestForPredTime)
Test prediction time (number of tests: 20)... 
imageSize = trainedModel.Layers(1).InputSize;
PredTime = zeros(NumTestForPredTime,1);
for i = 1:NumTestForPredTime
    x = randn(imageSize);
    tic;
    [YPred, probs] = classify(trainedModel,x,'ExecutionEnvironment',ExecutionEnvironment);
    PredTime(i) = toc;
end
AvgPredTimePerImage = mean(PredTime);
fprintf('Average prediction time (execution environment: %s): %.2e sec \n',...
    ExecutionEnvironment,AvgPredTimePerImage);
Average prediction time (execution environment: cpu): 2.94e-02 sec 

Сохраните результаты.

if ~LoadModel
    save(MatFile,'accuracy','confusionMat','PredTime','ModelMemSize', ...
        'AvgPredTimePerImage','-append')
end

Генерация кода GPU - Определение функций

Скалограмма сигнала - это вход «изображения» глубокому CNN. Создайте функцию, cwt_ecg_jetson_ex, который вычисляет скалограмму входного сигнала и возвращает изображение с заданными пользователем размерностями. Изображение использует jet(128) палитра. The %#codegen директива в функции указывает, что функция предназначена для генерации кода. При использовании coder.gpu.kernelfun pragma, генерация кода пытается сопоставить расчеты в cwt_ecg_jetson_ex функцию для графический процессор.

type cwt_ecg_jetson_ex.m
function im = cwt_ecg_jetson_ex(TimeSeriesSignal, ImgSize) %#codegen
% This function is only intended to support wavelet deep learning examples.
% It may change or be removed in a future release.

coder.gpu.kernelfun();

%% Create Scalogram
cfs = cwt(TimeSeriesSignal, 'morse', 1, 'VoicesPerOctave', 12);
cfs = abs(cfs);

%% Image generation
cmapj128 = coder.load('cmapj128');
imx = ind2rgb_custom_ecg_jetson_ex(round(255*rescale(cfs))+1,cmapj128.cmapj128);

% resize to proper size and convert to uint8 data type
im = im2uint8(imresize(imx, ImgSize)); 

end

Создайте функцию точки входа, model_predict_ecg.m, для генерации кода. Функция принимает сигнал ЭКГ как вход и вызывает cwt_ecg_jetson_ex функция для создания изображения скалограммы. The model_predict_ecg функция использует сеть, содержащуюся в ecg_model.mat файл для классификации сигнала ECG.

type model_predict_ecg.m
function PredClassProb = model_predict_ecg(TimeSeriesSignal) %#codegen
% This function is only intended to support wavelet deep learning examples.
% It may change or be removed in a future release.
    coder.gpu.kernelfun();
    
    % parameters
    ModFile = 'ecg_model.mat'; % file that saves neural network model
    ImgSize = [227 227]; % input image size for the ML model
    
    % sanity check signal is a row vector of correct length
    assert(isequal(size(TimeSeriesSignal), [1 65536])) 
    %% cwt transformation for the signal
    im = cwt_ecg_jetson_ex(TimeSeriesSignal, ImgSize);
    
    %% model prediction
    persistent model;
    if isempty(model)
        model = coder.loadDeepLearningNetwork(ModFile, 'mynet');
    end

    PredClassProb = predict(model, im);
    
end

Чтобы сгенерировать исполняемый файл CUDA, который можно развернуть на целевом устройстве NVIDIA, создайте пользовательский основной файл (main_ecg_jetson_ex.cu) и заголовочный файл (main_ecg_jetson_ex.h). Можно сгенерировать пример основного файла и использовать его как шаблон для переписывания новых основных и заголовочных файлов. Для получения дополнительной информации смотрите GenerateExampleMain свойство coder.CodeConfig. Основной файл вызывает код, сгенерированный для функции точки входа MATLAB. Основной файл сначала читает сигнал ЭКГ из текстового файла, передает данные в функцию точки входа и записывает результаты предсказания в текстовый файл (predClassProb.txt). Чтобы максимизировать эффективность расчетов на графическом процессоре, исполняемый файл обрабатывает данные с одной точностью.

type main_ecg_jetson_ex.cu
//
// File: main_ecg_jetson_ex.cu
//
// This file is only intended to support wavelet deep learning examples.
// It may change or be removed in a future release.
        
//***********************************************************************
// Include Files
#include "rt_nonfinite.h"
#include "model_predict_ecg.h"
#include "main_ecg_jetson_ex.h"
#include "model_predict_ecg_terminate.h"
#include "model_predict_ecg_initialize.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Function Definitions

/* Read data from a file*/
int readData_real32_T(const char * const file_in, real32_T data[65536])
{
  FILE* fp1 = fopen(file_in, "r");
  if (fp1 == 0)
  {
    printf("ERROR: Unable to read data from %s\n", file_in);
    exit(0);
  }
  for(int i=0; i<65536; i++)
  {
      fscanf(fp1, "%f", &data[i]);
  }
  fclose(fp1);
  return 0;
}

/* Write data to a file*/
int writeData_real32_T(const char * const file_out, real32_T data[3])
{
  FILE* fp1 = fopen(file_out, "w");
  if (fp1 == 0) 
  {
    printf("ERROR: Unable to write data to %s\n", file_out);
    exit(0);
  }
  for(int i=0; i<3; i++)
  {
    fprintf(fp1, "%f\n", data[i]);
  }
  fclose(fp1);
  return 0;
}

// model predict function
static void main_model_predict_ecg(const char * const file_in, const char * const file_out)
{
  real32_T PredClassProb[3];
  //  real_T b[65536];
  real32_T b[65536];

  // readData_real_T(file_in, b);
  readData_real32_T(file_in, b);
       
  model_predict_ecg(b, PredClassProb);

  writeData_real32_T(file_out, PredClassProb);

}

// main function
int32_T main(int32_T argc, const char * const argv[])
{
  const char * const file_out = "predClassProb.txt";
  // Initialize the application.
  model_predict_ecg_initialize();
  
  // Run prediction function
  main_model_predict_ecg(argv[1], file_out); // argv[1] = file_in

  // Terminate the application.
  model_predict_ecg_terminate();
  return 0;
}
type main_ecg_jetson_ex.h
//
// File: main_ecg_jetson_ex.h
//
// This file is only intended to support wavelet deep learning examples.
// It may change or be removed in a future release.

//
//***********************************************************************
#ifndef MAIN_H
#define MAIN_H

// Include Files
#include <stddef.h>
#include <stdlib.h>
#include "rtwtypes.h"
#include "model_predict_ecg_types.h"

// Function Declarations
extern int32_T main(int32_T argc, const char * const argv[]);

#endif

//
// File trailer for main_ecg_jetson_ex.h
//
// [EOF]
//

Генерация кода GPU - установка целевого процессора

Чтобы создать исполняемый файл, который можно развернуть на целевом устройстве, установите CodeGenMode равным 1. Если вы хотите создать исполняемый файл, который запускается локально и удаленно соединяется с целевым устройством, установите CodeGenMode равным 2.

The main функция считывает данные из текстового файла, заданного signalFile и записывает результаты классификации в resultFile. Задайте ExampleIndex для выбора репрезентативного сигнала ЭКГ. Вы будете использовать этот сигнал, чтобы протестировать исполняемый файл против classify функция. Jetson_BuildDir задает директорию для выполнения процесса удаленной сборки на целевом компьютере. Если указанная директория сборки не существует в целевом устройстве, то программное обеспечение создает директорию с заданным именем.

CodeGenMode = 1;
signalFile = 'signalData.txt';
resultFile = 'predClassProb.txt'; % consistent with "main_ecg_jetson_ex.cu"
Jetson_BuildDir = '~/projectECG';
ПримерИндекс = 1; % 1,4: type ARR; 2,5: type CHF; 3,6: type NSR

Function_to_Gen = 'model_predict_ecg';
ModFile = 'ecg_model.mat'; % file that saves neural network model; consistent with "main_ecg_jetson_ex.cu"
ImgSize = [227 227]; % input image size for the ML model

switch ExampleIndex
    case 1 % ARR 7
        SampleSignalIdx = 7;
    case 2 % CHF 97
        SampleSignalIdx = 97;
    case 3 % NSR 132
        SampleSignalIdx = 132;
    case 4 % ARR 31
        SampleSignalIdx = 31;
    case 5 % CHF 101
        SampleSignalIdx = 101;
    case 6 % NSR 131
        SampleSignalIdx = 131;
end
signal_data = single Данных (SampleSignalIdx,:));
ECGtype = метки {SampleSignalIdx};

Генерация кода GPU - подключение к оборудованию

Для связи с оборудованием NVIDIA создайте объект подключения к активному оборудованию с помощью jetson функция. Для создания объекта подключения к активному оборудованию необходимо знать имя хоста или IP-адрес, имя пользователя и пароль целевой платы.

Создайте объект подключения к оборудованию Jetson. Во время оборудования объекта создания оборудования выполняется установка сервера ввода-вывода и сбор периферийной информации о цели. Эта информация отображается в Командном окне.

hwobj = jetson('gpucoder-nano-2','ubuntu','ubuntu');
Checking for CUDA availability on the Target...
Checking for 'nvcc' in the target system path...
Checking for cuDNN library availability on the Target...
Checking for TensorRT library availability on the Target...
Checking for prerequisite libraries is complete.
Gathering hardware details...
Checking for third-party library availability on the Target...
Gathering hardware details is complete.
 Board name         : NVIDIA Jetson TX1
 CUDA Version       : 10.0
 cuDNN Version      : 7.3
 TensorRT Version   : 5.0
 GStreamer Version  : 1.14.5
 V4L2 Version       : 1.14.2-1
 SDL Version        : 1.2
 Available Webcams  :  
 Available GPUs     : NVIDIA Tegra X1

Используйте coder.checkGpuInstall и проверьте, что компиляторы и библиотеки, необходимые для выполнения этого примера, настроены правильно на оборудовании.

envCfg = coder.gpuEnvConfig('jetson');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.HardwareObject = hwobj;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg)
ans = struct with fields:
                 gpu: 1
                cuda: 1
               cudnn: 1
            tensorrt: 0
        basiccodegen: 0
       basiccodeexec: 0
         deepcodegen: 1
        deepcodeexec: 0
    tensorrtdatatype: 0
           profiling: 0

Генерация кода GPU - компиляция

Создайте объект строения кода GPU, необходимый для компиляции. Используйте coder.hardware функция для создания объекта строения для платформы Jetson и назначения его Hardware свойство объекта строения кода cfg. Использование 'NVIDIA Jetson' для TX1 Jetson или TX2 плат. Пользовательский основной файл является оболочкой, которая вызывает функцию точки входа в сгенерированном коде. Пользовательский файл необходим для развернутого исполняемого файла.

Используйте coder.DeepLearningConfig функция для создания CuDNN объект строения глубокого обучения и присвоение его DeepLearningConfig свойство объекта строения кода GPU. Генератор кода использует преимущества библиотеки глубоких нейронных сетей (cuDNN) NVIDIA ® CUDA ® для графических процессоров NVIDIA. cuDNN является библиотекой примитивов для глубоких нейронных сетей с ускорением графического процессора.

if CodeGenMode == 1
    cfg = coder.gpuConfig('exe');
    cfg.Hardware = coder.hardware('NVIDIA Jetson');
    cfg.Hardware.BuildDir = Jetson_BuildDir;
    cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
    cfg.CustomSource = fullfile('main_ecg_jetson_ex.cu');
elseif CodeGenMode == 2
    cfg = coder.gpuConfig('lib');
    cfg.VerificationMode = 'PIL';
    cfg.Hardware = coder.hardware('NVIDIA Jetson');
    cfg.Hardware.BuildDir = Jetson_BuildDir;
    cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
end

Чтобы сгенерировать код CUDA, используйте codegen и передайте строение кода графического процессора вместе с размером и типом входа для model_predict_ecg функция точки входа. После завершения генерации кода на хосте сгенерированные файлы копируются и строятся на целевом компьютере.

codegen('-config ',cfg,Function_to_Gen,'-args',{signal_data},'-report');
Code generation successful: View report

Генерация кода GPU - Выполнение

Если вы скомпилировали исполняемый файл, который будет развернут на целевой объект, запишите пример сигнала ECG в текстовый файл. Используйте putFile() функция аппаратного объекта для размещения текстового файла на целевом объекте. The workspaceDir свойство содержит путь к codegen папка на целевом объекте.

if CodeGenMode == 1
    fid = fopen(signalFile,'w');
    for i = 1:length(signal_data)
        fprintf(fid,'%f\n',signal_data(i));
    end
    fclose(fid);
    hwobj.putFile(signalFile,hwobj.workspaceDir);
end

Запустите исполняемый файл.

При запуске развернутого исполняемого файла удалите предыдущий файл результатов, если он существует. Используйте runApplication() функцию для запуска исполняемого файла на целевом компьютере, а затем и getFile() функция для извлечения результатов. Поскольку результаты могут не существовать сразу после runApplication() вызов функции возвращается и, чтобы разрешить задержки связи, установите максимальное время для извлечения результатов равным 90 секундам. Используйте evalc функция для подавления выхода в командной строке.

if CodeGenMode == 1 % run deployed executable
    maxFetchTime = 90;
    resultFile_hw = fullfile(hwobj.workspaceDir,resultFile);
    if ispc
        resultFile_hw = strrep(resultFile_hw,'\','/');
    end
    
    ta = tic;
    
    hwobj.deleteFile(resultFile_hw)
    hwobj.runApplication(Function_to_Gen,signalFile);
    
    tf = tic;
    success = false;
    while toc(tf) < maxFetchTime
        try
            evalc('hwobj.getFile(resultFile_hw)');
            success = true;
        catch ME
        end
        if success
            break
        end
    end
    fprintf('Fetch time = %.3e sec\n',toc(tf));
    assert(success,'Unable to fetch the prediction')
    PredClassProb = readmatrix(resultFile);
    PredTime = toc(ta);
elseif CodeGenMode == 2 % run PIL executable
    ta = tic;
    eval(sprintf('PredClassProb = %s_pil(signal_data);',Function_to_Gen));
    PredTime = toc(ta);
    eval(sprintf('clear %s_pil;',Function_to_Gen)); % terminate PIL execution
end
### Launching the executable on the target...
Executable launched successfully with process ID 5672.
Displaying the simple runtime log for the executable...

Note: For the complete log, run the following command in the MATLAB command window:
system(hwobj,'cat /home/ubuntu/projectECG/MATLAB_ws/R2021a/C/Users/pkostele/OneDrive_-_MathWorks/Documents/MATLAB/Examples/deeplearning_shared-ex54874305/model_predict_ecg.log')
Fetch time = 9.743e+00 sec

Используйте classify функция для предсказания меток классов для сигнала примера.

ModData = load(ModFile,'net');
im = cwt_ecg_jetson_ex(signal_data,ImgSize);
[ModPred, ModPredProb] = classify(ModData.net,im);
PredCat = categories(ModPred)';

Сравните результаты.

PredTableJetson = array2table(PredClassProb(:)','VariableNames',matlab.lang.makeValidName(PredCat));
fprintf('tPred = %.3e sec\nExample ECG Type: %s\n',PredTime,ECGtype)
tPred = 1.288e+01 sec
Example ECG Type: ARR
disp(PredTableJetson)
      ARR        CHF         NSR   
    _______    ________    ________

    0.99872    0.001131    0.000153
PredTableMATLAB = array2table(ModPredProb(:)','VariableNames',matlab.lang.makeValidName(PredCat));
disp(PredTableMATLAB)
      ARR         CHF          NSR    
    _______    _________    __________

    0.99872    0.0011298    0.00015316

Закройте аппаратное подключение.

clear hwobj

Сводные данные

В этом примере показано, как создать и развернуть исполняемый файл CUDA, который использует CNN для классификации сигналов ECG. У вас также есть опция создать исполняемый файл, который запускается локально и соединяется с удаленным объектом. Полный рабочий процесс представлен в этом примере. После загрузки данных CWT используется для извлечения функций из сигналов ECG. Затем SqueezeNet переобучается, чтобы классифицировать сигналы на основе их скалограмм. Две пользовательские функции создаются и компилируются на целевом устройстве NVIDIA. Результаты выполнения сравниваются с MATLAB.

Ссылки

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

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

  3. 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)

Вспомогательные функции

helperCreateECGDirectories

function helperCreateECGDirectories(ECGData,parentFolder,dataFolder)
% This function is only intended to support wavelet deep learning examples.
% It may change or be removed in a future release.

rootFolder = parentFolder;
localFolder = dataFolder;
mkdir(fullfile(rootFolder,localFolder))

folderLabels = unique(ECGData.Labels);
for i = 1:numel(folderLabels)
    mkdir(fullfile(rootFolder,localFolder,char(folderLabels(i))));
end
end

helperPlotReps

function helperPlotReps(ECGData)
% This function is only intended to support wavelet deep learning examples.
% It may change or be removed in a future release.

folderLabels = unique(ECGData.Labels);

for k=1:3
    ecgType = folderLabels{k};
    ind = find(ismember(ECGData.Labels,ecgType));
    subplot(3,1,k)
    plot(ECGData.Data(ind(1),1:1000));
    grid on
    title(ecgType)
end
end

helperCreateRGBfromTF

function helperCreateRGBfromTF(ECGData,parentFolder, childFolder)
% This function is only intended to support wavelet deep learning examples.
% It may change or be removed in a future release.

imageRoot = fullfile(parentFolder,childFolder);

data = ECGData.Data;
labels = ECGData.Labels;

[~,signalLength] = size(data);

fb = cwtfilterbank('SignalLength',signalLength,'VoicesPerOctave',12);
r = size(data,1);

for ii = 1:r
    cfs = abs(fb.wt(data(ii,:)));
    im = ind2rgb(im2uint8(rescale(cfs)),jet(128));
    
    imgLoc = fullfile(imageRoot,char(labels(ii)));
    imFileName = strcat(char(labels(ii)),'_',num2str(ii),'.jpg');
    imwrite(imresize(im,[227 227]),fullfile(imgLoc,imFileName));
end
end

См. также

Функции

Объекты

Похожие темы