exponenta event banner

Классификация сигналов ЭКГ с использованием сети DAG, развернутой в FPGA

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

Обучение глубокому CNN с нуля является дорогостоящим с точки зрения вычислений и требует большого количества обучающих данных. В различных применениях достаточный объем обучающих данных недоступен, и синтезировать новые реалистичные обучающие примеры невозможно. В этих случаях желательно использовать существующие нейронные сети, которые были обучены большим наборам данных для концептуально аналогичных задач. Это использование существующих нейронных сетей называется обучением передаче. В этом примере мы адаптируем два глубоких CNN, GoogLeNet и SqueeNet, предварительно подготовленных для распознавания изображения, для классификации форм сигналов ЭКГ на основе частотно-временного представления.

GoogLeNet и SqueeeNet являются глубокими CNN, изначально предназначенными для классификации изображений в 1000 категорий. Мы повторно используем сетевую архитектуру CNN для классификации сигналов ЭКГ на основе изображений из CWT данных временных рядов. Данные, используемые в этом примере, являются общедоступными из PhysioNet.

Описание данных

В этом примере используются данные ЭКГ, полученные от трех групп людей: лиц с сердечной аритмией (ARR), лиц с застойной сердечной недостаточностью (CHF) и лиц с нормальными синусовыми ритмами (СМП). Всего используется 162 записей ЭКГ из трех баз данных PhysioNet: база данных аритмии MIT-BIH [3] [7], база данных нормального синусового ритма MIT-BIH [3] и база данных застойной сердечной недостаточности BIDMC [1] [3]. Более конкретно, 96 записей от людей с аритмией, 30 записей от людей с застойной сердечной недостаточностью и 36 записей от людей с нормальными синусовыми ритмами. Цель состоит в том, чтобы обучить классификатора различать ARR, CHF и NSR.

Загрузить данные

Первым шагом является загрузка данных из репозитория GitHub. Чтобы загрузить данные с веб-сайта, нажмите Code и выбрать Download ZIP. Сохранить файл physionet_ECG_data-main.zip в папке, в которой имеется разрешение на запись. В инструкциях для этого примера предполагается, что файл загружен во временный каталог. tempdir, в MATLAB. Измените последующие инструкции по распаковке и загрузке данных, если вы решили загрузить данные в папку, отличную от tempdir. Если вы знакомы с Git, вы можете загрузить последнюю версию инструментов (git) и получить данные из системной командной строки с помощью git clone https://github.com/mathworks/physionet_ECG_data/.

После загрузки данных из GitHub распакуйте файл во временном каталоге.

unzip(fullfile(tempdir,'physionet_ECG_data-main.zip'),tempdir)

Распаковка создает папку physionet-ECG_data-main во временном каталоге. Эта папка содержит текстовый файл README.md и ECGData.zip. 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. Data поле представляет собой матрицу 162 на 65536, где каждая строка представляет собой запись ЭКГ, дискретизированную при 128 герц. Labels представляет собой массив диагностических меток типа 162 на 1, по одной для каждой строки Data. Тремя диагностическими категориями являются: 'ARR', 'CHF', и 'NSR'.

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

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

Постройте график представителя каждой категории ЭКГ. Вспомогательная функция helperPlotReps делает это. helperPlotReps принимает ECGData в качестве входных данных. Исходный код для этой вспомогательной функции можно найти в разделе «Вспомогательные функции» в конце этого примера.

helperPlotReps(ECGData)

Создание частотно-временных представлений

После создания папок создайте частотно-временные представления сигналов ЭКГ. Эти представления называются скалограммами. Скалограмма - это абсолютное значение коэффициентов CWT сигнала.

Чтобы создать скалограммы, предварительно вычислите банк фильтров CWT. Предварительное вычисление набора фильтров CWT является предпочтительным способом при получении CWT многих сигналов с использованием одних и тех же параметров.

Перед формированием скалограмм осмотрите одну из них. Создание банка фильтров CWT с помощью cwtfilterbank (Vavelet Toolbox) для сигнала с 1000 выборок. Используйте набор фильтров, чтобы взять CWT первых 1000 выборок сигнала и получить скалограмму из коэффициентов.

Fs = 128;
fb = cwtfilterbank('SignalLength',1000,...
    'SamplingFrequency',Fs,...
    'VoicesPerOctave',12);
sig = ECGData.Data(1,1:1000);
[cfs,frq] = wt(fb,sig);
t = (0:999)/Fs;figure;pcolor(t,frq,abs(cfs))
set(gca,'yscale','log');shading interp;axis tight;
title('Scalogram');xlabel('Time (s)');ylabel('Frequency (Hz)')

Использовать функцию помощника helperCreateRGBfromTF для создания скалограмм в виде изображений RGB и записи их в соответствующий подкаталоги в dataDir. Исходный код для этой вспомогательной функции находится в разделе «Вспомогательные функции» в конце этого примера. Чтобы быть совместимым с архитектурой GoogLeNet, каждое изображение RGB - множество размера 224 на 224 на 3.

helperCreateRGBfromTF(ECGData,parentDir,dataDir)

Разделить на данные обучения и проверки

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

allImages = imageDatastore(fullfile(parentDir,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, архитектура которого поддерживает изображения размера 227 на 227 на 3. Несмотря на то, что размеры изображения отличаются для GoogLeNet, нет необходимости создавать новые изображения RGB для размеров SqueeeNet. Можно использовать исходные изображения RGB.

Груз

Загрузите пользовательскую нейронную сеть SqueeEcNet.

sqz = squeezenet;

Извлеките график слоев из сети. Подтвердите, что SqueeENet имеет меньше слоев, чем GoogLeNet. Также убедитесь, что SqueeEcNet настроен для изображений размером 227-на-227-на-3

lgraphSqz = layerGraph(sqz);
disp(['Number of Layers: ',num2str(numel(lgraphSqz.Layers))])
Number of Layers: 68
disp(lgraphSqz.Layers(1).InputSize)
   227   227     3

Изменение параметров сети SqueeENet

Чтобы переобучить SqueeEcNet для классификации новых изображений, внесите изменения, аналогичные тем, которые сделаны для GoogLeNet.

Проверьте последние шесть сетевых уровней.

lgraphSqz.Layers(end-5:end)
ans = 
  6×1 Layer array with layers:

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

Замените 'drop9' уровень, последний уровень отсева в сети, с уровнем отсева вероятности 0,6.

tmpLayer = lgraphSqz.Layers(end-5);
newDropoutLayer = dropoutLayer(0.6,'Name','new_dropout');
lgraphSqz = replaceLayer(lgraphSqz,tmpLayer.Name,newDropoutLayer);

В отличие от GoogLeNet, последний обучаемый уровень в SqueeEcNet является сверточным уровнем 1 на 1, 'conv10', а не полностью подключенного слоя. Замените 'conv10' слой с новым сверточным слоем с числом фильтров, равным числу классов. Как это было сделано с GoogLeNet, увеличить коэффициенты скорости обучения нового слоя.

numClasses = numel(categories(imgsTrain.Labels));
tmpLayer = lgraphSqz.Layers(end-4);
newLearnableLayer = convolution2dLayer(1,numClasses, ...
        'Name','new_conv', ...
        'WeightLearnRateFactor',10, ...
        'BiasLearnRateFactor',10);
lgraphSqz = replaceLayer(lgraphSqz,tmpLayer.Name,newLearnableLayer);

Замените классификационный слой новым без меток классов.

tmpLayer = lgraphSqz.Layers(end);
newClassLayer = classificationLayer('Name','new_classoutput');
lgraphSqz = replaceLayer(lgraphSqz,tmpLayer.Name,newClassLayer);

Проверьте последние шесть уровней сети. Подтвердите изменение уровней отсева, свертки и вывода.

lgraphSqz.Layers(63:68)
ans = 
  6×1 Layer array with layers:

     1   'new_dropout'       Dropout                  60% dropout
     2   'new_conv'          Convolution              3 1×1 convolutions with stride [1  1] and padding [0  0  0  0]
     3   'relu_conv10'       ReLU                     ReLU
     4   'pool10'            Global Average Pooling   Global average pooling
     5   'prob'              Softmax                  softmax
     6   'new_classoutput'   Classification Output    crossentropyex

Подготовка данных RGB для SqueeNet

Образы RGB имеют размеры, соответствующие архитектуре GoogLeNet. Создайте хранилища данных дополненных изображений, которые автоматически изменяют размер существующих образов RGB для архитектуры SqueeNet. Дополнительные сведения см. в разделе augmentedImageDatastore.

augimgsTrain = augmentedImageDatastore([227 227],imgsTrain);
augimgsValidation = augmentedImageDatastore([227 227],imgsValidation);

Настройка параметров обучения и SqueeNet поезда

Создайте новый набор параметров обучения для использования с SqueeEcNet. Установите для случайного начального значения значение по умолчанию и выполните обучение сети. Процесс обучения обычно занимает 1-5 минут на настольном процессоре.

ilr = 3e-4;
miniBatchSize = 10;
maxEpochs = 15;
valFreq = floor(numel(augimgsTrain.Files)/miniBatchSize);
opts = trainingOptions('sgdm',...
    'MiniBatchSize',miniBatchSize,...
    'MaxEpochs',maxEpochs,...
    'InitialLearnRate',ilr,...
    'ValidationData',augimgsValidation,...
    'ValidationFrequency',valFreq,...
    'Verbose',1,...
    'ExecutionEnvironment','cpu',...
    'Plots','training-progress');

rng default
trainedSN = trainNetwork(augimgsTrain,lgraphSqz,opts);
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:06 |       20.00% |       53.12% |       4.2000 |       1.2709 |          0.0003 |
|       1 |          13 |       00:00:16 |       60.00% |       62.50% |       0.9170 |       0.9294 |          0.0003 |
|       2 |          26 |       00:00:25 |       60.00% |       59.38% |       0.7670 |       0.8397 |          0.0003 |
|       3 |          39 |       00:00:35 |       60.00% |       62.50% |       0.7033 |       0.7413 |          0.0003 |
|       4 |          50 |       00:00:42 |       70.00% |              |       0.7629 |              |          0.0003 |
|       4 |          52 |       00:00:44 |       70.00% |       81.25% |       0.5941 |       0.6664 |          0.0003 |
|       5 |          65 |       00:00:53 |       90.00% |       84.38% |       0.4883 |       0.5273 |          0.0003 |
|       6 |          78 |       00:01:02 |       90.00% |       84.38% |       0.3627 |       0.3791 |          0.0003 |
|       7 |          91 |       00:01:11 |       90.00% |       87.50% |       0.2145 |       0.3710 |          0.0003 |
|       8 |         100 |       00:01:17 |       90.00% |              |       0.3157 |              |          0.0003 |
|       8 |         104 |       00:01:20 |       80.00% |       84.38% |       0.2166 |       0.3212 |          0.0003 |
|       9 |         117 |       00:01:29 |      100.00% |       90.62% |       0.0720 |       0.2111 |          0.0003 |
|      10 |         130 |       00:01:38 |       90.00% |       90.62% |       0.2510 |       0.1933 |          0.0003 |
|      11 |         143 |       00:01:47 |      100.00% |       93.75% |       0.0443 |       0.1763 |          0.0003 |
|      12 |         150 |       00:01:51 |      100.00% |              |       0.1377 |              |          0.0003 |
|      12 |         156 |       00:01:56 |       90.00% |       90.62% |       0.1190 |       0.3878 |          0.0003 |
|      13 |         169 |       00:02:04 |       80.00% |       87.50% |       0.4859 |       0.4950 |          0.0003 |
|      14 |         182 |       00:02:13 |      100.00% |       87.50% |       0.0395 |       0.3245 |          0.0003 |
|      15 |         195 |       00:02:22 |      100.00% |       84.38% |       0.0399 |       0.2639 |          0.0003 |
|======================================================================================================================|

Проверьте последний уровень сети. Подтвердите, что уровень «Classification Output» включает три класса.

trainedSN.Layers(end)
ans = 
  ClassificationOutputLayer with properties:

            Name: 'new_classoutput'
         Classes: [ARR    CHF    NSR]
    ClassWeights: 'none'
      OutputSize: 3

   Hyperparameters
    LossFunction: 'crossentropyex'

Оценка точности SqueeENet

Анализ сети с использованием данных проверки.

[YPred,probs] = classify(trainedSN,augimgsValidation);
accuracy = mean(YPred==imgsValidation.Labels);
disp(['SqueezeNet Accuracy: ',num2str(100*accuracy),'%'])
SqueezeNet Accuracy: 84.375%

Создание целевого объекта

Используйте dlhdl.Target класс для создания целевого объекта с пользовательским именем для целевого устройства и интерфейсом для подключения целевого устройства к хост-компьютеру. Опции интерфейса - JTAG и Ethernet. Чтобы использовать JTAG, установите Xilinx™ Vivado™ Design Suite 2019.2. Чтобы задать траекторию инструмента Xilinx Vivado, введите:

% hdlsetuptoolpath('ToolName', 'Xilinx Vivado', 'ToolPath', 'C:\Xilinx\Vivado\2019.2\bin\vivado.bat');

hTarget = dlhdl.Target('Xilinx','Interface','Ethernet');

Создание объекта WorkFlow

Используйте dlhdl.Workflow для создания объекта. При создании объекта укажите сеть и имя битового потока. Укажите сохраненную предварительно обученную нейронную сеть alexnet в качестве сети. Убедитесь, что имя битового потока соответствует типу данных и целевой плате FPGA. В этом примере целевой платой FPGA является плата Xilinx ZCU102 SoC. Битовый поток использует один тип данных.

hW=dlhdl.Workflow('Network', trainedSN, 'Bitstream', 'zcu102_single','Target',hTarget)
hW = 
  Workflow with properties:

            Network: [1×1 DAGNetwork]
          Bitstream: 'zcu102_single'
    ProcessorConfig: []
             Target: [1×1 dlhdl.Target]

Компиляция модифицированной сети SqueeENet DAG

Для компиляции trainedSN Сеть DAG, запустите метод компиляции dlhdl.Workflow объект.

dn = hW.compile          
### Compiling network for Deep Learning FPGA prototyping ...
### Targeting FPGA bitstream zcu102_single ...
### The network includes the following layers:

     1   'data'                    Image Input              227×227×3 images with 'zerocenter' normalization                     (SW Layer)
     2   'conv1'                   Convolution              64 3×3×3 convolutions with stride [2  2] and padding [0  0  0  0]    (HW Layer)
     3   'relu_conv1'              ReLU                     ReLU                                                                 (HW Layer)
     4   'pool1'                   Max Pooling              3×3 max pooling with stride [2  2] and padding [0  0  0  0]          (HW Layer)
     5   'fire2-squeeze1x1'        Convolution              16 1×1×64 convolutions with stride [1  1] and padding [0  0  0  0]   (HW Layer)
     6   'fire2-relu_squeeze1x1'   ReLU                     ReLU                                                                 (HW Layer)
     7   'fire2-expand1x1'         Convolution              64 1×1×16 convolutions with stride [1  1] and padding [0  0  0  0]   (HW Layer)
     8   'fire2-relu_expand1x1'    ReLU                     ReLU                                                                 (HW Layer)
     9   'fire2-expand3x3'         Convolution              64 3×3×16 convolutions with stride [1  1] and padding [1  1  1  1]   (HW Layer)
    10   'fire2-relu_expand3x3'    ReLU                     ReLU                                                                 (HW Layer)
    11   'fire2-concat'            Depth concatenation      Depth concatenation of 2 inputs                                      (HW Layer)
    12   'fire3-squeeze1x1'        Convolution              16 1×1×128 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    13   'fire3-relu_squeeze1x1'   ReLU                     ReLU                                                                 (HW Layer)
    14   'fire3-expand1x1'         Convolution              64 1×1×16 convolutions with stride [1  1] and padding [0  0  0  0]   (HW Layer)
    15   'fire3-relu_expand1x1'    ReLU                     ReLU                                                                 (HW Layer)
    16   'fire3-expand3x3'         Convolution              64 3×3×16 convolutions with stride [1  1] and padding [1  1  1  1]   (HW Layer)
    17   'fire3-relu_expand3x3'    ReLU                     ReLU                                                                 (HW Layer)
    18   'fire3-concat'            Depth concatenation      Depth concatenation of 2 inputs                                      (HW Layer)
    19   'pool3'                   Max Pooling              3×3 max pooling with stride [2  2] and padding [0  1  0  1]          (HW Layer)
    20   'fire4-squeeze1x1'        Convolution              32 1×1×128 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    21   'fire4-relu_squeeze1x1'   ReLU                     ReLU                                                                 (HW Layer)
    22   'fire4-expand1x1'         Convolution              128 1×1×32 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    23   'fire4-relu_expand1x1'    ReLU                     ReLU                                                                 (HW Layer)
    24   'fire4-expand3x3'         Convolution              128 3×3×32 convolutions with stride [1  1] and padding [1  1  1  1]  (HW Layer)
    25   'fire4-relu_expand3x3'    ReLU                     ReLU                                                                 (HW Layer)
    26   'fire4-concat'            Depth concatenation      Depth concatenation of 2 inputs                                      (HW Layer)
    27   'fire5-squeeze1x1'        Convolution              32 1×1×256 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    28   'fire5-relu_squeeze1x1'   ReLU                     ReLU                                                                 (HW Layer)
    29   'fire5-expand1x1'         Convolution              128 1×1×32 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    30   'fire5-relu_expand1x1'    ReLU                     ReLU                                                                 (HW Layer)
    31   'fire5-expand3x3'         Convolution              128 3×3×32 convolutions with stride [1  1] and padding [1  1  1  1]  (HW Layer)
    32   'fire5-relu_expand3x3'    ReLU                     ReLU                                                                 (HW Layer)
    33   'fire5-concat'            Depth concatenation      Depth concatenation of 2 inputs                                      (HW Layer)
    34   'pool5'                   Max Pooling              3×3 max pooling with stride [2  2] and padding [0  1  0  1]          (HW Layer)
    35   'fire6-squeeze1x1'        Convolution              48 1×1×256 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    36   'fire6-relu_squeeze1x1'   ReLU                     ReLU                                                                 (HW Layer)
    37   'fire6-expand1x1'         Convolution              192 1×1×48 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    38   'fire6-relu_expand1x1'    ReLU                     ReLU                                                                 (HW Layer)
    39   'fire6-expand3x3'         Convolution              192 3×3×48 convolutions with stride [1  1] and padding [1  1  1  1]  (HW Layer)
    40   'fire6-relu_expand3x3'    ReLU                     ReLU                                                                 (HW Layer)
    41   'fire6-concat'            Depth concatenation      Depth concatenation of 2 inputs                                      (HW Layer)
    42   'fire7-squeeze1x1'        Convolution              48 1×1×384 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    43   'fire7-relu_squeeze1x1'   ReLU                     ReLU                                                                 (HW Layer)
    44   'fire7-expand1x1'         Convolution              192 1×1×48 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    45   'fire7-relu_expand1x1'    ReLU                     ReLU                                                                 (HW Layer)
    46   'fire7-expand3x3'         Convolution              192 3×3×48 convolutions with stride [1  1] and padding [1  1  1  1]  (HW Layer)
    47   'fire7-relu_expand3x3'    ReLU                     ReLU                                                                 (HW Layer)
    48   'fire7-concat'            Depth concatenation      Depth concatenation of 2 inputs                                      (HW Layer)
    49   'fire8-squeeze1x1'        Convolution              64 1×1×384 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    50   'fire8-relu_squeeze1x1'   ReLU                     ReLU                                                                 (HW Layer)
    51   'fire8-expand1x1'         Convolution              256 1×1×64 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    52   'fire8-relu_expand1x1'    ReLU                     ReLU                                                                 (HW Layer)
    53   'fire8-expand3x3'         Convolution              256 3×3×64 convolutions with stride [1  1] and padding [1  1  1  1]  (HW Layer)
    54   'fire8-relu_expand3x3'    ReLU                     ReLU                                                                 (HW Layer)
    55   'fire8-concat'            Depth concatenation      Depth concatenation of 2 inputs                                      (HW Layer)
    56   'fire9-squeeze1x1'        Convolution              64 1×1×512 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    57   'fire9-relu_squeeze1x1'   ReLU                     ReLU                                                                 (HW Layer)
    58   'fire9-expand1x1'         Convolution              256 1×1×64 convolutions with stride [1  1] and padding [0  0  0  0]  (HW Layer)
    59   'fire9-relu_expand1x1'    ReLU                     ReLU                                                                 (HW Layer)
    60   'fire9-expand3x3'         Convolution              256 3×3×64 convolutions with stride [1  1] and padding [1  1  1  1]  (HW Layer)
    61   'fire9-relu_expand3x3'    ReLU                     ReLU                                                                 (HW Layer)
    62   'fire9-concat'            Depth concatenation      Depth concatenation of 2 inputs                                      (HW Layer)
    63   'new_dropout'             Dropout                  60% dropout                                                          (HW Layer)
    64   'new_conv'                Convolution              3 1×1×512 convolutions with stride [1  1] and padding [0  0  0  0]   (HW Layer)
    65   'relu_conv10'             ReLU                     ReLU                                                                 (HW Layer)
    66   'pool10'                  Global Average Pooling   Global average pooling                                               (HW Layer)
    67   'prob'                    Softmax                  softmax                                                              (SW Layer)
    68   'new_classoutput'         Classification Output    crossentropyex with 'ARR' and 2 other classes                        (SW Layer)

4 Memory Regions created.

Skipping: data
Compiling leg: conv1>>fire2-relu_squeeze1x1 ...
Compiling leg: conv1>>fire2-relu_squeeze1x1 ... complete.
Compiling leg: fire2-expand1x1>>fire2-relu_expand1x1 ...
Compiling leg: fire2-expand1x1>>fire2-relu_expand1x1 ... complete.
Compiling leg: fire2-expand3x3>>fire2-relu_expand3x3 ...
Compiling leg: fire2-expand3x3>>fire2-relu_expand3x3 ... complete.
Do nothing: fire2-concat
Compiling leg: fire3-squeeze1x1>>fire3-relu_squeeze1x1 ...
Compiling leg: fire3-squeeze1x1>>fire3-relu_squeeze1x1 ... complete.
Compiling leg: fire3-expand1x1>>fire3-relu_expand1x1 ...
Compiling leg: fire3-expand1x1>>fire3-relu_expand1x1 ... complete.
Compiling leg: fire3-expand3x3>>fire3-relu_expand3x3 ...
Compiling leg: fire3-expand3x3>>fire3-relu_expand3x3 ... complete.
Do nothing: fire3-concat
Compiling leg: pool3>>fire4-relu_squeeze1x1 ...
Compiling leg: pool3>>fire4-relu_squeeze1x1 ... complete.
Compiling leg: fire4-expand1x1>>fire4-relu_expand1x1 ...
Compiling leg: fire4-expand1x1>>fire4-relu_expand1x1 ... complete.
Compiling leg: fire4-expand3x3>>fire4-relu_expand3x3 ...
Compiling leg: fire4-expand3x3>>fire4-relu_expand3x3 ... complete.
Do nothing: fire4-concat
Compiling leg: fire5-squeeze1x1>>fire5-relu_squeeze1x1 ...
Compiling leg: fire5-squeeze1x1>>fire5-relu_squeeze1x1 ... complete.
Compiling leg: fire5-expand1x1>>fire5-relu_expand1x1 ...
Compiling leg: fire5-expand1x1>>fire5-relu_expand1x1 ... complete.
Compiling leg: fire5-expand3x3>>fire5-relu_expand3x3 ...
Compiling leg: fire5-expand3x3>>fire5-relu_expand3x3 ... complete.
Do nothing: fire5-concat
Compiling leg: pool5>>fire6-relu_squeeze1x1 ...
Compiling leg: pool5>>fire6-relu_squeeze1x1 ... complete.
Compiling leg: fire6-expand1x1>>fire6-relu_expand1x1 ...
Compiling leg: fire6-expand1x1>>fire6-relu_expand1x1 ... complete.
Compiling leg: fire6-expand3x3>>fire6-relu_expand3x3 ...
Compiling leg: fire6-expand3x3>>fire6-relu_expand3x3 ... complete.
Do nothing: fire6-concat
Compiling leg: fire7-squeeze1x1>>fire7-relu_squeeze1x1 ...
Compiling leg: fire7-squeeze1x1>>fire7-relu_squeeze1x1 ... complete.
Compiling leg: fire7-expand1x1>>fire7-relu_expand1x1 ...
Compiling leg: fire7-expand1x1>>fire7-relu_expand1x1 ... complete.
Compiling leg: fire7-expand3x3>>fire7-relu_expand3x3 ...
Compiling leg: fire7-expand3x3>>fire7-relu_expand3x3 ... complete.
Do nothing: fire7-concat
Compiling leg: fire8-squeeze1x1>>fire8-relu_squeeze1x1 ...
Compiling leg: fire8-squeeze1x1>>fire8-relu_squeeze1x1 ... complete.
Compiling leg: fire8-expand1x1>>fire8-relu_expand1x1 ...
Compiling leg: fire8-expand1x1>>fire8-relu_expand1x1 ... complete.
Compiling leg: fire8-expand3x3>>fire8-relu_expand3x3 ...
Compiling leg: fire8-expand3x3>>fire8-relu_expand3x3 ... complete.
Do nothing: fire8-concat
Compiling leg: fire9-squeeze1x1>>fire9-relu_squeeze1x1 ...
Compiling leg: fire9-squeeze1x1>>fire9-relu_squeeze1x1 ... complete.
Compiling leg: fire9-expand1x1>>fire9-relu_expand1x1 ...
Compiling leg: fire9-expand1x1>>fire9-relu_expand1x1 ... complete.
Compiling leg: fire9-expand3x3>>fire9-relu_expand3x3 ...
Compiling leg: fire9-expand3x3>>fire9-relu_expand3x3 ... complete.
Do nothing: fire9-concat
Compiling leg: new_conv>>relu_conv10 ...
Compiling leg: new_conv>>relu_conv10 ... complete.
Compiling leg: pool10 ...
Compiling leg: pool10 ... complete.
Skipping: prob
Skipping: new_classoutput
Creating Schedule...
.......................................
Creating Schedule...complete.
Creating Status Table...
......................................
Creating Status Table...complete.
Emitting Schedule...
......................................
Emitting Schedule...complete.
Emitting Status Table...
........................................
Emitting Status Table...complete.

### Allocating external memory buffers:

          offset_name          offset_address    allocated_space 
    _______________________    ______________    ________________

    "InputDataOffset"           "0x00000000"     "24.0 MB"       
    "OutputResultOffset"        "0x01800000"     "4.0 MB"        
    "SchedulerDataOffset"       "0x01c00000"     "4.0 MB"        
    "SystemBufferOffset"        "0x02000000"     "28.0 MB"       
    "InstructionDataOffset"     "0x03c00000"     "4.0 MB"        
    "ConvWeightDataOffset"      "0x04000000"     "12.0 MB"       
    "FCWeightDataOffset"        "0x04c00000"     "0.0 MB"        
    "EndOffset"                 "0x04c00000"     "Total: 76.0 MB"

### Network compilation complete.
dn = struct with fields:
             weights: [1×1 struct]
        instructions: [1×1 struct]
           registers: [1×1 struct]
    syncInstructions: [1×1 struct]

Передача битового потока в FPGA и загрузка веса сети

Для развертывания сети на оборудовании Xilinx ZCU102 выполните функцию развертывания dlhdl.Workflow объект. Эта функция использует выходные данные функции компиляции для программирования платы FPGA с помощью файла программирования. Он также загружает веса сети и отклонения. Функция развертывания запускает программирование устройства FPGA, отображает сообщения о ходе выполнения и время, необходимое для развертывания сети.

hW.deploy
### FPGA bitstream programming has been skipped as the same bitstream is already loaded on the target FPGA.
### Loading weights to Conv Processor.
### Conv Weights loaded. Current time is 12-Jan-2021 16:28:17

Загрузить изображение для прогнозирования и прогона

idx=randi(32);
testim=readimage(imgsValidation,idx);
im=imresize(testim,[227 227]);
imshow(testim)

[YPred1,probs1] = classify(trainedSN,im);
accuracy1 = (YPred1==imgsValidation.Labels);
[YPred2,probs2] = hW.predict(single(im),'profile','on');
### Finished writing input activations.
### Running single input activations.


              Deep Learning Processor Profiler Performance Results

                   LastFrameLatency(cycles)   LastFrameLatency(seconds)       FramesNum      Total Latency     Frames/s
                         -------------             -------------              ---------        ---------       ---------
Network                    8847610                  0.04022                       1            8847610             24.9
    conv1                   626502                  0.00285 
    pool1                   579473                  0.00263 
    fire2-squeeze1x1        308065                  0.00140 
    fire2-expand1x1         305121                  0.00139 
    fire2-expand3x3         305091                  0.00139 
    fire3-squeeze1x1        624849                  0.00284 
    fire3-expand1x1         305136                  0.00139 
    fire3-expand3x3         305587                  0.00139 
    pool3                   290789                  0.00132 
    fire4-squeeze1x1        262881                  0.00119 
    fire4-expand1x1         263129                  0.00120 
    fire4-expand3x3         262617                  0.00119 
    fire5-squeeze1x1        703951                  0.00320 
    fire5-expand1x1         262552                  0.00119 
    fire5-expand3x3         262599                  0.00119 
    pool5                   216737                  0.00099 
    fire6-squeeze1x1        192738                  0.00088 
    fire6-expand1x1         142333                  0.00065 
    fire6-expand3x3         142132                  0.00065 
    fire7-squeeze1x1        286437                  0.00130 
    fire7-expand1x1         142363                  0.00065 
    fire7-expand3x3         142079                  0.00065 
    fire8-squeeze1x1        364915                  0.00166 
    fire8-expand1x1         240660                  0.00109 
    fire8-expand3x3         240946                  0.00110 
    fire9-squeeze1x1        483766                  0.00220 
    fire9-expand1x1         240624                  0.00109 
    fire9-expand3x3         241242                  0.00110 
    new_conv                 93673                  0.00043 
    pool10                    6135                  0.00003 
 * The clock frequency of the DL processor is: 220MHz
accuracy2 = (YPred==imgsValidation.Labels);
[val,idx]= max(YPred2);
trainedSN.Layers(end).ClassNames{idx}
ans = 
'CHF'

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

helperCreateECGDataDirectory создает каталог данных внутри родительского каталога, затем создает три подкаталога внутри каталога данных. Подкаталоги именуются после каждого класса сигнала ЭКГ, найденного в ECGData.

function helperCreateECGDirectories(ECGData,parentFolder,dataFolder)
% This function is only intended to support the ECGAndDeepLearningExample.
% 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 строит графики первой тысячи образцов представителя каждого класса сигнала ЭКГ, обнаруженного в ECGData.

function helperPlotReps(ECGData)
% This function is only intended to support the ECGAndDeepLearningExample.
% 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

helperCreateRUREstartTF использует cwtfilterbank (Vavelet Toolbox) для получения непрерывного вейвлет-преобразования ЭКГ-сигналов и генерирует скалограммы из вейвлет-коэффициентов. Вспомогательная функция изменяет размер скалограмм и записывает их на диск в виде изображений jpeg.

function helperCreateRGBfromTF(ECGData,parentFolder,childFolder)
% This function is only intended to support the ECGAndDeepLearningExample.
% 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,[224 224]),fullfile(imgLoc,imFileName));
end
end