2017-05-30 234 views
7

同时预测我与tensorflow工作,我想通过同时使用加快预测阶段预先训练Keras模型(我不感兴趣,在训练阶段)的CPU和一个GPU。Tensorflow:在GPU和CPU

我试着创建两个不同的线程,它们提供两个不同的tensorflow会话(一个运行在CPU上,另一个运行在GPU上)。每个线程提供固定数量的批处理(例如,如果我们总共有100个批处理,我想为循环中的CPU分配20个批处理,或者在GPU上分配80个批处理,或者将这两个批处理任意组合),并将结果合并。如果分割是自动完成的话会更好。

然而,即使在这种情况下,批处理似乎是以同步方式进行馈送,因为即使向CPU发送少量批次并计算GPU中的所有其他批量(以GPU为瓶颈),我观察到总体预测时间总是高于仅使用GPU进行的测试。

我认为它会更快,因为当只有GPU工作时,CPU使用率约为20-30%,因此有一些CPU可用来加速计算。

我读了很多讨论,但他们都处理与多GPU的并行性,而不是在GPU和CPU之间。

这里是我所编写的代码的一个示例:

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() 

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) 

然后,预测如下完成:tensor_cputensor_gpu对象从以这种方式相同Keras模型加载

我该如何实现这种CPU/GPU并行?我想我错过了一些东西。

任何形式的帮助将非常感激!

+0

我有没有回答你的问题? – MaxB

+0

是的,是的,是的!对于迟到的回答,我很抱歉,我忙于另一个项目,而且我没有时间去尝试。 我检查了你的代码..它可能是它没有工作的唯一原因是intra_op_parallelism_thread选项? – battuzz

+0

关于如何让tensorflow找到合适的批量以供给CPU和GPU以便我可以最小化总预测时间? – battuzz

回答

3

这里是我的代码,演示了如何CPU和GPU的执行可以并行完成:

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 

时机结果是:

  • CPU线程:4-5s(将机器有所不同, 当然)。

  • GPU线程:5s(它的工作量是16x)。

  • 都在同一时间:5秒

注意,有没有必要有2次会议(但也为我工作)。

的原因,你可能会看到不同的结果可能是

  • 一些争夺系统资源(GPU执行确实会消耗一些主机系统资源,如果运行CPU线程排挤它,这可能会恶化性能)

  • 不正确时机

  • 模型只能在GPU/CPU运行的一部分

  • 瓶颈其他地方

  • 其他一些问题