如何强制Theano在GPU上并行执行操作(测试案例:numpy.bincount)

3

我希望能够利用GPU加速计算bincount。

Numpy中的参考代码:

x_new = numpy.random.randint(0, 1000, 1000000)
%timeit numpy.bincount(x_new)
100 loops, best of 3: 2.33 ms per loop

我想测量操作速度,而不是花费在传递数组上的时间,因此我创建了一个共享变量:

x = theano.shared(numpy.random.randint(0, 1000, 1000000))
theano_bincount = theano.function([], T.extra_ops.bincount(x))

这个操作当然可以高度并行化,但在GPU上实际运行时,这段代码比CPU版本慢了数倍:

%timeit theano_bincount()
10 loops, best of 3: 25.7 ms per loop

我的问题是:

  1. 为什么性能如此低?
  2. 我能否使用Theano编写并行版本的bincount?

2
仅在孤立的情况下计时并不特别有趣,因为您的GPU计时将受到从主内存复制输入数据到GPU内存以及再次将输出复制回来的成本的影响。实际上,事实可能会更糟,因为Theano GPU操作目前仅支持“float32”数据类型。 - Daniel Renshaw
@DanielRenshaw 当然,你是对的,bincount操作需要在循环内对数据进行多次评估,这些数据已经在GPU上,并且每次都会在GPU上重新计算权重。Bincount是瓶颈,所以我只是要求优化它。 - Alleo
@DanielRenshaw,根据您的说法,我得出结论:除了float32,我们不能在GPU内存中存储其他任何数据类型。我是对的吗? - Amir
1
目前是正确的。正在开发中的后端最终将支持更多的数据类型。 - Daniel Renshaw
2个回答

4
我认为,除非您能够以某种方式手动告诉Theano以并行化的方式执行此操作,否则无法进一步在GPU上增加此操作。在GPU上,那些不能并行执行的计算会与CPU相比以相同或较慢的速度执行。
引用来自Daniel Renshaw的话:
“Theano希望您更多地关注您想要计算的内容而不是您想要如何计算。Idea是Theano优化编译器将自动并行化尽可能多的内容(使用OpenMP在GPU或CPU上)。”
还有另外一句引用:
“您需要能够按照Theano操作来指定您的计算。如果这些操作可以在GPU上并行处理,它们应该被自动并行化。”
来自Theano网页的引用:
“对于索引、维度重组和常量时间重塑,GPU和CPU的速度将是相同的。” “对于张量的行/列求和,在GPU上可能比在CPU上慢一点。”
我认为您唯一能做的就是在您的.theanorc文件中将openmp标志设置为True。
无论如何,我试过一个想法。现在它不起作用,但希望有人能帮助我们使它工作。如果可以,您可能能够在GPU上并行化操作。下面的代码尝试在GPU上使用CUDA API完成所有操作。但是,有两个瓶颈不允许操作发生:1)目前(截至2016年1月4日)Theano和CUDA不支持任何数据类型而不是float32,2)T.extra_ops.bincount()仅适用于int数据类型。因此,这可能是Theano无法完全并行化操作的瓶颈。
import theano.tensor as T
from theano import shared, Out, function
import numpy as np
import theano.sandbox.cuda.basic_ops as sbasic

shared_var = shared(np.random.randint(0, 1000, 1000000).astype(T.config.floatX), borrow = True)
x = T.vector('x');
computeFunc = T.extra_ops.bincount(sbasic.as_cuda_ndarray_variable(T.cast(x, 'int16')))
func = function([], Out(sbasic.gpu_from_host(computeFunc), borrow = True), givens = {x: shared_var})

参考资料

1- 如何在Theano中并行设置多个元素

2- GPU可以加速哪些内容

3- 多核处理器在Theano中的应用


嗨,Amir。我测试了OpenMP - bincount在使用线程时没有任何加速(而其他操作则有)。我想知道bincount是否可以只是numpy的bincount操作的包装器... - Alleo
@Alleo,我认为你的问题的答案是,在没有办法绕过瓶颈或者单独并行化函数的可能性之前,无法并行化某些函数。 - Amir

0
尝试使用Cupy库并使用cupy.bincount()代替。这可能会给您更好的加速结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接