Cloud TPU パフォーマンス ガイド

TPU のパフォーマンスに関するトラブルシューティングの最初の手順は、モデルのプロファイリングを行うことです。パフォーマンス プロファイルのキャプチャの詳細については、Cloud TPU でのモデルのプロファイリングをご覧ください。

TPU モデルのパフォーマンス

このセクションでは、モデルのパフォーマンスを低下させる可能性がある一般的な問題と、その対処方法について説明します。

  1. モデルが入力に縛られている

    TPU は非常に高速に計算を実行します。TPU がアイドル状態になっていないことを確認するには、TPU に読み込まれているデータの安定したストリームがあることを確認します。これを行う方法は、データセットを読み込んで前処理する方法によって異なります。たとえば、tf.data.TFRecordset()num_parallel_reads パラメータを使用してデータファイルを並列で読み取ることができます。

  2. シャーディング(コア間でのバッチの分割)のためにバッチサイズが小さすぎる

    TPU ランタイムは、TPU デバイスの 8 つのコアすべてにバッチを分割します(v2-8 や v3-8 など)。グローバル バッチサイズを 128 に指定すると、各コアは 16(128 / 8)のバッチサイズを受け取ります。

    最適なメモリ使用量を実現するには、TPU メモリに収まる最も大きいバッチサイズを使用します。各 TPU コアは、行列乗算の処理に 2 次元 8 X 128 ベクトル レジスタを使用します。一般的に、バッチサイズは 8 または 128 で割り切れる必要があります。

  3. メモリ管理のチューニング

    TPU_PREMAPPED_BUFFER_SIZE 環境変数を使用すると、低レベルのランタイム動作を微調整できます。

  • 説明: TPU_PREMAPPED_BUFFER_SIZE は、データ転送(DMA など)用に TPU ランタイムで使用するために事前マッピングされ、固定されたホスト メモリ バッファのサイズ(バイト単位)を設定します。デフォルト値は 4,294,967,296 バイトです。値は 2^12(4 KB = 4 * 1,024 バイト = 4,096 = 2^12)の倍数にする必要があります。

    次の例は、有効な TPU_PRE_MAPPED_BUFFER_SIZE 値です。

        17179869184 = 2^34 = 2^22 * 2^12 (2^22 4KB pages will be premapped).
        40000000000 = 5^10 * 2^12 = (5^10 4KB pages will be premapped).
    
  • 影響: このサイズを大きくすると、ホストと TPU デバイスの間のデータ転送パフォーマンスが向上する可能性があります。特に、大きなテンソルを使用するワークロードや、ホストとデバイスの通信が頻繁に行われるワークロードで効果があります。ただし、固定されたホストメモリの量も増えるため、他のプロセスで使用できるメモリが減ります。

    バッファサイズ

    プログラムの実行時にメモリを割り当てるのに十分な大きさの事前にマッピングされたバッファ領域がない場合、ワークロードは失敗し、次のような RESOURCE_EXHAUSTED エラーが返されます。

    「Allocating buffer from premmaped region failed with: RESOURCE_EXHAUSTED: Attempting to allocate allocation_size. That was not possible. There are available_size free.」

    バッファが大きすぎると、TPU の初期化に時間がかかり(15 秒以上かかる可能性もあります)、TPU がスタックしているように見えることがあります。

    これを診断するには、TPU ランタイムログを調べます。これらのログには、バッファの事前マッピングなど、実行されているオペレーションの詳細が記録されます。ログは /tmp/tpu_logs/tpu_driver.INFO にあります。また、環境変数 TPU_STDERR_LOG_LEVEL=0 を設定すると、ログをコンソールに直接出力できます。この設定により、次のような出力が生成されます。

     I0604 12:45:24.926233   62136 tpu_hal.cc:214] Starting premapped memory manager initialization...
     I0604 12:45:29.411218   62136 system.cc:1059] tpu::System initialized, current host id: 0, logical device ids: 0
     I0604 12:45:29.411244   61600 tfrt_tpu_system_state.cc:216] CreateTpuSystemState: TPU initialization is successful and it took 5.583190661s
     I0604 12:45:29.411267   61600 tfrt_tpu_system_state.cc:220] CreateTpuSystemState: using TPU host premapped buffer of size: 4294967296
     ```
    
    This output will tell you how long it took to initialize the TPU and
    the size of the premapped buffer.
    
  • 使用方法: 事前にマッピングされたバッファが小さすぎるか大きすぎる場合は、次の環境変数を使用してバッファサイズを手動で設定できます。

    TPU_PREMAPPED_BUFFER_SIZE: Sets the total size (in bytes) of the
    pre-mapped buffer region.
    TPU_PREMAPPED_BUFFER_TRANSFER_THRESHOLD_BYTES: Sets the maximum size of
    a single buffer that can be allocated from the pre-mapped region.
    

    たとえば、次のようなことを行えます。

     export TPU_PREMAPPED_BUFFER_SIZE=4294967296
    

    バッファサイズを設定します。

     export TPU_PREMAPPED_BUFFER_TRANSFER_THRESHOLD_BYTES
     ```
     to enable it.
    
     This export sets the size to the default.
    
  • ガイダンス: ホストとデバイスの間のデータ転送がボトルネックになっていると思われる場合は、TPU_PREMAPPED_BUFFER_SIZE の値を調整します。ホストのメモリ使用量とモデルのパフォーマンスをモニタリングして、最適なバランスを見つけます。通常は、ほとんどのユースケースでデフォルト値で十分です。

XLA コンパイラの最適化

XLA は、TPU、CPU、GPU などのプラットフォーム用のバイナリを生成できる機械学習用のコンパイラです。XLA は標準の TensorFlow コードベースの一部ですが、PyTorch モデルと JAX モデルでも使用できます。Cloud TPU のモデルは XLA グラフに変換され、XLA は TPU 実行可能ファイルにコンパイルします。XLA の詳細については、XLA: ML のためのコンパイラの最適化をご覧ください。

パディング

TPU のメモリを効率的に使用するには、128 x 8 のチャンクにタイリングできるようにデータを構造化します。行列計算のデータが 128 x 8 チャンク全体を満たさない場合、XLA コンパイラはテンソルをパディングします。パディングには次の 2 つの欠点があります。

  1. パディングされたテンソルでは、TPU コアが十分に活用されません。
  2. パディングによって、テンソルに必要なオンチップ メモリ ストレージ量が増加し、メモリ不足エラーにつながる可能性があります。

パディングは必要に応じて XLA コンパイラによって自動的に行われますが、メモリ ビューアツールを使用してパディングの量を決定できます。TPU に適したテンソル次元を選択することで、パディングを回避できます。

テンソル ディメンション

ピーク時の FLOPS を達成するには、行列乗算のディメンションは、使用している TPU バージョンの MXU サイズよりも大きくする必要があります。MXU のサイズは、v6e では 256 x 256、v6e より前のバージョンでは 128 x 128 です。詳細については、Cloud TPU システム アーキテクチャをご覧ください。

バッチサイズ

計算をより効率的に実行するために、XLA コンパイラは TPU HBM メモリに保存されたテンソルのサイズを切り上げます。このパディングはハードウェア レベルで透過的に行われ、結果には影響しません。ただし、場合によっては、パディングによってメモリ使用量と実行時間が大幅に増加する可能性があります。

TPU ランタイムは、計算効率を最大にし、パディングを最小限に抑えるように、メモリ内にテンソルをレイアウトします。メモリのオーバーヘッドを最小限に抑え、計算効率を最大化するには、次のいずれかに該当する必要があります。

  1. バッチサイズの合計は 64 の倍数(TPU コアあたり 8)であり、特徴ディメンションのサイズが 128 の倍数である。

  2. バッチサイズの合計は 1,024 の倍数(TPU コアあたり 128)であり、特徴ディメンションのサイズが 8 の倍数である。

バッチサイズ 1,024 と 128 の倍数である特徴ディメンションを使用すると、最大の効率性が得られます。ただし、これをすべてのモデルで実現できるとは限りません。

融合

融合は、XLA コンパイラがプログラムの最適化に使用する一般的な手法です。融合演算は、組み合わせて実行する、複数の構成演算の組み合わせです。

たとえば、次の一連の演算について考えてみます。

    tmp = tf.add(x, y)
    result = tf.multiply(tmp, z)

このコードは、次の擬似コードとほぼ同じです。

    for (i = 0; i < element_count; i++) {
      tmp[i] = x[i] + y[i];
    }

    for (i = 0; i < element_count; i++) {
      result[i] = tmp[i] * z[i];
    }

融合により、配列アクセスが同時に発生します。

    for (i = 0; i < element_count; i++) {
      result[i] = (x[i] + y[i]) * z[i];
    }

この例では、メモリのラウンド トリップ数が削減され、XLA は tmp にスペースを割り当てる必要はありません。

融合は非常に重要な最適化であり、次のいくつかの点で Cloud TPU にメリットがあります。

  • 低速のメインメモリに中間結果を保存する必要をなくして、メモリ転送を低減します。
  • 通常は使用されないようなハードウェア ユニットを有効に活用できます。
  • 同時にアクティブ化されるバッファの数が少ないため、モデルのメモリ使用率を低減できます。

ブロードキャスト

ブロードキャストは、異なるが互換性のあるシェイプを持つ 2 つのテンソルが組み合わされたときに暗黙的に発生します。

たとえば、tf.add(vector, matrix) は、マトリックスのシェイプにベクトルをブロードキャストすることを要求します。演算の結果は、マトリックスと同じシェイプになります。詳細については、配列のブロードキャストのガイドをご覧ください。

ブロードキャストは多くの場合コンシューマーと融合できますが、ブロードキャストを強制するとパフォーマンスが低下し、メモリ使用量が増加する可能性があります。

次の例では、ベクトルとマトリックスを追加する際の暗黙のブロードキャストを、ブロードキャストを実体化する argmax と融合することはできません。

`tf.argmax(tf.add(vector, zero_matrix), axis=0)`