Apprentissage distribué avec Apache MXNet et Horovod

La traduction de l'article a été préparée en prévision du lancement du cours «Apprentissage ML industriel sur de grandes données»

L'apprentissage distribué sur plusieurs instances de calcul haute performance peut réduire le temps d'entraînement des réseaux de neurones profonds modernes sur un grand volume de données de plusieurs semaines à quelques heures, voire minutes, faisant de cette technique d'apprentissage un standard pour l'utilisation pratique de l'apprentissage profond. Les utilisateurs doivent comprendre comment partager et synchroniser les données sur plusieurs instances, ce qui a un impact significatif sur l'efficacité de l'échelle. De plus, les utilisateurs doivent également savoir comment déployer un script d'entraînement sur plusieurs instances qui fonctionne sur une seule instance.

Dans cet article, nous allons discuter d'un moyen rapide et simple d'apprentissage distribué en utilisant la bibliothèque open source d'apprentissage profond Apache MXNet et le framework d'apprentissage distribué Horovod. Nous allons illustrer les avantages du framework Horovod en matière de performance et montrer comment rédiger un script d'entraînement MXNet pour qu'il fonctionne en mode distribué avec Horovod.

Qu'est-ce qu'Apache MXNet

Apache MXNet est un framework open source pour l'apprentissage profond, utilisé pour créer, entraîner et déployer des réseaux de neurones profonds. MXNet abstrait les complexités liées à l'implémentation de réseaux de neurones, offrant une haute performance et une évolutivité, ainsi qu'une API pour les langages de programmation populaires tels que Python, C++, Clojure, Java, Julia, R, Scala et d'autres.

Apprentissage distribué dans MXNet avec un serveur de paramètres

Le module standard d'apprentissage distribué dans MXNet utilise une approche de serveur de paramètres. Il utilise un ensemble de serveurs de paramètres pour recueillir les gradients de chaque worker, effectuer l'agrégation et renvoyer les gradients mis à jour aux workers pour la prochaine itération d'optimisation. Déterminer le bon ratio de serveurs par rapport aux workers est la clé d'un scale efficace. S'il n'y a qu'un seul serveur de paramètres, il peut devenir un goulet d'étranglement dans le calcul. À l'inverse, si trop de serveurs sont utilisés, la connexion « plusieurs-à-plusieurs » peut saturer toutes les connexions réseau.

Qu'est-ce que Horovod

Horovod – un framework ouvert d'apprentissage profond distribué, développé par Uber. Il utilise des technologies efficaces pour l'interaction entre plusieurs GPU et nœuds, telles que la NVIDIA Collective Communications Library (NCCL) et le Message Passing Interface (MPI) pour distribuer et agréger les paramètres du modèle entre les workers. Il optimise l'utilisation de la bande passante réseau et se redimensionne bien lors du travail avec des modèles de réseaux de neurones profonds. Actuellement, il prend en charge plusieurs frameworks d'apprentissage automatique populaires, à savoir MXNet, Tensorflow, Keras et PyTorch.

Intégration de MXNet et Horovod

MXNet s'intègre avec Horovod via l'API d'apprentissage distribué définie dans Horovod. Dans Horovod, les API de communication horovod.broadcast(), horovod.allgather() et horovod.allreduce() sont mises en œuvre à l'aide de rappels asynchrones du moteur MXNet, dans le cadre de son graphe de tâches. Ainsi, les dépendances des données entre la communication et les calculs sont facilement gérées par le moteur MXNet pour éviter les pertes de performance dues à la synchronisation. L'objet optimiseur distribué, défini dans Horovod horovod.DistributedOptimizer élargit Optimiseur dans MXNet de manière à ce qu'il appelle les API Horovod appropriées pour la mise à jour distribuée des paramètres. Tous ces détails d'implémentation sont transparents pour les utilisateurs finaux.

Démarrage rapide

Vous pouvez rapidement commencer à entraîner un petit réseau de neurones convolutif sur le jeu de données MNIST avec MXNet et Horovod sur votre MacBook.
Pour commencer, installez mxnet et horovod depuis PyPI :

pip install mxnet
pip install horovod

Remarque : Si vous rencontrez une erreur lors de pip install horovod, vous devez peut-être ajouter la variable MACOSX_DEPLOYMENT_TARGET=10.vv, où vv – est la version de votre version MacOS, par exemple, pour MacOSX Sierra, vous devrez écrire MACOSX_DEPLOYMENT_TARGET=10.12 pip install horovod

Ensuite, installez OpenMPI d'ici.

Enfin, téléchargez le script de test mxnet_mnist.py d'ici et exécutez les commandes suivantes dans le terminal du MacBook dans le répertoire de travail :

mpirun -np 2 -H localhost:2 -bind-to none -map-by slot python mxnet_mnist.py

Ainsi, vous exécuterez l'entraînement sur deux cœurs de votre processeur. En sortie, vous obtiendrez ce qui suit :

INFO:root:Epoch[0] Batch [0-50] Speed: 2248.71 samples/sec      accuracy=0.583640
INFO:root:Epoch[0] Batch [50-100] Speed: 2273.89 samples/sec      accuracy=0.882812
INFO:root:Epoch[0] Batch [50-100] Speed: 2273.39 samples/sec      accuracy=0.870000

Démonstration des performances

Lors de l'entraînement du modèle ResNet50-v1 sur le jeu de données ImageNet sur 64 GPU avec huit instances p3.16xlarge EC2, chacun contenant 8 GPU NVIDIA Tesla V100 sur le cloud AWS, nous avons atteint un débit d'apprentissage de 45 000 images/seconde (c'est-à-dire le nombre d'exemples appris par seconde). L'entraînement s'est terminé en 44 minutes après 90 époques avec une précision maximale de 75,7%.

Nous avons comparé cela à l'apprentissage distribué MXNet avec une approche utilisant des serveurs de paramètres sur 8, 16, 32 et 64 GPU avec un serveur à un seul paramètre et un rapport serveurs/travailleurs de 1 à 1 et 2 à 1 respectivement. Le résultat est visible sur la Figure 1 ci-dessous. Sur l'axe y à gauche, les colonnes reflètent le nombre d'images pour l'apprentissage par seconde, et les lignes reflètent l'efficacité de mise à l'échelle (c'est-à-dire le rapport entre le débit réel et idéal) sur l'axe y à droite. Comme vous pouvez le constater, le choix du nombre de serveurs influence l'efficacité de mise à l'échelle. Si le serveur de paramètres est unique, l'efficacité de mise à l'échelle chute à 38% sur 64 GPU. Pour atteindre la même efficacité de mise à l'échelle qu'avec Horovod, il faut doubler le nombre de serveurs par rapport au nombre de travailleurs.

Apprentissage distribué avec Apache MXNet et Horovod
Figure 1. Comparaison de l'apprentissage distribué utilisant MXNet avec Horovod et avec un serveur de paramètres.

Dans le Tableau 1 ci-dessous, nous avons comparé le coût total par instance lors des expériences sur 64 GPU. L'utilisation de MXNet avec Horovod offre le meilleur débit au coût le plus bas.

Apprentissage distribué avec Apache MXNet et Horovod
Tableau 1. Comparaison des coûts entre Horovod et un serveur de paramètres avec un rapport serveurs/travailleurs de 2 à 1.

Étapes pour reproduire

Dans les étapes suivantes, nous allons expliquer comment reproduire le résultat de l'apprentissage distribué avec MXNet et Horovod. Pour en savoir plus sur l'apprentissage distribué avec MXNet, lisez cet article..

Étape 1

Créez un cluster d'instances homogènes avec MXNet version 1.4.0 ou supérieure et Horovod version 0.16.0 ou supérieure pour utiliser l'apprentissage distribué. Vous devrez également installer les bibliothèques nécessaires pour l'apprentissage sur GPU. Pour nos instances, nous avons choisi Ubuntu 16.04 Linux, avec le pilote GPU 396.44, CUDA 9.2, la bibliothèque cuDNN 7.2.1, le communicateur NCCL 2.2.13 et OpenMPI 3.1.1. Vous pouvez également utiliser Amazon Deep Learning AMI, où ces bibliothèques sont déjà préinstallées.

Étape 2

Ajoutez la possibilité de travailler avec l'API Horovod dans votre script d'entraînement MXNet. Le script ci-dessous, basé sur MXNet Gluon API, peut être utilisé comme un modèle simple. Les lignes en gras sont nécessaires si vous avez déjà un script d'entraînement correspondant. Voici quelques changements critiques à apporter pour l'entraînement avec Horovod :

  • Définissez le contexte en fonction du rang local de Horovod (ligne 8), afin de comprendre que l'entraînement se fait sur le bon cœur graphique.
  • Transmettez les paramètres initiaux d'un worker à tous (ligne 18) pour vous assurer que tous les workers commencent avec les mêmes paramètres initiaux.
  • Créez Horovod DistributedOptimizer (ligne 25), pour mettre à jour les paramètres de manière distribuée.

Pour obtenir le script complet, consultez les exemples Horovod-MXNet. MNIST et ImageNet.

1  import mxnet as mx
2  import horovod.mxnet as hvd
3
4  # Horovod : initialiser Horovod
5  hvd.init()
6
7  # Horovod : épingler un GPU à utiliser pour le rang local
8  context = mx.gpu(hvd.local_rank())
9
10 # Construire le modèle
11 model = ...
12
13 # Initialiser les paramètres
14 model.initialize(initializer, ctx=context)
15 params = model.collect_params()
16
17 # Horovod : diffuser les paramètres
18 hvd.broadcast_parameters(params, root_rank=0)
19
20 # Créer l'optimiseur
21 optimizer_params = ...
22 opt = mx.optimizer.create('sgd', **optimizer_params)
23
24 # Horovod : envelopper l'optimiseur avec DistributedOptimizer
25 opt = hvd.DistributedOptimizer(opt)
26
27 # Créer le formateur et la fonction de perte
28 trainer = mx.gluon.Trainer(params, opt, kvstore=None)
29 loss_fn = ...
30
31 # Entraîner le modèle
32 for epoch in range(num_epoch):
33    ...

Étape 3

Connectez-vous à l'un des workers pour lancer l'entraînement distribué en utilisant la directive MPI. Dans cet exemple, l'entraînement distribué est lancé sur quatre instances avec 4 GPU chacune, totalisant 16 GPU dans le cluster. Un optimiseur de descente de gradient stochastique (SGD) sera utilisé avec les hyperparamètres suivants :

  • taille de mini-lot : 256
  • taux d'apprentissage : 0.1
  • momentum : 0.9
  • weight decay : 0.0001

En passant d'un GPU à 64 GPU, nous avons linéairement augmenté la vitesse d'apprentissage en fonction du nombre de GPU (de 0,1 pour 1 GPU à 6,4 pour 64 GPU), tout en maintenant le nombre d'images par GPU à 256 (d'un lot de 256 images pour 1 GPU à 16 384 pour 64 GPU). Les paramètres de weight decay et de momentum ont été ajustés lors de l'augmentation du nombre de GPU. Nous avons utilisé l'apprentissage à précision mixte avec le type de données float16 pour la propagation avant et float32 pour les gradients, afin d'accélérer les calculs float16 pris en charge par les GPU NVIDIA Tesla.

$ mpirun -np 16 
    -H server1:4,server2:4,server3:4,server4:4 
    -bind-to none -map-by slot 
    -mca pml ob1 -mca btl ^openib 
    python mxnet_imagenet_resnet50.py

Conclusion

Dans cet article, nous avons examiné une approche évolutive pour l'apprentissage distribué des modèles en utilisant Apache MXNet et Horovod. Nous avons démontré l'efficacité de la montée en charge et sa rentabilité par rapport à l'approche basée sur un serveur de paramètres, en utilisant le jeu de données ImageNet, sur lequel le modèle ResNet50-v1 a été entraîné. Nous avons également détaillé les étapes que vous pouvez suivre pour modifier un script existant afin de démarrer l'apprentissage sur plusieurs instances avec Horovod.

Si vous débutez avec MXNet et l'apprentissage profond, rendez-vous sur la page d'installation MXNe, pour commencer à compiler MXNet. Nous recommandons également fortement de lire l'article MXNet en 60 minutes, pour commencer à travailler.

Si vous avez déjà travaillé avec MXNet et souhaitez essayer l'apprentissage distribué avec Horovod, jetez un œil à la page d'installation de Horovod, compilez-le avec MXNet et suivez l'exemple MNIST ou ImageNet.

*le coût est calculé sur la base de taux horaire AWS pour les instances EC2

En savoir plus sur le cours «Apprentissage ML industriel sur de grandes données»

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster