ドキュメンテーション

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

この例では、深層学習ネットワーク用に生成された CUDA® コードを Simulink® に統合する方法を説明します。GPU Coder™ は Simulink ブロックではサポートされていませんが、GPU Coder でダイナミック リンク ライブラリ (dll) を生成し、次にレガシ コード ツールを使用してそれを S-Function ブロックとして Simulink に統合することにより、Simulink で GPU の計算能力を使用することはできます。この概念を説明するための例として、GPU Coder による車線検出を使用します。元の例では OpenCV 関数を使った C++ ファイルを使用して、フレームを読み取り、車線を描画し、フレーム レート情報をビデオ出力の上に重ね合わせていました。しかし、この例では、Computer Vision Toolbox™ の Simulink ブロックを使用して同じ操作を実行します。

必要条件

  • Compute Capability 3.2 以上の CUDA 対応 NVIDIA® GPU。

  • NVIDIA CUDA ツールキットおよびドライバー。

  • NVIDIA cuDNN ライブラリ (v7)。

  • コンパイラおよびライブラリの環境変数。サポートされているコンパイラおよびライブラリのバージョンの詳細は、Third-party Products を参照してください。環境変数の設定は、Environment Variables を参照してください。

  • Simulink (モデルの作成用)。

  • Computer Vision Toolbox™ (この例で使用するビデオ リーダー、ビューアー、および車線区分線機能用)。

  • Deep Learning Toolbox™ (SeriesNetwork オブジェクトを使用するため)。

フォルダーの作成と関連ファイルのコピー

次のコード行は、現在の作業フォルダー (pwd) にフォルダーを作成し、すべての関連ファイルをこのフォルダーにコピーします。この操作を実行したくない、またはこのフォルダーにファイルを生成できない場合、現在の作業フォルダーを変更してください。

gpucoderdemo_setup('gpucoderdemo_lane_detection_simulink');

GPU 環境の検証

関数 coder.checkGpuInstall を使用し、この例を実行するのに必要なコンパイラおよびライブラリが適切に設定されていることを検証します。

envCfg = coder.gpuEnvConfig('host');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

ワークフローの概要

次の図に、Legacy Code Tool を使用して、深層学習ネットワーク用に生成された CUDA コードを Simulink に統合するための一般的な手順を示しています。

事前学習済みの SeriesNetwork の取得

[laneNet, coeffMeans, coeffStds] = getLaneDetectionNetwork();

事前学習済みの SeriesNetwork のアーキテクチャは AlexNet に似ていますが、最後の数層は、規模の小さい全結合層と回帰出力層に置き換えられています。このネットワークは入力としてイメージを受け取り、自車の左右の車線に対応する 2 つの車線境界線を出力します。各車線境界線は、放物線方程式 によって表すことができます。ここで、 は横方向オフセット、 は車両からの縦方向の距離です。このネットワークは、左右の車線境界線の放物線方程式を記述する 3 つのパラメーター 、および を出力します。

メイン エントリ ポイント関数

この例では、元の例と同じエントリポイント関数 detect_lane.m を使用します。関数 detect_lane は、、および パラメーターから、車線の位置に対応する 座標と 座標を計算します。関数 detect_lane は、 座標と 座標をイメージの座標にマッピングする計算も実行します。

関数の DLL の生成

変数 coeffStds および coeffMeans には、学習済みネットワークからの平均値と標準偏差値が格納されます。これらの値はシミュレーション中に必要になります。関数 detect_lane を Simulink から GPU で実行するには、GPU Coder を使用して共有ライブラリを生成します。関数 detect_lane の入力は、ビデオ フレーム、平均値、および標準偏差値です。-args オプションを使用して渡される値は、これらの入力のサイズを反映します。生成されたライブラリを最上位フォルダーにコピーします。

coeffStds = [0.002995595096857,0.076600147330248,0.631288082601997,0.002600128777275,0.073641936476251,0.984567040148445];
coeffMeans = [-1.939450143265110e-04,1.557727430093527e-04,1.473991581706893,-1.909623131136531e-04,0.004474616468621,-1.378729416735388];
Isize = single(zeros(227,227));

cfg = coder.gpuConfig('dll');
cfg.TargetLang = 'C++';
cfg.GenerateReport = true;
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -args {ones(227,227,3,'single'),ones(1,6,'double'),ones(1,6,'double')} -config cfg detect_lane

if ispc
    copyfile(fullfile(pwd, 'codegen','dll', 'detect_lane','detect_lane.dll'), pwd);
else
    copyfile(fullfile(pwd, 'codegen','dll', 'detect_lane','detect_lane.so'), pwd);
end
Code generation successful: To view the report, open('codegen/dll/detect_lane/html/report.mldatx').

入力データ変数への非結合アクセスに関する警告がスローされます。これは、codegen コマンドにより列優先コードが生成されるためです。この例では、この警告は無視できます。

S-Function の生成とコンパイル

車線検出の例は、NVIDIA CUDA ランタイム、cuBLAS、および cuDNN ライブラリに依存しています。以下を指定するために Legacy Code Tool のデータ構造体を使用します。

  • S-Function の名前

  • 既存の C++ 関数の仕様

  • コンパイルに必要なすべてのライブラリ、ヘッダー ファイルとそのパス

  • 生成された S-Function のオプション

構造を定義した後、関数 legacy_code を以下のために使用します。

  • C++ 関数用の Legacy Code Tool のデータ構造体の初期化

  • シミュレーション中に使用する S-Function の生成

  • 動的読み込み可能な実行可能ファイル (MEX) への生成された S-Function のコンパイルとリンク

  • 生成された S-Function を呼び出すためのマスク S-Function ブロックの生成

srcPath = fullfile(pwd, 'codegen', 'dll', 'detect_lane');

if ispc
    cuPath = getenv('CUDA_PATH');
    cudaLibPath = fullfile(cuPath,'lib','x64');
    cudaIncPath = fullfile(cuPath,'include');

    cudnnPath = getenv('NVIDIA_CUDNN');
    cudnnIncPath = fullfile(cudnnPath,'include');
    cudnnLibPath = fullfile(cudnnPath,'lib','x64');

    libs = {'detect_lane.lib','cudart.lib','cublas.lib','cudnn.lib'};

else
    [~,nvccPath] = system('which nvcc');
    nvccPath = regexp(nvccPath, '[\f\n\r]', 'split');
    cuPath = erase(nvccPath{1},'/bin/nvcc');
    cudaLibPath = fullfile(cuPath,'lib64');
    cudaIncPath = fullfile(cuPath,'include');

    cudnnPath = getenv('NVIDIA_CUDNN');
    cudnnIncPath = fullfile(cudnnPath,'include');
    cudnnLibPath = fullfile(cudnnPath,'lib64');

    libs = {'detect_lane.so','libcudart.so','libcublas.so','libcudnn.so'};
end

headerPath = {srcPath;cudnnIncPath;cudaIncPath};
libPath = {srcPath;cudnnLibPath;cudaLibPath};

% Define the Legacy Code Tool data structure
def = legacy_code('initialize');
def.SFunctionName = 'lane_detect_sfun';
def.OutputFcnSpec = 'void detect_lane(single u1[154587],double u2[6],double u3[6],uint8 y1[1],single y2[56],single y3[56])';
def.IncPaths = headerPath;
def.HeaderFiles = {'detect_lane.h'};
def.LibPaths = libPath;
def.HostLibFiles = libs;
def.Options.useTlcWithAccel = false;
def.Options.language = 'C++';

legacy_code('sfcn_cmex_generate', def);
legacy_code('compile', def);
### Start Compiling lane_detect_sfun
    mex('lane_detect_sfun.cpp', '-I/mathworks/devel/sbs/37/vravicha.lcmFirst/matlab/toolbox/gpucoder/gpucoderdemos/gpucoderdemo_lane_detection_simulink2/codegen/dll/detect_lane', '-I/mathworks/hub/3rdparty/R2019a/3840803/glnxa64/cuDNN/cuda/include', '-I/usr/local/cuda/include', '-I/mathworks/devel/sbs/37/vravicha.lcmFirst/matlab/toolbox/gpucoder/gpucoderdemos/gpucoderdemo_lane_detection_simulink2', '/mathworks/devel/sbs/37/vravicha.lcmFirst/matlab/toolbox/gpucoder/gpucoderdemos/gpucoderdemo_lane_detection_simulink2/codegen/dll/detect_lane/detect_lane.so', '/usr/local/cuda/lib64/libcudart.so', '/usr/local/cuda/lib64/libcublas.so', '/mathworks/hub/3rdparty/R2019a/3840803/glnxa64/cuDNN/cuda/lib64/libcudnn.so')
Building with 'g++'.
MEX completed successfully.
### Finish Compiling lane_detect_sfun
### Exit

OutputFcnSpec 引数は、各タイム ステップで S-Function から呼び出す関数を指定します。codegen フォルダーの detect_lane.h ヘッダー ファイルは関数の仕様情報を提供します。関数 detect_lane の引数は、入力端子用の一意な番号が付けられた u トークンと出力端子用の y トークンを使用して、Simulink S-Function ブロックにマッピングしなければなりません。tmwtypes.h で定義されたコード生成のデータ型も、Simulink でサポートされるデータ型にマッピングしなければなりません。詳細については、Declaring Legacy Code Tool Function Specifications を参照してください。この例には既に完全な Simulink モデルが含まれているため、S-Function ブロックの生成は実行されません。S-Function ブロックを生成するには、以下を使用します。

legacy_code('slblock_generate', def);

車線検出用 Simulink モデルの作成

元の例の main_lanenet.cpp ファイル内で行われているすべての前処理および後処理演算を Simulink に移動しなければなりません。Input Video Processing サブシステムは、multimedia reader ブロックで実行された正規化を除去し、入力ビデオ フレームのサイズを車線検出ネットワークの入力層サイズ (227x227x3) に変更します。次に、3 次元ビデオ フレームを detect_lane ライブラリで要求される 1 次元ベクトルに変換します。Lane Points Enabled Subsystem は、左右にある車線の点の処理を実行して、それが Draw Lanes ブロックに適したものになるようにします。Simulink モデルはビデオ表示を使用し、サンプル ビデオに車線検出を表示します。

open_system('main_lanenet');
set_param('main_lanenet', 'SimulationCommand', 'update');

Simulink モデルの実行 (車線検出)

シミュレーションを実行し、サンプル ビデオに車線検出を表示します。

sim('main_lanenet', 'timeout', 30);

コマンドの実行: クリーンアップ

メモリ リソースをクリアし、一時ファイルを削除して、元のフォルダーに戻します。

close_system('main_lanenet');
clear mex
cleanup