2016-07-11 27 views
5

Ich benutze Tensorflow mit Titan-X GPUs und ich habe festgestellt, dass, wenn ich das CIFAR10-Beispiel ausführen, die Volatile GPU-utilization ziemlich konstant um 30% ist, während ich trainiere mein eigenes Modell, das Volatile GPU-utilization ist weit davon entfernt, stetig, es ist fast immer 0% und Spikes bei 80/90% vor dem Zurückgehen auf 0%, immer und immer wieder.Tensorflow: GPU Auslastung ist fast immer bei 0%

Ich dachte, dass dieses Verhalten auf die Art und Weise zurückzuführen war, wie ich die Daten dem Netzwerk zuführte (ich holte die Daten nach jedem Schritt ab, was einige Zeit in Anspruch nahm). Aber nach dem Implementieren einer Warteschlange, um die Daten zu füttern und diese Latenz zwischen den Schritten zu vermeiden, blieb das Problem bestehen (siehe unten für das Warteschlangensystem).

Irgendeine Idee?

batch = 128 # size of the batch 
x = tf.placeholder("float32", [None, n_steps, n_input]) 
y = tf.placeholder("float32", [None, n_classes]) 

# with a capacity of 100 batches, the bottleneck should not be the data feeding 
queue = tf.RandomShuffleQueue(capacity=100*batch, 
        min_after_dequeue=80*batch, 
        dtypes=[tf.float32, tf.float32], 
        shapes=[[n_steps, n_input], [n_classes]]) 
enqueue_op = queue.enqueue_many([x, y]) 
X_batch, Y_batch = queue.dequeue_many(batch) 

sess = tf.Session() 

def load_and_enqueue(data): 
    while True: 
     X, Y = data.get_next_batch(batch) 
     sess.run(enqueue_op, feed_dict={x: X, y: Y}) 

train_thread = threading.Thread(target=load_and_enqueue, args=(data)) 
train_thread.daemon = True 
train_thread.start() 

for _ in xrange(max_iter): 
    sess.run(train_op) 
+0

Wie lange ist 'data.get_next_batch' relativ zu anderen Operationen? Es scheint das einzige zu sein, das nur auf der CPU läuft, und es kann die Pipeline verlangsamen. –

+0

Bei einem Batch der Größe 128 dauert 'get_next_batch' ungefähr 14x mehr Zeit als' sess.run (train_op) ', um ausgeführt zu werden. Aber bevor ich mit dem Training anfange, füttere ich die Warteschlange mit 100 * Batch-Beispielen, also sollte ich zumindest am Anfang eine gute GPU-Auslastung haben, nicht? – BiBi

+0

Wenn das Training um eine Größenordnung schneller ist als das Füttern, ist es möglich, dass die Auslagerungsoperation die meiste Zeit wartet, dh der GPU-Laufteil ('train_op') wartet auf den CPU-Lauf-Thread (für' load_and_enqueue) '). Mir ist aber noch nicht klar, was das Zusammenspiel mit dem 'min_after_dequeue' ist. Wie wäre es mit dem Ausführen aller auf der CPU (* d. H. * Kein Thread), und sehen Sie, ob die Verwendung reibungsloser ist? –

Antwort

9

Nachdem ich einige Experimente gemacht habe, fand ich die Antwort, also poste ich es, da es für jemand anderen nützlich sein könnte.

Erstens ist get_next_batch ungefähr 15x langsamer als train_op (Danke an Eric Platon für das Hinzeigen).

Allerdings dachte ich, dass die Warteschlange bis capacity satt war und das erst nach dem Training sollte beginnen. Daher dachte ich, dass, selbst wenn get_next_batch war viel langsamer, die Warteschlange sollte diese Latenz verstecken, zumindest am Anfang, da es capacity Beispiele enthält und es würde nur neue Daten abrufen, nachdem es min_after_dequeue erreicht, die niedriger als capacity und das ist es würde zu einer irgendwie stabilen GPU-Nutzung führen.

Aber tatsächlich beginnt das Training, sobald die Warteschlange min_after_dequeue Beispiele erreicht. Somit wird die Warteschlange aus der Warteschlange entfernt, sobald die Warteschlange min_after_dequeue Beispiele zum Ausführen der train_op erreicht, und da die Zeit zum Zuführen der Warteschlange 15x langsamer ist als die Ausführungszeit von train_op, fällt die Anzahl der Elemente in der Warteschlange direkt unter min_after_dequeue die erste Iteration der train_op und der train_op muss warten, bis die Warteschlange wieder min_after_dequeue Beispiele erreicht.

Wenn ich die train_op zwingen zu warten, bis die Warteschlange bis capacity zugeführt wird (mit capacity = 100*batch) stattdessen automatisch zu starten, wenn es min_after_dequeue (mit min_after_dequeue=80*batch) erreicht, wird die GPU-Auslastung für wie 10 Sekunden stabil ist, bevor auf 0 zurück %, was verständlich ist, da die Warteschlange beispielsweise in weniger als 10 Sekunden min_after_dequeue erreicht.