J'ai lu Doc distribué Tensorflow , et il mentionne que dans la formation asynchrone,
chaque réplique du graphique possède une boucle d'apprentissage indépendante qui s'exécute sans coordination.
D'après ce que je comprends, si nous utilisons un serveur de paramètres avec une architecture de parallélisme de données, cela signifie que chaque travailleur calcule des gradients et met à jour ses propres poids sans se soucier des mises à jour des autres travailleurs pour la formation distribuée Neural Network. Comme tous les poids sont partagés sur le serveur de paramètres (ps), je pense que ps doit encore coordonner (ou agréger) les mises à jour de poids de tous les travailleurs d'une manière ou d'une autre. Je me demande comment fonctionne l'agrégation dans la formation asynchrone. Ou, en termes plus généraux, comment fonctionne la formation asynchrone dans Tensorflow distribué?
Lorsque vous vous entraînez de manière asynchrone dans Distributed TensorFlow, un travailleur particulier effectue les opérations suivantes:
Le travailleur lit tous les paramètres de modèle partagés en parallèle à partir des tâches PS et les copie dans la tâche travailleur. Ces lectures ne sont pas coordonnées avec des écritures simultanées et aucun verrou n'est acquis: en particulier, le travailleur peut voir des mises à jour partielles d'un ou plusieurs autres travailleurs (par exemple, un sous-ensemble des mises à jour d'un autre travailleur peut avoir été appliqué, ou un sous-ensemble des éléments dans une variable peut avoir été mise à jour).
L'ouvrier calcule les gradients localement, sur la base d'un lot de données d'entrée et des valeurs de paramètre qu'il a lues à l'étape 1.
Le travailleur envoie les gradients de chaque variable à la tâche PS appropriée, et applique les gradients à leur variable respective, en utilisant une règle de mise à jour qui est déterminée par l'algorithme d'optimisation (par exemple SGD, SGD avec Momentum, Adagrad, Adam, etc.). Les règles de mise à jour utilisent généralement (approximativement) commutative les opérations, de sorte qu'elles peuvent être appliquées indépendamment sur les mises à jour de chaque travailleur, et l'état de chaque variable sera un agrégat en cours d'exécution de la séquence de mises à jour reçues .
Dans la formation asynchrone, chaque mise à jour du travailleur est appliquée simultanément et les mises à jour peuvent être quelque peu coordonnées si l'option use_locking=True
L'indicateur a été défini lorsque l'optimiseur respectif (par exemple tf.train.GradientDescentOptimizer
) a été initialisé. Notez cependant que le verrouillage ici ne fournit une exclusion mutuelle que pour deux mises à jour simultanées et (comme indiqué ci-dessus) les lectures n'acquièrent pas de verrous; le verrouillage ne fournit pas d'atomicité sur l'ensemble des mises à jour.
(En revanche, dans la formation synchrone, un utilitaire comme tf.train.SyncReplicasOptimizer
veillera à ce que tous les travailleurs lisent les mêmes valeurs à jour pour chaque paramètre du modèle; et que toutes les mises à jour d'une étape synchrone sont agrégées avant d'être appliquées aux variables sous-jacentes. Pour ce faire, les travailleurs sont synchronisés par une barrière, qu'ils entrent après avoir envoyé leur mise à jour de gradient et quittent après que la mise à jour agrégée a été appliquée à toutes les variables.)
Dans la formation asynchrone, il n'y a pas de synchronisation des poids entre les travailleurs. Les poids sont stockés sur le serveur de paramètres. Chaque travailleur charge et modifie les poids partagés indépendamment les uns des autres. De cette façon, si un travailleur a terminé une itération plus rapidement que les autres travailleurs, il passe à l'itération suivante sans attendre. Les travailleurs interagissent uniquement avec le serveur de paramètres partagés et n'interagissent pas entre eux.
Globalement, cela peut (selon la tâche) accélérer considérablement le calcul. Cependant, les résultats sont parfois pires que ceux obtenus avec les mises à jour synchrones plus lentes.
En regardant l'exemple dans la documentation à laquelle vous accédez:
with tf.device("/job:ps/task:0"):
weights_1 = tf.Variable(...)
biases_1 = tf.Variable(...)
with tf.device("/job:ps/task:1"):
weights_2 = tf.Variable(...)
biases_2 = tf.Variable(...)
with tf.device("/job:worker/task:7"):
input, labels = ...
layer_1 = tf.nn.relu(tf.matmul(input, weights_1) + biases_1)
logits = tf.nn.relu(tf.matmul(layer_1, weights_2) + biases_2)
# ...
train_op = ...
with tf.Session("grpc://worker7.example.com:2222") as sess:
for _ in range(10000):
sess.run(train_op)
Vous pouvez voir que la formation est répartie sur trois machines qui partagent toutes une copie de poids identiques, mais comme mentionné juste en dessous de l'exemple:
Dans l'exemple ci-dessus, les variables sont créées sur deux tâches dans le travail ps et la partie à forte intensité de calcul du modèle est créée dans le travail travailleur. TensorFlow insérera les transferts de données appropriés entre les travaux (de ps à travailleur pour la passe avant, et de travailleur à ps pour appliquer des dégradés).
En d'autres termes, un gpu est utilisé pour calculer la passe avant, puis transmet les résultats aux deux autres machines, tandis que chacune des autres machines calcule la propagation arrière pour une partie des poids, puis envoie les résultats aux autres machines afin ils peuvent tous mettre à jour leurs poids de manière appropriée.
Les GPU sont utilisés pour accélérer les multiplications matricielles et les opérations mathématiques parallèles qui sont très intensives pour la propagation avant et arrière. Ainsi, la formation distribuée signifie simplement que vous distribuez ces opérations sur de nombreux GPU, le modèle est toujours synchronisé entre les machines, mais maintenant la propagation arrière de différents poids peut être calculée en parallèle et la transmission directe sur un mini-lot différent peut être calculée à le même temps que le backprop du mini-lot précédent est toujours en cours de calcul. La formation distribuée ne signifie pas que vous avez des modèles et des poids totalement indépendants sur chaque machine.