

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Conseils et pièges de configuration de la bibliothèque de parallélisme des modèles SageMaker distribués
<a name="model-parallel-customize-tips-pitfalls"></a>

Consultez les conseils et astuces suivants avant d'utiliser la bibliothèque de parallélisme de modèles d'Amazon SageMaker AI. Cette liste contient des conseils qui s'appliquent à tous les cadres. Pour TensorFlow des conseils PyTorch spécifiques, voir [Modifier un script TensorFlow d'entraînement](model-parallel-customize-training-script-tf.md) et[Modifier un script PyTorch d'entraînement](model-parallel-customize-training-script-pt.md), respectivement. 

## Taille de lot et nombre de micro-lots
<a name="model-parallel-customize-tips-pitfalls-batch-size"></a>
+ La bibliothèque est la plus efficace lorsque la taille du lot est augmentée. Dans les cas d'utilisation où le modèle tient dans un seul périphérique, mais ne peut être entraîné qu'avec un lot de petite taille, la taille du lot peut et doit être augmentée après l'intégration de la bibliothèque. Le parallélisme des modèles permet d'économiser de la mémoire pour les grands modèles, ce qui permet un entraînement avec des tailles de lots qui ne tenaient pas dans la mémoire auparavant.
+ Choisir un nombre de micro-lots trop petit ou trop grand peut baisser les performances. La bibliothèque exécute chaque micro-lot séquentiellement dans chaque périphérique, de sorte que la taille du micro-lot (taille du lot divisée par le nombre de micro-lots) doit être suffisamment grande pour utiliser pleinement chaque GPU. Dans le même temps, comme l'efficacité du pipeline augmente avec le nombre de micro-lots, il est important de trouver le bon équilibre. Normalement, un bon point de départ consiste à essayer 2 ou 4 micro-lots, en augmentant la taille du lot jusqu'à la limite de mémoire, puis à expérimenter avec des tailles de lot et un nombre de micro-lots supérieurs. L'augmentation du nombre de micro-lots permet d'envisager des tailles de lots supérieures, si un pipeline entrelacé est utilisé.
+ La taille de votre lot doit toujours être divisible par le nombre de micro-lots. Veuillez noter que, selon la taille du jeu de données, la taille du dernier lot de chaque époque peut parfois être inférieure au reste, mais ce petit lot doit également être divisible par le nombre de micro-lots. Si ce n'est pas le cas, vous pouvez définir `drop_remainder=True` l'`tf.Dataset.batch()`appel (in TensorFlow) ou le définir `DataLoader` (`drop_last=True`in PyTorch), afin que ce dernier petit lot ne soit pas utilisé. Si vous utilisez une API différente pour le pipeline de données, vous devrez peut-être ignorer manuellement le dernier lot chaque fois qu'il n'est pas divisible par le nombre de micro-lots.

## Partitionnement manuel
<a name="model-parallel-customize-tips-pitfalls-manual-partitioning"></a>
+ Si vous utilisez le partitionnement manuel, pensez toujours aux paramètres qui sont utilisés par plusieurs opérations et modules de votre modèle, tels que la table d'incorporation dans les architectures de transformateur. À des fins d'exactitude, les modules qui partagent le même paramètre doivent être placés dans le même périphérique. Lorsque vous utilisez le partitionnement automatique, la bibliothèque applique automatiquement cette contrainte.

## Préparation des données
<a name="model-parallel-customize-tips-pitfalls-data-preparation"></a>
+ Si le modèle utilise plusieurs entrées, veillez à répartir les opérations aléatoires dans votre pipeline de données (remaniement, par exemple) avec `smp.dp_rank()`. Si le jeu de données est partitionné de manière déterministe entre des périphériques parallèles de données, assurez-vous que la partition est indexée par `smp.dp_rank()`. Ceci permet de garantir la cohérence de l'ordre des données affichées sur tous les rangs qui forment une partition de modèle.

## Renvoyer les tenseurs à partir de `smp.DistributedModel`
<a name="model-parallel-customize-tips-pitfalls-return-tensors"></a>
+ Tout tenseur renvoyé par la fonction `smp.DistributedModel.call` (for TensorFlow) ou `smp.DistributedModel.forward` (for PyTorch) est diffusé vers tous les autres rangs, à partir du rang qui a calculé ce tenseur particulier. Par conséquent, tout tenseur qui n'est pas nécessaire en dehors des méthodes d'appel et de transmission (activations intermédiaires, par exemple) ne doit pas être renvoyé, car cela provoque un surdébit inutile de communication et de mémoire et nuit aux performances.

## Le décorateur `@smp.step`
<a name="model-parallel-customize-tips-pitfalls-smp-step-decorator"></a>
+ Si l'argument tenseur d'une fonction décorée `smp.step` n'a pas de dimension de lot, le nom de l'argument doit être fourni dans la liste `non_split_inputs` lors de l'appel `smp.step`. Cela empêche la bibliothèque d'essayer de diviser le tenseur en micro-lots. Pour plus d’informations, consultez [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/latest/smd_model_parallel_common_api.html](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/latest/smd_model_parallel_common_api.html) dans la documentation sur l’API.

## Retarder l'initialisation des paramètres
<a name="model-parallel-customize-tips-pitfalls-delaying-param-initialization"></a>

Pour les très grands modèles comportant plus de 100 milliards de paramètres, l'initialisation du poids via la mémoire du processeur peut entraîner une out-of-memory erreur. Pour contourner ce problème, la bibliothèque propose un gestionnaire de contexte `smp.delay_param_initialization`. Cela retarde l'allocation physique des paramètres jusqu'à ce qu'ils se déplacent vers le GPU lors de la première exécution d'une fonction décorée `smp.step`. Cela évite l'utilisation inutile de la mémoire du processeur pendant l'initialisation de la formation. Utilisez le gestionnaire de contexte lorsque vous créez un objet de modèle comme illustré dans le code suivant.

```
with smp.delay_param_initialization(enabled=True):    
    model = MyModel()
```

## Parallélisme tensoriel pour PyTorch
<a name="model-parallel-customize-tips-pitfalls-tensor-parallelism-pytorch"></a>
+ Si vous utilisez une graine pour des résultats déterministes, définissez la graine en fonction de `smp.dp_rank()` (par exemple, `torch.manual_seed(42 + smp.dp_rank())`). Si vous ne le faites pas, différentes partitions d'un paramètre `nn.Parameter` sont initialisés de la même manière, ce qui a un impact sur la convergence. 
+ SageMakerde la bibliothèque de parallélisme des modèles utilise NCCL pour implémenter les collectifs nécessaires à la distribution des modules. En particulier pour les modèles plus petits, si trop d'appels NCCL sont programmés simultanément sur le GPU, l'utilisation de la mémoire peut augmenter en raison de l'espace supplémentaire utilisé par NCCL. Pour contrer cela, `smp` limite les appels NCCL de sorte que le nombre d'opérations de la NCCL en cours à un moment donné soit inférieur ou égal à une limite donnée. La limite par défaut est 8, mais elle peut être ajustée à l'aide de la variable d'environnement `SMP_NCCL_THROTTLE_LIMIT`. Si vous constatez une utilisation de la mémoire plus importante que prévu lors de l'utilisation du parallélisme de tenseur, vous pouvez essayer de réduire cette limite. Toutefois, le choix d'une limite trop faible peut entraîner une perte de débit. Pour désactiver complètement la limitation, vous pouvez définir `SMP_NCCL_THROTTLE_LIMIT=-1`. 
+ L'identité suivante, qui s'applique lorsque le degré de parallélisme de tenseur est de 1, ne tient pas lorsque le degré de parallélisme de tenseur est supérieur à 1 : `smp.mp_size() * smp.dp_size() == smp.size()`. En effet, le groupe de parallélisme de tenseur fait partie du groupe de parallélisme du modèle et du groupe de parallélisme des données. Si votre code contient déjà des références à `mp_rank`, `mp_size`, `MP_GROUP`, et ainsi de suite, et si vous souhaitez travailler uniquement avec le groupe parallèle de pipeline, vous devrez peut-être remplacer les références par `smp.pp_size()`. Les identités suivantes sont toujours vraies : 
  +  `smp.mp_size() * smp.rdp_size() == smp.size()` 
  +  `smp.pp_size() * smp.dp_size() == smp.size()` 
  +  `smp.pp_size() * smp.tp_size() * smp.rdp_size() == smp.size()` 
+ Depuis la fonction wrapper `smp.DistributedModel` modifie les paramètres du modèle lorsque le parallélisme de tenseur est activé, l'optimiseur doit être créé après l'appel `smp.DistributedModel`, avec les paramètres distribués. Par exemple, les éléments suivants ne fonctionnent pas : 

  ```
  ## WRONG
  model = MyModel()
  optimizer = SomeOptimizer(model.parameters())
  model = smp.DistributedModel(model)  # optimizer now has outdated parameters! 
  ```

  Au lieu de cela, l'optimiseur doit être créé avec les paramètres du `smp.DistributedModel` comme suit :

  ```
  ## CORRECT
  model = smp.DistributedModel(MyModel())
  optimizer = SomeOptimizer(model.optimizers())
  ```
+ Lorsqu'un module est remplacé par son homologue distribué par parallélisme de tenseur, le module distribué n'hérite pas de ses poids du module d'origine et initialise de nouveaux poids. Cela signifie que, par exemple, si les pondérations doivent être initialisées dans un appel particulier (par exemple, via un appel `load_state_dict`), cela doit se produire après l'appel `smp.DistributedModel`, une fois que la distribution du module a eu lieu. 
+ Lorsque vous accédez directement aux paramètres des modules distribués, notez que le poids n'a pas la même forme que le module d'origine. Par exemple,  

  ```
  with smp.tensor_parallelism():
      linear = nn.Linear(60, 60)
  
  # will pass
  assert tuple(linear.weight.shape) == (60, 60)
  
  distributed_linear = smp.DistributedModel(linear)
  
  # will fail. the number of input channels will have been divided by smp.tp_size()
  assert tuple(distributed_linear.module.weight.shape) == (60, 60)
  ```
+ A l'aide de `torch.utils.data.distributed.DistributedSampler` est fortement recommandé pour le parallélisme de tenseur. Cela garantit que chaque classement parallèle de données reçoit le même nombre d'échantillons de données, ce qui évite les blocages pouvant résulter de différents `dp_rank` prenant un certain nombre de mesures différentes. 
+ Si vous utilisez l'`join`API PyTorch de la `DistributedDataParallel` classe pour gérer les cas dans lesquels différents rangs parallèles de données comportent un nombre de lots différent, vous devez tout de même vous assurer que les rangs appartenant à la même classe `TP_GROUP` contiennent le même nombre de lots ; sinon, les collectifs de communication utilisés dans l'exécution distribuée des modules risquent de se bloquer. Les rangs qui sont dans des `TP_GROUP` différents peuvent avoir un nombre différent de lots, à condition que l'API `join` est utilisé. 
+ Si vous souhaitez contrôler votre modèle et utiliser le parallélisme tenseur, tenez compte des points suivants : 
  + Pour éviter les conditions de décrochage et de course lors de l'enregistrement et du chargement des modèles lorsque vous utilisez le parallélisme de tenseurs, assurez-vous d'appeler les fonctions appropriées à partir des états de modèle et d'optimiseur suivants dans un rang de parallélisme réduit des données.
  + Si vous faites la transition d'un script parallèle de pipeline existant et que vous activez le parallélisme de tenseur pour le script, veillez à modifier n'importe quel bloc `if smp.dp_rank() == 0` utilisé pour enregistrer et charger avec les blocs `if smp.rdp_rank() == 0`. Sinon, cela pourrait entraîner le blocage de votre tâche d'entraînement. 

  Pour en savoir plus sur les points de contrôle d'un modèle avec parallélisme de tenseur, consultez [Point de contrôle d'un modèle distribué](distributed-model-parallel-checkpointing-and-finetuning.md#distributed-model-parallel-checkpoint).