2017-05-30 12 views
7

Pracuję z tensorflow i chcę przyspieszyć fazę przewidywania fazę wcześniej wyszkolonego modelu Keras (nie jestem zainteresowany fazą szkolenia), używając jednocześnie procesor i jeden procesor graficzny.Tensorflow: przewidywania symultaniczne na GPU i procesorze

Próbowałem utworzyć 2 różne wątki, które zasilają dwie różne sesje tensorflow (jedna działająca na procesorze, a druga działająca na GPU). Każda nić podaje stałą liczbę partii (np. Jeśli mamy ogółem 100 partii, chcę przypisać 20 partii procesora i 80 na GPU lub jakąkolwiek możliwą kombinację tych dwóch) w pętli i połączyć wynik. Byłoby lepiej, gdyby podział został wykonany automatycznie.

Jednak nawet w tym scenariuszu wydaje się, że partie są podawane w sposób synchroniczny, ponieważ nawet wysyłanie kilku partii do procesora i obliczanie wszystkich pozostałych w GPU (z wykorzystaniem GPU jako wąskiego gardła) zauważyłem, że ogólny czas przewidywania jest zawsze wyższy w odniesieniu do testu wykonanego wyłącznie za pomocą GPU.

Spodziewałabym się, że jest to szybsze, ponieważ gdy działa tylko GPU, zużycie procesora wynosi około 20-30%, dlatego jest dostępny procesor do przyspieszenia obliczeń.

Przeczytałem wiele dyskusji, ale wszystkie dotyczą paralelizmu z wieloma procesorami graficznymi, a nie między procesorem graficznym a procesorem.

Oto przykładowy kod mam napisane: że tensor_cpu i tensor_gpu obiekty są ładowane z tego samego modelu Keras w następujący sposób:

with tf.device('/gpu:0'): 
    model_gpu = load_model('model1.h5') 
    tensor_gpu = model_gpu(x) 

with tf.device('/cpu:0'): 
    model_cpu = load_model('model1.h5') 
    tensor_cpu = model_cpu(x) 

Następnie przewidywanie odbywa się w następujący sposób:

def predict_on_device(session, predict_tensor, batches): 
    for batch in batches: 
     session.run(predict_tensor, feed_dict={x: batch}) 


def split_cpu_gpu(batches, num_batches_cpu, tensor_cpu, tensor_gpu): 
    session1 = tf.Session(config=tf.ConfigProto(log_device_placement=True)) 
    session1.run(tf.global_variables_initializer()) 
    session2 = tf.Session(config=tf.ConfigProto(log_device_placement=True)) 
    session2.run(tf.global_variables_initializer()) 

    coord = tf.train.Coordinator() 

    t_cpu = Thread(target=predict_on_device, args=(session1, tensor_cpu, batches[:num_batches_cpu])) 
    t_gpu = Thread(target=predict_on_device, args=(session2, tensor_gpu, batches[num_batches_cpu:])) 

    t_cpu.start() 
    t_gpu.start() 

    coord.join([t_cpu, t_gpu]) 

    session1.close() 
    session2.close() 

Jak mogę osiągnąć to zrównoleglenie CPU/GPU? Chyba coś mi brakuje.

Wszelkiego rodzaju pomoc byłaby bardzo ceniona!

+0

Czy odpowiedziałem na Twoje pytanie? – MaxB

+0

Tak, tak, tak !! Przykro mi z powodu późnej odpowiedzi, byłem zajęty innym projektem i nie miałem czasu, aby to wypróbować. Sprawdziłem twój kod. Czy to możliwe, że jedynym powodem, dla którego to nie zadziałało, była opcja intra_op_parallelism_thread? – battuzz

+0

Każdy pomysł, w jaki sposób mogę pozwolić tensorflow znaleźć odpowiednią ilość partii do zasilania procesora i GPU, dzięki czemu mogę zminimalizować całkowity czas przewidywania? – battuzz

Odpowiedz

3

Oto mój kod, który pokazuje, jak CPU i GPU realizacja może odbywać się równolegle:

import tensorflow as tf 
import numpy as np 
from time import time 
from threading import Thread 

n = 1024 * 8 

data_cpu = np.random.uniform(size=[n//16, n]).astype(np.float32) 
data_gpu = np.random.uniform(size=[n , n]).astype(np.float32) 

with tf.device('/cpu:0'): 
    x = tf.placeholder(name='x', dtype=tf.float32) 

def get_var(name): 
    return tf.get_variable(name, shape=[n, n]) 

def op(name): 
    w = get_var(name) 
    y = x 
    for _ in range(8): 
     y = tf.matmul(y, w) 
    return y 

with tf.device('/cpu:0'): 
    cpu = op('w_cpu') 

with tf.device('/gpu:0'): 
    gpu = op('w_gpu') 

def f(session, y, data): 
    return session.run(y, feed_dict={x : data}) 


with tf.Session(config=tf.ConfigProto(log_device_placement=True, intra_op_parallelism_threads=8)) as sess: 
    sess.run(tf.global_variables_initializer()) 

    coord = tf.train.Coordinator() 

    threads = [] 

    # comment out 0 or 1 of the following 2 lines: 
    threads += [Thread(target=f, args=(sess, cpu, data_cpu))] 
    threads += [Thread(target=f, args=(sess, gpu, data_gpu))] 

    t0 = time() 

    for t in threads: 
     t.start() 

    coord.join(threads) 

    t1 = time() 


print t1 - t0 

Wyniki czasowe są: gwint

  • CPU: 4-5s (będzie się zmieniać przez maszynę , oczywiście).

  • Gwint GPU: 5 s (robi 16 razy więcej pracy).

  • Zarówno w tym samym czasie: 5s

Należy pamiętać, że nie trzeba było mieć 2 sesje (ale pracował dla mnie zbyt).

Powody ty można zobaczyć różne wyniki mogą być

  • niektóre rywalizacji o zasoby systemowe (wykonanie GPU robi spożywać pewne zasoby systemu hosta, a jeśli uruchomiony wątek procesora wypiera go, które mogłyby pogorszyć osiągi)

  • nieprawidłowy rozrządu

  • częścią modelu można uruchomić tylko na GPU/CPU

  • gardłem gdzie indziej

  • inny problem

Powiązane problemy