Cette page explique comment exécuter des jobs d'entraînement distribué dans Vertex AI.
Exigences relatives au code
Utiliser un framework de ML compatible avec l'entraînement distribué. Dans votre code d'entraînement, vous pouvez utiliser les variables d'environnement CLUSTER_SPEC
ou TF_CONFIG
pour référencer des parties spécifiques de votre cluster d'entraînement.
Structure du cluster d'entraînement
Si vous exécutez un job d'entraînement distribué avec Vertex AI, vous spécifiez plusieurs machines (nœuds) dans un cluster d'entraînement. Le service d'entraînement alloue les ressources pour les types de machines que vous spécifiez. Le job en cours d'exécution sur un nœud spécifique s'appelle une instance dupliquée. Un groupe d'instances dupliquées avec la même configuration est appelé pool de nœuds de calcul.
Chaque instance dupliquée du cluster d'entraînement se voit attribuer un rôle ou une tâche unique dans l'entraînement distribué. Exemple :
Instance dupliquée principale : une instance dupliquée est désignée comme instance dupliquée principale. Cette tâche gère les autres et consigne l'état du job dans son ensemble.
Nœud(s) de calcul : une ou plusieurs instances dupliquées peuvent être désignées comme nœuds de calcul. Ces instances dupliquées exécutent ce qui leur incombe conformément à la configuration du job.
Serveur(s) de paramètres : si votre framework de ML est compatible, une ou plusieurs instances dupliquées peuvent être désignées comme serveurs de paramètres. Ces instances dupliquées stockent les paramètres du modèle et coordonnent l'état du modèle partagé entre les nœuds de calcul.
Évaluateurs : si votre framework de ML est compatible, une ou plusieurs instances dupliquées peuvent être désignées comme évaluateurs. Ces instances dupliquées peuvent être utilisées pour évaluer votre modèle. Si vous utilisez TensorFlow, notez que celui-ci s'attend généralement à ce que vous n'utilisiez pas plus d'un évaluateur.
Configurer un job d'entraînement distribué
Vous pouvez configurer n'importe quel job d'entraînement personnalisé en tant que job d'entraînement distribué en définissant plusieurs pools de nœuds de calcul. Vous pouvez également exécuter un entraînement distribué au sein d'un pipeline d'entraînement ou d'un job de réglage d'hyperparamètres.
Pour configurer un job d'entraînement distribué, définissez votre liste de pools de nœuds de calcul (workerPoolSpecs[]
) en spécifiant un ID de machine (WorkerPoolSpec
) pour chaque type de tâche :
Position dans workerPoolSpecs[] |
Tâche effectuée dans le cluster |
---|---|
Premier (workerPoolSpecs[0] ) |
Principal, chef, programmeur ou "maître" |
Seconde (workerPoolSpecs[1] ) |
Instances secondaires, instances dupliquées, nœuds de calcul |
Troisième (workerPoolSpecs[2] ) |
Serveurs de paramètres, Reduction Server |
Quatrième (workerPoolSpecs[3] ) |
Évaluateurs |
Vous devez spécifier une instance dupliquée principale, qui coordonne le travail effectué par toutes les autres instances dupliquées. Utilisez la spécification de premier pool de nœuds de calcul uniquement pour votre instance dupliquée principale, puis définissez son replicaCount
sur 1
:
{
"workerPoolSpecs": [
// `WorkerPoolSpec` for worker pool 0, primary replica, required
{
"machineSpec": {...},
"replicaCount": 1,
"diskSpec": {...},
...
},
// `WorkerPoolSpec` for worker pool 1, optional
{},
// `WorkerPoolSpec` for worker pool 2, optional
{},
// `WorkerPoolSpec` for worker pool 3, optional
{}
]
...
}
Spécifier des pools de nœuds de calcul supplémentaires
Selon votre framework de ML, vous pouvez spécifier des pools de nœuds de calcul supplémentaires à d'autres fins. Par exemple, si vous utilisez TensorFlow, vous pouvez spécifier des pools de nœuds de calcul pour configurer des instances dupliquées de nœuds de calcul, des instances dupliquées de serveurs de paramètres et des instances dupliquées d'évaluateurs.
L'ordre des pools de nœuds de calcul que vous spécifiez dans la liste workerPoolSpecs[]
détermine le type de pool de nœuds de calcul. Définissez des valeurs vides pour les pools de nœuds de calcul que vous ne souhaitez pas utiliser afin de pouvoir les ignorer dans la liste workerPoolSpecs[]
de manière à spécifier les pools de nœuds de calcul que vous souhaitez utiliser. Exemple :
Si vous souhaitez spécifier un job qui ne comporte qu'une instance dupliquée principale et un pool de nœuds de calcul de serveur de paramètres, vous devez définir une valeur vide pour le pool de nœuds de calcul 1 :
{
"workerPoolSpecs": [
// `WorkerPoolSpec` for worker pool 0, required
{
"machineSpec": {...},
"replicaCount": 1,
"diskSpec": {...},
...
},
// `WorkerPoolSpec` for worker pool 1, optional
{},
// `WorkerPoolSpec` for worker pool 2, optional
{
"machineSpec": {...},
"replicaCount": 1,
"diskSpec": {...},
...
},
// `WorkerPoolSpec` for worker pool 3, optional
{}
]
...
}
Réduire le temps d'entraînement avec Reduction Server
Lorsque vous entraînez un modèle de ML volumineux à l'aide de plusieurs nœuds, la communication des gradients entre les nœuds peut augmenter considérablement la latence. Reduction Server est un algorithme entièrement réduit qui peut augmenter le débit et réduire la latence de l'entraînement distribué. Vertex AI rend Reduction Server disponible dans une image de conteneur Docker que vous pouvez utiliser pour l'un de vos pools de nœuds de calcul pendant l'entraînement distribué.
Pour en savoir plus sur le fonctionnement de Reduction Server, consultez la section Entraînement GPU distribué plus rapide avec Reduction Server sur Red AI.
Prérequis
Vous pouvez utiliser Reduction Server si vous remplissez les conditions suivantes :
Vous effectuez un entraînement distribué avec des nœuds de calcul GPU.
Votre code d'entraînement utilise TensorFlow ou PyTorch, et il est configuré pour un entraînement avec parallélisme des données sur plusieurs hôtes avec des GPU à l'aide de l'algorithme NCCL entièrement réduit. (Vous pouvez également utiliser d'autres frameworks de ML utilisant NCCL.)
Les conteneurs s'exécutant sur votre nœud principal (
workerPoolSpecs[0]
) et les nœuds de calcul (workerPoolSpecs[1]
) sont compatibles avec Reduction Server. Plus précisément, chaque conteneur est l'un des éléments suivants :Un conteneur d'entraînement TensorFlow prédéfini, version 2.3 ou ultérieure.
Un conteneur d'entraînement Pytorch prédéfini, version 1.4 ou ultérieure.
Un conteneur personnalisé avec la version NCCL 2.7 ou ultérieure et le package
google-reduction-server
installé. Vous pouvez installer ce package sur une image de conteneur personnalisé en ajoutant la ligne suivante à votre fichier Dockerfile :RUN echo "deb https://packages.cloud.google.com/apt google-fast-socket main" | tee /etc/apt/sources.list.d/google-fast-socket.list && \ curl -s -L https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \ apt update && apt install -y google-reduction-server
Entraîner avec Reduction Server
Pour utiliser Reduction Server, procédez comme suit lorsque vous créez une ressource d'entraînement personnalisée :
Spécifiez l'un des URI suivants dans le champ
containerSpec.imageUri
du troisième pool de nœuds de calcul (workerPoolSpecs[2]
) :us-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
europe-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
asia-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
Le choix de l'emplacement multirégional le plus proche de l'emplacement où vous effectuez l'entraînement personnalisé peut réduire la latence.
Lorsque vous sélectionnez le type de machine et le nombre de nœuds pour le troisième pool de nœuds de calcul, assurez-vous que la bande passante réseau totale du troisième pool de nœuds correspond ou dépasse la bande passante réseau totale du premier et du deuxième pools de nœuds de calcul.
Pour en savoir plus sur la bande passante maximale disponible de chaque nœud dans le deuxième pool de nœuds de calcul, consultez la section Bande passante réseau et GPU.
Vous n'utilisez pas de GPU pour les nœuds de Reduction Server. Pour en savoir plus sur la bande passante maximale disponible de chaque nœud du troisième pool de nœuds de calcul, consultez les colonnes "Bande passante de sortie maximale (Gbit/s)" de la section Famille des machines à usage général.
Par exemple, si vous configurez les premier et deuxième pools de nœuds de calcul pour qu'ils utilisent 5 nœuds
n1-highmem-96
, chacun avec 8 GPUNVIDIA_TESLA_V100
, chaque nœud dispose d'une bande passante maximale de 100 Gbit/s, pour une bande passante totale de 500 Gbit/s. Pour correspondre à cette bande passante dans le troisième pool de nœuds de calcul, vous pouvez utiliser 16 nœudsn1-highcpu-16
, chacun avec une bande passante maximale de 32 Gbit/s, pour une bande passante totale de 512 Gbit/s.Nous vous recommandons d'utiliser le type de machine
n1-highcpu-16
pour les nœuds de Reduction Server, car il offre une bande passante relativement élevée pour ses ressources.
La commande suivante fournit un exemple de création d'une ressource CustomJob
utilisant Reduction Server :
gcloud ai custom-jobs create \
--region=LOCATION \
--display-name=JOB_NAME \
--worker-pool-spec=machine-type=n1-highmem-96,replica-count=1,accelerator-type=NVIDIA_TESLA_V100,accelerator-count=8,container-image-uri=CUSTOM_CONTAINER_IMAGE_URI \
--worker-pool-spec=machine-type=n1-highmem-96,replica-count=4,accelerator-type=NVIDIA_TESLA_V100,accelerator-count=8,container-image-uri=CUSTOM_CONTAINER_IMAGE_URI \
--worker-pool-spec=machine-type=n1-highcpu-16,replica-count=16,container-image-uri=us-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
Pour plus de contexte, consultez le guide de création d'un CustomJob
.
Bonnes pratiques pour l'entraînement avec Reduction Server
Type et nombre de machines
Lors de l'entraînement avec Reduction Server, chaque nœud de calcul doit se connecter à tous les hôtes de réducteur. Pour réduire le nombre de connexions sur l'hôte de calcul, utilisez un type de machine avec la bande passante réseau la plus élevée pour votre hôte de réducteur.
Un bon choix pour les hôtes de réducteur est une VM N1/N2 à usage général avec au moins 16 processeurs virtuels fournissant une bande passante de sortie de 32 Gbit/s, telle que n1-highcpu-16
et n2-highcpu-16
. La bande passante de VM de niveau 1 pour les VM N1/N2 augmente la bande passante de sortie maximale, allant de 50 Gbit/s à 100 Gbit/s, ce qui en fait un bon choix pour les nœuds de VM de réducteur.
La bande passante de sortie totale des nœuds de calcul et de réducteur doit être identique. Par exemple, si vous utilisez 8 VM a2-megagpu-16g
en tant que nœuds de calcul, vous devez utiliser au moins 25 VM n1-highcpu-16
en tant que nœuds de réducteur.
`(8 worker VMs * 100 Gbps) / 32 Gbps egress = 25 reducer VMs`.
Regrouper les petits messages
Reduction Server fonctionne mieux si les messages à agréger sont suffisamment volumineux. La plupart des frameworks de ML fournissent déjà des techniques selon une terminologie différente pour regrouper des petits Tensors de gradient avant d'effectuer une réduction globale (all-reduce).
Horovod
Hoovod est compatible avec Tensor Fusion pour regrouper des petits Tensors pour effectuer une réduction globale (all-reduce). Les Tensors sont remplis dans un tampon de fusion jusqu'à ce que le tampon soit entièrement rempli et que l'opération de réduction globale sur le tampon s'exécute. Vous pouvez ajuster la taille du tampon de fusion en définissant la variable d'environnement HOROVOD_FUSION_THRESHOLD
.
La valeur recommandée pour la variable d'environnement HOROVOD_FUSION_THRESHOLD
est d'au moins 128 Mo. Dans ce cas, définissez la variable d'environnement HOROVOD_FUSION_THRESHOLD
sur 134217728 (128 * 1024 * 1024).
PyTorch
PyTorch DistributedDataParallel accepte les messages par lot en tant que "binning de gradient". Définissez le paramètre bucket_cap_mb
dans le constructeur DistributedDataParallel
pour contrôler la taille de vos buckets par lots.
La taille par défaut est de 25 Mo.
BONNE PRATIQUE : la valeur recommandée de bucket_cap_mb est de 64 (64 Mo).
Variables d'environnement pour votre cluster
Vertex AI insère une variable d'environnement, CLUSTER_SPEC
, sur chaque instance dupliquée afin de décrire la façon dont le cluster global est configuré. À l'instar de la variable d'environnement TF_CONFIG
de TensorFlow, CLUSTER_SPEC
décrit chaque instance dupliquée du cluster, y compris son index et son rôle (instance dupliquée principale, nœud de calcul, serveur de paramètres ou évaluateur).
Lorsque vous procédez à un entraînement distribué avec TensorFlow, TF_CONFIG
est analysé pour créer tf.train.ClusterSpec
.
De même, lorsque vous réalisez un entraînement distribué avec d'autres frameworks de ML, vous devez analyser CLUSTER_SPEC
pour insérer les variables d'environnement ou les paramètres requis par le framework.
Format de CLUSTER_SPEC
La variable d'environnement CLUSTER_SPEC
est une chaîne JSON au format suivant :
Clé | Description | |
---|---|---|
"cluster"
|
Description du cluster pour votre conteneur personnalisé. Comme avec La description du cluster contient une liste de noms d'instances dupliquées pour chaque pool de nœuds de calcul que vous spécifiez. |
|
"workerpool0"
|
Tous les jobs d'entraînement distribué ont une instance dupliquée principale dans le premier pool de nœuds de calcul. | |
"workerpool1"
|
Ce pool de nœuds de calcul contient des instances dupliquées de nœuds de calcul, si vous les avez spécifiées lors de la création de votre job. | |
"workerpool2"
|
Ce pool de nœuds de calcul contient des serveurs de paramètres, si vous les avez spécifiés lors de la création de votre job. | |
"workerpool3"
|
Ce pool de nœuds de calcul contient des évaluateurs, si vous les avez spécifiés lors de la création de votre job. | |
"environment"
|
Correspond à la chaîne cloud .
|
|
"task"
|
Décrit la tâche du nœud spécifique sur lequel s'exécute votre code. Vous pouvez exploiter ces informations pour rédiger du code pour des nœuds de calcul spécifiques dans un job distribué. Cette entrée est un dictionnaire contenant les clés suivantes : | |
"type"
|
Type de pool de nœuds de calcul dans lequel cette tâche s'exécute. Par exemple, "workerpool0" fait référence à l'instance dupliquée principale.
|
|
"index"
|
Index basé sur zéro de la tâche. Par exemple, si votre job d'entraînement inclut deux nœuds de calcul, cette valeur est définie sur |
|
"trial"
|
Identifiant de l'essai de réglage des hyperparamètres en cours d'exécution. Lorsque vous configurez le réglage des hyperparamètres pour votre job, vous définissez un nombre d'essais d'entraînement. Cette valeur vous permet de différencier, au sein de votre code, les essais qui s'exécutent. L'identifiant est une valeur de chaîne contenant le numéro d'essai qui démarre à partir de 1. | |
job |
Données de saisie d'entraînement ( |
Exemple CLUSTER_SPEC
Voici un exemple de valeur :
{ "cluster":{ "workerpool0":[ "cmle-training-workerpool0-ab-0:2222" ], "workerpool1":[ "cmle-training-workerpool1-ab-0:2222", "cmle-training-workerpool1-ab-1:2222" ], "workerpool2":[ "cmle-training-workerpool2-ab-0:2222", "cmle-training-workerpool2-ab-1:2222" ], "workerpool3":[ "cmle-training-workerpool3-ab-0:2222", "cmle-training-workerpool3-ab-1:2222", "cmle-training-workerpool3-ab-2:2222" ] }, "environment":"cloud", "task":{ "type":"workerpool0", "index":0, "trial":"TRIAL_ID" }, "job": { ... } }
Format de TF_CONFIG
En plus de CLUSTER_SPEC
, Vertex AI définit la variable d'environnement TF_CONFIG
sur chaque instance dupliquée de tous les jobs d'entraînement distribué. Vertex AI ne définit pas la valeur TF_CONFIG
pour les jobs d'entraînement à instance dupliquée unique.
CLUSTER_SPEC
et TF_CONFIG
partagent certaines valeurs mais ont des formats différents. Les deux variables d'environnement incluent des champs supplémentaires qui ne sont pas nécessairement requis par TensorFlow.
L'entraînement distribué avec TensorFlow fonctionne de la même manière avec les conteneurs personnalisés qu'avec un conteneur prédéfini.
La variable d'environnement TF_CONFIG
est une chaîne JSON au format suivant :
TF_CONFIG champs |
|||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
cluster |
Description du cluster TensorFlow. Dictionnaire associant un ou plusieurs noms de tâches ( Il s'agit d'un premier argument valide pour le constructeur |
||||||||||
task |
Description de la tâche de la VM sur laquelle cette variable d'environnement est définie. Pour un job d'entraînement donné, ce dictionnaire est identique sur toutes les VM. Vous pouvez vous servir de ces informations pour personnaliser le code exécuté sur chaque VM dans un job d'entraînement distribué. Vous pouvez également l'utiliser pour modifier le comportement de votre code d'entraînement pour différents essais d'un job de réglage d'hyperparamètres. Ce dictionnaire inclut les paires clé-valeur suivantes :
|
||||||||||
job |
Données de saisie d'entraînement ( |
||||||||||
environment |
Correspond à la chaîne |
Exemple TF_CONFIG
L'exemple de code suivant imprime la variable d'environnement TF_CONFIG
dans vos journaux d'entraînement :
import json
import os
tf_config_str = os.environ.get('TF_CONFIG')
tf_config_dict = json.loads(tf_config_str)
# Convert back to string just for pretty printing
print(json.dumps(tf_config_dict, indent=2))
Dans un job de réglage d'hyperparamètres exécuté dans la version d'exécution 2.1 ou ultérieure et utilisant un nœud de calcul maître, deux nœuds de calcul et un serveur de paramètres, ce code génère le journal suivant pour l'un des nœuds de calcul lors du premier essai de réglage d'hyperparamètres. L'exemple de résultat masque le champ job
pour plus de concision et remplace certains ID par des valeurs génériques.
{
"cluster": {
"chief": [
"training-workerpool0-[ID_STRING_1]-0:2222"
],
"ps": [
"training-workerpool2-[ID_STRING_1]-0:2222"
],
"worker": [
"training-workerpool1-[ID_STRING_1]-0:2222",
"training-workerpool1-[ID_STRING_1]-1:2222"
]
},
"environment": "cloud",
"job": {
...
},
"task": {
"cloud": "[ID_STRING_2]",
"index": 0,
"trial": "1",
"type": "worker"
}
}
Dans quel contexte utiliser TF_CONFIG
?
TF_CONFIG
n'est défini que pour les jobs d'entraînement distribué.
Vous n'aurez probablement pas besoin d'interagir directement avec la variable d'environnement TF_CONFIG
dans votre code d'entraînement. N'accédez à la variable d'environnement TF_CONFIG
que si les stratégies de distribution de TensorFlow et le workflow standard de réglage d'hyperparamètres de Vertex AI décrits dans les sections suivantes ne fonctionnent pas.
Entraînement distribué
Vertex AI définit la variable d'environnement TF_CONFIG
afin d'étendre les spécifications requises par TensorFlow pour un entraînement distribué.
Pour effectuer un entraînement distribué avec TensorFlow, utilisez l'API tf.distribute.Strategy
.
En particulier, nous vous recommandons d'utiliser l'API Keras avec MultiWorkerMirroredStrategy
ou, si vous spécifiez des serveurs de paramètres pour votre job, avec ParameterServerStrategy
.
Toutefois, notez que TensorFlow ne fournit actuellement qu'une compatibilité expérimentale pour ces stratégies.
Ces stratégies de distribution utilisent la variable d'environnement TF_CONFIG
pour attribuer des rôles à chaque VM dans votre job d'entraînement et pour faciliter la communication entre les VM. Vous n'avez pas besoin d'accéder à la variable d'environnement TF_CONFIG
directement dans votre code d'entraînement, car TensorFlow s'en charge pour vous.
N'analysez la variable d'environnement TF_CONFIG
directement que si vous souhaitez personnaliser le comportement des différentes VM exécutant votre job d'entraînement.
Réglages d'hyperparamètres
Lorsque vous exécutez un job de réglage d'hyperparamètres, Vertex AI fournit des arguments différents à votre code d'entraînement pour chaque essai. Votre code d'entraînement ne doit pas nécessairement savoir quel essai est en cours. En outre, vous pouvez surveiller la progression des jobs de réglage d'hyperparamètres dans la console Google Cloud.
Si nécessaire, votre code peut lire le numéro d'essai en cours dans le champ trial
du champ task
de la variable d'environnement TF_CONFIG
.
Étape suivante
- Créez un pipeline d'entraînement.