2017-08-31 2 views
1

J'expérimente des options d'entraînement distribuées sur Cloud ML Engine et j'observe des résultats particuliers. J'ai fondamentalement modifié l'exemple de l'estimateur personnalisé du recensement pour qu'il contienne un modèle légèrement différent et que ma fonction de perte ait été modifiée par AdamOptimizer en tant que seuls véritables changements. D'après ce que j'ai compris, toute formation distribuée devrait être une formation asynchrone parallèle aux données, ce qui suggère «Si vous distribuez 10 000 lots parmi 10 nœuds travailleurs, chaque nœud fonctionne sur environ 1 000 lots». Dans mon expérience, j'ai ~ 650k exemples d'entraînement et je cours les expériences suivantes pour 1 époque avec une taille de lot de 128. Compte tenu des exemples d'entraînement 650k et une taille de lot de 128, je m'attendrais à des étapes ~ 5.1k dans un époque. Voici la performance que je vois pour différentes l »Formation distribuée avec tf.estimator entraînant plusieurs étapes de formation

--scale-tier PAS DISTRIBUÉ

  • BASIC: 8 étapes/s, 5.1k étapes, le temps de mur 11 minutes
  • BASIC_GPU: 24 étapes/sec, 5.1k étapes, le temps de paroi de 3,5 minute

DISTRIBUE

  • STANDARD_1: 14.5 étapes/sec - 26k étapes (26k * 128 = ~ 3,3M qui est beaucoup plus que les échantillons d'apprentissage en fait dans les données), temps de paroi 29 min

  • CUSTOM - 5 travailleurs complex_model_m, 2 serveurs de paramètres large_model: 27 étapes/s, 31k étapes (128 * 31k = ~ 3,9M qui est beaucoup plus que les 650k échantillons de formation réellement dans les données), le temps de mur 20 minutes

Mon l'attente était que les données-parallèle sur la base de l'article était que la formation distribuée serait diviser les lots entre tous les travailleurs, donc si j'avais 5 travailleurs sur ~ 5k chauve-souris ches, alors chaque travailleur effectuerait ~ 1000 lots. Cependant, le comportement réel que j'observe est qu'il semble plus proche de CHACUN des 5 travailleurs effectuant 1 époque eux-mêmes. Quand on s'entraîne dans un environnement réparti, il y a 6 fois plus d'étapes que d'exemples d'entraînement - je sais que la vraie définition d'une étape est chaque fois que les gradients sont mis à jour, mais ma compréhension de l'entraînement parallèle est que cela diviserait simplement les lots de sorte qu'il devrait y avoir le même nombre de mises à jour de gradient - y a-t-il une raison pour laquelle ce comportement serait attendu? Serait-il sensé qu'il y ait plus d'étapes de formation nécessaires dans un environnement distribué d'entraînement asynchrone parallèle aux données? Quelqu'un peut-il expliquer le comportement que j'observe?

Répondre

3

La réponse précédente a fait un bon travail pour expliquer les goulets d'étranglement de performance. Laissez-moi vous expliquer les «époques» et comment TensorFlow traite les ensembles de données. La façon dont la formation distribuée fonctionne dans TensorFlow est que chaque travailleur itère de manière indépendante tout au long de l'ensemble de données. C'est une idée fausse commune que l'ensemble d'entraînement est partagé entre les ouvriers, mais ce n'est pas le cas.

Dans une configuration standard avec des files d'attente (voir this tutorial), chaque travailleur crée sa propre file d'attente. Cette file d'attente est remplie avec une liste de tous les noms de fichier de tous les fichiers d'apprentissage (généralement, la liste est mélangée et chaque fois que la file est épuisée, elle est repeuplée et remaniée). Chaque fichier est lu dans l'instance par instance, et les données sont analysées, prétraitées, puis envoyées dans une autre file où les instances sont mélangées et groupées. Une fois que la dernière instance d'un fichier est lue, le nom de fichier suivant est supprimé de la file d'attente de nom de fichier. S'il n'y a plus de fichiers à afficher, une "époque" est terminée.

Le point important ici est que toutes ces files d'attente sont par défaut local - non partagé. Ainsi, chaque travailleur répète indépendamment le même travail - en créant des files d'attente avec tous les fichiers et en itérant tout le jeu de données. Une époque complète, donc, est à peu près égale au nombre d'instances dans l'ensemble de données complet * le nombre de travailleurs. (Je ne suis pas sûr de votre résultat standard_1, mais le résultat sur CUSTOM signifie que vous avez votre maître + 5 travailleurs = 6 travailleurs * 650K exemples * (1 lot/128 exemples) = 31K étapes). L'utilisation des époques est déconseillée pour le paramétrage de l'entraînement distribué car il est trop confus et peut même poser des problèmes avec lui en général

Il suffit de coller avec max_steps.

Notez que, en raison de la conception de TensorFlow, «taille de lot» signifie la taille de lot de chaque travailleur. Mais chaque travailleur enverra des mises à jour aux serveurs de paramètres à peu près au même rythme, donc sur une période de temps équivalente au temps nécessaire pour traiter un "batch", le nombre de mises à jour des paramètres est approximativement batch_size * num_workers. C'est ce que nous appelons le effectif taille de lot. Cela a quelques conséquences pratiques:

  1. Vous avez tendance à utiliser batch_sizes plus petits, surtout si vous avez un grand nombre de travailleurs, de sorte que la taille du lot efficace reste sain d'esprit. Lorsque vous augmentez le nombre de travailleurs, votre taille de lot efficace augmente et vous devez donc diminuer votre taux d'apprentissage, du moins lorsque vous utilisez la descente de gradient stochastique "vanille". Les optimiseurs avec des taux d'apprentissage adaptatifs (comme Adagrad, Adam, etc.) ont tendance à être robustes aux taux d'apprentissage initiaux, mais si vous ajoutez suffisamment de travailleurs, vous devrez peut-être ajuster le taux d'apprentissage.

Vous vous demandez peut-être pourquoi TensorFlow gère les données d'entraînement de cette manière. C'est parce que dans les systèmes distribués, vous ne pouvez pas compter sur des machines ayant les mêmes vitesses, ou même être fiable du tout.Si vous partitionnez les données d'entraînement en ensembles disjoints qui vont à chaque travailleur et qu'une ou plusieurs machines sont lentes l'une par rapport à l'autre ou que le réseau tombe sur un, etc., votre processus de formation verra les données du "rapide"/travailleurs fiables plus fréquemment que les travailleurs «lents»/peu fiables. Cela polarise les résultats vers ces instances (ou, dans les cas extrêmes, les ignore tous ensemble).

+0

réponse incroyable! Cela ferait un excellent article de blog car il était très difficile de trouver cette information expliquée sur la documentation distribuée tensorflow disponible en ligne. Je suppose que ma seule préoccupation est que si je traite une donnée non équilibrée, je l'ai aimé l'utilisation des époques pour faire en sorte que je passe par tous les exemples des classes minoritaires et il semble que l'utilisation max_steps il n'y a vraiment aucune garantie (si si vous prenez assez de mesures, vous devriez échantillonner même dans les plus petites classes minoritaires). – reese0106

+0

Ma compréhension des optimiseurs comme Adam est que l'on utilise généralement les taux d'apprentissage "out of the box" car ils ont été plus ou moins optimisés. Existe-t-il des heuristiques suggérées pour ajuster le taux d'apprentissage afin de traiter la plus grande taille de lot efficace? Je reconnais que l'expérimentation/tuning hyperparam'etre est probablement nécessaire, mais en espérant en savoir plus pour obtenir dans le bon ordre de grandeur – reese0106

+0

, vous faites référence à max_steps aussi - serait-ce même que train_steps dans l'échantillon de recensement estimateur personnalisé à ce [en ligne] (https : //github.com/GoogleCloudPlatform/cloudml-samples/blob/master/census/customestimator/trainer/task.py#L201) ou est-ce un argument tout à fait différent? – reese0106

1

Il existe deux types de Severs:

  • travailleurs: qui effectuent le calcul graphique
  • serveurs Paramètres: qui stockent les paramètres, de sorte que tous les travailleurs peuvent partager et mettre à jour les paramètres

Vous pouvez avoir un goulot d'étranglement dans les serveurs de paramètres. Si le modèle est très grand et que vous avez peu de paramètres, vous avez besoin de plus de communication entre les travailleurs et le serveur de paramètres. Par exemple, si vous avez 2 serveurs de paramètres, vous aurez la moitié des paramètres du modèle dans un serveur et l'autre moitié dans l'autre. Si vous avez beaucoup de travailleurs, ils devront obtenir et envoyer beaucoup de paramètres à différents travailleurs, et les travailleurs auront un grand décalage.Si vous augmentez le nombre de serveurs de paramètres, le décalage sera réduit car la communication entre chaque serveur de paramètres et les opérateurs est moindre. Comme votre taille de lot est 128 (assez grande) et que vous pouvez effectuer 8 pas par seconde seulement dans la CPU, je pense que votre modèle est si rapide qu'il faut plus de temps pour partager les paramètres du serveur que d'exécuter une seule itération. Vous pouvez également essayer d'augmenter la taille du lot.

+0

J'apprécie la réponse. Bien que je pense que je suis la plupart de ce que vous dites - je ne suis toujours pas tout à fait sûr pourquoi cela se traduirait par plus de pas de train que d'exemples de train. Essayez-vous de suggérer que parce qu'il y a un goulot d'étranglement dans la communication avec le serveur de paramètres, chaque taille de lot entraîne plusieurs mises à jour? Le problème que j'essaie de comprendre est pourquoi une époque se traduit par des étapes d'apprentissage de 5.1k sur CPU/GPU, mais le réglage distribué entraîne des étapes de 30k + sur la même époque. – reese0106

+0

Je ne vous ai pas bien compris. Ma réponse n'a rien à voir avec ça. Il devrait être le même nombre d'étapes indépendamment de la machine distribuée ou unique. Quelle session utilisez-vous? est-ce que 'MonitoredTrainingSession'? Comment comptez-vous les étapes? utilisez-vous le global_step 'tensorflow.python.training_util.get_or_create_global_step()'? Utilisez-vous des files d'attente ou envoyez-vous les échantillons dans 'session.run'? – jorgemf

+0

Je suivais l'échantillon d'estimateur personnalisé qui se trouve [ici] (https://github.com/GoogleCloudPlatform/cloudml-samples/blob/master/census/customestimator/trainer/model.py#L193) - Je suis en utilisant tf.contrib.framework.get_or_create_global_step() et en passant cela au train_op comme le fait l'exemple. Je cours une expérience ie. learn_runner.run() et les données d'entrée sont générées en utilisant tf.train.batch. Voyez-vous quelque chose dans cet échantillon qui causerait des problèmes? Je crois que la fonction expérimentale utilise une session d'entraînement surveillée par défaut. – reese0106