Python Theano中reduce操作的加速

Python Theano中reduce操作的加速,python,numpy,parallel-processing,gpgpu,theano,Python,Numpy,Parallel Processing,Gpgpu,Theano,编辑: 很抱歉,在我进行测试时,我的GPU上运行了其他进程,我在空闲的GPU上更新了计时结果,对于较大的矩阵,加速变得很明显 原职: 如中所示,L是一个矩阵列表,其中每个项目M是一个x*n矩阵(x是一个变量,n是固定的) 我想计算L中所有项的M'*M之和(M'是M的转置),如下Python代码所示 for M in L: res += np.dot(M.T, M) 以下是Numpy和Theano实现的一些示例(有关可执行脚本,请参阅@DanielRenshaw对问题的回答) 我在CPU上运

编辑
很抱歉,在我进行测试时,我的GPU上运行了其他进程,我在空闲的GPU上更新了计时结果,对于较大的矩阵,加速变得很明显

原职:

如中所示,
L
是一个矩阵列表,其中每个项目
M
是一个
x*n
矩阵(
x
是一个变量,
n
是固定的)

我想计算
L
中所有项的
M'*M
之和(
M'
M
的转置),如下Python代码所示

for M in L:
  res += np.dot(M.T, M)
以下是Numpy和Theano实现的一些示例(有关可执行脚本,请参阅@DanielRenshaw对问题的回答)

我在CPU上运行了Numpy版本,在GPU上运行了Theano版本,设置不同,似乎Theano版本总是比Numpy版本慢(不管Maties的数量和大小)

但我希望有一些优化w.r.t GPU,因为它是一个简单的简化操作

有人能帮我了解引擎盖下发生了什么吗

编辑:
以下是用于生成数据的脚本(来自@DanielRenshaw)、设置和结果

L = [np.random.standard_normal(size=(x, n)).astype(dtype)
     for x in range(min_x, number_of_matrices + min_x)]

dtype = 'float32'
theano.config.floatX = dtype
iteration_count = 10
min_x = 20

# base case:
# numpy_version1 0.100589990616
# theano_version1 0.243968963623
# theano_version2 0.198153018951
number_of_matrices = 200
n = 100

# increase matrix size:
# numpy_version1 4.90120816231
# theano_version1 0.984472036362
# theano_version2 3.56008815765
number_of_matrices = 200
n = 1000

# increase number of matrices:
# numpy_version1 5.11445093155
# theano_version1 compilation error
# theano_version2 6.54448604584
number_of_matrices = 2000
n = 100

你遇到的问题不是矩阵的数量,而是矩阵的大小

您的测试示例创建的矩阵的大小取决于您拥有的矩阵的数量,因此,矩阵越多,矩阵越大,但python循环开销也越大(在reduce操作中),因此,它使检测速度提高变得更加困难

为了进行一些新的测试,我特意修改了矩阵生成:

S = 1000 # Size of the matrices
N = 10 # Number of matrices

L = [np.random.standard_normal(size=(np.random.randint(S//2, S*2), S)).astype(np.float32) for _ in range(N)]
这只生成10个大小为
(x,1000)
的矩阵,其中
x
[S//2,S*2]==[5002000]
范围内的某个值

f1 = compile_theano_version1(N, S, np.float32)
f2 = compile_theano_version2(N, S)

  • 现在使用
    N=10
    大矩阵进行一些测试:
对于
S=1000
N=10

 %timeit numpy_version1(*L)   # 10 loops, best of 3: 131 ms per loop
 %timeit f1(*L)               # 10 loops, best of 3: 37.3 ms per loop
 %timeit f2(L)                # 10 loops, best of 3: 68.7 ms per loop
 %timeit numpy_version1(*L)   # 1 loops, best of 3: 4 s per loop
 %timeit f1(*L)               # 1 loops, best of 3: 907 ms per loop
 %timeit f2(L)                # 1 loops, best of 3: 1.77 s per loop
其中,ANO函数在笔记本电脑中具有
x4
x2
加速比,该笔记本电脑配备了相当不错的
i7
和像样的NVIDIA 860M(这意味着您应该在这里获得更好的加速比)

对于
S=5000
N=10

 %timeit numpy_version1(*L)   # 10 loops, best of 3: 131 ms per loop
 %timeit f1(*L)               # 10 loops, best of 3: 37.3 ms per loop
 %timeit f2(L)                # 10 loops, best of 3: 68.7 ms per loop
 %timeit numpy_version1(*L)   # 1 loops, best of 3: 4 s per loop
 %timeit f1(*L)               # 1 loops, best of 3: 907 ms per loop
 %timeit f2(L)                # 1 loops, best of 3: 1.77 s per loop
因此,总的来说,通过这种设置,
S
越大,CPU的加速比越大


  • 一些使用
    N=100
    大矩阵的测试:theano似乎更快
对于
S=1000
N=100

%timeit numpy_version1(*L)   # 1 loops, best of 3: 1.46 s per loop
%timeit f1(*L)               # 1 loops, best of 3: 408 ms per loop
%timeit f2(L)                # 1 loops, best of 3: 724 s per loop
%timeit numpy_version1(*L)   # 1 loops, best of 3: 11.3 s per loop
%timeit f1(*L)               # 1 loops, best of 3: 2.72 s per loop
%timeit f2(L)                # 1 loops, best of 3: 4.01 s per loop
%timeit numpy_version1(*L)   # 100 loops, best of 3: 1.17 ms per loop
%timeit f1(*L)               # 100 loops, best of 3: 4.21 ms per loop
%timeit f2(L)                # 100 loops, best of 3: 7.42 ms per loop
对于
S=2000
N=100

%timeit numpy_version1(*L)   # 1 loops, best of 3: 1.46 s per loop
%timeit f1(*L)               # 1 loops, best of 3: 408 ms per loop
%timeit f2(L)                # 1 loops, best of 3: 724 s per loop
%timeit numpy_version1(*L)   # 1 loops, best of 3: 11.3 s per loop
%timeit f1(*L)               # 1 loops, best of 3: 2.72 s per loop
%timeit f2(L)                # 1 loops, best of 3: 4.01 s per loop
%timeit numpy_version1(*L)   # 100 loops, best of 3: 1.17 ms per loop
%timeit f1(*L)               # 100 loops, best of 3: 4.21 ms per loop
%timeit f2(L)                # 100 loops, best of 3: 7.42 ms per loop

  • 使用
    N=100
    小矩阵进行测试:numpy似乎更快
对于
S=50
N=100

%timeit numpy_version1(*L)   # 1 loops, best of 3: 1.46 s per loop
%timeit f1(*L)               # 1 loops, best of 3: 408 ms per loop
%timeit f2(L)                # 1 loops, best of 3: 724 s per loop
%timeit numpy_version1(*L)   # 1 loops, best of 3: 11.3 s per loop
%timeit f1(*L)               # 1 loops, best of 3: 2.72 s per loop
%timeit f2(L)                # 1 loops, best of 3: 4.01 s per loop
%timeit numpy_version1(*L)   # 100 loops, best of 3: 1.17 ms per loop
%timeit f1(*L)               # 100 loops, best of 3: 4.21 ms per loop
%timeit f2(L)                # 100 loops, best of 3: 7.42 ms per loop

试验规范:

  • 处理器:i7 4710HQ
  • GPU:NVIDIA GeForce GTX 860M
  • Numpy:使用“英特尔MKT”构建的1.10.2版
  • Theano:版本0.70;floatX=float32;使用GPU

您有哪个GPU?这可能是答案的关键。如果你有最新的i7和最糟糕的GPU,不管阵列有多大,CPU版本可能会更快,特别是如果你有用MKL、OpenBLAS等构建的numpy。。它使用所有的内核进行点操作。@imaluengo我使用i7,nvidia titan x,numpy是用OpenBLASOps构建的,那么情况就不应该是这样了:P你能添加你在测试中尝试过的
L
M
的值,以及你得到的结果(至少是其中的一部分)吗?@imaluengo谢谢,我很快会添加它们。这只是为了让我可以复制准确的结果。更容易测试出哪里出了问题。另一个起作用的因素是在主内存和GPU内存之间复制数据的开销。CPU版本完全避免了这种开销,但我现在还不清楚超参数的变化会如何影响GPU的速度。它确实需要在真实的使用环境中进行测试,而不是在像这样的人为情况下进行测试。@DanielRenshaw yep,很难说在真实的环境中真正的加速是什么。我现在所能做的就是添加更多的合成测试:P只是添加了更多具有更大
N
(矩阵数)的测试,并且速度不断提高。使用更小的
S
(矩阵的大小),numpy似乎更快(正如我所期望的),因为将矩阵复制到GPU的开销大于在GPU中乘以它所获得的加速比。