メインコンテンツ

Raspberry Pi での信号セグメンテーション ディープ ネットワークの展開

この例では、短時間フーリエ変換と双方向長短期記憶 (BiLSTM) ネットワークを使用した、心電図 (ECG) 信号の波形セグメンテーションのワークフローについて詳しく説明します。また、この例では、Raspberry Pi® ターゲット (ARM® ベースのデバイス) でのセグメンテーション用に、コードを生成してそのコードと学習済み BiLSTM ネットワークを展開する方法についても説明しています。

この例の事前学習済みのネットワークは、深層学習を使用した波形セグメンテーションの例に似ています。

この例の詳細:

  • Raspberry Pi での展開および実行用に MATLAB® から生成されるコードを検証するプロセッサインザループ (PIL) ベースのワークフロー

  • スタンドアロンの実行可能ファイルの生成

PIL 検証プロセスは、設計サイクルの重要な部分であり、スタンドアロンの実行可能ファイルを展開する前に、生成コードの動作が設計と一致することを確認します。

ECG データセット

この例では、一般に公開されている QT データベースからの ECG 信号を使用します [1] [2]。データは、サンプル レート 250 Hz で合計 105 人の患者から測定された、約 15 分間のラベル付き ECG 記録で構成されています。

ECG 信号は次の心拍形態に分けられます [3]。

  • P 波 — QRS 群が心房性脱分極を表す前の小さいたわみ

  • QRS 群 — 心拍の最大振幅部分

  • T 波 — QRS 群が心室再分極を表した後の小さいたわみ

ECG 波形のこれらの領域のセグメンテーションでは、人間の心臓全体の健康状態と異常の存在を評価する測定値の基準を提供できます。

前提条件

サポートされるライブラリのバージョン、および環境変数の設定の詳細については、深層学習に MATLAB Coder を使用するための前提条件 (MATLAB Coder)を参照してください。

生成されたコードの機能

生成された実行可能ファイルの主な機能:

  • 15,000 個の単精度の ECG データ サンプルを入力として使用します。

  • 信号の短時間フーリエ変換を計算します。

  • 出力を標準化および正規化します。

  • 事前学習済みの BiLSTM ネットワークを使用して信号の領域にラベルを付けます。

  • ラベル付きの出力ファイルを生成します。

waveformSegmentation エントリポイント関数

"最上位" 関数または "基本" 関数とも呼ばれる "エントリポイント" 関数は、コード生成のために定義する関数です。エントリポイント関数は、コード生成を可能にする関数を呼び出し、エントリポイント関数から C/C++ コードを生成できるように定義しなければなりません。エントリポイント関数内のすべての関数は、コード生成をサポートしていなければなりません。

この例では、waveformSegmentation がエントリポイント関数です。ECG 信号を入力として受け取り、それを予測のために学習済みの BiLSTM ネットワークに渡します。関数 performPreprocessing は、生の信号を前処理し、短時間フーリエ変換を適用します。関数 genClassifiedResults は、前処理された信号を予測用のネットワークに渡し、分類結果を表示します。

type waveformSegmentation
function out = waveformSegmentation(in)
%#codegen
% Copyright 2020-2024 The MathWorks, Inc.
persistent net;

if isempty(net)
    net = coder.loadDeepLearningNetwork('trained-network-STFTBILSTM.mat', 'net');
end

preprocessedSignal = performPreprocessing(in);
out = cell(3,1);
% Specify coder.cstructname to lock down the structure name and ensure
% consistency with the one specified in the ecgsegmentation_main.cpp file.
coder.cstructname(out, 'waveformOutputs');
for indx = 1:3
    dlIn = dlarray(preprocessedSignal{1,indx},"CT");
    out{indx,1} = genClassifedResults(extractdata(net.predict(dlIn)));
end

end

Raspberry Pi への接続の作成

MATLAB Support Package for Raspberry Pi の関数 raspi を使用して、Raspberry Pi への接続を作成します。以下のコードで、次を置き換えます。

  • raspiname: 自分の Raspberry Pi のホスト名

  • username: 自分のユーザー名

  • password: 自分のパスワード

r = raspi(raspiname','username','password');

この例では、コードと設計を検証するための PIL ベースのワークフローを示し、スタンドアロンの実行可能ファイルを作成して展開します。オプションとして、スタンドアロンの実行可能ファイルをすぐに展開したい場合は、PIL の実行を省略してスタンドアロンの実行可能ファイルの作成に進むことができます。

PIL MEX 関数の生成

最初の手順では、関数 waveformSegmentation の MEX 関数を生成するための PIL ベースのワークフローを示します。

Raspberry Pi 用のコード生成ハードウェア パラメーターの構成

スタティック ライブラリを生成するために coder.EmbeddedCodeConfig オブジェクトを作成します。PIL ベースの実行を有効にするには、VerificationMode プロパティを 'PIL' に設定します。

cfg = coder.config('lib','ecoder',true);
cfg.VerificationMode = 'PIL';

coder.Hardware オブジェクトを作成し、ターゲット ハードウェアを Raspberry Pi として指定します。cfgHardware プロパティにハードウェア オブジェクトを割り当てます。

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

深層学習構成オブジェクトを作成し、ターゲット ライブラリを none に設定します。コード生成構成オブジェクトに深層学習構成オブジェクトを追加します。

dlcfg = coder.DeepLearningConfig(TargetLibrary = 'none');
cfg.DeepLearningConfig = dlcfg;

Raspberry Pi 上のビルド フォルダーを指定します。

cfg.Hardware.BuildDir = '~/waveformSegmentation';

関数 codegen を使用した C++ ソース コードの生成

関数 codegen を使用して C++ コードを生成します。MATLAB Support Package for Raspberry Pi Hardware で codegen を使用すると、生成コードがボードにダウンロードされ、そこでコンパイルされます。PIL MEX 関数は、MATLAB と、Raspberry Pi で実行される生成コードとの間で通信をするために生成されます。

codegen -config cfg waveformSegmentation -args {coder.typeof(single(ones(1,15000)),[1,15000],[0,0])} -report

Raspberry Pi での実行可能プログラムの実行

MAT ファイル ecgsignal_test を読み込みます。ファイルには、生成コードをテストできるように、サンプルの ECG 信号が格納されています。

生成された MEX 関数 waveformSegmentation_pil をテスト信号で実行します。

load ecgsignal_test.mat;
out = waveformSegmentation_pil(test);
### Starting application: 'codegen\lib\waveformSegmentation\pil\waveformSegmentation.elf'
    To terminate execution: clear waveformSegmentation_pil
### Launching application waveformSegmentation.elf...

信号と予測ラベルを表示します。

labels = categorical(out{1}(1,2000:3000));
msk = signalMask(labels);
plotsigroi(msk,test(1,2000:3000))
title('Predicted Labels')

PIL MEX 関数の出力を確認した後、関数 waveformSegmentation のスタンドアロンの実行可能ファイルを作成できます。

次の部分では、MATLAB Coder アプリを使用して、予測用のコードからスタンドアロンの実行可能ファイルを生成し、Raspberry Pi に展開するコード生成ワークフローを示します。

MATLAB Coder アプリを使用したスタンドアロンの実行可能ファイルの作成

"MATLAB Coder" アプリは、MATLAB コードから C または C++ コードを生成します。ワークフローに基づくユーザー インターフェイスにより、コード生成プロセスを進めることができます。以下の手順では、MATLAB Coder アプリを使用する簡単なワークフローを説明します。詳細については、MATLAB Coder (MATLAB Coder)およびMATLAB Coder アプリを使用した C コードの生成 (MATLAB Coder)を参照してください。

エントリポイント関数ファイルの選択

MATLAB ツールストリップの [アプリ] タブの [コード生成] で、[MATLAB Coder] アプリ アイコンをクリックします。アプリの [MATLAB Coder プロジェクトの作成] ダイアログ ボックスが開きます。プロジェクト ファイルの名前と、ファイルを保存するフォルダーを指定します。この例では、現在の作業フォルダーに waveformSegmentation.coderprj という名前のファイルを作成します。

"MATLAB Coder" ツールストリップが開きます。このツールストリップには、C/C++ コード生成用の MATLAB コードの準備、コードの生成、生成したコードの検証の実行、コード生成レポートの表示、生成されたコードのエクスポートなど、コード生成時に実行する主なアクションに対応するセクションがあります。

MATLAB Coder アプリのこの状態において、コード生成パネルの [次のステップ] セクションでエントリポイント関数を追加します。コード生成パネルの [入力] セクションにある [エントリ ポイントの追加] ボタン、またはツールストリップの [エントリ ポイント] ボタンをクリックします。[エントリ ポイント] ペインが開きます。エントリポイント関数の名前 waveformSegmentation を入力します。

入力の型の定義

すべてのエントリポイント関数への入力のプロパティを指定しなければなりません。この例では、入力 in の値を single の (1x15000) として指定します。MATLAB Coder アプリにおける入力の型の定義の詳細については、MATLAB Coder アプリを使用した C コードの生成 (MATLAB Coder)を参照してください。

コードの生成

MATLAB Coder ツールストリップの [準備] セクションで、[出力]"C" に設定され、[ビルド タイプ]"Executable (.exe)" に設定されていることを確認します。[設定] ボタンをクリックして [スタンドアロン コード生成設定] ダイアログを開き、次を行います。

  • [ハードウェア] ペインで、[ハードウェア ボード]Raspberry Pi に設定し、ボードの [ユーザー名][パスワード] のパラメーターを入力します。

  • [カスタム コード] ペインの追加のソース ファイルで、ecgsegmentation_main.cpp を参照して選択します。C/C++ main 関数の記述の詳細については、生成された C/C++ main 関数の例の構造 (MATLAB Coder)を参照してください。

[設定] ウィンドウを閉じて、[コードを生成してビルド] ボタンをクリックします。

生成された実行可能ファイル ディレクトリの取得

コード生成が完了したら、生成されたコードを Raspberry Pi でテストします。最初のステップでは、生成されたコードのディレクトリに、ECG の入力信号をコピーします。このディレクトリを見つけるには、手動で検索するか、raspi.utils.getRemoteBuildDirectory API を使用します。この関数は、関数 codegen を使用して生成されたバイナリ ファイルのディレクトリをリストします。バイナリが 1 つのディレクトリでのみ見つかったと仮定して、次を入力します。

applicationDirPaths = ...

raspi.utils.getRemoteBuildDirectory('applicationName','waveformSegmentation');

targetDirPath = applicationDirPaths{1}.directory;

入力ファイルの Raspberry Pi へのコピー

実行可能プログラムを実行するのに必要なファイルをコピーするには、putFile を使用します。これは、MATLAB Support Package for Raspberry Pi Hardware で提供されています。input.csv ファイルには、展開されたコードをテストするために使用されるサンプル ECG 信号が含まれています。

r.putFile('input.csv',targetDirPath);

input = dlmread('input.csv');

Raspberry Pi での実行可能プログラムの実行

MATLAB から Raspberry Pi 上の実行可能プログラムを実行し、出力ファイルを MATLAB に取得します。入力ファイル名は、実行可能ファイルのコマンド ライン引数として渡す必要があります。

exeName = 'waveformSegmentation.elf'; % Executable name

command = ['cd ' targetDirPath ';./' exeName];

system(r,command)

outputPath = strcat(targetDirPath,'/*.txt');

getFile(r,outputPath)

信号と予測ラベルを表示します。出力は以下の図のようになります。

load ecgsignal_test.mat;

labels = categorical(textread('out.txt','%s')');

msk = signalMask(labels(1,2000:3000));

plotsigroi(msk,test(1,2000:3000))

title('Predicted Labels')

参考文献

[1] McSharry, Patrick E., et al. "A dynamical model for generating synthetic electrocardiogram signals." IEEE® Transactions on Biomedical Engineering. Vol. 50, No. 3, 2003, pp. 289–294.

[2] Laguna, Pablo, Raimon Jané, and Pere Caminal. "Automatic detection of wave boundaries in multilead ECG signals: Validation with the CSE database." Computers and Biomedical Research. Vol. 27, No. 1, 1994, pp. 45–60.

[3] Goldberger, Ary L., Luis A. N. Amaral, Leon Glass, Jeffery M. Hausdorff, Plamen Ch. Ivanov, Roger G. Mark, Joseph E. Mietus, George B. Moody, Chung-Kang Peng, and H. Eugene Stanley. "PhysioBank, PhysioToolkit, and PhysioNet: Components of a New Research Resource for Complex Physiologic Signals." Circulation. Vol. 101, No. 23, 2000, pp. e215–e220. [Circulation Electronic Pages; https://circ.ahajournals.org/content/101/23/e215.full].

参考

アプリ

関数

トピック