LiteRT の GPU デリゲート

グラフィック プロセッシング ユニット(GPU)を使用して ML モデルを実行すると、モデルのパフォーマンスと ML 対応アプリケーションのユーザー エクスペリエンスを大幅に向上させることができます。LiteRT では、デリゲートと呼ばれるハードウェア ドライバを介して GPU やその他の専用プロセッサを使用できます。LiteRT ML アプリケーションで GPU を使用すると、次のようなメリットがあります。

  • 速度 - GPU は、超並列ワークロードの高スループットを実現するように構築されています。この設計により、多数の演算子で構成され、並列処理可能な入力テンソルを処理するディープ ニューラル ネットワークに適しています。通常、レイテンシが短縮されます。最適なシナリオでは、GPU でモデルを実行することで、これまで不可能だったリアルタイム アプリケーションを実現できるほど高速に実行できます。
  • 電力効率 - GPU は ML 計算を非常に効率的かつ最適化された方法で実行します。通常、CPU で同じタスクを実行するよりも消費電力が少なく、発熱も少なくなります。

このドキュメントでは、LiteRT での GPU サポートの概要と、GPU プロセッサの高度な使用方法について説明します。特定のプラットフォームで GPU サポートを実装する方法について詳しくは、次のガイドをご覧ください。

GPU ML オペレーションのサポート

LiteRT GPU デリゲートで高速化できる TensorFlow ML オペレーション(op)には、いくつかの制限があります。デリゲートは、16 ビットと 32 ビットの浮動小数点精度で次のオペレーションをサポートしています。

  • ADD
  • AVERAGE_POOL_2D
  • CONCATENATION
  • CONV_2D
  • DEPTHWISE_CONV_2D v1-2
  • EXP
  • FULLY_CONNECTED
  • LOGICAL_AND
  • LOGISTIC
  • LSTM v2 (Basic LSTM only)
  • MAX_POOL_2D
  • MAXIMUM
  • MINIMUM
  • MUL
  • PAD
  • PRELU
  • RELU
  • RELU6
  • RESHAPE
  • RESIZE_BILINEAR v1-3
  • SOFTMAX
  • STRIDED_SLICE
  • SUB
  • TRANSPOSE_CONV

デフォルトでは、すべてのオペレーションはバージョン 1 でのみサポートされます。量子化サポートを有効にすると、適切なバージョン(ADD v2 など)が有効になります。

GPU のトラブルシューティング サポート

一部のオペレーションが GPU デリゲートでサポートされていない場合、フレームワークはグラフの一部のみを GPU で実行し、残りの部分を CPU で実行します。CPU/GPU 同期のコストが高いため、このような分割実行モードでは、ネットワーク全体を CPU だけで実行する場合よりもパフォーマンスが低下することがよくあります。この場合、アプリケーションは次のような警告を生成します。

WARNING: op code #42 cannot be handled by this delegate.

これは実際の実行時エラーではないため、このタイプのエラーのコールバックはありません。GPU デリゲートでモデルの実行をテストする際は、これらの警告に注意する必要があります。このような警告が多数表示される場合は、モデルが GPU アクセラレーションの使用に最適ではない可能性があり、モデルのリファクタリングが必要になることがあります。

サンプルモデル

次のサンプルモデルは、LiteRT で GPU アクセラレーションを活用するように構築されており、リファレンスとテスト用に提供されています。

GPU 向けに最適化する

LiteRT GPU デリゲートを使用して GPU ハードウェアでモデルを実行する際に、パフォーマンスを向上させるには、次の手法が役立ちます。

  • 形状変更オペレーション - CPU では高速なオペレーションでも、モバイル デバイスの GPU ではコストが高くなることがあります。特に、BATCH_TO_SPACESPACE_TO_BATCHSPACE_TO_DEPTH などの形状変更オペレーションは実行コストが高くなります。reshape オペレーションの使用を詳しく調べ、データ探索やモデルの初期のイテレーションでのみ適用された可能性があることを考慮する必要があります。これらを削除すると、パフォーマンスが大幅に向上する可能性があります。

  • 画像データチャネル - GPU では、テンソルデータが 4 つのチャネルにスライスされるため、形状 [B,H,W,5] のテンソルに対する計算は、形状 [B,H,W,8] のテンソルに対する計算とほぼ同じですが、[B,H,W,4] よりも大幅に悪くなります。使用しているカメラ ハードウェアが RGBA の画像フレームをサポートしている場合、3 チャンネルの RGB から 4 チャンネルの RGBX へのメモリコピーを回避できるため、4 チャンネルの入力を供給する方が大幅に高速になります。

  • モバイル向けに最適化されたモデル - 最適なパフォーマンスを得るには、モバイル向けに最適化されたネットワーク アーキテクチャで分類子を再トレーニングすることを検討してください。オンデバイス推論の最適化により、モバイル ハードウェアの機能を活用して、レイテンシと消費電力を大幅に削減できます。

高度な GPU サポート

GPU 処理で高度な手法を追加して、モデルのパフォーマンスをさらに向上させることができます。たとえば、量子化やシリアル化などがあります。以降のセクションでは、これらの手法について詳しく説明します。

量子化モデルの使用

このセクションでは、GPU デリゲートが 8 ビット量子化モデルを高速化する方法について説明します。内容は次のとおりです。

パフォーマンスを最適化するには、浮動小数点入力テンソルと出力テンソルの両方を持つモデルを使用します。

仕組み

GPU バックエンドは浮動小数点実行のみをサポートしているため、元のモデルの「浮動小数点ビュー」を指定して量子化モデルを実行します。大まかな手順は次のとおりです。

  • 定数テンソル(重み/バイアスなど)は、GPU メモリに 1 回だけ逆量子化されます。このオペレーションは、LiteRT でデリゲートが有効になっている場合に発生します。

  • GPU プログラムへの入力と出力は、8 ビット量子化の場合、各推論で逆量子化と量子化がそれぞれ行われます。このオペレーションは、LiteRT の最適化されたカーネルを使用して CPU で行われます。

  • 量子化シミュレータは、量子化された動作を模倣するためにオペレーション間に挿入されます。このアプローチは、量子化中に学習した境界に従ってアクティベーションが行われることをオペレーションが想定しているモデルで必要です。

GPU デリゲートでこの機能を有効にする方法については、以下をご覧ください。

シリアル化による初期化時間の短縮

GPU デリゲート機能を使用すると、以前の実行でシリアル化されてディスクに保存された、事前コンパイル済みのカーネルコードとモデルデータを読み込むことができます。このアプローチでは再コンパイルが不要になり、起動時間を最大 90% 短縮できます。この改善は、ディスク容量と時間の節約を交換することで実現されます。次のコード例に示すように、いくつかの構成オプションを使用してこの機能を有効にできます。

C++

    TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
    options.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION;
    options.serialization_dir = kTmpDir;
    options.model_token = kModelToken;

    auto* delegate = TfLiteGpuDelegateV2Create(options);
    if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
      

Java

    GpuDelegate delegate = new GpuDelegate(
      new GpuDelegate.Options().setSerializationParams(
        /* serializationDir= */ serializationDir,
        /* modelToken= */ modelToken));

    Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
      

シリアル化機能を使用する場合は、コードが次の実装ルールに準拠していることを確認してください。

  • シリアル化されたデータは、他のアプリからアクセスできないディレクトリに保存します。Android デバイスでは、現在のアプリケーションに固有の場所を指す getCodeCacheDir() を使用します。
  • モデルトークンは、特定のモデルのデバイスに対して一意である必要があります。モデルトークンは、farmhash::Fingerprint64 などのライブラリを使用してモデルデータからフィンガープリントを生成することで計算できます。