現在のモデルはますます大きくなり、多くの場合は数 B、場合によっては数百 B になります。ただし、グラフィックス カードのメモリのサイズでは、トレーニング推論をまったくサポートできません。たとえば、RTX2090 の 10G ビデオ メモリを使用すると、モデルをロードするだけで十分でありOOM
、その後のトレーニングの最適化は言うまでもありません。
従来の pytorch DataParallel の代替として、DeepSpeed の目標は、数億のパラメータを持つモデルを独自の個人作業サーバー上でトレーニングおよび推論できるようにすることです。
この記事では、大規模モデルトレーニングのための Deepspeed の中心的な概念と、最も基本的な使用方法を簡単に紹介することを目的としています。詳細については、HuggingFace Transformer 公式 Web サイトにある DeepSpeed チュートリアルを読むことを著者は強くお勧めします。
1. コアアイデア (TLDR)
DeepSpeed の核心は、GPU メモリが十分ではなく、それを補うために CPU メモリが使用されることです。
たとえば、10 GB の GPU しかない場合、大規模なモデルをトレーニングするにはおそらく 80 GB の CPU が必要になります。
このコンセプトについての公式 Web サイトの説明を見てください。
1 つの GPU だけで DeepSpeed を使用したいのはなぜですか?
- これには、一部の計算とメモリをホストの CPU と RAM に委任できるZeRO オフロード機能があり 、モデルのニーズに合わせてより多くの GPU リソースを残す ことができます。たとえば、より大きなバッチ サイズや、通常は適用できない非常に大きなモデルのフィッティングを可能にします。フィット。
- スマートな GPU メモリ管理システムを提供し、メモリの断片化を最小限に抑え、より大きなモデルやデータ バッチに適合できるようにします。
具体的には、DeepSpeed は現時点でトレーニング モデルで使用されていないパラメーターを CPU にキャッシュし、必要になったときに CPU から GPU にそれらを移動します。ここでの「パラメーター」とは、モデル パラメーターだけでなく、オプティマイザー、勾配なども指します。
CPU に移動されるパラメータが増えるほど、GPU の負担は減りますが、その代償として CPU と GPU のやり取りがより頻繁になり、トレーニング推論の時間オーバーヘッドが大幅に増加します。したがって、DeepSpeed の中心的な本質の 1 つは、時間オーバーヘッドとメモリ使用量の間のトレードオフです。
2. インストール方法
pip の直接インストール:
pip install deepspeed
公式の推奨事項は、ウェアハウス内でローカルにコンパイルしてインストールすることです。これにより、ローカルのハードウェア環境に適切に適応できます。
git clone https://github.com/microsoft/DeepSpeed/
cd DeepSpeed
rm -rf build
TORCH_CUDA_ARCH_LIST="8.6" DS_BUILD_CPU_ADAM=1 DS_BUILD_UTILS=1 pip install . \
--global-option="build_ext" --global-option="-j8" --no-cache -v \
--disable-pip-version-check 2>&1 | tee build.log
さらに、HuggingFace は DeepSpeed とのフレンドリーな統合を提供し、DeepSpeed の使用に必要な多くのパラメータは Transformer のTrainerによって自動的に指定できます。HuggingFace Transformer 上で DeepSpeed を使用すると、より便利になると言えます (もちろん、DeepSpeed は Transformer に依存せず単独で使用することもできます)。
アドオン パッケージとして Transformer にインストールします。
pip install transformers[deepspeed]
3. 使用方法
DeepSpeed を使用すると、コマンド ラインは次のようになります。
deepspeed --master_port 29500 --num_gpus=2 run_s2s.py \
--deepspeed ds_config.json
--master_port
:ポート番号。明示的に指定するのが最善です。デフォルトは 29500 ですが、占有されている可能性があります (つまり、複数の DeepSpeed プロセスを実行しています)。--num_gpus
: GPU の数デフォルトでは、現在表示されているすべての GPU が使用されます。--deepspeed
: 提供された構成ファイルは、DeepSpeed の多くの重要なパラメータを指定するために使用されます。
config
DeepSpeed を使用する際の中心的なポイントの 1 つは、ファイル (.json または json のような形式の構成ファイルにすることができます) を作成することです。この構成ファイルでは、重み付けなどの必要なパラメーターを指定できます。時間とビデオ メモリ (前述したように、これは重要なトレードオフです)。したがって、上記のパラメーターの中で最も重要なのは、--deepspeed
提供する構成ファイル、つまり ですZeRO
。この記事では次に焦点を当てます。
3.1 ZeROの概要
Zero Redundancy Optimizer (ZeRO) は DeepSpeed の主力製品であり、ユーザーはさまざまな ZeRO 構成ファイルを提供して、DeepSpeed のさまざまな機能を実装できます。
公式ウェブサイトのチュートリアルで ZeRO の説明を見てみましょう。
Zero Redundancy Optimizer (ZeRO) は、3 つのモデル状態 (オプティマイザーの状態、勾配、パラメーター) を複製するのではなく、データ並列プロセス間で分割することにより、データ並列プロセス間のメモリ冗長性を削除します。これにより、計算の粒度と通信効率を維持しながら、従来のデータ並列処理と比較してメモリ効率が向上します。
一文の要約: partitioning instead of replicating
、コピーするのではなく分割します。
つまり、従来のディープ ラーニングと並列モデル トレーニングでは、モデル パラメーターを複数の GPU にコピーし、データを分割するだけです (torch の DataParallel など)。これにより、ビデオ メモリが大量に無駄になります。ZeRO は、この冗長性を排除し、メモリ使用率を向上させるように設計されています。ここでの「メモリ」には複数の GPU メモリだけでなく、CPU も含まれることに注意してください。
ZeROの実装方法は、パラメータ占有を論理的に3種類に分けることです。次のタイプのパラメータを分割します。
optimizer states
: つまり、オプティマイザのパラメータのステータスです。たとえば、アダムの運動量パラメータです。gradients
: オプティマイザーに対応するグラデーション キャッシュ。parameters
: モデルパラメータ。
同様に、DeepSpeed の ZeRO 構成ファイルは次のカテゴリに分類できます。
ZeRO Stage 1
: オプティマイザーの状態を分割します。オプティマイザのパラメータは複数のメモリに分割されており、各 momoey のプロセスはパラメータの独自の部分を更新することのみを担当します。ZeRO Stage 2
:グラデーションを分割します。各メモリは、割り当てられているオプティマイザ状態に対応する勾配のみを保持します。グラデーションとオプティマイザーは密接にリンクされているため、これは当然のことです。勾配のみがわかり、オプティマイザーの状態はわからないため、モデル パラメーターを最適化する方法はありません。ZeRO Stage 3
: モデル パラメータ、または異なるレイヤーを分割する ZeRO-3 は、フォワードおよびバックワード中にモデル パラメータを複数のメモリに自動的に割り当てます。
ZeRO-1 はオプティマイザーの状態を割り当てるだけ (パラメーターの数が非常に少ない) ため、実際に使用する場合は、通常はZeRO-2
合計のみを考慮しますZeRO-3
。
次に、ステージ 2 と 3 で一般的に使用される構成ファイルを紹介します。
3.2 ZeRO ステージ 2
公式 Web サイトの紹介に基づいて、作成者は一般的に使用される ZeRO-stage-2 構成ファイルを提供しています。
{
"bfloat16": {
"enabled": "auto"
},
"fp16": {
"enabled": "auto",
"loss_scale": 0,
"loss_scale_window": 1000,
"initial_scale_power": 16,
"hysteresis": 2,
"min_loss_scale": 1
},
"optimizer": {
"type": "AdamW",
"params": {
"lr": "auto",
"betas": "auto",
"eps": "auto",
"weight_decay": "auto"
}
},
"scheduler": {
"type": "WarmupLR",
"params": {
"warmup_min_lr": "auto",
"warmup_max_lr": "auto",
"warmup_num_steps": "auto"
}
},
"zero_optimization": {
"stage": 2,
"offload_optimizer": {
"device": "cpu",
"pin_memory": true
},
"allgather_partitions": true,
"allgather_bucket_size": 2e8,
"overlap_comm": true,
"reduce_scatter": true,
"reduce_bucket_size": 2e8,
"contiguous_gradients": true
},
"gradient_accumulation_steps": "auto",
"gradient_clipping": "auto",
"train_batch_size": "auto",
"train_micro_batch_size_per_gpu": "auto",
"steps_per_print": 1e5
}
- について
offload
上記のパラメータの中で最も重要なものは です"offload_optimizer"
。上に示したように、”device“
これを cpu に設定すると、DeepSpeed は前述の ZeRO 操作に従い、トレーニング プロセス中にオプティマイザーの状態を CPU に割り当てます。これにより、単一の GPU のメモリ使用量が削減されます。
- について
overlap_comm
言及する必要があるもう 1 つのパラメータは ですoverlap_comm
。簡単に理解すると、複数のメモリ上のプロセス間の通信のためのバッファのサイズを制御します。この値が大きいほど、プロセス間の通信が高速になり、モデルのトレーニング速度が向上しますが、それに対応するグラフィックス メモリの使用量も増加します。逆も同様です。
したがって、overlap_comm
これは特定のトレードオフを必要とするパラメータでもあります。
- について
auto
上記の多数のパラメータが に設定されていることがわかりますauto
。DeepSpeed が HuggingFace Transformer フレームワークに統合されているためです。DeepSpeed の多くのパラメータは、Transformer の Trainer パラメータ設定とまったく同じです"optimizer"
。"scheduler"
したがって、一般的に使用される多くのモデル トレーニング パラメーターを に設定することが公式に推奨されており、auto
トレーニングに Trainer を使用する場合、これらの値は Trainer の設定に自動的に更新されるか、自動的に計算されます。
もちろん自分で設定することもできますが、Trainer の設定と同じであることを確認してください。なぜなら、設定が間違っている場合でも、DeepSpeed は通常どおり実行され、すぐにはエラーを報告しません。
- 要約する
ほとんどの場合、DeepSpedd 固有のパラメーター (オフロードなど) に注意するだけで済みます。 Trainer によって複製される他のパラメーターを設定することを強くお勧めしますauto
。これらの各パラメーターの具体的な意味や値の設定については、公式 Web サイトの詳細な紹介を参照してください。
全体として、設定によりauto
、上記の構成はほとんどの Transformer フレームワークのユースケースに適応できますstage-2
。
3.3 Zero ステージ 3
ステージ 2 と同様に、作成者はステージ 3 のテンプレート構成も提供します。
{
"bfloat16": {
"enabled": false
},
"fp16": {
"enabled": "auto",
"loss_scale": 0,
"loss_scale_window": 1000,
"initial_scale_power": 16,
"hysteresis": 2,
"min_loss_scale": 1
},
"optimizer": {
"type": "AdamW",
"params": {
"lr": "auto",
"betas": "auto",
"eps": "auto",
"weight_decay": "auto"
}
},
"scheduler": {
"type": "WarmupLR",
"params": {
"warmup_min_lr": "auto",
"warmup_max_lr": "auto",
"warmup_num_steps": "auto"
}
},
"zero_optimization": {
"stage": 3,
"offload_optimizer": {
"device": "cpu",
"pin_memory": true
},
"offload_param": {
"device": "cpu",
"pin_memory": true
},
"overlap_comm": true,
"contiguous_gradients": true,
"sub_group_size": 1e9,
"reduce_bucket_size": "auto",
"stage3_prefetch_bucket_size": "auto",
"stage3_param_persistence_threshold": "auto",
"stage3_max_live_parameters": 1e9,
"stage3_max_reuse_distance": 1e9,
"stage3_gather_fp16_weights_on_model_save": true
},
"gradient_accumulation_steps": "auto",
"gradient_clipping": "auto",
"steps_per_print": 1e5,
"train_batch_size": "auto",
"train_micro_batch_size_per_gpu": "auto",
"wall_clock_breakdown": false
}
- について
“offload_param”
offload_optimizer
ご覧のとおり、 stage2 と同じパラメーターに加えて、stage3 にも 1 つのoffload_param
パラメーターがあります。つまり、モデルパラメータを分割します。
- ステージ 3 に関連するその他のパラメータ
次のパラメータはステージ 3 固有です。
"sub_group_size": 1e9,
"reduce_bucket_size": "auto",
"stage3_prefetch_bucket_size": "auto",
"stage3_param_persistence_threshold": "auto",
"stage3_max_live_parameters": 1e9,
"stage3_max_reuse_distance": 1e9,
"stage3_gather_fp16_weights_on_model_save": true
同様に、これらの値の多くは、ステージ 3 のメモリ使用量とトレーニング効率を制御するために使用できます (例: sub_group_size
); 同時に、一部のパラメーターを auto に設定して、トレーナーが決定できるようにすることもできます。値 (例: 、 reduce_bucket_size
、stage3_prefetch_bucket_size
) stage3_param_persistence_threshold
。
これらのパラメータの詳細な説明と値のトレードオフについては、公式 Web サイトを参照してください:
ZeRO-3 Config
- 要約する
同じ理由で、上記の構成ファイルもほとんどのユースケースに適応できます。一部のステージ 3 固有のパラメーターには追加の注意が必要な場合があります。具体的には、公式ドキュメントを読むことをお勧めします。
3.4 ゼロインフィニティ
ステージ 2 と 3 に加えて、ここでは簡単に説明しますZeRO-Infinity
。
ZeRO-Infinity
これはステージ 3 の高度なバージョンと見なすことができ、NVMeサポートに依存する必要があります。すべてのモデルパラメータステータスを CPU と NVMe にオフロードできます。NMVe プロトコルのおかげで、ZeRO は CPU メモリの使用に加えて SSD (ソリッド ステート) も利用できるため、メモリのオーバーヘッドが大幅に節約され、通信速度が高速化されます。
公式ウェブサイトにはZeRO-Infinity
詳細な紹介が記載されています。
DeepSpeed官方教程 :
ZeRO-Infinity は、ZeRO-Offload のすべての節約に加えて、より多くのモデルの重みをオフロードすることができ、より効果的な帯域幅の利用と計算と通信の重複を実現します。
HuggingFace官网:
NVMeメモリでGPUとCPUメモリを拡張することで、信じられないほど大規模なモデルのトレーニングを可能にします。スマート パーティショニングおよびタイリング アルゴリズムのおかげで、各 GPU はオフロード中に非常に少量のデータを送受信する必要があるため、最新の NVMe がトレーニング プロセスで使用できる合計メモリ プールをさらに大きくするのに適していることが証明されました。ZeRO-Infinity には、ZeRO-3 が有効になっている必要があります。
具体的な設定ファイルや使い方については公式サイトを参照してください。
4. その他
4.1 モデル推論
モデルのトレーニングに加えて、モデルが大きすぎる場合があり、予測推論でもビデオ メモリを使い果たす可能性があります。
DeepSpeedは当然推論もサポートします。当然のことながら、推論するときは、 stage-3 と同じパラメータを持つ構成ファイルを使用できますが、一部のトレーニング パラメータ (オプティマイザー、lr など) は自動的に無視されます。
具体的な参照先:
ZeRO-Inference
4.2 メモリの推定
これまで何度も強調したように、DeepSpeed を使用する際の難しさの 1 つは时间和空间
トレードオフです。
CPU に割り当てるパラメータを増やすとメモリのオーバーヘッドを減らすことができますが、時間のオーバーヘッドも大幅に増加します。
DeepSpeed は、単純なメモリ推定コードを提供します。
from transformers import AutoModel
from deepspeed.runtime.zero.stage3 import estimate_zero3_model_states_mem_needs_all_live
## specify the model you want to train on your device
model = AutoModel.from_pretrained("t5-large")
## estimate the memory cost (both CPU and GPU)
estimate_zero3_model_states_mem_needs_all_live(model, num_gpus_per_node=1, num_nodes=1)
T5-large を例に挙げると、GPU を 1 つだけ使用すると、DeepSpeed を使用するオーバーヘッドは次のようになります。
上記のように、stage2 と stage3 (下の 2 行) が使用されていない場合、T5-large のトレーニングには、少なくとも 12.49 GB のビデオ メモリを備えたグラフィック カードが必要です (他の多くのキャッシュ変数や、batch_size を考慮すると、実際には 24GB のカードが必要です)。ステージ 2 と 3 を連続して使用した後、グラフィックス メモリのオーバーヘッドは大幅に減少しましたが、CPU メモリの消費量は大幅に増加し、それに応じてモデル トレーニング時間のオーバーヘッドも増加しました。
推奨事項:
DeepSpeed を使用する前に、上記のコードを使用してビデオ メモリの消費量を大まかに見積もり、使用する GPU の数と ZeRO ステージを決定します。
原則として、複数のカードで直接トレーニングできる場合は ZeRO を使用せず、ZeRO-2 を使用できる場合は ZeRO-3 を使用しないでください。
詳細については、公式 Web サイトを参照してください:メモリ要件
4.3 使用評価
著者はDeepSpeedを使用してモデルをトレーニングしようとしました。
1 つ目はステージ 2 で、CPU にオプティマイザーを配置するだけです。以下は、使用前と使用後の GPU メモリ使用量とトレーニング速度の比較です。
- GPU メモリ:
20513
MB =>17349
MiB - トレーニング速度 (
tqdm
推定値):1.3
iter/s =>0.77
iter/s
GPU メモリの使用量が大幅に減少していることがはっきりとわかりますが、トレーニング速度も遅くなりました。著者の現在の経験に基づくと、deepspeed は何のメリットももたらしません。
著者のマシンには24000
MB のグラフィック カードが搭載されています。batch_size が 2 の場合、MB を占有します。ただし、DeepSpeed はMB のビデオ メモリ20513
を解放するのに役立つだけであり、 batch_size を増やすのに十分ではなく、著者の合計トレーニング時間が長くなる。3000
したがって、DeepSpeed は、ビデオ メモリが極端に不足している状況 (モデルが大きすぎて、batch_size == 1 を実行できない場合)、または DeepSpped を使用して節約されたビデオ メモリで十分な状況にのみ適している可能性があります。より大きなbatch_sizeをサポートするため。それ以外の場合、著者の現在の状況では、DeepSpeed を使用しても時間のオーバーヘッドが増加するだけで、他の利点はありません。
その後、ステージ3も試してみましたが、速度が非常に遅かったです。当初6時間かかったトレーニングプロセスは、DeepSpeed stage3を使用した後、2日2晩実行され、終わる気配がありませんでした。著者はテストを中止せざるを得ませんでした。
さらに、DeepSpeed stage2を使用する場合、モデルパラメータが複数のデバイスに割り当てられるため、コンソールに出力情報が表示されず(ただし、GPUはまだブンブン唸り、ユーティリティは100%です)、人々はプログラムに気づかなくなります。 . 走行進行はユーザーにとって非常に不親切だと言えます。
4.4 よくある質問
DeepSpeedはCPUメモリを占有することでGPUのオーバーヘッドを遅くするため、システムのCPUが不足するとDeepSpeedプロセスがシステムによって自動的に停止され、エラーなくDeepSpeedを起動できない現象が発生します。まず、上記で紹介した見積もりを使用してCPU メモリ使用量を見積もり、次にfree -h
マシンの CPU メモリ容量を確認して DeepSpeed が使用できるかどうかを判断することをお勧めします。
さらに、損失の原因がトレーニングの精度の問題である可能性もありますNAN
。詳細については、 「トラブルシューティング」を参照してください。
DeepSpeed stage2使用後はオプティマイザを柔軟に変更できなくなります。次の図は、DeepSpeed.py のソース コードです。
デフォルトのオプティマイザーは構成で設定する必要があります。つまり、デフォルトのオプティマイザーと学習率が使用され、グループ学習率は達成できません。オプティマイザーの初期化プロセスをカスタマイズする場合は、オプティマイザーの 2 つのバージョン (CPU+GPU) を実装する必要があります。公式に述べられているように:
ZeRO オフロードおよび非 DeepSpeed オプティマイザーが検出されました: この組み合わせは、カスタム オプティマイザーに CPU と GPU の両方が実装されている限り機能します (LAMB を除く)。
つまり、この場合オプティマイザをカスタマイズしようとすると、さらに面倒になります。
最後に、VScode に大きく依存している患者については、
残念ながら、対応する VScode コンパイル プラグインがサポートされていないため、DeepSpeed プロセスは現在 Vscode でのデバッグをサポートしていません。詳細については、github の問題を参照してください。