it-swarm.com.de

Sehr geringe GPU-Nutzung während des Trainings in Tensorflow

Ich versuche, ein einfaches mehrschichtiges Perzeptron für eine 10-Klassen-Bildklassifizierungsaufgabe zu trainieren, die Teil der Aufgabe für den Udacity Deep-Learning-Kurs ist. Genauer gesagt, besteht die Aufgabe darin, aus verschiedenen Schriftarten gerenderte Buchstaben zu klassifizieren (das Dataset heißt notMNIST).

Der Code, den ich am Ende erhalten habe, sieht recht einfach aus, aber egal, was ich während des Trainings immer sehr wenig GPU brauche. Ich messe die Last mit GPU-Z und sie zeigt nur 25-30%.

Hier ist mein aktueller Code:

graph = tf.Graph()
with graph.as_default():
    tf.set_random_seed(52)

    # dataset definition
    dataset = Dataset.from_tensor_slices({'x': train_data, 'y': train_labels})
    dataset = dataset.shuffle(buffer_size=20000)
    dataset = dataset.batch(128)
    iterator = dataset.make_initializable_iterator()
    sample = iterator.get_next()
    x = sample['x']
    y = sample['y']

    # actual computation graph
    keep_prob = tf.placeholder(tf.float32)
    is_training = tf.placeholder(tf.bool, name='is_training')

    fc1 = dense_batch_relu_dropout(x, 1024, is_training, keep_prob, 'fc1')
    fc2 = dense_batch_relu_dropout(fc1, 300, is_training, keep_prob, 'fc2')
    fc3 = dense_batch_relu_dropout(fc2, 50, is_training, keep_prob, 'fc3')
    logits = dense(fc3, NUM_CLASSES, 'logits')

    with tf.name_scope('accuracy'):
        accuracy = tf.reduce_mean(
            tf.cast(tf.equal(tf.argmax(y, 1), tf.argmax(logits, 1)), tf.float32),
        )
        accuracy_percent = 100 * accuracy

    with tf.name_scope('loss'):
        loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))

    update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
    with tf.control_dependencies(update_ops):
        # ensures that we execute the update_ops before performing the train_op
        # needed for batch normalization (apparently)
        train_op = tf.train.AdamOptimizer(learning_rate=1e-3, epsilon=1e-3).minimize(loss)

with tf.Session(graph=graph) as sess:
    tf.global_variables_initializer().run()
    step = 0
    Epoch = 0
    while True:
        sess.run(iterator.initializer, feed_dict={})
        while True:
            step += 1
            try:
                sess.run(train_op, feed_dict={keep_prob: 0.5, is_training: True})
            except tf.errors.OutOfRangeError:
                logger.info('End of Epoch #%d', Epoch)
                break

        # end of Epoch
        train_l, train_ac = sess.run(
            [loss, accuracy_percent],
            feed_dict={x: train_data, y: train_labels, keep_prob: 1, is_training: False},
        )
        test_l, test_ac = sess.run(
            [loss, accuracy_percent],
            feed_dict={x: test_data, y: test_labels, keep_prob: 1, is_training: False},
        )
        logger.info('Train loss: %f, train accuracy: %.2f%%', train_l, train_ac)
        logger.info('Test loss: %f, test accuracy: %.2f%%', test_l, test_ac)

        Epoch += 1

Folgendes habe ich bisher ausprobiert:

  1. Ich habe die Eingabepipeline von einfachem feed_dict in tensorflow.contrib.data.Dataset geändert. Soweit ich es verstanden habe, soll es für die Effizienz der Eingabe sorgen, z. Daten in einen separaten Thread laden. Es sollte also kein Engpass mit der Eingabe verbunden sein.

  2. Ich habe die hier vorgeschlagenen Spuren gesammelt: https://github.com/tensorflow/tensorflow/issues/1824#issuecomment-225754659 Diese Spuren zeigten jedoch nichts Interessantes. > 90% der Zugstufe sind Matmuloperationen.

  3. Geänderte Stapelgröße Wenn ich sie von 128 auf 512 ändere, steigt die Last von ~ 30% auf ~ 38%, wenn ich sie weiter auf 2048 anwende, geht die Last auf ~ 45%. Ich habe einen 6-GB-GPU-Speicher, und der Datensatz besteht aus einkanaligen 28x28-Bildern. Soll ich wirklich eine so große Losgröße verwenden? Soll ich es weiter erhöhen?

Sollte ich mir im Allgemeinen Sorgen über die geringe Belastung machen? Ist das wirklich ein Zeichen dafür, dass ich ineffizient trainiere?

Hier sind die GPU-Z-Screenshots mit 128 Bildern im Stapel. Sie können niedrige Last mit gelegentlichen Spitzen auf 100% sehen, wenn ich die Genauigkeit des gesamten Datensatzes nach jeder Epoche messe.

 GPU load

4
Alexey Petrenko

MNIST-Netzwerke sind winzig und es ist schwierig, eine hohe GPU- (oder CPU-) Effizienz für sie zu erreichen. Ich denke, 30% sind für Ihre Anwendung nicht ungewöhnlich. Sie erhalten eine höhere Rechenleistung bei größeren Losgrößen. Das bedeutet, Sie können mehr Beispiele pro Sekunde verarbeiten. Sie erhalten jedoch auch eine geringere statistische Effizienz. Sie müssen also mehr Beispiele insgesamt verarbeiten, um die Zielgenauigkeit zu erreichen. Es ist also ein Kompromiss. Bei winzigen Charaktermodellen wie dem Ihren fällt die statistische Effizienz nach einem Wert von 100 sehr schnell ab. Es lohnt sich also wahrscheinlich nicht, die Batchgröße für das Training zu erhöhen. Als Schlussfolgerung sollten Sie die größtmögliche Losgröße verwenden.

9

Wenn ich bei meiner nVidia GTX 1080 ein Faltungs-Neuronales Netzwerk in der MNIST-Datenbank verwende, beträgt die GPU-Last ~ 68%.

Wenn ich zu einem einfachen, nicht konvolutionellen Netzwerk wechsle, beträgt die GPU-Last ~ 20%.

Sie können diese Ergebnisse replizieren, indem Sie im Tutorial Building Autoencoder in Keras von Francis Chollet - fortlaufend erweiterte Modelle erstellen.

1
Contango