TT Lab
はじめる
学ぶ 学習パス コース

コンピュータ構成

GPU — レイテンシを削る代わりにスループットを広げた設計

TT Labで続きを見る

一言でいうと

CPUは1つのスレッドをできるだけ速く終わらせるように作られていて、GPUは数万のスレッドを同時に回して、メモリの待ち時間を互いに隠すように作られています。

なぜ必要なのか

CPUは、1つの流れのレイテンシを減らすことにトランジスタを使います。分岐予測器、アウトオブオーダー実行エンジン、大きなキャッシュが、すべて「今このスレッドが止まらないようにする」ための装置です。問題は、この方式の見返りが逓減することです。予測器を2倍に大きくしても、性能は数パーセントしか上がりません。

同じトランジスタを別の使い方をする方法があります。制御回路を極端に単純化して算術ユニットを詰め込み、スレッドをとても多く載せておきます。1つのスレッドがメモリを待っている間に別のスレッドを実行すれば、待ち時間が隠れます。これがGPUの設計思想で、だからGPUはレイテンシを減らす装置ではなく、レイテンシを隠す装置です。

どう動くのか

GPUは、複数のストリーミングマルチプロセッサー(SM)で構成されます。各SMの中で、スレッドは32個ずつ束ねられてワープ(warp)単位でスケジューリングされ、1つのワープの中のスレッドは、同じ命令を、それぞれのデータに対して実行します(SIMT)。

ここから、2つの性能上の落とし穴が出てきます。

分岐ダイバージェンス(divergence): ワープの中で半分がifへ、半分がelseへ進むと、ハードウェアは両方の経路を順番に実行しながら、該当しないスレッドを一時的にオフにします。結果は正しいですが、時間は2つの経路の合計になります。条件がデータによってばらばらなカーネルが遅い理由です。

コアレスアクセス(coalescing): 1つのワープの32個のスレッドが連続したアドレスを読むと、メモリトランザクション数個で済みます。散らばったアドレスを読むと、最悪の場合32個のトランザクションが必要です。同じ計算なのに、インデックスの付け方を変えるだけで倍数で差が出る理由がここにあります。

メモリ階層もCPUとは違います。SMの中には、プログラマーが明示的に管理する共有メモリがあります。キャッシュが勝手にやってくれるのを待つ代わりに、再利用するデータを自分で載せておき、複数のスレッドで分け合って使います。行列乗算カーネルの性能の大部分は、この共有メモリのタイリングから生まれます。

オキュパンシー(occupancy)は、SMが同時に維持できるワープ数に対する、実際に載っているワープ数です。オキュパンシーが低いと、隠すためのスレッドが足りず、メモリの待ちがそのまま表に出ます。ただし、オキュパンシーが高ければいつも速いわけではありません。レジスターを多く使うカーネルは、オキュパンシーを下げてでも、スレッドあたりの作業量を増やしたほうがよいことがあります。

現場での姿

AI推論で、GPU使用率が30パーセントを超えられないという話はよくあります。原因は、たいてい演算の不足ではなく、メモリ帯域幅です。LLMのデコードは、巨大な重みを読み込んで、小さな入力と掛け合わせて捨てるので、演算強度が低く、そのためrooflineの左側の斜面に位置します。この区間では、演算性能がより高いチップを買っても、性能は上がりません。答えは、読むバイトを減らすこと(量子化)や、バッチサイズを大きくして、同じ重みの読み込みを複数のリクエストで分け合えるようにすることです。

TPUのようなアクセラレーターが別の答えを出したのも、ここです。シストリックアレイは、データを格子の間に流しながら再利用して、メモリアクセスあたりの演算数を最大化します。汎用性を捨てて、演算強度を買ってきた設計です。

何がGPUに向いていて、何が向いていないか

同じ問題でも、GPUに載せて得をするものと、かえって損をするものに分かれます。判断基準は3つです。

一度にやる仕事が十分に多いか。GPUは、数万のスレッドを回してはじめて元が取れるので、要素が数千個しかない計算は、カーネルを起動するコストすら回収できません。カーネルの実行自体に数マイクロ秒かかり、その時間があれば、CPUがすでに終えていたことがよくあります。

移す量が、計算量に比べて小さいか。CPUのメモリとGPUのメモリは別なので、データをコピーする必要があり、その経路は、GPUの内部の帯域幅よりずっと狭いです。コピーにかかる時間が計算時間より長ければ、GPUは純粋な損です。 そのため、実務の定石は、一度載せたデータを、複数の段階にわたってGPUの上で使い続けることで、段階ごとにCPUへ下ろしたり上げたりする構造は、ほとんどいつも誤った設計です。

スレッドごとにやることが同じか。要素ごとに条件が違って分岐する計算は、前に見た分岐ダイバージェンスのせいで、得が大きく減ります。そのため、GPUに向く問題は、おおむね、密な配列の上の規則的な演算です。

この3つを裏返せば、GPUに向かない仕事がそのまま出てきます。分岐の多いロジック、ポインターをたどるデータ構造、前の結果がなければ次を始められない逐次処理、そして、毎回少しだけ計算する短い作業です。AIの学習と推論がGPUによく合う理由は、神秘的な性質のためではなく、この3つの条件を正確に満たしているからです。

実務の感覚を1つ付け加えます。GPUが付いたサーバーで性能が出ないとき、人はまずGPUを疑いますが、原因がデータを供給する側であることが非常に多くあります。ディスクから読み込んで、前処理して、載せてやるパイプラインがGPUを満たせないと、高価なカードが、ほとんどの時間を待って遊びます。使用率を時間に沿ってグラフにしたとき、のこぎりの歯のように上下しているなら、それがこの状況の典型的な姿です。

続くクイズで確認すること

「GPUはCPUより速い」という言葉が、なぜ半分しか正しくないのか、そしてGPUを買っても性能が出ない典型的な理由を、説明できるかを確認します。