web-dev-qa-db-ja.com

TensorRTを使用してセマンティックセグメンテーションネットワーク(U-Net)をデプロイする(アップサンプリングサポートなし)

TensorRTでトレーニング済みのU-Netをデプロイしようとしています。モデルはKerasを使用してトレーニングされました(バックエンドとしてTensorflowを使用)。コードは次のコードと非常に似ています: https://github.com/zhixuhao/unet/blob/master/model.py

次のようなコードを使用して、モデルをUFF形式に変換したとき:

import uff
import os
uff_fname = os.path.join("./models/", "model_" + idx + ".uff")
uff_model = uff.from_tensorflow_frozen_model(
    frozen_file = os.path.join('./models', trt_fname), output_nodes = output_names, 
    output_filename = uff_fname
)

次の警告が表示されます。

Warning: No conversion function registered for layer: ResizeNearestNeighbor yet.
Converting up_sampling2d_32_12/ResizeNearestNeighbor as custom op: ResizeNearestNeighbor
Warning: No conversion function registered for layer: DataFormatVecPermute yet.
Converting up_sampling2d_32_12/Shape-0-0-VecPermuteNCHWToNHWC-LayoutOptimizer as custom op: DataFormatVecPermute

私は、アップサンプリングレイヤーをアップサンプリング(双線形補間)で置き換え、畳み込みを転置することでこれを回避しようとしました。しかし、コンバーターは私に同様のエラーをスローします。私は https://docs.nvidia.com/deeplearning/sdk/tensorrt-support-matrix/index.html を確認しましたが、これらのすべての操作がまだサポートされていないようです。

この問題の回避策はありますか? TensorRTが好きで、アップサンプリングがサポートされている他の形式/フレームワークはありますか?または、サポートされている他の操作に置き換えることはできますか?

また、TensorRTでサポートされていない操作を置き換えるためにカスタマイズされた操作を追加できることもどこかで見ました。ワークフローがどうなるかはわかりませんが。また、カスタムレイヤーの例を誰かが指摘できると、とても役に立ちます。

前もって感謝します!

18
Yayuchen

警告は、すでに述べたように、これらの操作がTensorRTによって まだサポートされていない であるためです。残念ながら、これを修正する簡単な方法はありません。サポートされている組み合わせの操作のみを使用するには、グラフを変更する必要があります(トレーニング トレーニング後 でも)。または、これらの操作を カスタムレイヤー と自分で記述します。

ただし、C++の他のデバイスで推論を実行するより良い方法があります。 TensorFlowとTensorRTを組み合わせたもの を使用できます。 TensorRTは、サポートする演算のグラフを分析し、それらをTensorRTノードに変換します。残りのグラフは、通常どおりTensorFlowによって処理されます。詳細 ここ 。このソリューションは、自分で操作を書き換えるよりもはるかに高速です。唯一の複雑な部分は、ターゲットデバイスのソースからTensorFlowをビルドし、 動的ライブラリを生成するtensorflow_cc。最近、さまざまなアーキテクチャへのTensorFlowポートの多くのガイドとサポートがあります。 [〜#〜]腕[〜#〜]

2
Xenon

ちょっと似たようなことをしたのですが、問題に対処する最善の方法は、モデルを.onnxにエクスポートすることです。 this oneサポートマトリックスのonnx を確認してください。アップサンプルがサポートされています: enter image description here

次に、 https://github.com/onnx/onnx-tensorrt を使用してonnx-modelをtensorrtに変換できます。これを使って、pytorchでトレーニングしたネットワークを変換しますそしてそれはアップサンプルを持っていました。 onnx-tensorrtのリポジトリはもう少しアクティブです。prタブをチェックすると、そこからカスタムレイヤーとフォークを作成している他の人をチェックできます。

1
bpinaya

更新09/28/2019

Nvidiaは約2週間前に TensorRT 6.0.1 をリリースし、「IResizeLayer」という新しいAPIを追加しました。このレイヤーは「最も近い」補間をサポートしているため、アップサンプリングの実装に使用できます。カスタムレイヤー/プラグインを使用する必要はもうありません!

元の答え:

ここに投稿されたすべての回答と提案に感謝します!

最後に、TensorRT C++ APIにネットワークを直接実装し、.h5モデルファイルから重みをロードしました。ソリューションのプロファイルを作成して磨く時間はまだありませんが、提供されたテスト画像によると、推論は機能しているようです。

採用したワークフローは次のとおりです。

ステップ1:アップサンプリングレイヤーをコーディングします。

U-Netモデルでは、すべてのアップサンプリングレイヤーに(2、2)のスケーリングファクターがあり、すべてResizeNearestNeighbor補間を使用します。基本的に、元のテンソルの(x、y)のピクセル値は、(2x、2y)、(2x + 1、2y)、(2x、2y + 1)および(2x + 1、2y + 1)の4つのピクセルになります。 )新しいテンソルで。これは、CUDAカーネル関数に簡単にコード化できます。

アップサンプリングカーネルを取得したら、TensorRT API、具体的には IPluginV2Extクラス でラップする必要があります。開発者用リファレンスには、実装する必要のある関数の説明がいくつかあります。 CUDAカーネルがそこで実行されるため、enqueue()が最も重要な関数だと思います。

TensorRT Samplesフォルダにも例があります。私のバージョンでは、次のリソースが役立ちます。

ステップ2:TensorRT APIを使用して残りのネットワークをコーディングする

ネットワークの残りの部分は非常に単純である必要があります。 TensorRTネットワーク定義 から別の「addxxxLayer」関数を呼び出すだけです。

覚えておくべきことの1つは、使用しているTRTのバージョンによって、パディングを追加する方法が異なる場合があるということです。最新バージョン(5.1.5)では、開発者がaddConvolution()にパラメーターを追加できるため、適切なパディングモードを選択できます。

私のモデルはKerasを使用してトレーニングされました。デフォルトのパディングモードでは、パディングの総数が均一でない場合、右と下のパディングが増えます。詳細はこちら Stack Overflow link を確認してください。 5.1.5には、このパディング方式を表す mode があります。

古いバージョン(5.1.2.2)を使用している場合は、畳み込みレイヤーの前に 別のレイヤー としてパディングを追加する必要があります。これには、プリパディングとポストパディングの2つのパラメーターがあります。

また、すべてがTensorRTのNCHWです

役立つサンプル:

  • TensorRT-5.1.2.2/samples/sampleMNISTAP

ステップ3:ウェイトをロードする

TensorRTは[out_c、in_c、filter_h、filter_w]の形式の重みを必要とします。これは アーカイブされたドキュメント で言及されています。 Kerasは[filter_h、filter_w、c_in、c_out]という形式の重みを持っています。

Pythonでmodel.save_weights('weight.h5')を呼び出して、純粋なウェイトファイルを取得しました。次に、h5pyを使用してNumpy配列に重みを読み取り、転置を実行して、転置した重みを新しいファイルとして保存できます。また、h5pyを使用してグループとデータセットの名前を特定しました。この情報は、 HDF5 C++ API を使用してウェイトをC++コードにロードするときに使用されました。

C++コードとPythonコードの間で出力層を層ごとに比較しました。U-Netの場合、2番目のプール後の3番目のブロックまで、すべてのアクティベーションマップは同じです。その後、ピクセル値にはわずかな違いがあります。絶対パーセンテージエラーは10 ^ -8なので、それほど悪いとは思われません。C++の実装を改善する過程にあります。

繰り返しますが、この投稿で得たすべての提案と回答に感謝します。私たちのソリューションも役立つことを願っています!

1
Yayuchen