Accélérer les transformateurs PyTorch avec Intel Sapphire Rapids – partie 1
'Accélérer PyTorch avec Intel Sapphire Rapids - partie 1'
Il y a environ un an, nous vous avons montré comment distribuer la formation des transformateurs de Hugging Face sur un cluster ou sur des processeurs Intel Xeon Scalable de troisième génération (également appelés Ice Lake). Récemment, Intel a lancé la quatrième génération de processeurs Xeon, appelée Sapphire Rapids, avec de nouvelles instructions passionnantes qui accélèrent les opérations couramment utilisées dans les modèles d’apprentissage profond.
Dans cet article, vous apprendrez comment accélérer un travail de formation PyTorch avec un cluster de serveurs Sapphire Rapids exécutant sur AWS. Nous utiliserons la bibliothèque Intel oneAPI Collective Communications Library (CCL) pour distribuer le travail, et la bibliothèque Intel Extension pour PyTorch (IPEX) pour mettre automatiquement en œuvre les nouvelles instructions du processeur. Comme les deux bibliothèques sont déjà intégrées à la bibliothèque Hugging Face transformers, nous serons en mesure d’exécuter nos scripts d’exemple sans avoir à modifier une seule ligne de code.
Dans un article ultérieur, nous examinerons l’inférence sur les processeurs Sapphire Rapids et l’augmentation des performances qu’ils apportent.
Pourquoi vous devriez envisager de vous former sur des CPUs
L’entraînement d’un modèle d’apprentissage profond (DL) sur des CPUs Intel Xeon peut être une approche rentable et évolutive, notamment lors de l’utilisation de techniques telles que l’entraînement distribué et le réglage fin sur des ensembles de données de petite taille et VoAGI.
- IA pour le développement de jeux Création d’un jeu de ferme en 5 jours. Partie 1
- Introduction à l’apprentissage machine sur les graphes
- IA pour le développement de jeux Création d’un jeu de ferme en 5 jours. Partie 2
Les CPUs Xeon prennent en charge des fonctionnalités avancées telles que les Advanced Vector Extensions (AVX-512) et l’Hyper-Threading, qui améliorent le parallélisme et l’efficacité des modèles DL. Cela permet des temps d’entraînement plus rapides ainsi qu’une meilleure utilisation des ressources matérielles.
De plus, les CPUs Xeon sont généralement plus abordables et largement disponibles par rapport à des matériels spécialisés tels que les GPU, qui sont généralement nécessaires pour l’entraînement de grands modèles d’apprentissage profond. Les CPUs Xeon peuvent également être facilement réutilisés pour d’autres tâches de production, des serveurs web aux bases de données, ce qui en fait un choix polyvalent et flexible pour votre infrastructure informatique.
Enfin, les utilisateurs de cloud peuvent réduire davantage les coûts de formation sur les CPUs Xeon avec des instances Spot. Les instances Spot sont créées à partir de capacités de calcul inutilisées et vendues à un prix réduit. Elles peuvent permettre des économies de coûts importantes par rapport à l’utilisation d’instances à la demande, parfois jusqu’à 90%. Enfin, les instances Spot CPU sont généralement plus faciles à obtenir que les instances GPU.
Maintenant, examinons les nouvelles instructions de l’architecture Sapphire Rapids.
Advanced Matrix Extensions : Nouvelles instructions pour l’apprentissage profond
L’architecture Sapphire Rapids introduit les Advanced Matrix Extensions (AMX) d’Intel pour accélérer les charges de travail DL. Les utiliser est aussi simple que d’installer la dernière version de IPEX. Il n’est pas nécessaire de modifier quoi que ce soit dans votre code Hugging Face.
Les instructions AMX accélèrent la multiplication de matrices, une opération centrale dans l’entraînement des modèles DL sur des lots de données. Elles prennent en charge à la fois le Brain Floating Point (BF16) et les valeurs entières sur 8 bits (INT8), ce qui permet une accélération pour différents scénarios d’entraînement.
AMX introduit de nouveaux registres CPU bidimensionnels, appelés registres de tuile. Comme ces registres doivent être sauvegardés et restaurés lors des changements de contexte, ils nécessitent une prise en charge du noyau : sous Linux, vous aurez besoin de la version 5.16 ou ultérieure.
Maintenant, voyons comment construire un cluster de CPUs Sapphire Rapids pour une formation distribuée.
Construction d’un cluster de CPUs Sapphire Rapids
À l’heure actuelle, la manière la plus simple d’obtenir des serveurs Sapphire Rapids est d’utiliser la nouvelle famille d’instances Amazon EC2 R7iz. Comme elle est encore en préversion, vous devez vous inscrire pour y avoir accès. De plus, les serveurs virtuels ne prennent pas encore en charge AMX, nous utiliserons donc des instances bare metal (r7iz.metal-16xl, 64 vCPU, 512 Go de RAM).
Pour éviter de configurer chaque nœud du cluster manuellement, nous commencerons par configurer le nœud maître et créer une nouvelle image de machine Amazon (AMI) à partir de celui-ci. Ensuite, nous utiliserons cette AMI pour lancer des nœuds supplémentaires.
Sur le plan de la mise en réseau, nous aurons besoin de la configuration suivante :
-
Ouvrir le port 22 pour l’accès ssh sur toutes les instances pour la configuration et le débogage.
-
Configurer un accès ssh sans mot de passe depuis l’instance maître (celle à partir de laquelle vous lancerez la formation) vers toutes les autres instances (y compris le maître). En d’autres termes, la clé publique ssh du nœud maître doit être autorisée sur tous les nœuds.
-
Autoriser tout le trafic réseau à l’intérieur du cluster, de sorte que la formation distribuée s’exécute sans encombre. AWS fournit un moyen sûr et pratique de le faire avec les groupes de sécurité. Nous devons simplement créer un groupe de sécurité qui autorise tout le trafic provenant d’instances configurées avec le même groupe de sécurité et nous assurer de le joindre à toutes les instances du cluster. Voici à quoi ressemble ma configuration.
Travaillons maintenant et construisons le nœud maître du cluster.
Configuration du nœud maître
Nous créons d’abord le nœud maître en lançant une instance r7iz.metal-16xl
avec une AMI Ubuntu 20.04 ( ami-07cd3e6c4915b2d18
) et le groupe de sécurité que nous avons créé précédemment. Cette AMI inclut Linux v5.15.0, mais Intel et AWS ont heureusement corrigé le noyau pour ajouter la prise en charge d’AMX. Ainsi, nous n’avons pas besoin de mettre à niveau le noyau vers v5.16.
Une fois l’instance en cours d’exécution, nous nous y connectons en utilisant ssh et vérifions avec lscpu
que AMX est effectivement pris en charge. Vous devriez voir ce qui suit dans la section des indicateurs :
amx_bf16 amx_tile amx_int8
Ensuite, nous installons les dépendances natives et Python.
sudo apt-get update
# Install tcmalloc for extra performance (https://github.com/google/tcmalloc)
sudo apt install libgoogle-perftools-dev -y
# Create a virtual environment
sudo apt-get install python3-pip -y
pip install pip --upgrade
export PATH=/home/ubuntu/.local/bin:$PATH
pip install virtualenv
# Activate the virtual environment
virtualenv cluster_env
source cluster_env/bin/activate
# Install PyTorch, IPEX, CCL and 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
# Clone the transformers repository for its example scripts
git clone https://github.com/huggingface/transformers.git
cd transformers
git checkout v4.24.0
Ensuite, nous créons une nouvelle paire de clés ssh appelée “cluster” avec ssh-keygen
et la stockons à l’emplacement par défaut ( ~/.ssh
).
Enfin, nous créons une nouvelle AMI à partir de cette instance.
Configuration du cluster
Une fois l’AMI prête, nous l’utilisons pour lancer 3 instances supplémentaires r7iz.16xlarge-metal
, sans oublier d’attacher le groupe de sécurité créé précédemment.
Pendant que ces instances sont en cours de démarrage, nous nous connectons au nœud maître en utilisant ssh pour terminer la configuration réseau. Tout d’abord, nous modifions le fichier de configuration ssh à l’emplacement ~/.ssh/config
pour permettre les connexions sans mot de passe du maître à tous les autres nœuds, en utilisant leur adresse IP privée et la paire de clés créée précédemment. Voici à quoi ressemble mon fichier :
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
À ce stade, nous pouvons utiliser ssh node[1-3]
pour nous connecter à n’importe quel nœud sans aucune demande.
Sur le nœud maître, nous créons un fichier ~/hosts
avec les noms de tous les nœuds du cluster, tels que définis dans la configuration ssh ci-dessus. Nous utilisons localhost
pour le maître car nous lancerons le script d’entraînement là-bas. Voici à quoi ressemble mon fichier :
localhost
node1
node2
node3
Le cluster est maintenant prêt. Commençons l’entraînement !
Lancement d’un travail d’entraînement distribué
Dans cet exemple, nous allons affiner un modèle DistilBERT pour la réponse aux questions sur l’ensemble de données SQUAD. N’hésitez pas à essayer d’autres exemples si vous le souhaitez.
source ~/cluster_env/bin/activate
cd ~/transformers/examples/pytorch/question-answering
pip3 install -r requirements.txt
Comme vérification de cohérence, nous lançons d’abord un travail d’entraînement local. Veuillez noter plusieurs indicateurs importants :
no_cuda
s’assure que le travail ignore tout GPU sur cette machine,use_ipex
active la bibliothèque IPEX et donc les instructions AVX et AMX,bf16
active l’entraînement 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
Pas besoin de laisser le travail s’exécuter jusqu’à la fin, nous le lançons simplement pendant une minute pour nous assurer que toutes les dépendances ont été correctement installées. Cela nous donne également une référence pour l’entraînement sur une seule instance : 1 époque prend environ 26 minutes. Pour référence, nous avons mesuré le même travail sur une instance Ice Lake comparable (c6i.16xlarge
) avec la même configuration logicielle à 3 heures et 30 minutes par époque. C’est un gain de vitesse de 8 fois. Nous pouvons déjà voir à quel point les nouvelles instructions sont bénéfiques !
Maintenant, répartissons le travail d’entraînement sur quatre instances. Une instance r7iz.16xlarge
a 32 cœurs de CPU physiques, que nous préférons utiliser directement au lieu des vCPU (KMP_HW_SUBSET=1T
). Nous décidons d’allouer 24 cœurs pour l’entraînement (OMP_NUM_THREADS
) et 2 pour la communication CCL (CCL_WORKER_COUNT
), laissant les 6 derniers threads au noyau et aux autres processus. Les 24 threads d’entraînement prennent en charge 2 processus Python (NUM_PROCESSES_PER_NODE
). Ainsi, le nombre total de travaux Python s’exécutant sur le cluster à 4 nœuds est de 8 (NUM_PROCESSES
).
# Configuration des variables d'environnement pour 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
Maintenant, nous lançons le travail d’entraînement distribué.
# Lancement de l'entraînement distribué
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
Une époque prend maintenant 7 minutes et 30 secondes.
Voici à quoi ressemble le travail. Le nœud maître est en haut, et vous pouvez voir les deux processus d’entraînement s’exécutant sur chacun des 3 autres nœuds.
Une mise à l’échelle linéaire parfaite sur 4 nœuds serait de 6 minutes et 30 secondes (26 minutes divisées par 4). Nous sommes très proches de cette valeur idéale, ce qui montre à quel point cette approche est évolutive.
Conclusion
Comme vous pouvez le voir, l’entraînement des transformeurs Hugging Face sur un cluster de processeurs Intel Xeon est une solution flexible, évolutive et rentable, surtout si vous travaillez avec des modèles et des ensembles de données de petite taille ou de taille VoAGI.
Voici quelques ressources supplémentaires pour vous aider à démarrer :
- Intel IPEX sur GitHub
- Documentation de Hugging Face : ” Entraînement efficace sur CPU ” et ” Entraînement efficace sur plusieurs CPU “.
Si vous avez des questions ou des commentaires, nous aimerions les lire sur le forum Hugging Face.
Merci de votre lecture !
We will continue to update IPGirl; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles
- Similarité d’image avec les ensembles de données et les transformateurs Hugging Face
- Bienvenue à PaddlePaddle sur le Hugging Face Hub
- Segmentation universelle des images avec Mask2Former et OneFormer
- Génération d’actifs 3D IA pour le développement de jeux #3
- Optimum+ONNX Runtime – Formation plus facile et plus rapide pour vos modèles Hugging Face
- Qu’est-ce qui rend un agent de dialogue utile ?
- Utilisation de LoRA pour un affinage de diffusion stable et efficace