Publié par

Il y a 8 mois -

Temps de lecture 10 minutes

What’s new in TensorFlow ? Des nouvelles du TensorFlow Dev Summit 2018 (2/3)

Suite de notre retour sur le 2e TensorFlow Dev Summit qui a eu lieu le 30 mars dernier. Dans le précédent article, nous avons fait le focus sur toutes les nouvelles API plus haut niveau de TensorFlow et la manière de les utiliser de manière optimale.

Dans cet article, nous allons cette fois rentrer dans le détail des nouveaux outils qui gravitent autour de TensorFlow, pour faciliter la vie de l’utilisateur ou pour étendre ses possibilités :

  • Eager Execution : pour utiliser TensorFlow de manière dynamique, déboguer facilement son code et s’abstraire des tf.Session() ;
  • TensorBoard Debugger Plugin : pour comprendre et déboguer son modèle dynamiquement dans l’interface graphique phare de TensorFlow ;
  • Distributed TensorFlow : entraînement en mode distribué de modèles grâce à l’API haut niveau Estimator.

Eager Execution (Alexandre Passos)

Le mode « Eager Execution » de TensorFlow est défini comme une nouvelle manière plus « Pythonic » d’utiliser TensorFlow via des commandes orientées objet, et qui fait maintenant partie de TensorFlow core.

TensorFlow est initialement un moteur d’exécution orienté graphe pour le Machine Learning. C’est cette orientation graphe qui a souvent été reprochée par les utilisateurs de TensorFlow, les obligeant à définir toutes leurs opérations avant de les exécuter dans un graphe, chose peu commune dans le monde du développement Python.

Pourquoi ce mode d’exécution orienté graphe a-t-il été choisi dans ce cas ? Plusieurs raisons à cela :

  • Différenciation automatique des opérations ;
  • Indépendant par rapport au Python au déploiement : possibilité de déployer sur un serveur n’exécutant pas du Python, ou sur un smartphone par exemple ;
  • Optimisations au niveau du graphe : il est nécessaire d’avoir une vue complète du graphe d’exécution pour trouver des optimisations globales ;
  • Distribution automatique sur des centaines de machines : une fois que le graphe est généré, il est très simple de le déployer sur plusieurs machines en même temps.

Ainsi, pourquoi passer à un mode d’exécution plus direct (Eager Mode) ? Encore une fois, les raisons sont nombreuses :

  • Facilité pour debugger et pour utiliser des outils d’analyse du code ;
  • Une manière plus dynamique de construire son code ;
  • Possibilité d’itérer beaucoup plus rapidement (tester son modèle lors de sa construction, rajouter des opérations facilement, etc.).

Maintenant que nous sommes convaincus de son utilité, comment le mettre en pratique ? Simplement en appelant la méthode tf.enalble_eager_execution() :

Eager Execution
import tensorflow as tf

tf.enable_eager_execution()

a = tf.constant([[2.0, 3.0], [4.0, 5.0]])
print(tf.matmul(a, a))

# => tf.Tensor([[16., 21.], [28., 37.]], shape=(2,2), dtype=float32)

Comme on peut le voir, fini les tf.Session() et sess.run() pour exécuter le graphe. Il est maintenant possible de le faire à la volée et de vérifier étape par étape ce que produisent nos calculs. Grâce à ce mode de calcul, il est maintenant possible d’entraîner son modèle via une simple boucle for, ce qui est encore une fois bien plus confortable à l’usage.

D’un point de vue Software Craftsmanship, ce nouveau mode d’exécution est idéal pour faire du debugging dans votre IDE préféré, ou encore faire vos tests unitaires. En effet, chaque morceau de code peut être pris séparément pour contrôler les valeurs qu’il produit. Autre avantage, il est maintenant possible de faire passer le code par un Python profiler afin de voir par exemple le temps d’exécution de chacune des opérations afin de voir s’il n’y a pas des bottlenecks dans le code.

Une des principales questions qui se posent concerne les performances. Le mode d’exécution graphe était optimisé pour les performances, est-ce toujours le cas pour le Eager Mode ? Les concepteurs semblent dire qu’il n’y a quasiment pas d’impact lors de l’entraînement et l’optimisation de gros modèles. Les seules petites différences apparaissent lorsque l’on fait de plus petites tâches (même si de gros efforts sont faits constamment dans ce domaine). Le message est que tant que l’on maintient le GPU occupé à travailler, il n’y a aucune différence.

Les nouvelles API de TensorFlow sont toutes compatibles avec le Eager Execution Mode ainsi que le mode clasique orienté graphe. Il est tout à fait possible de créer et tester son modèle en Eager Mode, puis d’importer le modèle en graphe pour déploiement (les checkpoints sont compatibles). Quelques exemples sont disponibles sur le github de TensorFlow.

En conclusion, une bonne pratique est donc d’écrire du code qui est eager-compatible : utiliser tf.keras.layers, tf.keras.Model, tf.contrib.summary, tfe.metrics, etc.

En résumé, pourquoi utiliser le Eager Execution Mode ?

  • Plus simple si on est un nouvel utilisateur de TensorFlow ou dans le monde du Machine Learning ;
  • Dans un environnement de recherche où il faut itérer très rapidement pour améliorer et comparer ses modèles :
  • Pour déboguer son modèle comme un simple code Python ;
  • Pour profiler des modèles et trouver des bottlenecks ;
  • Certains modèles sont beaucoup plus simples à appréhender en Eager Mode, comme les RNN récursifs qui sont des modèles dynamiques.

Vous trouverez toutes les explications nécessaires à ce nouveau mode d’exécution dans les Starting Guides sur le site de TensorFlow.

Pour plus d’informations, consultez la vidéo associée à ce sujet.

Debugging TensorFlow with TensorBoard plugins (Justine Tunney & Shanqing Cai)

TensorFlow Debugger est une web GUI interactive pour contrôler l’exécution des modèles TensorFlow, mettre des checkpoints, naviguer dans les noeuds, et bien d’autres. Cet outil est maintenant intégré à TensorBoard via son API de plugin.

TensorFlow Debugger est en réalité l’interface graphique liée à tfdbg, le debugger en ligne de commande introduit dans les dernières versions de TensorFlow. Il permet de regarder plus simplement et en détails le fonctionnement interne de votre modèle.

Pour utiliser ce nouveau plugin, il suffit de rajouter sa référence dans l’appel à TensorBoard lors de son lancement en ligne de commande :

>>> tensorboard --logdir /tmp/logdir --debugger_port 7000

Le plugin, une fois lancé, donne quelques exemples de code pour pouvoir faire appel à lui et l’utiliser efficacement, soit via une Session, un Estimator ou un modèle Keras :

Voici à quoi ressemble le plugin lors de son utilisation :

L’ensemble des variables ou placeholders utilisés sont présents, et il est possible de naviguer dans les opérations qui les concernent et de voir la distribution de leurs valeurs. Il est aussi très simple de regarder comment se comporte le calcul des gradients ou la fonction de coût.

Une fonctionnalité très intéressante est celle des conditional breakpoints : Il est possible de demander au plugin de spécifier si l’un des tenseurs contient des valeurs infinies ou NaN et de nous orienter vers eux. Le modèle arrête alors de s’entraîner le temps que l’on puisse inspecter ce qu’il se passe. Une fois le tenseur identifié, il est alors possible d’être directement orienté vers le bloc de code qui est à l’origine de sa création et voir le sous-ensemble du graphe associé.

Grâce à ce type de plugin, TensorBoard devient bien plus qu’un simple outil de reporting, avec des manières beaucoup plus interactives de comprendre et d’examiner ses modèles.

Voir la vidéo du talk pour plus d’informations.

Distributed TensorFlow (Igor Saprykin)

L’entraînement de modèles de Deep Learning peut prendre énormément de temps, parfois des semaines entières. Passer à un mode d’entraînement distribué sur plusieurs GPU permet de réduire ce temps, mais ce n’est pas toujours simple à mettre en place.

Une première manière pour distribuer l’entraînement est via la réplication du modèle complet sur chaque GPU. La plus grosse difficulté de ce mode est qu’il faut trouver un moyen de combiner les gradients calculés sur chaque GPU. D’autres problèmes apparaîssent aussi, notamment lorsque l’on utilise de la Batch Normalization : difficile de savoir quoi faire des statistiques calculées sur chaque GPU.

Une autre manière de faire est d’utiliser plusieurs machines. Dans ce cas, nous nous retrouvons dans une configuration similaire au cas précédent, sauf que le bottleneck sera probablement la communication entre les machines.

Une solution proposée pour tacler le problème de l’entraînement distribué dans un contexte d’une machine avec plusieurs GPU est d’utiliser une approche basée sur all-reduce : la réduction des valeurs et la distribution des résultats à tous les processus via du broadcast. C’est une approche aussi utilisée par les fabricants de hardware, qui est exploitée par TensorFlow.

Alors que d’autres approches envoient toute la donnée dans un même emplacement, all-reduce distribue la coordination entre les GPU de manière beaucoup plus équitable. Chaque GPU envoie et reçoit une partie de la réponse finale :

Dans cet exemple, chaque layer et variable est répliquée sur chaque GPU. La traversée du réseau de neurones (forward pass) se fait en parallèle de manière normale. C’est lors de la backpropagation que all-reduce opère : lorsque les gradients deviennent disponibles, all-reduce est utilisé pour combiner chaque gradient avec ses homologues des autres GPU.

Pour utiliser le mode multi-GPU dans TensorFlow sans avoir à changer drastiquement le code, il faut utiliser ses API plus haut niveau, et notamment l’API Estimator. Une seule ligne de code est alors à changer dans la configuration de run pour passer sur ce mode :

Multi-GPU mode in Estimators
distribution = tf.contrib.distribute.MirroredStrategy(num_gpus=2)
run_config = tf.estimator.RunConfig(distribute=distribution)

classifier = tf.estimator.Estimator(
	model_fn=model_function,
	model_dir=model_dir,
	config=run_config)

MirroredStrategy est une implémentation pour la nouvelle stratégie de distribution dans TensorFlow. Cette stratégie explique à TensorFlow comment répliquer le modèle et appliquer all-reduce pour la communication. L’argument num_gpus peut être un nombre, une liste de noms de GPU, ou encore être laissé vide, auquel cas TensorFlow va chercher lui-même les GPU disponibles et tous les utiliser.

Les mises à jour de gradients de tous les GPU sont combinés avant de mettre à jour les poids. Chaque copie du modèle sur chaque GPU fait partie d’un unique graphe TensorFlow. Cela signifie qu’il y a une réplication au sein du graphe avec des entraînements synchrones qui utilisent all-reduce sur plusieurs GPU.

Cette implémentation a le mérite d’être performante pour le scaling : 90 % pour 8 GPU, sans que cela n’implique un quelconque changement dans le modèle créé par l’utilisateur. Cela veut donc dire que l’on multiplie par 7,2 notre puissance de calcul en passant de 1 à 8 GPU.

En revanche, tout ce qui n’est pas lié au modèle de l’utilisateur a été modifié afin de pouvoir gérer la distribution : les optimiseurs, les résumés, la batch normalization. Mais cela n’impacte pas la manière dont on utilise le framework. Autre avantage à cette implémentation, les Estimators écrivent des checkpoints comme avant, qui ne contiennent qu’une seule copie des variables (pas de réplication). Enfin, le Eager Mode est aussi supporté avec cette implémentation, même si des optimisations sont encore en cours.

D’autres stratégies de distribution sont en cours de développement : distribution synchrone, asynchrone, multi-node, etc. Toutes ces stratégies feront partie d’une API spécifique.

Une autre possibilité pour l’entraînement distribué, supportant notamment le multi-node, est d’utiliser le projet Horovod, développé chez Uber, qui est de plus en plus utilisé, et qui affiche aussi un facteur de scaling de 90 %.

Pour plus d’informations, consultez la vidéo associée à ce sujet.

Conclusion

Grâce à la mise à disposition d’outils pour faciliter la vie du développeur, TensorFlow devient un framework de plus en plus complet pour le Machine Learning dans sa globalité. Petit à petit, les développeurs de TensorFlow s’attaquent aux principales reproches qui avaient été faites dans les premières versions du framework, notamment sur les questions de code dynamique et de débogage. Avec ces nouvelles évolutions, des gains de temps très conséquents dans le développement de modèles de Deep Learning sont possibles.

Dans le dernier article de cette série, nous ferons un focus sur les évolutions proposées par TensorFlow pour être accessible à plus de communautés de développeurs, pour partager des modèles et pour trouver automatiquement le meilleur modèle pour son cas d’usage.

 

Publié par

Publié par Yoann Benoit

Yoann est Data Scientist chez Xebia. Il est également formateur au sein de Xebia Training .

Commentaire

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Xebian, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.