【发布时间】:2014-07-23 20:24:24
【问题描述】:
numpy 数组的顺序如何影响乘法速度?以及如何根据矩阵的大小自动选择它?
问题最初来自使用 cudamat 的代码:
def test_mat():
#need to init cublas?
# cm.cublas_init()
n = 1024
for i in xrange(1,20): # 2^15 max or python fails
m= 2
m=m**i
# print m
print i
try:
t0= time.time()
# cpum1 = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='C')
# cpum2 = np.array(np.random.rand(m, 1)*10, dtype=np.float32, order='C')
#CUDA need fortran order of array for speed?
cpum1 = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='F')
cpum2 = np.array(np.random.rand(m, 1)*10, dtype=np.float32, order='F')
c = np.dot(cpum2.T, cpum1.T)
print (time.time()-t0)
t0= time.time()
gpum1 = cm.CUDAMatrix(cpum1)
gpum2 = cm.CUDAMatrix(cpum2)
gm = cm.dot(gpum2.T, gpum1.T)
gm.copy_to_host()
print (time.time()-t0)
except:
pass
# cm.cublas_shutdown()
print 'done'
这是我做过的一些测试,但我需要一些理论观点。
def test_order(m,n):
#default
a = np.array(np.random.rand(m, n)*10, dtype=np.float32)
b = np.array(np.random.rand(n, m)*10, dtype=np.float32)
t0= time.time()
c = np.dot(a,b)
print (time.time()-t0)
#1
a = np.array(np.random.rand(m, n)*10, dtype=np.float32, order='C')
b = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='C')
t0= time.time()
c = np.dot(a,b)
print (time.time()-t0)
#2
a = np.array(np.random.rand(m, n)*10, dtype=np.float32, order='C')
b = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='F')
t0= time.time()
c = np.dot(a,b)
print (time.time()-t0)
#3
a = np.array(np.random.rand(m, n)*10, dtype=np.float32, order='F')
b = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='C')
t0= time.time()
c = np.dot(a,b)
print (time.time()-t0)
#4
a = np.array(np.random.rand(m, n)*10, dtype=np.float32, order='F')
b = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='F')
t0= time.time()
c = np.dot(a,b)
print (time.time()-t0)
print 'done'
m= 1024*10
n= 1024*1
7.125
7.14100003242
6.95299983025
8.14100003242
7.15600013733
m= 1024*1
n= 1024*10
0.718999862671
0.734000205994
0.641000032425
0.656000137329
0.655999898911
这是测试内存使用峰值的代码:
import numpy as np
import time
from memory_profiler import profile
@profile
def test_order_():
m= 1024*1
n= 1024*10
#what used by default when c= np.dot(a,b)
c = np.array(np.zeros((m, m)), dtype=np.float32, order='C')
#c = np.array(np.zeros((m, m)), dtype=np.float32, order='F')
#1
a = np.array(np.random.rand(m, n)*10, dtype=np.float32, order='C')
b = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='C')
t0= time.time()
c[:]= np.dot(a,b)
# np.dot(a,b,out= c) # only for C-Array !
print (time.time()-t0)
del a
del b
# del c
#2
a = np.array(np.random.rand(m, n)*10, dtype=np.float32, order='C')
b = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='F')
t0= time.time()
c[:]= np.dot(a,b)
# np.dot(a,b,out= c) # only for C-Array !
print (time.time()-t0)
del a
del b
# del c
#3
a = np.array(np.random.rand(m, n)*10, dtype=np.float32, order='F')
b = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='C')
t0= time.time()
c[:]= np.dot(a,b)
# np.dot(a,b,out= c) # only for C-Array !
print (time.time()-t0)
del a
del b
# del c
#4
a = np.array(np.random.rand(m, n)*10, dtype=np.float32, order='F')
b = np.array(np.random.rand(n, m)*10, dtype=np.float32, order='F')
t0= time.time()
c[:]= np.dot(a,b)
# np.dot(a,b,out= c) # only for C-Array !
print (time.time()-t0)
del a
del b
# del c
print 'done'
if __name__ == '__main__':
test_order_()
还发现了一些关于 numpy.dot 复制和fast_dot的信息
dot 的内部运作有点模糊,因为它试图使用 BLAS 优化例程,有时需要数组副本 使用 Fortran 顺序
还有一些performance tips 这很奇怪,但我每次运行示例时都无法重现结果。(也许在重新运行一些数据之前?)
【问题讨论】:
-
如果您在代码中自动且任意地在 C 样式和 FORTRAN 样式之间更改数组的顺序,那么您将严重混淆人们。
-
如果只是二维的,那么你可以根据矩阵的形状用.T方法变换矩阵,然后再变换回来吗?我可以想象在某些情况下它可能值得做。
-
@Ffisegydd 该顺序仅影响内存布局。 API 保持不变。
-
@otterb 矩阵的转置只会创建一个视图,因此内存布局是相同的。
-
内存分析器只在每行之后报告内存。中间 numpy 的胆量中的任何内容都不会被看到。此外,最好使用 out 参数:
np.dot(a, b, out=c)。
标签: python arrays numpy cuda matrix-multiplication