データ並列は全員が同じモデルで別のデータを学習し、勾配をそろえる。通信が詰まると台数を増やしても速くならない。
大きなモデルや大量のデータを学習すると、GPU 1枚では時間がかかりすぎたり、そもそもモデルがメモリに載らなかったりします。複数の GPU にどう分けるかは学習の費用と期間を大きく左右し、「GPU を倍にしたのに速くならない」という問題の多くは、分け方と GPU 間の通信から来ます。
GPU は、同じ計算を大量に並べて同時に行うのが得意で、ニューラルネットの行列の計算に向いています。1台で時間がかかりすぎるときや、モデルが1枚の GPU のメモリに載らないときに、複数の GPU で分けて学習します(分散学習)。
| 方式 | 分け方 | 使う場面 |
|---|---|---|
| データ並列 | 全 GPU が同じモデルのコピーを持ち、別々のデータで計算して、勾配を平均してそろえる(PyTorch の DDP など) | モデルが1枚に載る。まずこれ |
| モデル並列(テンソル並列) | 1つの層の行列を GPU に分けて持ち、一緒に計算する | モデルが1枚に載らない。GPU 間の通信がとても多いので、同じサーバーの中の高速な接続で使う |
| パイプライン並列 | 層を前半・後半のように分けて GPU に置き、データを流れ作業で渡す | とても深いモデル。待ち時間(空き)を減らす工夫が要る |
大きなモデルでは、これらを組み合わせます。データ並列でも、モデルの重みやオプティマイザーの状態を GPU に分けて持ち、メモリを節約する方式(FSDP・ZeRO)がよく使われます。
データ並列では毎回の更新で勾配をそろえる通信が入るので、GPU 間・サーバー間の通信が遅いと、台数を増やしても速くなりません。サーバーをまたぐ学習では、高速なネットワーク(InfiniBand など)が要ります。
下の「ブラウザで試す」の図は、データ並列で4台の GPU が勾配をそろえる通信(リング all-reduce)です。最初に全員が rank 0 に集まって住所を教え合い、各自が勾配を計算したあと、勾配を4つに分けて右隣へ送りながら足し合わせ(reduce-scatter)、完成した切れをまた回して全員に配ります(all-gather)。毎回の更新でモデルと同じ大きさのデータが GPU の間を流れることと、1台が遅いと全員が待つことに注目すると、最後の段落の「通信が遅いと台数を増やしても速くならない」理由が見えます。
面接ではこう答える
分散学習には、全 GPU が同じモデルのコピーを持って別のデータを計算し、勾配を平均してそろえるデータ並列と、モデルが1枚の GPU に載らないときに層や行列を分けて持つモデル並列があります。まずはデータ並列を使い、メモリが足りなければ重みやオプティマイザーの状態を分けて持つ FSDP や ZeRO を使います。データ並列は毎回の更新で勾配をそろえる通信が入るので、GPU 間やサーバー間の通信が遅いと台数を増やしても速くなりません。
MLとの関わり学習が遅い・GPU に載らないという相談を受けたとき、どの並列化を選ぶかの判断に使います。
ネットワーク図を読み込んでいます…