Main Content

Raspberry Pi での LSTM ネットワークのコード生成

この例では、ARM® Compute Library を使用する事前学習済みの長短期記憶 (LSTM) ネットワークのコードを生成し、Raspberry Pi™ ターゲットにコードを展開する方法を説明します。この例では、LSTM ネットワークがマシンの残存耐用期間 (RUL) を予測します。ネットワークは、エンジン内のさまざまなセンサーを表す時系列データ セットを入力として受け取ります。ネットワークは、サイクルで測定されたエンジンの残存耐用期間を出力として返します。

この例では、[1] に記載のある Turbofan Engine Degradation Simulation Data Set を使用します。データ セットには 100 個の学習観測値と 100 個のテスト観測値が含まれています。学習データには、100 個のエンジンのシミュレートされた時系列データが含まれています。各シーケンスには 17 個の特徴があり、長さはさまざまで、故障するまで使用 (RTF) した事例全体に対応します。テスト データには、100 個の部分シーケンスと、各シーケンスの最後における対応する残存耐用期間の値が含まれています。

この例では事前学習済みの LSTM ネットワークを使用します。LSTM ネットワークに学習させる方法の詳細については、深層学習を使用したシーケンスの分類の例を参照してください。

この例は、LSTM ネットワークを使用して、予測を実行するための 2 つの異なる方法を示しています。

  • 1 番目の方法は、標準の LSTM ネットワークを使用し、時系列データのセットに対して推論を実行します。

  • 2 番目の方法は、同じ LSTM ネットワークのステートフルな動作を利用します。この方法では、一度にデータの単一のタイムステップを渡し、ネットワークにはタイム ステップごとにその状態を更新させます。

この例では、PIL ベースのワークフローを使用して、MEX 関数を生成します。この関数は、MATLAB からターゲット ハードウェアで生成された実行可能ファイルを呼び出します。

メモ:

  • この例のコード行はコメント アウトされています。例を実行する前に、コメントを解除してください。

  • この例で使用されている ARM Compute Library のバージョンは、コード生成でサポートされている最新バージョンではない可能性があります。サポートされているコンパイラおよびライブラリのバージョンの詳細は、サードパーティ製のハードウェアとソフトウェア (MATLAB Coder)を参照してください。

  • この例は、MATLABOnline ではサポートされていません。

必要条件

  • MATLAB® Coder™

  • Embedded Coder®

  • Deep Learning Toolbox™

  • MATLAB Coder Interface for Deep Learning Libraries。このサポート パッケージをインストールするには、アドオン エクスプローラーを使用します。

  • MATLAB Support Package for Raspberry Pi Hardware。このサポート パッケージをインストールするには、アドオン エクスプローラーを使用します。

  • Raspberry Pi ハードウェア

  • ARM Compute Library (ターゲット ARM ハードウェア上)

  • コンパイラおよびライブラリの環境変数。環境変数の設定は、環境変数 (MATLAB Coder)を参照してください。

スタティック ライブラリ用のコード生成構成オブジェクトの設定

指定されたエントリポイント関数に対して PIL MEX 関数を生成するには、スタティック ライブラリのコード構成オブジェクトを作成し、検証モードを 'PIL' に設定します。ターゲット言語を C++ に設定します。

% cfg = coder.config('lib', 'ecoder', true);
% cfg.VerificationMode = 'PIL';
% cfg.TargetLang = 'C++';

深層学習コード生成用の構成オブジェクトの設定

coder.ARMNEONConfig オブジェクトを作成します。Compute Library のバージョンと ARM アーキテクチャを指定します。この例では、Raspberry Pi ハードウェアの ARM Compute Library がバージョン 19.05 であると想定しています。

% dlcfg = coder.DeepLearningConfig('arm-compute');
% dlcfg.ArmComputeVersion = '19.05';
% dlcfg.ArmArchitecture = 'armv7';

コード生成構成オブジェクトの DeepLearningConfig プロパティに、深層学習構成オブジェクトを設定します。

% cfg.DeepLearningConfig = dlcfg;

Raspberry Pi への接続の作成

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

  • raspiname: 自分の Raspberry Pi の名前

  • username: 自分のユーザー名

  • password: 自分のパスワード

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

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

Raspberry Pi 用の coder.Hardware オブジェクトを作成してコード生成構成オブジェクトに追加します。

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

1 番目の方法: LSTM ネットワークの PIL MEX 関数の生成

この方法では、エントリポイント関数 rul_lstmnet_predict のコードを生成します。

エントリポイント関数 rul_lstmnet_predict.m は、時系列データ セット全体を入力として受け取り、予測のためにネットワークに渡します。具体的には、関数は深層学習を使用したシーケンスの分類の例で学習させる LSTM ネットワークを使用します。関数は、ネットワーク オブジェクトを rul_lstmnet.mat ファイルから永続変数に読み込み、以降の予測呼び出しではこの永続オブジェクトを再利用します。sequence-to-sequence LSTM ネットワークでは、データ シーケンスの個々のタイム ステップで異なる予測を行うことができます。

ネットワーク アーキテクチャの対話的な可視化とネットワーク層についての詳細情報を表示するには、関数analyzeNetworkを使用します。

type('rul_lstmnet_predict.m')
function out =  rul_lstmnet_predict(in) %#codegen

% Copyright 2019 The MathWorks, Inc. 

persistent mynet;

if isempty(mynet)
    mynet = coder.loadDeepLearningNetwork('rul_lstmnet.mat');
end


out = mynet.predict(in); 

codegen (MATLAB Coder)コマンドを使用してコードを生成し、関数coder.typeof (MATLAB Coder)を使用してエントリポイント関数への入力引数の型とサイズを指定します。この例では、入力は、特徴次元値 17 と可変のシーケンス長をもつ double のデータ型です。シーケンス長を可変サイズとして指定し、任意の長さの入力シーケンスについての予測を実行します。

% matrixInput = coder.typeof(double(0),[17 Inf],[false true]);

codegen コマンドを実行し、ホスト プラットフォームで PIL ベースの MEX 関数 rul_lstmnet_predict_pil を生成します。

% codegen -config cfg rul_lstmnet_predict -args {matrixInput} -report

テスト データでの生成された PIL MEX 関数の実行

MAT ファイル RULTestData を読み込みます。この MAT ファイルには、生成コードをテストできるセンサーの読み取り値のサンプル時系列を含む変数 XTestYTest が保存されます。このテスト データは、データの前処理の後に、深層学習を使用したシーケンスの分類の例から取得します。

load RULTestData;

変数 XTest には、100 個の入力観測値が含まれています。各観測には、シーケンス長が異なる 17 の特徴があります。

XTest(1:5)
ans=5×1 cell array
    {17×31  double}
    {17×49  double}
    {17×126 double}
    {17×106 double}
    {17×98  double}

変数 YTest には、入力変数 XTest に対応する 100 個の出力観測値が含まれています。各出力観測値は、シーケンス全体の各タイム ステップ データに対してサイクルで測定される残存耐用年数 (RUI) の値です。

YTest(1:5)
ans=5×1 cell array
    {[                                                                                                                                                                                                                                                                                                                                                             142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112]}
    {[                                                                                                                                                                                                                                                                                       146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98]}
    {[150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69]}
    {[                                                                   150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82]}
    {[                                                                                          150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91]}

生成された MEX 関数 rul_lstmnet_predict_pil をランダムなテスト データ セットで実行します。

% idx = randperm(numel(XTest), 1);
% inputData = XTest{idx};

% YPred1 = rul_lstmnet_predict_pil(inputData);

予測とテスト データとの比較

プロットを使用して MEX の出力データをテスト データと比較します。

% figure('Name', 'Standard LSTM', 'NumberTitle', 'off');
%     
% plot(YTest{idx},'--')
% hold on
% plot(YPred1,'.-')
% hold off
% 
% ylim([0 175])
% title("Test Observation " + idx)
% xlabel("Time Step")
% ylabel("RUL measured in cycles")

PIL のクリア

% clear rul_lstmnet_predict_pil;

2 番目の方法: ステートフルな LSTM ネットワークの PIL MEX 関数の生成

時系列データ全体をすべて一度に渡して predict で予測する代わりに、関数 predictAndUpdateState を使用して入力データをセグメントごとにストリーミングすることで予測を実行できます。

エントリポイント関数 rul_lstmnet_predict_and_update.m は、単一のタイムステップ入力を受け入れ、その入力を関数predictAndUpdateStateを使用して処理します。predictAndUpdateState は、入力タイムステップの予測を返し、ネットワークを更新して以降の入力が同じサンプルに続くタイム ステップとして扱われるようにします。

type('rul_lstmnet_predict_and_update.m')
function out = rul_lstmnet_predict_and_update(in) %#codegen

% Copyright 2019 The MathWorks, Inc. 

persistent mynet;

if isempty(mynet)
    mynet = coder.loadDeepLearningNetwork('rul_lstmnet.mat');
end

[mynet, out] = predictAndUpdateState(mynet, in);

end

codegen コマンドの入力タイプを作成します。rul_lstmnet_predict_and_update は、呼び出しごとに単一のタイムステップ データを受け入れ、入力タイプ matrixInput を、可変のシーケンス長ではなく固定のシーケンス長になるように 1 に指定します。

% matrixInput = coder.typeof(double(0),[17 1]);

codegen コマンドを実行して、ホスト プラットフォームで PIL ベースの MEX 関数 rul_lstmnet_predict_and_update_pil を生成します。

% codegen -config cfg rul_lstmnet_predict_and_update -args {matrixInput} -report

テスト データでの生成された PIL MEX 関数の実行

% Run generated MEX function(|rul_lstmnet_predict_and_update_pil|) for each
% time step data in the inputData sequence.

% sequenceLength = size(inputData,2);
% YPred2 = zeros(1, sequenceLength);
% for i=1:sequenceLength
%     inTimeStep = inputData(:,i);
%     YPred2(:, i) = rul_lstmnet_predict_and_update_pil(inTimeStep);
% end

すべてのタイムステップを 1 つずつ関数 rul_lstmnet_predict_and_update に渡した後、結果の出力は、すべての入力を一度に渡した 1 番目の方法の出力と同じになります。

予測とテスト データとの比較

プロットを使用して MEX の出力データをテスト データと比較します。

% figure('Name', 'Statefull LSTM', 'NumberTitle', 'off');
% 
% 
% plot(YTest{idx},'--')
% hold on
% plot(YPred2,'.-')
% hold off
% 
% ylim([0 175])
% title("Test Observation " + idx)
% xlabel("Time Step")
% ylabel("RUL measured in cycles")

PIL のクリア

% clear rul_lstmnet_predict_and_update_pil;

参考文献

[1] Saxena, Abhinav, Kai Goebel, Don Simon, and Neil Eklund. "Damage propagation modeling for aircraft engine run-to-failure simulation." In Prognostics and Health Management, 2008. PHM 2008. International Conference on, pp. 1-9. IEEE, 2008.

参考

(MATLAB Coder) | (MATLAB Coder) | (MATLAB Coder) |

関連するトピック