このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。
ウェーブレット解析と深層学習を使用した NVIDIA Jetson への信号分類器の展開
この例では、連続ウェーブレット変換 (CWT) と事前学習済みの畳み込みニューラル ネットワーク (CNN) を使用して人間の心電図 (ECG) 信号を分類する CUDA® 実行可能ファイルを生成および展開する方法を説明します。
SqueezeNet は、当初 1000 のカテゴリにイメージを分類するために設計された深層 CNN です。スカログラムを基にした ECG 信号を分類するために CNN のネットワーク アーキテクチャを再利用します。スカログラムは、信号の CWT の絶対値です。ECG 信号を分類するように SqueezeNet を学習させた後、ECG 信号のスカログラムを生成してから CNN を使用して信号を分類する CUDA 実行可能ファイルを作成します。実行可能ファイルと CNN の両方が NVIDIA ハードウェアに展開されます。
この例では、ウェーブレット解析と深層学習を使用した時系列の分類で使用したのと同じデータを使用します。この例では、GoogLeNet と SqueezeNet による転移学習を使用して、ECG 波形を 3 つのカテゴリのうちの 1 つに分類します。便宜上、ここではデータの概要とこのデータを取得する方法について再度説明します。
ECG データの説明とダウンロード
ECG データは人の 3 つのグループから取得されます。具体的には、心不整脈の患者 (ARR)、鬱血性心不全の患者 (CHF)、および正常洞調律の患者 (NSR) のグループです。次の 3 つの PhysioNet データベースから、合計 162 個の ECG 記録を取得します。MIT-BIH Arrhythmia Database [2][3]、MIT-BIH Normal Sinus Rhythm Database [3]、The BIDMC Congestive Heart Failure Database [1][3]。具体的には、不整脈の患者の記録は 96 個、鬱血性心不全の患者の記録は 30 個、正常洞調律の患者の記録は 36 個あります。目標は、ARR、CHF、NSR を区別するようにモデルに学習させることです。
このデータは MathWorks の GitHub リポジトリから入手できます。データを Web サイトからダウンロードするには、[Code
] をクリックして [Download ZIP
] を選択します。書き込み権限のあるフォルダーに、ファイル physionet_ECG_data-main.zip
を保存します。この例の手順では、ファイルを一時ディレクトリ (MATLAB の tempdir
) にダウンロードしているものと仮定します。tempdir
とは異なるフォルダーにデータをダウンロードすることを選択した場合は、データの解凍および読み込みに関する後続の手順を変更してください。
データを 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 のコピー ポリシーで必要になり、データのソース属性、および ECG の各記録に適用される前処理手順の説明を提供します。
physionet-ECG_data-main
内にある ECGData.zip
を解凍します。データ ファイルを 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 は、2 つのフィールド (Data
および Labels
) をもつ構造体配列です。Data
フィールドは 162 行 65,536 列の行列で、各行は 128 Hz でサンプリングした ECG 記録です。Labels
は 162 行 1 列の診断ラベルの cell 配列で、それぞれのラベルが Data
の各行に対応します。3 つの診断カテゴリは、'ARR'
、'CHF'
、および 'NSR'
です。
特徴抽出
データをダウンロードした後、信号のスカログラムを生成しなければなりません。スカログラムは CNN への "入力" イメージです。
各カテゴリのスカログラムを保存するには、最初に tempdir
内に ECG データ ディレクトリ 'data'
を作成します。その後、各 ECG カテゴリに由来した 'data'
に 3 つのサブディレクトリを作成します。これは、補助関数 helperCreateECGDirectories
によって実行されます。helperCreateECGDirectories
は、ECGData
、ECG データ ディレクトリの名前、親ディレクトリの名前を入力引数として受け入れます。tempdir
を書き込み権限のある別のディレクトリと置き換えることができます。この補助関数のソース コードは、この例の最後にあるサポート関数の節で見つけることができます。
parentDir = tempdir;
dataDir = 'data';
helperCreateECGDirectories(ECGData,parentDir,dataDir)
フォルダーを作成した後、ECG 信号のスカログラムを RGB イメージとして作成し、これらのイメージを dataDir
内の適切なサブディレクトリに書き込みます。スカログラムを作成するには、まず CWT フィルター バンクを事前に計算します。フィルター バンクの事前計算は、同じパラメーターを使用して多数の信号の CWT を取得するときに推奨される方法です。補助関数 helperCreateRGBfromTF
がこれを実行します。この補助関数のソース コードは、この例の最後にあるサポート関数の節にあります。SqueezeNet アーキテクチャと互換性をもたせるために、各 RGB イメージは 227 x 227 x 3 のサイズの配列になります。
helperCreateRGBfromTF(ECGData,parentDir,dataDir)
学習データと検証データへのデータ セットの分割
スカログラム イメージをイメージ データストアとして読み込みます。関数 imageDatastore
は、フォルダー名に基づいてイメージに自動的にラベルを付け、このデータを ImageDatastore
オブジェクトとして格納します。イメージ データストアを使用すると、メモリに収まらないデータなどのサイズが大きいイメージ データを格納して、CNN の学習中にイメージをバッチ単位で効率的に読み取ることができます。
allImages = imageDatastore(fullfile(tempdir,dataDir),... 'IncludeSubfolders',true,... 'LabelSource','foldernames');
イメージを 2 つのグループ (学習用と検証用) にランダムに分割します。イメージの 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 は、イメージを 1000 のカテゴリに分類できる事前学習済みの CNN です。ECG 分類問題に対応するように、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 を読み込みます。層グラフを抽出し、最後の 5 つの層を検査します。
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' 2-D Global Average Pooling 2-D global average pooling 4 'prob' Softmax softmax 5 'ClassificationLayer_predictions' Classification Output crossentropyex with 'tench' and 999 other classes
ECG 信号の 3 つのクラスを分類するように SqueezeNet に再学習させるには、'conv10'
層を、ECG クラスの数と同じ数のフィルターをもつ新しい畳み込み層で置き換えます。分類層をクラス ラベルがない新しい分類層に置き換えます。
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' 2-D Global Average Pooling 2-D 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);
すべてのパラメーターを 1 つの構造体内に保存します。学習済みネットワークと構造体は後で .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;
乱数シードを既定値に設定し、ネットワークを学習させます。学習済みネットワーク、試行パラメーター、学習実行時間、検証イメージが格納されているイメージ データストアを保存します。学習プロセスは、通常、デスクトップ CPU 上で 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:03 | 26.67% | 25.00% | 4.1769 | 2.9883 | 1.0000e-04 | | 2 | 10 | 00:00:18 | 73.33% | 59.38% | 0.9875 | 1.1554 | 1.0000e-04 | | 3 | 20 | 00:00:35 | 60.00% | 56.25% | 0.9157 | 0.9178 | 1.0000e-04 | | 4 | 30 | 00:00:52 | 86.67% | 68.75% | 0.6708 | 0.7883 | 1.0000e-04 | | 5 | 40 | 00:01:10 | 66.67% | 68.75% | 0.9026 | 0.7482 | 1.0000e-04 | | 7 | 50 | 00:01:29 | 80.00% | 78.12% | 0.5429 | 0.6788 | 1.0000e-04 | | 8 | 60 | 00:01:48 | 100.00% | 81.25% | 0.4165 | 0.6130 | 1.0000e-04 | | 9 | 70 | 00:02:06 | 93.33% | 84.38% | 0.3590 | 0.5480 | 1.0000e-04 | | 10 | 80 | 00:02:24 | 73.33% | 84.38% | 0.5113 | 0.4783 | 1.0000e-04 | | 12 | 90 | 00:02:42 | 86.67% | 84.38% | 0.4211 | 0.4065 | 1.0000e-04 | | 13 | 100 | 00:03:00 | 93.33% | 90.62% | 0.1935 | 0.3486 | 1.0000e-04 | | 14 | 110 | 00:03:18 | 100.00% | 90.62% | 0.1488 | 0.3119 | 1.0000e-04 | | 15 | 120 | 00:03:36 | 100.00% | 93.75% | 0.0788 | 0.2774 | 1.0000e-04 | | 17 | 130 | 00:03:55 | 86.67% | 93.75% | 0.2489 | 0.2822 | 1.0000e-04 | | 18 | 140 | 00:04:13 | 100.00% | 93.75% | 0.0393 | 0.2283 | 1.0000e-04 | | 19 | 150 | 00:04:32 | 100.00% | 93.75% | 0.0522 | 0.2364 | 1.0000e-04 | | 20 | 160 | 00:04:50 | 100.00% | 93.75% | 0.0227 | 0.2034 | 1.0000e-04 | |======================================================================================================================| Training finished: Max epochs completed.
Total training time: 3.03e+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 を保存します。混同チャートの下にあるテーブルに、精度が示されます。混同チャートの右側にあるテーブルに、再現率が示されます。
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: 2991.89 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): 1.67e-01 sec
結果を保存します。
if ~LoadModel save(MatFile,'accuracy','confusionMat','PredTime','ModelMemSize', ... 'AvgPredTimePerImage','-append') end
GPU コード生成 — 関数の定義
信号のスカログラムは、深層 CNN への入力 "イメージ" です。関数 cwt_ecg_jetson_ex
を作成します。この関数は、入力信号のスカログラムを計算し、ユーザーが指定した次元でイメージを返します。このイメージは jet(128)
カラーマップを使用します。この関数の %#codegen
命令は、この関数がコード生成用であることを指定します。coder.gpu.kernelfun
プラグマを使用すると、コード生成時に関数 cwt_ecg_jetson_ex
の計算を GPU にマッピングしようとします。
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
を作成します。この関数は ECG 信号を入力として受け取り、関数 cwt_ecg_jetson_ex
を呼び出してスカログラムのイメージを作成します。関数 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
NVIDIA ターゲットに展開できる CUDA 実行可能ファイルを生成するには、カスタムのメイン ファイル (main_ecg_jetson_ex.cu
) とヘッダー ファイル (main_ecg_jetson_ex.h
) を作成します。メイン ファイルの例を生成し、それをテンプレートとして使用して新しいメイン ファイルとヘッダー ファイルを再作成できます。詳細については、coder.CodeConfig
(MATLAB Coder)の GenerateExampleMain
プロパティを参照してください。メイン ファイルは、MATLAB エントリポイント関数用に生成されたコードを呼び出します。メイン ファイルは最初にテキスト ファイルから ECG 信号を読み取り、そのデータをエントリポイント関数に渡し、予測結果をテキスト ファイル (predClassProb.txt
) に書き込みます。GPU での計算効率性を最大化するために、実行可能ファイルは単精度のデータを処理します。
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 に設定します。
main
関数は signalFile
で指定されたテキスト ファイルからデータを読み取り、分類結果を resultFile
に書き込みます。ExampleIndex
を設定して、代表的な ECG 信号を選択します。この信号を使用して、関数 classify
に対して実行可能ファイルをテストします。Jetson_BuildDir
で、ターゲット上でリモート ビルド プロセスを実行するディレクトリを指定します。指定したビルド ディレクトリがターゲットに存在しない場合は、指定した名前でディレクトリが作成されます。
CodeGenMode =1; signalFile = 'signalData.txt'; resultFile = 'predClassProb.txt'; % consistent with "main_ecg_jetson_ex.cu" Jetson_BuildDir = '~/projectECG'; ExampleIndex = 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(ECGData.Data(SampleSignalIdx,:)); ECGtype = ECGData.Labels{SampleSignalIdx};
GPU コード生成 — ハードウェアへの接続
NVIDIA ハードウェアと通信するために、関数 jetson
を使用してライブ ハードウェア接続オブジェクトを作成します。ライブ ハードウェア接続オブジェクトを作成するには、ターゲット ボードのホスト名または IP アドレス、ユーザー名、およびパスワードを知っている必要があります。
Jetson ハードウェア用のライブ ハードウェア接続オブジェクトを作成します。以下のコードで、次を置き換えます。
NameOfJetsonDevice
: Jetson デバイスの名前または IP アドレスUsername
: 自分のユーザー名password
: 自分のパスワード
オブジェクトの作成時、このソフトウェアは、ハードウェアとソフトウェアをチェックし、IO サーバーをインストールし、ターゲットに接続されている周辺装置の情報を収集します。この情報はコマンド ウィンドウに表示されます。
hwobj = jetson("NameOfJetsonDevice","Username","password");
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 Nano 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 OpenCV Version : 3.3.1 Available Webcams : Available GPUs : NVIDIA Tegra X1 Available Digital Pins : 7 11 12 13 15 16 18 19 21 22 23 24 26 29 31 32 33 35 36 37 38 40
関数coder.checkGpuInstall
(GPU Coder)を使用して、この例を実行するのに必要なコンパイラおよびライブラリがハードウェア上に適切に設定されていることを検証します。
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 プラットフォーム用の構成オブジェクトを作成し、それをコード構成オブジェクト cfg
の Hardware
プロパティに割り当てます。Jetson TX1 または TX2 ボードには 'NVIDIA Jetson'
を使用します。カスタム メイン ファイルは、生成されたコード内でエントリポイント関数を呼び出すラッパーです。このカスタム ファイルは展開済みの実行可能ファイルに必要となります。
関数 coder.DeepLearningConfig
(GPU Coder) を使用して CuDNN
深層学習構成オブジェクトを作成し、それを GPU コード構成オブジェクトの DeepLearningConfig
プロパティに割り当てます。コード ジェネレーターは、NVIDIA GPU 対応の NVIDIA® CUDA® Deep Neural Network library (cuDNN) を利用します。cuDNN は深層ニューラル ネットワークに対するプリミティブの、GPU で高速化されたライブラリです。
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
を使用して、GPU コード構成およびエントリポイント関数 model_predict_ecg
の入力のサイズと型を渡します。ホスト上でコード生成が完了した後、生成されたファイルがターゲットにコピーされてビルドされます。
codegen('-config ',cfg,Function_to_Gen,'-args',{signal_data},'-report');
Code generation successful: View report
GPU コード生成 — 実行
ターゲットに展開される実行可能ファイルをコンパイルする場合、このサンプルの ECG 信号をテキスト ファイルに書き込みます。ハードウェア オブジェクトの関数 putFile()
を使用して、そのテキスト ファイルをターゲット上に配置します。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) evalc('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
Fetch time = 1.658e+01 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 = 2.044e+01 sec Example ECG Type: ARR
disp(PredTableJetson)
ARR CHF NSR _______ ________ ________ 0.99858 0.001252 0.000166
PredTableMATLAB = array2table(ModPredProb(:)','VariableNames',matlab.lang.makeValidName(PredCat));
disp(PredTableMATLAB)
ARR CHF NSR _______ _________ __________ 0.99858 0.0012516 0.00016613
ハードウェア接続を終了します。
clear hwobj
まとめ
この例では、CNN を使用して ECG 信号を分類する CUDA 実行可能ファイルを作成して展開する方法を説明しています。ローカルで実行してリモート ターゲットに接続する実行可能ファイルを作成することもできます。ワークフロー全体はこの例で紹介されています。データのダウンロード後に、CWT を使用して ECG 信号から特徴が抽出されます。続いて、スカログラムに基づいて信号を分類するように SqueezeNet に再学習させます。2 つのユーザー定義関数が作成されて、ターゲットの NVIDIA デバイス上でコンパイルされます。実行可能ファイルの結果が MATLAB で比較されます。
参考文献
Baim, D. S., W. S. Colucci, E. S. Monrad, H. S. Smith, R. F. Wright, A. Lanoue, D. F. Gauthier, B. J. Ransil, W. Grossman, and E. Braunwald."Survival of patients with severe congestive heart failure treated with oral milrinone."Journal of the American College of Cardiology.Vol. 7, Number 3, 1986, pp. 661–670.
Goldberger A. L., L. A. N. Amaral, L. Glass, J. M. Hausdorff, P. Ch. Ivanov, R. G. Mark, J. E. Mietus, G. B. Moody, C.-K. Peng, and H. E. Stanley. "PhysioBank, PhysioToolkit,and PhysioNet: Components of a New Research Resource for Complex Physiologic Signals." Circulation. Vol. 101, Number 23: e215–e220. [Circulation Electronic Pages;
http://circ.ahajournals.org/content/101/23/e215.full
]; 2000 (June 13). doi: 10.1161/01.CIR.101.23.e215.Moody, G. B., and R. G. Mark."The impact of the MIT-BIH Arrhythmia Database."IEEE Engineering in Medicine and Biology Magazine.Vol. 20. Number 3, May-June 2001, pp. 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
参考
coder.DeepLearningConfig
(GPU Coder) | cwtfilterbank
| cwt