GPU・製造・産業|Week 10

GPU性能とAI

演算器を待たせないためのデータ移動、行列積、低精度形式を整理します。

計算が速くても、材料の到着が遅いと手が止まる。GPUではデータの置き方も大事だよ。
回路図タブレットを持ち、学習者を案内する半導体設計者の先生

この週でできるようになること

  • GPUのメモリ階層とデータ移動コストを説明できる。
  • coalescing、arithmetic intensity、occupancyを区別できる。
  • 行列積がGPUやAIで重要な理由を説明できる。
  • FP32、FP16、BF16、INT8の使い分けを精度・速度・容量から考えられる。

まず、具体的な場面から

配列コピー

データを運ぶ量が多く、演算は少ない。

行列積

同じデータを何度も使うと演算量を稼げる。

小さな計算

GPU起動や転送の固定時間が目立つ。

見えてくること:GPU向きかどうかは演算回数だけでなく、再利用・転送量・問題の大きさで変わります。

ここで初めて、見えてきた関係を言葉や記号でまとめます。

演算強度 = 演算回数 ÷ 転送byte数

演算強度は1 byte運ぶ間に何回演算するか。coalescingは隣接threadのアクセスをまとめやすくすることです。

なぜそうなる?

行列積ではAとBの小さなtileを読み込み、複数の積和に使い回せます。転送の回数が減ると、多数の演算器へデータを供給しやすくなります。

講義ノートで詳しく読む

元のMarkdownにある仕組み・図・用語を、順番に確認します。

1. GPUのメモリ階層

単純化すると次の階層があります。

thread private registers      最速・小さい
block shared memory / L1      同じblockで共有
GPU-wide L2 cache
global memory (VRAM)          大容量・高帯域・高レイテンシー
CPU system memory             接続越しの転送が必要な場合

GPUは演算器が多いため、必要データを十分な速度で供給できないと演算器が待ちます。計算だけでなくデータの場所と移動量が重要です。

2. coalescing

隣接threadが隣接アドレスへアクセスすると、ハードウェアが少数のメモリトランザクションへまとめやすくなります。

良い例:thread 0→A[0], 1→A[1], 2→A[2]...
悪い例:thread 0→A[0], 1→A[1000], 2→A[2000]...

後者でも正しい結果は得られますが、多数の転送が必要になり帯域を有効利用しにくくなります。

3. 共有メモリで再利用する

global memoryから読み込んだデータをblock内の共有メモリへ置き、複数threadで再利用すると転送量を減らせます。

行列積では行列を小さなtileへ分割し、AとBのtileを共有メモリへ置いて複数の積和演算に再利用します。

4. Arithmetic intensity

転送1 byteあたり何回の演算を行うかという考え方です。

  • intensityが低い:データを少し計算してすぐ捨てる。メモリ帯域に制限されやすい。
  • intensityが高い:読み込んだデータを何度も計算に使う。演算性能を活かしやすい。

配列コピーは低く、うまくtile化した大規模行列積は高くできます。

5. occupancy

SMが保持可能な最大warp数に対し、実際に常駐しているwarpの割合を指す代表的な指標です。レジスタ、共有メモリ、block sizeなどで制約されます。

occupancyは高ければ常に最高性能というものではありません。十分に待ち時間を隠せた後は、データ再利用や命令効率など別の要因が支配します。

6. 行列積とAI

ニューラルネットワークの多くの処理は、行列積や畳み込みとして表せます。

C[i,j] = Σ A[i,k] × B[k,j]

各出力要素には似た積和演算があり、データをtile単位で再利用できるためGPUに適します。

Tensor Coreなどの専用演算器は、小さな行列ブロックの積和演算を高いスループットで実行します。GPUのすべての命令がTensor Coreで速くなるわけではありません。

7. 数値精度

形式 おおまかな特徴 主な用途例
FP32 精度と範囲の標準的な均衡 科学計算、学習、一般GPU計算
FP16 小容量・高スループット、範囲や精度に注意 AI学習・推論
BF16 FP32に近い指数範囲、仮数精度は低い AI学習
INT8 整数、非常に小さく高速に扱いやすい 量子化推論

低精度にすると、同じメモリ容量・帯域で多くの値を扱え、対応演算器のスループットも上がる場合があります。一方、丸め誤差、overflow、モデル精度への影響を評価する必要があります。

8. CPUとGPUの協調

典型的にはCPUがプログラム全体を制御し、GPUへkernelを起動します。

CPU:入力準備 → GPUへ転送 → kernel起動 → 結果待ち → 後処理
GPU:大量の要素を並列計算

処理が小さすぎると、起動や転送の固定コストが計算時間を上回り、CPUだけの方が速いことがあります。

例題で確かめる

例題

Aの1行が[1,2]、Bの1列が[5,7]なら、対応する行列積の1要素は?

  1. 同じ位置の値を掛ける:1×5 と 2×7。
  2. 積を足す:5 + 14。

答え:19。多くの出力要素で同様の積和を行います。

実習

python exercises/performance_lab.py vector --size 1000000
python exercises/performance_lab.py branch --size 1000000

次の表を埋めます。実測はCPU上ですが、処理形状からGPU適性を考えます。

処理 並列性 分岐 データ再利用 転送量 CPU/GPUどちら向きか
要素ごとの加算
小さい配列の加算
大規模行列積
逐次依存する探索
各要素で別経路の複雑な分岐

説明課題

「GPUはTFLOPSが高いので、どんなプログラムもCPUより速い」という主張を、転送、並列性、分岐、問題サイズの語を使って訂正してください。

練習問題

元ノートの小テストです。まず自分で答えを考え、必要なら下の答えを開いてください。

  1. 隣接threadの隣接メモリアクセスをまとめることを何というか。

    答えと考え方を見る

    coalescing。

  2. 転送byteあたりの演算量を表す概念は何か。

    答えと考え方を見る

    arithmetic intensity(演算強度)。

  3. shared memoryを使う主な目的を一つ答えよ。

    答えと考え方を見る

    global memoryから読んだデータをblock内で再利用し、低速な転送を減らすため。

  4. 行列積がGPUに適する理由を一つ答えよ。

    答えと考え方を見る

    多数の出力要素を並列計算でき、tile内のデータを積和演算へ再利用できるため。

  5. 低精度形式を使う利点と危険を一つずつ答えよ。

    答えと考え方を見る

    利点:容量・帯域・対応演算器のスループットを有効利用できる。危険:丸め誤差やoverflow、モデル精度低下など。