インテルのサファイアラピッズを使用してPyTorch Transformersを高速化する – パート1
Using Intel's Sapphire Rapids to accelerate PyTorch Transformers - Part 1.
約1年前、私たちはHugging Faceのtransformersをクラスターまたは第3世代のIntel Xeon Scalable CPU(別名:Ice Lake)でトレーニングする方法を紹介しました。最近、Intelは第4世代のXeon CPUであるSapphire Rapidsというコードネームの新しいCPUを発売しました。このCPUには、深層学習モデルでよく見られる操作を高速化するエキサイティングな新しい命令があります。
この投稿では、AWS上で実行するSapphire Rapidsサーバーのクラスターを使用して、PyTorchトレーニングジョブの処理を高速化する方法を学びます。ジョブの分散にはIntelのoneAPI Collective Communications Library(CCL)を使用し、新しいCPU命令を自動的に活用するためにIntel Extension for PyTorch(IPEX)ライブラリを使用します。両方のライブラリはすでにHugging Face transformersライブラリと統合されているため、コードの1行も変更せずにサンプルスクリプトをそのまま実行できます。
次の投稿では、Sapphire Rapids CPU上での推論とそれによるパフォーマンス向上について説明します。
CPUでのトレーニングを検討すべき理由
Intel Xeon CPUで深層学習(DL)モデルをトレーニングすることは、コスト効果がありスケーラブルなアプローチです。特に分散トレーニングや小規模でVoAGIデータセットでのファインチューニングなどの技術を使用する場合に適しています。
Xeon CPUは、Advanced Vector Extensions(AVX-512)やハイパースレッディングなどの高度な機能をサポートしており、DLモデルの並列性と効率を向上させるのに役立ちます。これにより、トレーニング時間が短縮され、ハードウェアリソースの効果的な利用が可能となります。
さらに、Xeon CPUは通常、大規模な深層学習モデルのトレーニングに必要なGPUなどの専用ハードウェアと比較して、より手頃な価格で広く利用できます。Xeon CPUはWebサーバーやデータベースなど、他のプロダクションタスクに簡単に転用することもできるため、ITインフラストラクチャの多目的で柔軟な選択肢となります。
最後に、クラウドユーザーはXeon CPUでのトレーニングコストをスポットインスタンスでさらに削減することができます。スポットインスタンスは予備の計算能力から構築され、割引価格で販売されます。オンデマンドインスタンスを使用する場合と比べて、90%までのコスト削減が可能です。CPUスポットインスタンスも一般的にGPUインスタンスよりも調達が容易です。
さあ、Sapphire Rapidsアーキテクチャの新しい命令を見てみましょう。
Advanced Matrix Extensions:深層学習の新しい命令
Sapphire Rapidsアーキテクチャでは、Intel Advanced Matrix Extensions(AMX)が導入され、DLワークロードの高速化が可能となります。AMXの使用は、最新バージョンのIPEXをインストールするだけで簡単です。Hugging Faceのコードを変更する必要はありません。
AMX命令は、データバッチ上でのDLモデルのトレーニングに中心的な演算である行列の乗算を高速化します。Brain Floating Point(BF16)および8ビット整数(INT8)の値の両方をサポートしており、さまざまなトレーニングシナリオでの高速化が可能です。
AMXは、タイルレジスタと呼ばれる新しい2次元CPUレジスタを導入しています。これらのレジスタはコンテキストスイッチ中に保存および復元する必要があるため、カーネルのサポートが必要です。Linuxでは、v5.16以降が必要です。
さあ、Sapphire Rapids CPUのクラスターを構築する方法を見てみましょう。
Sapphire Rapids CPUのクラスターの構築
現時点では、Sapphire Rapidsサーバーを手に入れる最も簡単な方法は、新しいAmazon EC2 R7izインスタンスファミリーを使用することです。まだプレビュー段階のため、アクセスを取得するためにサインアップする必要があります。また、仮想サーバーはまだAMXをサポートしていないため、ベアメタルインスタンス(r7iz.metal-16xl
、64 vCPU、512GB RAM)を使用します。
クラスター内の各ノードを手動で設定するのを避けるために、まずマスターノードを設定し、それを元に新しいAmazon Machine Image(AMI)を作成します。次に、このAMIを使用して追加のノードを起動します。
ネットワークの観点から、次の設定が必要です:
-
セットアップとデバッグのためにすべてのインスタンスでsshアクセス用のポート22を開く。
-
マスターインスタンス(トレーニングを開始するインスタンス)から他のすべてのインスタンス(マスターを含む)へのパスワードなしのsshを設定する。つまり、マスターノードのssh公開鍵はすべてのノードで認可されている必要があります。
-
クラスター内でのすべてのネットワークトラフィックを許可し、分散トレーニングがスムーズに実行されるようにします。AWSでは、セキュリティグループを使用してこれを安全かつ便利に行うことができます。同じセキュリティグループで構成されたインスタンスからのすべてのトラフィックを許可するセキュリティグループを作成し、クラスター内のすべてのインスタンスにアタッチする必要があります。以下に私のセットアップの例を示します。
さあ、作業を始めてクラスターのマスターノードを構築しましょう。
マスターノードの設定
まず、r7iz.metal-16xl
インスタンスを起動し、以前に作成したセキュリティグループとUbuntu 20.04 AMI( ami-07cd3e6c4915b2d18
)を使用してマスターノードを作成します。このAMIにはLinux v5.15.0が含まれていますが、幸いにもIntelとAWSはカーネルにAMXサポートを追加するためにパッチを当てています。したがって、カーネルをv5.16にアップグレードする必要はありません。
インスタンスが起動したら、sshで接続し、lscpu
でAMXがサポートされているか確認します。フラグのセクションに次のような表示が表示されるはずです:
amx_bf16 amx_tile amx_int8
次に、ネイティブおよびPythonの依存関係をインストールします。
sudo apt-get update
# パフォーマンス向上のためにtcmallocをインストールします(https://github.com/google/tcmalloc)
sudo apt install libgoogle-perftools-dev -y
# 仮想環境を作成します
sudo apt-get install python3-pip -y
pip install pip --upgrade
export PATH=/home/ubuntu/.local/bin:$PATH
pip install virtualenv
# 仮想環境をアクティブにします
virtualenv cluster_env
source cluster_env/bin/activate
# PyTorch、IPEX、CCL、Transformersをインストールします
pip3 install torch==1.13.0 -f https://download.pytorch.org/whl/cpu
pip3 install intel_extension_for_pytorch==1.13.0 -f https://developer.intel.com/ipex-whl-stable-cpu
pip3 install oneccl_bind_pt==1.13 -f https://developer.intel.com/ipex-whl-stable-cpu
pip3 install transformers==4.24.0
# Transformersの例のスクリプトのためにtransformersリポジトリをクローンします
git clone https://github.com/huggingface/transformers.git
cd transformers
git checkout v4.24.0
次に、ssh-keygen
を使用して ‘cluster’ という名前の新しいSSHキーペアを作成し、デフォルトの場所( ~/.ssh
)に保存します。
最後に、このインスタンスから新しいAMIを作成します。
クラスターの設定
AMIが準備できたら、それを使用して3つの追加のr7iz.16xlarge-metal
インスタンスを起動します。以前に作成したセキュリティグループをアタッチすることを忘れないでください。
これらのインスタンスが起動している間に、マスターノードにsshで接続してネットワークの設定を完了します。まず、マスターノードから他のすべてのノードへのパスワードなし接続を有効にするために、~/.ssh/config
でsshの設定ファイルを編集します。プライベートIPアドレスと以前に作成したキーペアを使用します。以下に私のファイルの例を示します。
Host 172.31.*.*
StrictHostKeyChecking no
Host node1
HostName 172.31.10.251
User ubuntu
IdentityFile ~/.ssh/cluster
Host node2
HostName 172.31.10.189
User ubuntu
IdentityFile ~/.ssh/cluster
Host node3
HostName 172.31.6.15
User ubuntu
IdentityFile ~/.ssh/cluster
この時点で、ssh node[1-3]
を使用してプロンプトなしで任意のノードに接続できます。
マスターノード上で、クラスターのすべてのノードの名前を含む ~/hosts
ファイルを作成します。上記のssh設定で定義されています。マスターには localhost
を使用します。以下に私のファイルの例を示します。
localhost
node1
node2
node3
クラスターは準備完了です。トレーニングを開始しましょう!
分散トレーニングジョブの開始
この例では、SQUADデータセット上で質問応答のためのDistilBERTモデルを微調整します。他の例を試してみても構いません。
source ~/cluster_env/bin/activate
cd ~/transformers/examples/pytorch/question-answering
pip3 install -r requirements.txt
まず、ローカルトレーニングジョブを起動して、サニティチェックとして使用します。いくつかの重要なフラグに注意してください:
no_cuda
は、このマシン上のすべてのGPUを無視することを保証します。use_ipex
は、IPEXライブラリを有効にし、AVXおよびAMX命令を有効にします。bf16
は、BF16トレーニングを有効にします。
export LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libtcmalloc.so"
python run_qa.py --model_name_or_path distilbert-base-uncased \
--dataset_name squad --do_train --do_eval --per_device_train_batch_size 32 \
--num_train_epochs 1 --output_dir /tmp/debug_squad/ \
--use_ipex --bf16 --no_cuda
ジョブを完了させる必要はありません。すべての依存関係が正しくインストールされていることを確認するために1分間だけ実行します。また、シングルインスタンスのトレーニングの基準となる時間も取得できます。1エポックには約26分かかります。参考までに、同じソフトウェア設定で同等のIce Lakeインスタンス(c6i.16xlarge
)で実行した場合、1エポックあたり3時間30分かかります。これは8倍の高速化です。新しい命令がどれだけ有益かがすでにわかります!
それでは、トレーニングジョブを4つのインスタンスに分散させましょう。 r7iz.16xlarge
インスタンスには32個の物理CPUコアがあり、vCPUではなく直接使用することをお勧めします( KMP_HW_SUBSET=1T
)。トレーニングには24のコアを割り当てることにし、CCL通信には2つのコアを割り当てます( CCL_WORKER_COUNT
)。残りの6つのスレッドはカーネルとその他のプロセスに割り当てられます。トレーニングには24のスレッドが必要で、2つのPythonプロセスをサポートします( NUM_PROCESSES_PER_NODE
)。したがって、4ノードのクラスタで実行されるPythonジョブの総数は8です( NUM_PROCESSES
)。
# CCLの環境変数を設定する
oneccl_bindings_for_pytorch_path=$(python -c "from oneccl_bindings_for_pytorch import cwd; print(cwd)")
source $oneccl_bindings_for_pytorch_path/env/setvars.sh
export MASTER_ADDR=172.31.3.190
export NUM_PROCESSES=8
export NUM_PROCESSES_PER_NODE=2
export CCL_WORKER_COUNT=2
export CCL_WORKER_AFFINITY=auto
export KMP_HW_SUBSET=1T
それでは、分散トレーニングジョブを起動しましょう。
# 分散トレーニングを起動する
mpirun -f ~/hosts \
-n $NUM_PROCESSES -ppn $NUM_PROCESSES_PER_NODE \
-genv OMP_NUM_THREADS=24 \
-genv LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libtcmalloc.so" \
python3 run_qa.py \
--model_name_or_path distilbert-base-uncased \
--dataset_name squad \
--do_train \
--do_eval \
--per_device_train_batch_size 32 \
--num_train_epochs 1 \
--output_dir /tmp/debug_squad/ \
--overwrite_output_dir \
--no_cuda \
--xpu_backend ccl \
--bf16
1エポックには今や7分30秒かかります。
ジョブの構造は次のようになります。マスターノードは上部にあり、他の3つのノードのそれぞれで2つのトレーニングプロセスが実行されているのが見えます。
4つのノードで完全な線形スケーリングは6分30秒(26分を4で割ったもの)です。この理想的な値に非常に近いことがわかります。このアプローチのスケーラビリティの高さが示されています。
結論
Hugging FaceのトランスフォーマーをIntel Xeon CPUクラスタでトレーニングすることは、特に小さなモデルやVoAGIサイズのモデルとデータセットを使用する場合に、柔軟でスケーラブルで費用効果の高い解決策です。
はじめるための追加リソース:
- Intel IPEX on GitHub
- Hugging Face documentation: ” Efficient training on CPU ” and ” Efficient training on many CPUs “.
質問やフィードバックがある場合は、Hugging Faceフォーラムでお待ちしております。
お読みいただき、ありがとうございました!
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles