【问题标题】:Calculate big covariance matrix using python使用python计算大协方差矩阵
【发布时间】:2014-05-28 07:28:42
【问题描述】:

我正在使用 numpy.memmap 来计算大型协方差矩阵。

问题是为什么第二种情况下的乘法(当我将 A.T 存储在磁盘上时)较慢?

def matrix_append_row(fm,tp,mat):
    #check if number of columns is the same
    rows= fm.shape[0] + mat.shape[0]
    new_fm = np.memmap(fm.filename, mode='r+', dtype= tp, shape=(rows,fm.shape[1]))
    new_fm[fm.shape[0]:rows,:]= mat[:]
    return new_fm
def generate_and_store_data(cols,batch,iter,tp):
    #create memmap file and append generated data in cycle

    #can't create empty array - need to store first entry by copy not by append
    fm= np.memmap('A.npy', dtype=tp, mode='w+', shape=(batch,cols))

    for i in xrange(iter):
        data= np.random.rand(batch,cols)*100  # [0-1]*100
        # print i
        # t0= time.time()
        if i==0:
            fm[:]= data[:]
        else:   
            fm= matrix_append_row(fm,tp,data)
        # print (time.time()-t0)

        # fm.flush()
        # print fm.shape

    return fm


A= generate_and_store_data(1000,5000,10,'float32')
#cov= A.T*A

# A memmaped file
print A.shape
M= A.shape[0]
N= A.shape[1]
#create cov mat
cov= np.memmap('cov.npy', dtype='float32', mode='w+', shape=(N,N))

#A.T don't copy data just view?
t0= time.time()
np.dot(A.T,A,out= cov)
print (time.time()-t0)

print A.T.shape

cov_= np.memmap('cov_.npy', dtype='float32', mode='w+', shape=(N,N))
At= np.memmap('At.npy', dtype='float32', mode='w+', shape=(N,M))

t0= time.time()
At= A.T # only reference
print (time.time()-t0)

t0= time.time()
At[:]= A.T # copy same as At[:]= (A.T)[:] ?
print (time.time()-t0)

t0= time.time()
At[:]= (A.T)[:]
print (time.time()-t0)

t0= time.time()
np.dot(At,A,out= cov_)
print (time.time()-t0)

输出是

(50000, 1000)
2.84399986267
(1000, 50000)
0.0
2.17100000381
2.07899999619
2.73399996758

更新:

也试过分块矩阵乘法,但是很慢(可能需要调整block_size)

cov2= np.memmap('cov2.npy', dtype='float32', mode='w+', shape=(N,N))
block_size=100
t0= time.time()
for i_start in range(0, At.shape[0], block_size):
    for j_start in range(0, A.shape[1], block_size):
        for k_start in range(0, At.shape[1], block_size):
            cov2[i_start:i_start+block_size, j_start:j_start + block_size] +=np.dot(At[i_start:i_start + block_size, k_start:k_start + block_size],A[k_start:k_start + block_size, j_start:j_start + block_size])
print (time.time()-t0)

【问题讨论】:

  • 可能是因为磁盘访问。当我尝试运行您的示例时,我有“名称 A 未定义”。你能告诉我们更多关于数据的信息吗?
  • @Louis A 作为内存映射文件 50000 x 1000 float32 存储在磁盘上。参见 generate_and_store_data 函数。
  • 我觉得你的问题不是很清楚。您想知道复制或点积的时间差异吗?也许您可以指出您确切想知道的时间。此外,您确实需要重复几次计时才能确定。
  • @Midnighter 由于stackoverflow.com/questions/17954990/… 之类的原因,我比较了点积时间,但似乎使用 A.T 并使用了一些操作系统缓存。
  • 我理解你为什么这样做,但从你发布的时间来看,第一个是最慢的......所以不太清楚你的要求是什么。

标签: python memory numpy


【解决方案1】:

因此,即使内存布局更改是时间的一部分,这也是我获得较小数组的结果:

arr = numpy.random.rand(500, 100)
arr *= 100

%timeit numpy.dot(arr.T, arr)
100 loops, best of 3: 7.52 ms per loop

%timeit numpy.dot(numpy.asfortranarray(arr.T), arr)
100 loops, best of 3: 7.53 ms per loop

%timeit numpy.dot(arr.T, numpy.asfortranarray(arr))
100 loops, best of 3: 5.26 ms per loop

我不确定为什么您发布的尺寸的运行时间差异如此惊人,但结果如下:

arr = numpy.random.rand(50000, 1000)
arr *= 100
cov = numpy.zeros((1000, 1000))

%timeit numpy.dot(arr.T, arr, out=cov)
1 loops, best of 3: 12min 45s per loop

%timeit numpy.dot(numpy.asfortranarray(arr.T), arr, out=cov)
1 loops, best of 3: 12min 42s per loop

%timeit numpy.dot(arr.T, numpy.asfortranarray(arr), out=cov)
1 loops, best of 3: 7min 19s per loop

当然,这也很大程度上取决于您编译 numpy 时使用的 BLAS 实现,但更改内存布局似乎非常值得。

【讨论】:

  • @mrgloom 用您在示例中使用的形状更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 2018-08-25
  • 2011-11-25
  • 2015-03-31
  • 1970-01-01
  • 2020-04-13
  • 2011-05-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多