世界を動かす技術を、日本語で。

GPUの基本的な知識

概要

  • GPU の計算性能とメモリ帯域の違いによるボトルネックの解説
  • メモリバウンドコンピュートバウンド の2つの性能領域
  • 演算強度(Arithmetic Intensity) による最適化指標
  • 性能向上の基本戦略: 演算融合(Fusion)タイル化(Tiling)
  • A100 アーキテクチャを例に、階層構造や最適化手法を図解

GPUの計算・メモリ階層と性能ボトルネック

  • GPUは 計算速度 が非常に高い一方で、 メインメモリ(VRAM) へのアクセス速度が相対的に遅い構造
  • 例: NVIDIA A100 は32bit演算で 19.5 TFLOPS、メモリ帯域は 1.5 TB/s
  • グローバルメモリ(VRAM) は大容量だが遅く、全データはここに格納
  • ストリーミングマルチプロセッサ(SM) が計算単位、各SMに 高速なオンチップSRAM(共有メモリ)レジスタ を搭載
  • スレッドは ワープ(32スレッド) 単位で同時実行、 ブロック (最大1024スレッド)がSM上で動作、ブロック内で共有メモリを利用

2つの性能領域:メモリバウンドとコンピュートバウンド

  • カーネル (GPUで並列実行される関数)は、 メモリ帯域 または 計算能力 のいずれかで性能が制限
    • メモリバウンド :データ転送速度がボトルネック(例:要素ごとの加算)
    • コンピュートバウンド :演算速度がボトルネック(例:大規模行列積)
  • 演算強度(AI)= 総FLOPs / 総バイトアクセス で性能領域を判別
  • Rooflineモデル :AIと性能の関係を図示、2つの「屋根(roof)」で物理的上限を示す
    • AI ≈ 13 FLOPs/Byte がA100の分岐点(リッジポイント)
    • AIが低いとメモリバウンド、高いとコンピュートバウンド
  • 最適化目標は AIを高めて コンピュートバウンド領域に到達させること

行列積のAI向上戦略

  • 単純実装 (1スレッドが1要素計算):AIは 0.25 FLOPs/Byte と低く、メモリバウンド
  • 2x2タイル計算 :AIは 0.5 FLOPs/Byte に増加するが、依然として低い
  • 共有メモリの活用 でスレッドブロック全体がデータを協調的に再利用し、AIを大幅に向上
    • 1024スレッドのブロックで AI > 13 を実現可能

第三のボトルネック:オーバーヘッド

  • CPU側の準備・カーネル起動遅延 がボトルネックとなる場合(小規模・高頻度のカーネル実行時)
  • 非同期実行バッチ化 で隠蔽可能
  • 本記事ではカーネルが十分大きい前提で、主にメモリ・計算ボトルネックに注目

性能向上の基本戦略:FusionとTiling

  • 演算融合(Fusion) :複数の単純操作を1つのカーネルにまとめ、中間メモリアクセスを削減
    • 例:y = relu(x + 1)を別々に実行せず、1カーネルで同時処理
  • タイル化(Tiling) :複雑な処理(例:行列積)でデータの再利用性を最大化し、AIを向上
    • 共有メモリ に大きなタイルをロードし、スレッド間で協調的に演算

まとめ

  • GPU最適化 の本質は、 限られたメモリ帯域 を最大限に活用し、 AIを高めて コンピュートバウンド領域へ移行すること
  • Fusion で中間メモリ転送を減らし、 Tiling でデータ再利用性を高めることが重要
  • A100 など最新GPUでは、 共有メモリワープ 構造を意識した設計が高性能化の鍵

この内容は、GPUアーキテクチャや最適化の基礎を理解し、実際のカーネル設計やパフォーマンスチューニングに役立つ知識体系としてまとめられています。

Hackerたちの意見

これはすごく良いイントロで、感謝してるよ。AI PCを作るとき、GPUについて深く調べるのに数日かかったけど、これを見れば一目瞭然だね。特に、生成的人工知能みたいな高価値なアプリケーションに触れてるのが素晴らしい。ページにあったA100 GPUのメモリ階層を示す図は、他ではあまり見つけられなかったから、すごく役立ったよ。図がとても助かった。ありがとう!

同じ4070でllama.cppとvllmを動かして、もっとプロンプトをバッチ処理しようとしてるんだけど、バッチ8くらいに達したらllama.cppがすごく遅くなった。GPUの使用率は問題なさそうだったけどね。vllmはずっと良く処理できた。後でわかったんだけど、vllmはページングされたkvキャッシュを使ってて、GPUが完全に結合されたデータをストライドジャンプなしで読み取るのに合ったレイアウトになってる。llama.cppは単一プロンプトにはいいけど、バッチ処理するとL2アクセスパターンが崩れるフラットなレイアウトを使ってた。llama.cppのkvテンソルをインターリーブするように形を変えて、[head, seq, dim]にしたら、vllmがデータを融合注意カーネルに供給する方法に近づいた。これで同じ操作に対して2倍のスピードアップができたよ。GPUはボトルネックじゃなかった。問題はメモリのレイアウトがSMの期待するアクセスストライドと合ってなかったことだね。vllmは共有メモリをうまく使って、グローバルリードを減らすレイアウトにデフォルトでなってる。それがバッチごとのスケールが良い本当の理由だよ。これには2日以上かかったし、きれいなGPUグラフの下に隠れたボトルネックを見つけるのに苦労した。正直、かなりの試行錯誤だった。> こういう実験をホットリロードモードで、あまり手間をかけずにやる方法知ってる人いる?

これらの変更を llama.cpp に統合するためのPRは出した?2倍のスピードアップはマジでヤバいね。

昨日、DeepSeekの社員が出した nano-vllm 見た?1200行のコードで、バニラのvllmより速いんだって。1. https://github.com/GeeeekExplorer/nano-vllm

https://github.com/ikawrakow/ik_llama.cpp を試してみて。

GPUは全然ボトルネックじゃなかったよ メモリのレイアウトが問題だったんだ ああ、じゃあGPUがボトルネックだったってことか。

対照的な色を使おう!

作者が見てたら、コードブロック内のリンクやコメントは、ちょっと読みづらかったから、もう少しコントラストを上げる価値があるかも。内容は本当に素晴らしいけどね!

ウェブサイトはテキストにアルファ透明度を使ってるみたい。これは深刻な、コントラストを減少させる罪だね。

作者はダークモードでフォーマットや編集してるかも。私はedge://flags/#enable-force-darkを使ってるけど、リンクは読みやすいよ。

font-weight: 300; このサイトのデザインは、著者が「フォントスムージング」を有効にしたApple Macで作ったんじゃないかな。これがあると、普通のフォントが人工的に「セミボールド」になるから、普通の見た目のフォントを作るためにMacのデザイナーはこの細いフォントウェイトを使って、Appleがちょっと「普通」に見せてくれるんだよね。 https://news.ycombinator.com/item?id=23553486

いい記事で、人々がある程度知っておくべき情報をまとめてるね。ただ、タイトルが少し誤解を招くかも。これはNVIDIAがGPUアーキテクチャを開発する際の選択肢について話してるけど、他の企業が必ずしもそうするわけじゃないから。例えば、算術強度のブレークイーブンポイント(リッジポイント)は、NVIDIAの領域を離れるとかなり違う。AMD Instinct MI300を見てみると、最大160 TFLOPSのFP32に約6 TB/sのHBM3/3E帯域幅が組み合わさって、リッジポイントは約27 FLOPs/バイトで、A100の13 FLOPs/バイトの約2倍になる。パッケージ内のHBM(128~256 GB)GPUメモリも、タイルの深さと占有率の実際のトレードオフを変える。これは非常に高価で、CUDAがない(これは良い面も悪い面もある)。

残念ながら、NvidiaのGPUだけが重要で、AMDが自社のソフトウェアを真剣に取り組むまでそうだね。

スポイラー: GPUの動作についてじゃなくて、機械学習の計算にどう使うかについてだよ。

CUDAの基本的な説明だね。MLとは関係なくて、例でreluを使ってるだけで、torchについて言及してるくらい。

ASCIIダイアグラム、マジで?

これ、「Nvidia GPUの基本的な事実」ってタイトルにした方がいいかも。WARPの用語は現代のNvidia GPUの特徴だからね。ここで強調したいのは「現代」ってこと。2003年頃のNVIDIA GPUは全然違うし、その時代のビデオゲーム用のレンダリングパイプラインに特化した回路が組み込まれてるんだ。だから、この投稿のほとんどは「GPU」全般には当てはまらないよ。現代のNvidia GPUが使う一般的な計算とは全然違うデバイスの広いカテゴリーだからね。