web-dev-qa-db-fra.com

Exécution simultanée de plusieurs sessions tensorflow

J'essaie d'exécuter plusieurs sessions de TensorFlow simultanément sur une machine CentOS 7 dotée de 64 processeurs. Mon collègue indique qu'il peut utiliser les deux blocs de code suivants pour produire une accélération parallèle sur sa machine en utilisant 4 cœurs:

mnist.py

import numpy as np
import input_data
from PIL import Image
import tensorflow as tf
import time


def main(randint):
    print 'Set new seed:', randint
    np.random.seed(randint)
    tf.set_random_seed(randint)
    mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

    # Setting up the softmax architecture
    x = tf.placeholder("float", [None, 784])
    W = tf.Variable(tf.zeros([784, 10]))
    b = tf.Variable(tf.zeros([10]))
    y = tf.nn.softmax(tf.matmul(x, W) + b)

    # Setting up the cost function
    y_ = tf.placeholder("float", [None, 10])
    cross_entropy = -tf.reduce_sum(y_*tf.log(y))
    train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

    # Initialization 
    init = tf.initialize_all_variables()
    sess = tf.Session(
        config=tf.ConfigProto(
            inter_op_parallelism_threads=1,
            intra_op_parallelism_threads=1
        )
    )
    sess.run(init)

    for i in range(1000):
        batch_xs, batch_ys = mnist.train.next_batch(100)
        sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

    print sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})

if __== "__main__":
    t1 = time.time()
    main(0)
    t2 = time.time()
    print "time spent: {0:.2f}".format(t2 - t1)

parallel.py

import multiprocessing
import numpy as np

import mnist
import time

t1 = time.time()
p1 = multiprocessing.Process(target=mnist.main,args=(np.random.randint(10000000),))
p2 = multiprocessing.Process(target=mnist.main,args=(np.random.randint(10000000),))
p3 = multiprocessing.Process(target=mnist.main,args=(np.random.randint(10000000),))
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
t2 = time.time()
print "time spent: {0:.2f}".format(t2 - t1)

En particulier, il dit qu'il observe 

Running a single process took: 39.54 seconds
Running three processes took: 54.16 seconds

Cependant, quand je lance le code:

python mnist.py
==> Time spent: 5.14

python parallel.py 
==> Time spent: 37.65

Comme vous pouvez le constater, le multitraitement ralentit considérablement, contrairement à mon collègue. Quelqu'un at-il une idée de la raison pour laquelle cela pourrait se produire et de ce qui peut être fait pour y remédier?

MODIFIER

Voici un exemple de sortie. Notez que le chargement des données semble se faire en parallèle, mais la formation des modèles individuels a une apparence très séquentielle dans la sortie (et peut être vérifiée en regardant l'utilisation du processeur dans top pendant l'exécution du programme)

#$ python parallel.py 
Set new seed: 9672406
Extracting MNIST_data/train-images-idx3-ubyte.gz
Set new seed: 4790824
Extracting MNIST_data/train-images-idx3-ubyte.gz
Set new seed: 8011659
Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
I tensorflow/core/common_runtime/local_device.cc:25] Local device intra op parallelism threads: 1
I tensorflow/core/common_runtime/local_session.cc:45] Local session inter op parallelism threads: 1
0.9136
I tensorflow/core/common_runtime/local_device.cc:25] Local device intra op parallelism threads: 1
I tensorflow/core/common_runtime/local_session.cc:45] Local session inter op parallelism threads: 1
0.9149
I tensorflow/core/common_runtime/local_device.cc:25] Local device intra op parallelism threads: 1
I tensorflow/core/common_runtime/local_session.cc:45] Local session inter op parallelism threads: 1
0.8931
time spent: 41.36

Un autre EDIT

Supposons que nous souhaitions confirmer que le problème concerne apparemment TensorFlow et non le multitraitement. J'ai remplacé le contenu de mnist.py par une grande boucle comme suit:

def main(randint):
    c = 0
    for i in xrange(100000000):
        c += i

Pour la sortie:

#$ python mnist.py
==> time spent: 5.16
#$ python parallel.py 
==> time spent: 4.86

Par conséquent, je pense que le problème ici ne concerne pas le multitraitement lui-même.

13
user1936768

Commentaire de OP ( user1936768 ):

J'ai une bonne nouvelle: il se trouve, du moins sur mon système, que mes programmes d'essai n'ont pas fonctionné assez longtemps pour que les autres instances de TF puissent démarrer. Quand je mets un exemple de programme plus long dans main, je vois effectivement des calculs simultanés 

2
Guy Coder

Cela peut être fait avec élégance avec Ray , une bibliothèque pour Python parallèle et distribué, qui vous permet de former vos modèles en parallèle à partir d'un seul script Python.

Cela a l’avantage de vous permettre de paralléliser les "classes" en les transformant en "acteurs", ce qui peut être difficile à faire avec un multitraitement Python classique. Ceci est important car il est souvent coûteux d’initialiser le graphique TensorFlow. Si vous créez un acteur, puis appelez la méthode train plusieurs fois, le coût d'initialisation du graphique est amorti.

import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
from PIL import Image
import ray
import tensorflow as tf
import time


@ray.remote
class TrainingActor(object):
    def __init__(self, seed):
        print('Set new seed:', seed)
        np.random.seed(seed)
        tf.set_random_seed(seed)
        self.mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)

        # Setting up the softmax architecture.
        self.x = tf.placeholder('float', [None, 784])
        W = tf.Variable(tf.zeros([784, 10]))
        b = tf.Variable(tf.zeros([10]))
        self.y = tf.nn.softmax(tf.matmul(self.x, W) + b)

        # Setting up the cost function.
        self.y_ = tf.placeholder('float', [None, 10])
        cross_entropy = -tf.reduce_sum(self.y_*tf.log(self.y))
        self.train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

        # Initialization
        self.init = tf.initialize_all_variables()
        self.sess = tf.Session(
            config=tf.ConfigProto(
                inter_op_parallelism_threads=1,
                intra_op_parallelism_threads=1
            )
        )

    def train(self):
        self.sess.run(self.init)

        for i in range(1000):
            batch_xs, batch_ys = self.mnist.train.next_batch(100)
            self.sess.run(self.train_step, feed_dict={self.x: batch_xs, self.y_: batch_ys})

        correct_prediction = tf.equal(tf.argmax(self.y, 1), tf.argmax(self.y_, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))

        return self.sess.run(accuracy, feed_dict={self.x: self.mnist.test.images,
                                                  self.y_: self.mnist.test.labels})


if __== '__main__':
    # Start Ray.
    ray.init()

    # Create 3 actors.
    training_actors = [TrainingActor.remote(seed) for seed in range(3)]

    # Make them all train in parallel.
    accuracy_ids = [actor.train.remote() for actor in training_actors]
    print(ray.get(accuracy_ids))

    # Start new training runs in parallel.
    accuracy_ids = [actor.train.remote() for actor in training_actors]
    print(ray.get(accuracy_ids))

Si vous souhaitez uniquement créer une copie du jeu de données au lieu de laisser chaque acteur le lire, vous pouvez réécrire les choses comme suit. Sous le capot, cela utilise le magasin d'objets de mémoire partagée Plasma et le format de données Apache Arrow .

@ray.remote
class TrainingActor(object):
    def __init__(self, mnist, seed):
        self.mnist = mnist
        ...

    ...

if __== "__main__":
    ray.init()

    # Read the mnist dataset and put it into shared memory once
    # so that workers don't create their own copies.
    mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)
    mnist_id = ray.put(mnist)

    training_actors = [TrainingActor.remote(mnist_id, seed) for seed in range(3)]

Vous pouvez en voir plus dans la documentation Ray . Notez que je suis l'un des développeurs de Ray.

0
Robert Nishihara

Une possibilité est que vos sessions essaient d'utiliser 64 cœurs chacun et se piétinent Peut-être essayez de définir NUM_CORES sur une valeur inférieure pour chaque session

sess = tf.Session(
    tf.ConfigProto(inter_op_parallelism_threads=NUM_CORES,
                   intra_op_parallelism_threads=NUM_CORES))
0
Yaroslav Bulatov