1

Je veux former un réseau de neurones en utilisant la descente de gradient de lot, mais je voudrais paralléliser le processus. Je souhaite séparer le lot en mini-lots, répartir le calcul du gradient entre les processus, puis les ramener au processus maître pour les établir en moyenne et les appliquer à la formation.TensorFlow moyennage des gradients de minibatch en parallèle

Comme un exemple simple, prenez ce script qui forme un réseau de neurones sur N points de données pour la parabole y = x^2:

import tensorflow as tf 
import numpy as np 

def add_layer(inputs, in_size, out_size, activation_function=None): 
    Weights = tf.Variable(tf.random_normal([in_size, out_size])) 
    biases = tf.Variable(tf.random_normal([1, out_size])) 
    Wx_plus_b = tf.matmul(inputs, Weights) + biases 
    if activation_function is None: 
     outputs = Wx_plus_b 
    else: 
     outputs = activation_function(Wx_plus_b) 
    return outputs 

# Make up some real data 
N = 50 
x_data = np.linspace(-2, 2, N)[:, np.newaxis] 
noise = np.random.normal(0, 0.05, x_data.shape) 
y_data = np.square(x_data) # - 0.5 + noise 

# Define placeholder for x_data and y_data 
xs = tf.placeholder(tf.float32, [None, 1]) 
ys = tf.placeholder(tf.float32, [None, 1]) 

""" Build the network""" 
# Add hidden layer 
l1 = add_layer(xs, 1, 5, activation_function=tf.tanh) 
# Add output layer 
prediction = add_layer(l1, 5, 1, activation_function=None) 

# Define loss 
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys-prediction), reduction_indices=[1])) 

# Define optimizer 
opt = tf.train.GradientDescentOptimizer(learning_rate=1e-2) 
# Compute the gradients for a list of variables. 
grads_and_vars = opt.compute_gradients(loss) 
# Ask the optimizer to apply the gradients 
train_opt = opt.apply_gradients(grads_and_vars) 

# Initialize global variables 
sess = tf.Session() 
init = tf.global_variables_initializer() 
sess.run(init) 

for i in range(2000): 
    # training 
    sess.run(train_opt, feed_dict={xs: x_data, ys: y_data}) 
    if i % 50 == 0: 
     prediction_value = sess.run(prediction, feed_dict={xs: x_data}) 
     print(sess.run(loss, feed_dict={xs: x_data, ys: y_data})) 

La section Je veux paralléliser le calcul des gradients, puis je veux ramener ces gradients au processus maître pour faire la moyenne et ensuite appliquer à l'étape de formation. Je veux diviser les N points de données en x_data sur P processus. Je pense que c'est ce que l'on appelle "l'entraînement synchrone", pour lequel j'ai vu des ressources mais personne ne l'explique jamais.

Comment puis-je paralléliser cet exemple simple de manière synchrone?

+1

pourquoi voulez-vous faire cela? Ne dis pas que c'est une mauvaise idée, je suis juste curieux – user3684792

+0

Dans ma vraie application, j'ai environ 30 000 exemples à adapter, en utilisant un réseau neuronal profond avec de nombreuses couches dans les nœuds. Je me suis dit que si je pouvais paralléliser la formation en mini-lot, je pourrais rendre ce parallèle embarrassant. Par exemple, en cours d'exécution sur 30 processus, je peux atteindre la vitesse de montage à 1000 exemples. – Drew

+0

Quels avantages cela donne-t-il à juste laisser tensorflow gérer la parallélisation? – user3684792

Répondre

1

Vous ne trouverez probablement pas grand-chose sur l'entraînement synchrone car il a été abandonné au profit de l'entraînement asynchrone.

En descente en gradient synchrone, tous les mini-lots doivent être terminés et leurs gradients respectifs sont tous appliqués en même temps pour mettre à jour les paramètres du réseau. Dans le cas asynchrone, les paramètres réseau sont mis à jour chaque fois que le gradient d'un mini-batch est disponible. Ces mises à jour sont dans un ordre plus ou moins aléatoire. Il semble que cette méthode ne soit pas valide: par exemple, disons que les paramètres réseau ont été itérés 1342 fois et que vous commencez à calculer le gradient pour un mini-batch. Au moment où le calcul est terminé, les paramètres du réseau ont pu être mis à jour 1349 fois parce que 7 mini-lots plus anciens ont signalé leurs gradients. Vous appliquerez donc une correction de gradient aux paramètres réseau qui ne sont pas ceux qui ont été spécifiés au début du calcul. De ce que j'ai écrit ci-dessus, il semble que la descente asynchrone est fausse, mais vous devez comprendre que la descente de gradient stochastique est un processus bâclé/inexact, et que l'ajout de la négligence des mises à jour asynchrones n'est pas préjudiciable. D'un autre côté, lorsque vous effectuez des mises à jour synchrones, certains GPU sont souvent inactifs car ils doivent attendre que tous les autres GPU soient terminés.

J'ai rapidement essayé de trouver une référence appropriée à ce sujet sur le web mais je n'ai pas pu. Je me souviens que l'astuce de l'utilisation des mises à jour asynchrones a été redécouvert plusieurs fois par différents groupes. Il y a ce vieux paper de Jeff Dean, mais ils n'analysent pas synchrone vs asynchrone.

La documentation officielle de tensorflow a un exemple avec asynchronous training, mais il pourrait y avoir de meilleurs tutoriels.

La page Web que j'ai liée ci-dessus pointe également vers ce synchronous training example.

+0

Il existe une extension TensorFlow utilisant MPI qui rend l'entraînement synchrone plus traitable: https://github.com/uber/horovod. Je l'ai essayé et cela fonctionne, même si la performance est pire sur mon ordinateur portable - besoin d'essayer avec plus de cœurs de processeurs. – Drew

+0

@Drew Vous devriez comparer les performances par rapport à Async, mais il semble que horovod et MPI ne sont pas faits pour ça. Si vous exécutez des calculs lourds qui prennent des jours sur GPU, vous pouvez chercher à trouver un autre moyen d'exécuter async. Cela pourrait vous faire gagner du temps à la fin. – toto2