TensorRT 7 でさらに快適な高速推論

オプティムの R&D チームで Deep な画像解析をやっている奥村です。TensorRT 7 の変更点についてメモしました。非推奨機能に関するポリシーの明確化や、NLP、特に BERT に関するサポートの拡充、ありそうでなかった PReLU のサポートが気になった変更点です。

はじめに

2019/12/18 の Tweet で TensorRT 7 のリリースを発見しました。TensorRT 6.0.1 のリリースから約三ヶ月ぶりのリリースとなります。今回も前回と同じく RC がなく、いきなり GA となっています。気になった内容がいくつかあったので、TensorRT 7.0.0 のリリースノートをベースに、意訳(直訳)したものをメモしました。公式情報ではないので参考程度にしてください。TensorRT については特にここでは触れませんが、 TensorRT で物体検出・姿勢推定はどれくらい速くなる? - OPTiM TECH BLOGTensorRT 6 でさらに快適な高速推論 - OPTiM TECH BLOG で少し触れていますので興味があれば参照してみてください。

気になった内容

非推奨機能に関するポリシー

これまでいくつかの機能は非推奨としてマークされていましたが、今回のリリースでそのポリシーが明確化されました。特に、TensorRT 8 のリリースでは、TensorRT 6 以前で非推奨となっていた機能が削除される予定らしく、注意が必要になります。以降、TensorRT 9 では TensorRT 7 の非推奨機能が削除、TensorRT 10 では TensorRT 8 の非推奨機能が削除・・・となるようです。

TensorRT 7 時点での非推奨機能は TensorRT: Deprecated List、TensorRT 6 時点での非推奨機能は TensorRT: Deprecated List にまとまっているので、これらを使っていれば、新しい機能で置き換えていく必要があります。

一部のパーザーの非推奨化

今回、Caffe パーザーと UFF パーザーが非推奨としてマークされました。TensorRT 9 で削除される可能性が大きいですので移行が必要になりそうです。ONNX については onnx-tensorrt でのサポートが続きそうです。

PReLU のビルトインサポート

ありそうでなかった PReLU が IParametricReluLayer クラスでビルトインサポートされました。これまではプラグインとして CUDA カーネルを実装する必要がありましたが、それが不要になります。

意訳

TensorRT 7.0.0.11 GA

これは Linux と Windows ユーザー向けの TensorRT 7.0.0 のリリースノートです。このリリースには、以前の TensorRT 6.0.1 リリースからの修正と、以下の追加の変更を含みます。このリリースノートは、特に記載のない限りはワークステーション、サーバー、および JetPack ユーザーに適用されます。Jetson プラットフォームには適用されません。

以前リリースされたバージョンについては TensorRT Documentation Archives を参照してください。

訳注:TensorRT 7.0.0.11 の関連資料は以下のとおりです。

  1. TensorRT Support Matrix
  2. TensorRT Release Notes
  3. TensorRT Developer Guide
  4. TensorRT Installation Guide
  5. Best Practices For TensorRT Performance Guide
  6. TensorRT Sample Support Guide
  7. TensorRT API
  8. TensorRT Software License Agreement

主要な機能と改善

ループの使用

TensorRT は、回帰型ネットワークに役立つループのような構造をサポートします。入力テンソルのスキャン、テンソルの回帰型定義、および「出力のスキャン」と「最終値の出力」の療法をサポートします。詳細は TensorRT Developer Guide の Working With Loops を参照してください。

ONNX パーザーの動的 shape のサポート

ONNX パーザーは full-demension モードのみをサポートします。ネットワーク定義は expliciBatch フラグがセットして作成しなければなりません。詳細は TensorRT Developer Guide の Importing An ONNX Model Using The C++ Parser APITensorRT Developer Guide の Working With Dynamic Shapes を参照してください。

OSS の TensorRT コンテナ

TensorRT の月次コンテナリリースに、TensorRT オープンソースレポジトリのビルド済みバイナリが含まれるようになりました。詳細は、TensorRT Container Release Notes の 19.12 以降 を参照してください。

BERT における INT8 と混合精度最適化

BERT モデルでは、GELU 活性化のあとにいくつかの GEMM レイヤーが続きます。TensorRT は IMMA (Integer Matrix Multiply and Accumulate) GEMM レイヤーをサポートしていないので、必要な精度に応じて、BERT ネットワークにおけるそうした GEMM レイヤーを IConvolutionLayerIFullyConnectedLayer のどちらかで実装できます。例えば、Conv1x1 の IConvolutionLayer を活用して全結合操作を実装し、INT8 モードで IMMA を活用できます。TensorRT は、畳み込み/全結合と GELU の合成をサポートしています。詳細は TensorRT Best Practives GuideTensorRT Developer Guide の Adding Custom Layers Using The C++ API を参照してください。

量子化済みネットワークの使用

TensorRT は、Quantization Aware Training (量子化を前提とした訓練)によって量子化されたモデルをサポートします。サポートは対象的に量子化されたモデル(ONNX では QuantizeLinearDequantizeLinear を使って zero_point = 0 としたもの)に制限されます。詳細は TensorRT Developer Guide の Working With Quantized NetworksBest Practices For TensorRT Performance Guide の QDQ Fusions を参照してください。

新しいレイヤー

IFillLayer

IFillLayer は、指定されたモードで出力テンソルを生成するために使います。詳細は C++ の IFillLayer クラスPython の IFillLayer クラス を参照してください。

IIteratorLayer

IIteratorLayer を使うと、テンソルの反復処理ができます。ループは、ループ境界レイヤーによって定義されます。詳細は C++ の IIteratorLayer クラスPython の IIteratorLayer クラスTensorRT Developer Guide の Working With Loops を参照してください。

ILoopBoundaryLayer

ILoopBoundaryLayer クラスは、関連付けられたループへのポインタを返す仮想メソッド getLoop を定義します。詳細は C++ の ILoopBoundaryLayer クラスPython の ILoopBoundaryLayer クラスTensorRT Developer Guide の Working With Loops を参照してください。

ILoopOutputLayer

ILoopOutputLayer は、ループからの出力を指定します。詳細は、C++ の ILoopOutputLayer クラスPython の ILoopOutputLayer クラスTensorRT Developer Guide の Working With Loops を参照してください。

IParametricReluLayer

IParametricReluLayer は、Parametric ReLU 操作を表現します。詳細は、C++ の IParametricReluLayer クラスPython の IParametricReluLayer クラス を参照してください。

訳注:IParametricReluLayer は実は TensorRT 6.0.1 のときにも存在していました。これはリリースノートに記載されていませんが、一部では知られていたようです。現在の onnx-tensorrt でも PReLU サポートが有効になっています。以下は、PReLU に関する対応の歴史です。

  1. Commenting out PRELU op by kevinch-nv · Pull Request #117 · onnx/onnx-tensorrt
  2. [8] No importer registered for op: PRelu · Issue #136 · onnx/onnx-tensorrt
  3. Why is there delay in providing support for Prelu? · Issue #208 · onnx/onnx-tensorrt
IRecurrenceLayer

IRecurrenceLayer は、回帰の定義を指定します。詳細は、 C++ の IRecurrenceLayer クラスPython の IRecurenceLayer クラスTensorRT Developer Guide の Working With Loops を参照してください。

ISelectLayer

ISelectLayer は、2つの入力のうち条件に応じていずれかを返します。詳細は、 C++ の ISelectLayer クラスPython の ISelectLayer クラス を参照してください。

ITripLimitLayer

ITripLimitLayer は、ループを何回反復するかを指定します。詳細は、C++ の ITripLimitLayer クラスPython の ITripLimitLayer クラスTensorRT Developer Guide の Working With Loops を参照してください。

新しいオペレーター

ONNX オペレーターのサポートを追加しました。

ConstantOfShapeDequantizeLinearEqualErfExpandGreaterGRULessLoopLRNLSTMNotPReluQuantizeLinearRandomUniformRandomUniformLikeRangeRNNScanSqrtTileWhere

詳細は、TensorRT Support Matrix の Supported Ops を参照してください。

Boolean テンソルのサポート

TensorRT は、ネットワークの入力および出力として使える boolean テンソルをサポートします。IElementWiseLayerIUnaryLayerkNOT のみ)、IShuffleLayerITripLimitkWHILE のみ)、ISelectLayer は boolean データ型をサポートします。Boolean テンソルは、FP32 および FP16 精度のネットワークでのみ使用できます。詳細は、TensorRT Developer Guide の TensorRT Layers セクション を参照してください。

互換性

制約事項

  1. sampleUffMNISTsampleUffSSDsampleUffPluginV2ExtsampleUffMaskRCNNsampleUffFasterRCNNuff_custom_pluginuff_ssd のような UFF サンプルは、TensorFlow 1.x をサポートしていますが、TensorFlow 2.0 で訓練されたモデルはサポートしていません。
  2. ループと DataType::kBOOL は、制限されたプラットフォームでサポートされています。ループのサポートされていないプラットフォームでは、INetworkDefinition::addLoopnullptr を返します。サポートされていない環境で DataType::kBOOL を消費・生成する操作を使ったエンジンをビルドしようとすると、検証時にネットワークが拒否されます。ループをサポートしているプラットフォームについての詳細は、TensorRT Support Matrix の Features For Platforms And Software セクション を参照してください(訳注:現状では Linux AArch64 がループをサポートしていないようです)。
  3. 量子化された・量子化解除されたノードを持つ明確な精度のネットワークは、ハードウェアで INT8 をサポートしているデバイス上でのみサポートされています。そうでないデバイスで実行すると、未定義の動作が発生します。

非推奨機能

TensorRT 7.0.0. で以下の機能が非推奨になりました。

後方互換性と非推奨ポリシー

新しい関数が最初に導入されたとき(例えば foo)、それに対して明示的なバージョンはなく、バージョンは 1 と仮定されます。(大抵いくつかの新しい機能をサポートするために)既存の関数 foo の API を変更するとき、まず新しいルーチン fooV<N> が作成されます。N は、その関数の N 番目のバージョンであることを表現します。また、後方互換性を確保するために、何も変更のないものとして fooV<N-1> が残されます。この時点で fooV<N-1> は非推奨とみなされ、TensorRT ユーザーは非推奨として扱っていくべきです。

TensorRT 7 以降、以下のポリシーに従って非推奨 API を削除していきます。

  1. TensorRT 7 よりも古いバージョン(TensorRT 6 以前)ですでに非推奨になっている API は、TensorRT 8 の次のメジャーリリースで削除されます。
  2. TensorRT <M> で非推奨となった API(M は 7 以上のメジャーバージョン)は、TensorRT <M+2> で削除されます。つまり、非推奨 API は、削除される前の2つのメジャーリリースで引き続き機能します。

Caffe パーザーと UFF パーザーの非推奨

TensorRT 7 では、Caffe パーザーと UFF パーザーを非推奨とします。TensorRT 8 の次のメジャーリリースではテスト・機能する予定ですが、その後のメジャーリリースではサポートを削除するよう計画しています。tf2onnxkeras2onnx、または TensorFlow-TensorRT (TR-TRT) などを使ってワークフローを移行するよう計画してください。

修正された問題

  1. pybind11 の互換性問題を回避するために、ONNX と TensorFlow をソースからビルドする必要がなくなりました。TensorRT の Python バインディングは、pybind11 v 2.4.3 を使用してビルドされています。
  2. Windows ユーザーが、TensorRT refittable エンジン機能を使うよう設計されたアプリケーションをビルドできるようになりました。未解決シンボルに関する問題が解決されました。
  3. IPluginFactory クラスに仮想デストラクターが追加されました。

既知の問題

  1. UFF パーザーは、未使用の IConstantLayer オブジェクトを生成します。これらのオブジェクトは NetworkDefinition::getLayer メソッドで表示されますが、TensorRT によって最適化されます。そのため、IRefitter::setWeights によって重みを refit しようとしても、却下されます。IConstantLayer が与えられている場合、layer->getOutput(0)->isExecutionTensor() をチェックすることで、実行に使われているかどうかを検出できます。
  2. ONNX パーザーは、双方向の場合に順伝搬パスと逆伝搬パスの活性化タイプが一致しないような RNN・LSTM・GRU ノードをサポートしていません。
  3. INT8 キャリブレーションは、動的 shape で機能しません。この問題を回避するには、コードに2つのパスがあることを確認してください。
    1. TensorRT がキャリブレーションキャッシュを生成できるように、最初のパスでエンジンをビルドする固定 shape の入力が使用されている
    2. 動的 shape の入力を使用してエンジンを再度生成し、ビルダーが最初のパスで生成されたキャリブレーションキャッシュを再利用している

まとめ

TensorRT 6/7 のリリースを見ると、メジャーアップデートの更新間隔が狭くなっています。また、非推奨機能に関するポリシーも明確になったので、今後もこのようなペースで積極的なリリースが行われていくように感じました。

オプティムでは、こうした技術に興味がある・作ってみたい・既に作っている、というエンジニアを募集しています。興味のある方は、こちらをご覧ください。

www.optim.co.jp