Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

Sequence-to-Sequence 深層学習 Simulink モデルの汎用 C/C++ の生成

この例では、深層学習 Simulink® モデルからサードパーティの深層学習ライブラリに依存しない汎用 C/C++ 実行可能ファイルを生成する方法を示します。この例では、ターボファン エンジンの残存耐用期間 (RUL) を予測します。これは、エンジンの各種センサーからのデータを表す入力時系列の各ステップにおいてサイクル単位で測定されます。

この例のビデオによるデモについては、Generate Generic C/C++ Code for Deep Learning Networks in Simulink を参照してください。

この例は、MATLAB® Coder™ の "Generate Generic C/C++ Code for Sequence-to-Sequence Regression That Uses Deep Learning" の例に基づいています。詳細については、Generate Generic C/C++ Code for Sequence-to-Sequence Regression That Uses Deep Learningを参照してください。

前提条件

PIL 検証用に以下が必要になります。

  • STMicroelectronics STM32F407G-Discovery、STM32F746G-Discovery、または STM32F769I-Discovery ボード

  • USB type A Mini-B ケーブル

  • USB TTL-232 ケーブル - TTL-232R 3.3V (STM32F4-Discovery ボードのシリアル通信)

  • Embedded Coder® Support Package for STMicroelectronics Discovery Boards。このサポート パッケージをインストールするには、MATLAB の [ホーム] タブの [環境] セクションにある [アドオン] メニューを使用します。

事前学習済みの RUL ネットワーク

この例では、事前学習済みの LSTM ネットワークを使用して、サイクル単位で測定されるエンジンの残存耐用期間を予測します。LSTM ネットワークは、200 の隠れユニットをもつ LSTM 層に続き、サイズ 50 の全結合層とドロップアウト確率 0.5 のドロップアウト層で構成されます。このネットワークに [1] に記載された "Turbofan Engine Degradation Simulation Data Set" を使用して学習させてあります。学習データには、100 個のエンジンのシミュレートされた時系列データが含まれています。各シーケンスの長さはさまざまで、故障するまで使用 (RTF) した事例全体に対応します。テスト データには、100 個の部分シーケンスと、各シーケンスの最後における対応する残存耐用期間の値が含まれています。ネットワークの学習の詳細については、深層学習を使用した sequence-to-sequence 回帰 (Deep Learning Toolbox)の例を参照してください。

net = coder.loadDeepLearningNetwork('rulNetwork.mat')
net = 
  SeriesNetwork with properties:

         Layers: [6×1 nnet.cnn.layer.Layer]
     InputNames: {'sequenceinput'}
    OutputNames: {'regressionoutput'}

コード生成でサポートされるネットワーク、層、およびクラスの詳細については、コード生成でサポートされているネットワークとレイヤーを参照してください。

テスト データの準備

TurboFanRULValidate MAT ファイルを読み込みます。これには "Turbofan Engine Degradation Validation Data Set" が含まれています。この MAT ファイルに、Simulink モデルのテストに使用するセンサーの読み取り値を表す 100 サンプルの観測値を含む変数 XValidate が格納されます。

load('TurboFanRULValidate.mat')

入力検証データが Simulink のコード生成と互換性をもつように、独立した 100 個の各観測値のシーケンス長がゼロでパディングされ、均一なサイズの 17 行 303 列の入力配列が作成されます。

sequenceLengths = cellfun(@length,XValidate,'UniformOutput',true);
maxSequenceLen = max(sequenceLengths);
padFcn = @(x) [x,zeros(size(x,1),maxSequenceLen-size(x,2))];             
XValidatePad = cellfun(padFcn,XValidate,'UniformOutput',false);

その後、パディングされた値が 17×303×100 の数値配列に変換されます。このデータを Simulink モデルにインポートするには、データ値と空の時間ベクトルを含む構造体変数を指定します。シミュレーション時、最初のタイム ステップの入力が配列の最初の 17 行 303 列の要素から読み取られます。次に 2 番目のタイム ステップの値が 2 番目の要素からというように、合計 100 ステップまで読み取られます。

simin.time = [];
simin.signals.values = cell2mat(reshape(XValidatePad,1,1,[]));
simin.signals.dimensions = size(XValidatePad{1});

予測用の Simulink モデル

ターボファン エンジンの残存耐用期間の予測に使用する Simulink モデルを次に示します。このモデルでは、rulNetwork MAT ファイルから学習済みネットワークをインポートする Deep Neural Networks ライブラリの Predict ブロックを使用しています。さらに、ブロックの Mini-batch size パラメーターは 1 に設定されています。

model = 'rulPredict';
open_system(model)

シミュレーションの実行

Simulink モデルを検証するには、シミュレーションを実行します。

set_param(model,'SimulationMode','Normal');
sim(model);

Simulink モデルの出力 YPred にネットワークによる残存耐用期間の予測値が格納されます。この出力は、ゼロでパディングされた値からの結果を削除するために最初に平衡化されてから cell 配列に変換されます。

YPred_cell = squeeze(mat2cell(YPred,1,maxSequenceLen,ones(1,100)));

for t = 1:length(sequenceLengths)   
    YPred_cell{t}(:,sequenceLengths(t) + 1:end) = [];
end 

ランダムに選択された 4 つの観測値について、残存耐用期間 (RUL) の予測値をプロットし、それらを検証データと比較します。

observationIdx = randperm(100,4);
rulExamplePlots(observationIdx,YValidate,YPred_cell);

コード生成のためのモデルの構成

サードパーティの深層学習ライブラリに依存しない C/C++ コードを生成して実行可能ファイルをビルドするには、Embedded Coder™ から汎用リアルタイム (ERT) ターゲットを選択します。

cs = getActiveConfigSet(model);
switchTarget(cs,'ert.tlc',[]);

コード生成の固有のパラメーターを構成します。MAT ファイルのログを設定すると、生成コードから MAT ファイルへのシミュレーション データのリダイレクトが有効になります。

set_param(cs,'TargetLang','C');
set_param(cs,'Toolchain','Automatically locate an installed toolchain');
set_param(cs,'ObjectivePriorities','Execution efficiency');
set_param(cs,'DLTargetLibrary','None');
set_param(cs,'GenerateReport','on');
set_param(cs,'CodeInterfacePackaging','Nonreusable function'); 
set_param(cs,'MatFileLogging', 'on');

Simulink モデルの生成とビルド

slbuild コマンドを使用して Simulink モデルを生成およびビルドします。コード ジェネレーターは、ファイルを "ビルド フォルダー" に配置します。これは、現在の作業フォルダーの配下にある rulPredict_ert_rtw という名前のサブフォルダーです。

evalc("slbuild('rulPredict')");

生成された実行可能ファイルの実行

生成された実行可能ファイルを実行します。rulPredict 実行可能ファイルが正常に実行されると、現在の作業フォルダーに rulPredict MAT ファイルが作成されます。

if ispc
    status = system('rulPredict.exe');
else
    status = system('./rulPredict');
end 
** created rulPredict.mat ** 
 
load('rulPredict.mat')

出力 rt_YPred にネットワークによる残存耐用期間の予測値が格納されます。この出力は、ゼロでパディングされた値からの結果を削除するために最初に平衡化されてから cell 配列に変換されます。

rt_YPred_cell = squeeze(mat2cell(rt_YPred,1,maxSequenceLen,ones(1,100)));

for t = 1:length(sequenceLengths)   
    rt_YPred_cell{t}(:,sequenceLengths(t) + 1:end) = [];
end 

ランダムに選択された 4 つの観測値について、残存耐用期間 (RUL) の予測値をプロットし、それらを検証データと比較します。

rulExamplePlots(observationIdx,YValidate,rt_YPred_cell);

プロセッサインザループ (PIL) シミュレーションによるコード検証

展開コードの動作が設計と一致することを確認するために、組み込みボードで PIL シミュレーションを実行するように Simulink モデルを構成できます。PIL シミュレーションでは、STMicroelectronics® Discovery などの組み込みボードで生成コードが実行されます。PIL シミュレーションの結果が Simulink に転送され、シミュレーションとコード生成の結果の数値的等価性が検証されます。

この例では、STMicroelectronics Discovery ボードでの "Embedded Coder® Support Package for STMicroelectronics Discovery Boards" を使用した PIL 検証を示します。この例は STM32F746G-Discovery ボードで実行するように事前に構成されています。[モデル コンフィギュレーション パラメーター] の [ハードウェア実行] ペインにある [ハードウェア ボード] で選択することにより、サポートされている他の組み込みボードをこのモデルで使用するように構成できます。

テスト データの準備

PIL シミュレーション用に、この例では観測値をシーケンス長の順に並べ替えて最初の 10 個を選択します。これらの観測値がゼロでパディングされ、均一なサイズの 17 行 54 列の入力配列が作成されます。その後、パディングされた値が 17×54×10 の数値配列に変換されます。このデータを Simulink モデルにインポートするには、データ値と空の時間ベクトルを含む構造体変数を指定します。シミュレーション時、最初のタイム ステップの入力が配列の最初の 17 行 54 列の要素から読み取られます。次に 2 番目のタイム ステップの値が 2 番目の要素からというように、合計 10 ステップまで読み取られます。

[~,idx] = sort(cellfun(@length,XValidate));
XValidatePIL = XValidate(idx(1:10));
YValidatePIL = YValidate(idx(1:10));
sequenceLengths = cellfun(@length,XValidatePIL,'UniformOutput',true);
maxSequenceLen = max(sequenceLengths);
padFcn = @(x) [x,zeros(size(x,1),maxSequenceLen-size(x,2))];             
XValidatePILPad = cellfun(padFcn,XValidatePIL,'UniformOutput',false);
simin.time = [];
simin.signals.values = cell2mat(reshape(XValidatePILPad,1,1,[]));
simin.signals.dimensions = size(XValidatePILPad{1});

最上位モデルの PIL

rulPredict_pil は、rulPredict モデルを PIL 検証用に変更したバージョンです。テスト ベクトルを読み込むために、rulPredict_pil モデルでは From Workspace ブロックを Inport ブロックに置き換えてあります。Inport ブロックは、17 行 54 列の double データ型の配列を受け入れるように構成されています。

pilModel = 'rulPredict_pil';
open_system(pilModel);

rulPredict_pil モデルを "STM32F467G-Discovery" ターゲット用に構成します。

cs = getActiveConfigSet(pilModel);
set_param(cs,'HardwareBoard','STM32F746G-Discovery');
set_param(cs,'Toolchain','GNU Tools for ARM Embedded Processors');

STM32F4-Discovery ボードは、PIL 用に 2 種類の通信インターフェイスをサポートしています。ST-LINK とシリアルです。ST-LINK 通信インターフェイスでは、STM32F4-Discovery ボードをホスト コンピューターに接続するために使用する USB type A Mini-B ケーブルを除き、追加のケーブルやハードウェアを必要としません。シリアル通信インターフェイスでは、USB TTL-232 ケーブルが必要になります。シリアル通信インターフェイスを使用して PIL シミュレーションを実行すると、ST-LINK を使用して PIL シミュレーションを実行するよりもはるかに高速になります。この例はシリアル インターフェイスを使用するように構成されています。

さらに、[コンフィギュレーション パラメーター]、[ハードウェア実行]、[Target Hardware Resources]、[PIL] の [COM ポート] パラメーターを Windows コンピューターのシリアル インターフェイスのポート番号と一致するように設定する必要があります。

PIL シミュレーションの実行

PIL の結果をシミュレーションと比較するには、rulPredict_pil モデルをノーマル モードで実行してから PIL モードで実行します。

set_param(cs,'LoadExternalInput','on');
set_param(cs, 'ExternalInput','simin');
set_param(pilModel,'SimulationMode','Normal');

sim(pilModel);
YPred_ref = YPred_pil;

set_param(pilModel,'SimulationMode','Processor-in-the-Loop (PIL)')
sim(pilModel);

結果のプロット

出力 YPred_pilYPred_ref にネットワークによる残存耐用期間の予測値が格納されます。この出力は、ゼロでパディングされた値からの結果を削除するために最初に平衡化されてから cell 配列に変換されます。

PIL による残存耐用期間 (RUL) の予測値をプロットし、それらを検証データと比較します。

YPred_ref_cell = squeeze(mat2cell(YPred_ref,1,maxSequenceLen,ones(1,10)));
YPred_pil_cell = squeeze(mat2cell(YPred_pil,1,maxSequenceLen,ones(1,10)));

for t = 1:length(sequenceLengths)   
    YPred_ref_cell{t}(:,sequenceLengths(t) + 1:end) = [];
    YPred_pil_cell{t}(:,sequenceLengths(t) + 1:end) = [];
end 

rulExamplePlots([1:10],YValidatePIL,YPred_pil_cell);

PIL シミュレーションによる誤差を計算し、結果をプロットします。

YPred_error = YPred_ref-YPred_pil;

figure('Name', 'PIL Error')
for i = 1:10
    subplot(5,2,i)
    
    plot(YPred_error(:,:,i),'.-')
    maxerror = string(max(YPred_error(:,:,i)));
    ylim([-1e-4 1e-4])
    title("Test Observation " + i)
    xlabel("Time Step")
    ylabel("Difference")
end
legend(["Difference in Simulation Modes"],'Location','southeast')

サポート関数

function rulExamplePlots(observationIdx,YTest,YPred)
N = numel(observationIdx);

figure
for i = 1:N
    subplot(N/2,2,i)

    plot(YTest{observationIdx(i)},'--')
    hold on
    plot(YPred{observationIdx(i)},'.-')
    hold off

    ylim([0 175])
    title("Test Observation " + observationIdx(i))
    xlabel("Time Step")
    ylabel("RUL")
end
legend(["Test Data" "Predicted"],'Location','southeast')

end

参考文献

  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.