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

この週でできるようになること
- GPUのメモリ階層とデータ移動コストを説明できる。
- coalescing、arithmetic intensity、occupancyを区別できる。
- 行列積がGPUやAIで重要な理由を説明できる。
- FP32、FP16、BF16、INT8の使い分けを精度・速度・容量から考えられる。
まず、具体的な場面から
データを運ぶ量が多く、演算は少ない。
同じデータを何度も使うと演算量を稼げる。
GPU起動や転送の固定時間が目立つ。
見えてくること:GPU向きかどうかは演算回数だけでなく、再利用・転送量・問題の大きさで変わります。
ここで初めて、見えてきた関係を言葉や記号でまとめます。
演算強度は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×5 と 2×7。
- 積を足す: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より速い」という主張を、転送、並列性、分岐、問題サイズの語を使って訂正してください。
練習問題
元ノートの小テストです。まず自分で答えを考え、必要なら下の答えを開いてください。
隣接threadの隣接メモリアクセスをまとめることを何というか。
答えと考え方を見る
coalescing。
転送byteあたりの演算量を表す概念は何か。
答えと考え方を見る
arithmetic intensity(演算強度)。
shared memoryを使う主な目的を一つ答えよ。
答えと考え方を見る
global memoryから読んだデータをblock内で再利用し、低速な転送を減らすため。
行列積がGPUに適する理由を一つ答えよ。
答えと考え方を見る
多数の出力要素を並列計算でき、tile内のデータを積和演算へ再利用できるため。
低精度形式を使う利点と危険を一つずつ答えよ。
答えと考え方を見る
利点:容量・帯域・対応演算器のスループットを有効利用できる。危険:丸め誤差やoverflow、モデル精度低下など。