Numpy CUDA中同一类型Float32的不同计算时间

Numpy CUDA中同一类型Float32的不同计算时间,numpy,parallel-processing,numba,autojit,Numpy,Parallel Processing,Numba,Autojit,我使用以下脚本计算一个简单的矩阵乘法: import numpy as np import math from timeit import default_timer as timer from numba import cuda from numba import * from numba import autojit @autojit def mult2(a,b): return a*b @autojit def mult_cpu(a,b,c): Ni=c.shape[0]

我使用以下脚本计算一个简单的矩阵乘法:

import numpy as np
import math
from timeit import default_timer as timer
from numba import cuda
from numba import *
from numba import autojit

@autojit
def mult2(a,b):
    return a*b
@autojit
def mult_cpu(a,b,c):
    Ni=c.shape[0]
    Nj=c.shape[1]
    Nk=c.shape[2]
    for i in range(Ni):
        for j in range(Nj):
            for k in range(Nk):
                c[i,j,k]=mult2(a[i,k],b[j,k])

dimx=20
dimy=3072
dimz=50000

print "\ntest1"
A=np.ones((dimx,dimz),dtype=np.float32)
B=np.ones((dimy,dimz),dtype=np.float32)
C=np.ones((dimx,dimy,dimz),dtype=np.float32)
print A.shape,A.dtype
print B.shape,B.dtype
print C.shape,C.dtype
start=timer()
mult_cpu(A,B,C)
dt=timer()-start    
print "Computation autojit done in %f s"%(dt)
print 'C[:3,1,1] = ',C[:3,1,1]
print 'C[-3:,1,1] = ',C[-3:,1,1]
del A
del B
del C
del start
del dt


print "\ntest2"
A=np.zeros((dimx,dimz),dtype=np.float32)
B=np.zeros((dimy,dimz),dtype=np.float32)
C=np.zeros((dimx,dimy,dimz),dtype=np.float32)
print A.shape,A.dtype
print B.shape,B.dtype
print C.shape,C.dtype
start=timer()
mult_cpu(A,B,C)
dt=timer()-start    
print "Computation autojit done in %f s"%(dt)
print 'C[:3,1,1] = ',C[:3,1,1]
print 'C[-3:,1,1] = ',C[-3:,1,1]
del A
del B
del C
del start
del dt


print "\ntest3"
A=0.0001*np.random.randn(dimx,dimz).astype(np.float32)
B=0.0001*np.random.randn(dimy,dimz).astype(np.float32)
C=0.0001*np.random.randn(dimx,dimy,dimz).astype(np.float32)
print A.shape,A.dtype
print B.shape,B.dtype
print C.shape,C.dtype
start=timer()
mult_cpu(A,B,C)
dt=timer()-start    
print "Computation autojit done in %f s"%(dt)
print 'C[:3,1,1] = ',C[:3,1,1]
print 'C[-3:,1,1] = ',C[-3:,1,1]
除了初始化
A
B
C
,每个测试都是相同的。输出为:

test1
(20, 50000) float32
(3072, 50000) float32
(20, 3072, 50000) float32
Computation autojit done in 4.485923 s
C[:3,1,1] =  [ 1.  1.  1.]
C[-3:,1,1] =  [ 1.  1.  1.]

test2
(20, 50000) float32
(3072, 50000) float32
(20, 3072, 50000) float32
Computation autojit done in 7.031277 s
C[:3,1,1] =  [ 0.  0.  0.]
C[-3:,1,1] =  [ 0.  0.  0.]

test3
(20, 50000) float32
(3072, 50000) float32
(20, 3072, 50000) float32
Computation autojit done in 45.372899 s
C[:3,1,1] =  [ -3.09475023e-09   4.71271910e-09   2.36787634e-09]
C[-3:,1,1] =  [ -7.29189642e-09  -3.03451442e-09   1.95249439e-09]
因此,
np.one
的矩阵乘法比
np.zero
初始化更快。对于随机初始化,速度要慢得多。人们如何解释这种行为


如果不进行
@autojit
优化,计算时间几乎相等。

autojit编译器会意识到您正在乘以所有0,并完全删除矩阵乘法,只返回所有0的矩阵,在1中,它跳过实际的乘法部分,只执行矩阵乘法的求和部分,这比只返回所有0稍微慢一点,最后一个实际上迫使编译器执行矩阵乘法,因为它不能假定答案


在这种情况下,编译器比您预期的更智能。

实际上0比1慢。。返回所有0的矩阵比返回求和要慢。根据你的论证,这是一个矛盾。啊,考虑到你在做1s*1s,它增加了更多的优化空间。很明显,矩阵乘法在这两种语言中都可以被完全删除,现在还不完全清楚编译器仅仅通过查看代码就决定做什么,你必须查看它吐出的是什么样的代码才能真正了解到底。跑步过程中也可能会引入噪音,尤其是在跑步过程中,如果数字变化足够大。不管怎样,最终运行与前两次运行之间的巨大差异是由于矩阵乘法被计算出来的