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 ネットワークに学習させる方法の詳細については、深層学習を使用したシーケンスの分類 (Deep Learning Toolbox)の例を参照してください。

この例では、LSTM ネットワークを使用して予測を実行する 2 通りの方法を示します。

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

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

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

メモ:

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

  • この例で使用する ARM Compute Library のバージョンは、コード生成でサポートされている最新バージョンではない可能性があります。サポートされるコンパイラとライブラリのバージョンの詳細については、サードパーティ ライブラリを使用するコードの生成を参照してください。

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

前提条件

  • MATLAB® Coder™

  • Embedded Coder®

  • Deep Learning Toolbox™

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

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

  • Raspberry Pi ハードウェア

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

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

テスト データのダウンロードと準備

このセクションでは、この例で使用するテスト データをダウンロードして準備する手順について簡単に説明します。Turbofan Engine Degradation Simulation データ セットと前処理の手順の詳細については、深層学習を使用した sequence-to-sequence 回帰 (Deep Learning Toolbox)の例を参照してください。

データ セットのダウンロード

Turbofan Engine Degradation Simulation データ セットを保存するためのディレクトリを作成します。

dataFolder = fullfile(tempdir,"turbofan");
if ~exist(dataFolder,'dir')
    mkdir(dataFolder);
end

Turbofan Engine Degradation Simulation データ セットをダウンロードして解凍します。

filename = matlab.internal.examples.downloadSupportFile("nnet","data/TurbofanEngineDegradationSimulationData.zip");
unzip(filename,dataFolder)

学習データの平均と標準偏差の計算

以下の手順では、学習データの平均と標準偏差を使用してテスト用の予測子を正規化します。そのため、まず学習データを使用してこれらの正規化パラメーターを計算する必要があります。

学習データを読み込みます。各列は 1 つの観測値で、各行は 1 つの特徴量です。定数値をもつ特徴量を削除します。

filenamePredictors = fullfile(dataFolder,"train_FD001.txt");
[XTrain] = processTurboFanDataTrain(filenamePredictors);

m = min([XTrain{:}],[],2);
M = max([XTrain{:}],[],2);
idxConstant = M == m;

for i = 1:numel(XTrain)
    XTrain{i}(idxConstant,:) = [];
end

すべての観測値の平均と標準偏差を計算します。

mu = mean([XTrain{:}],2);
sig = std([XTrain{:}],0,2);

テスト データの準備

この例に添付されている関数 processTurboFanDataTest を使用してテスト データを準備します。関数 processTurboFanDataTestfilenamePredictorsfilenameResponses からデータを抽出し、テスト用の予測子と応答シーケンスをそれぞれ含む cell 配列 XTest および YTest を返します。

filenamePredictors = fullfile(dataFolder,"test_FD001.txt");
filenameResponses = fullfile(dataFolder,"RUL_FD001.txt");
[XTest,YTest] = processTurboFanDataTest(filenamePredictors,filenameResponses);

学習データから計算された idxConstant を使用して、定数値をもつ特徴量を削除します。学習データから計算されたパラメーター mu および sig を使用して、テスト用の予測子を正規化します。しきい値 150 でテスト用の応答をクリップします。これは、ネットワークの学習中に学習データに対して使用されたクリップしきい値と同じ値です。

thr = 150;
for i = 1:numel(XTest)
    XTest{i}(idxConstant,:) = [];
    XTest{i} = (XTest{i} -  mu) ./ sig;
    YTest{i}(YTest{i} > thr) = thr;
end

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

指定したエントリポイント関数の 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 が Version 20.02.1 であると仮定します。

% dlcfg = coder.DeepLearningConfig('arm-compute');
% dlcfg.ArmComputeVersion = '20.02.1';
% 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 は、時系列データ セット全体を入力として受け取り、それを予測のためにネットワークに渡します。特に、この関数は深層学習を使用したシーケンスの分類 (Deep Learning Toolbox)の例で学習した LSTM ネットワークを使用します。この関数は、ネットワーク オブジェクトを rul_lstmnet.mat ファイルから永続変数に読み込み、以降の予測呼び出しではこの永続オブジェクトを再利用します。sequence-to-sequence LSTM ネットワークでは、データ シーケンスの個々のタイム ステップで異なる予測を行うことができます。

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

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コマンドを使用してコードを生成するには、関数coder.typeofを使用してエントリポイント関数への入力引数の型とサイズを指定します。この例では、入力は特徴次元値 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 関数のテスト データについての実行

変数 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 に timeseries データ全体をすべて一度に渡す代わりに、関数 predictAndUpdateState を使用して、入力データをセグメント単位でストリーミングして予測を実行できます。

エントリポイント関数 rul_lstmnet_predict_and_update は、単一のタイム ステップ入力を受け入れ、関数predictAndUpdateState (Deep Learning Toolbox)を使用して処理します。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 は呼び出しごとに単一のタイム ステップ データを受け入れるため、可変のシーケンス長ではなく固定のシーケンス長 1 をもつように matrixInput 入力型を指定します。

% 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

関数 rul_lstmnet_predict_and_update にすべてのタイム ステップを 1 つずつ渡した後、出力結果は、一度にすべての入力を渡した 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.

参考

| | | (Deep Learning Toolbox)

関連するトピック