非常大的Numpy数组点积

4

我有一个非常慢的代码运行问题。我尝试计算一个非常大的二进制矩阵(170544 X 22)与其转置的点积。 起初,我试过了这段代码:

import numpy as np
start = time.time()
import warnings
warnings.filterwarnings("ignore", message='genfromtxt',     category=UserWarning)
np.set_printoptions(threshold=np.nan)

fin = open('E:/myscripts/Abin.txt', 'rb')    # input file (170544X22     binary matrix)
fin1 = open('E:/myscripts/AbinT.txt', 'rb')    # input file (22X170544        binary matrix the transpose of Abin)
fout = open('E:/myscripts/RPartial.txt', 'w+b')  # output file

FW = np.genfromtxt(fin,delimiter=',',   dtype=int)
WF = np.genfromtxt(fin1,delimiter=',',   dtype=int)

r = np.dot(FW,WF) #r calculation
np.savetxt(fout, r,  fmt='%i' ,delimiter=',', newline='\r\n')

fin.close()
fin1.close()
fout.close() 

但是出现了内存错误。然后我使用行方法更改了r的计算方式:

for row in FW:
    a=FW[row,:]
    r = np.dot(a,WF)
    np.savetxt(fout, r,  fmt='%i' ,delimiter=',', newline='\r\n')

目前代码可以运行,但速度非常慢,在90分钟后只计算了8000行。硬件配置为I7处理器、12GB内存,运行64位Windows操作系统。如何加速代码?

数据格式如下:

([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0],
 [1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0],
 [1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,0,0],
 [1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0],
 [1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,0,0])

并且结果应该是这样的。
([15,14,14,14,14],
 [14,15,14,14,14],
 [14,14,15,14,14],
 [14,14,14,15,14],
 [14,14,14,14,15]) .

使用您的行方法计算结果需要460秒(int)或129秒(float32)。您真正的问题是数据IO。为什么要使用文本文件保存和加载数据?在处理较大的数据时,这应该绝对避免...(非常慢,非常大的文件) - max9111
1
你的输出大小将约为232 GB(密集矩阵,未压缩int64)。请同时添加您想要对数据进行的操作... - max9111
我尝试将数据保存为npy文件。再次返回内存错误。在这个计算之后,我将按行汇总结果。 - N.Borges
2个回答

0
这听起来像是一个稀疏矩阵问题,scipy提供了相应的。这些矩阵有许多0元素(就像您的例子一样)。操作将考虑到稀疏性,并且矩阵在内存中占用的空间会更小。记得进行矩阵运算时使用FW.dot(WF)(而不是np.dot)。

样本中零的比例不高。 - hpaulj
是的,确实如此...有些列全部为零,在任何情况下大块也都为零。Scipy包可以处理这些情况。 - FHTMitchell
稀疏矩阵在稀疏度小于10%时非常有用。 - hpaulj
当然,但是将该示例(我假设为矩阵的左上角)向右和向下扩展...会得到什么?无论如何,没有完整的数据,我们就不知道。 - FHTMitchell
数据行中有40%到50%的零。 - N.Borges

0

正如我在评论中所写的,输出数组的大小将为232GB(int64)。如果您想使用h5py将结果存储到磁盘上,这将是一个合适的解决方案。

对第一个轴进行求和可以简化问题。如果您只想要纯点积,我可以更新我的答案。但这会稍微复杂一些,速度也会慢一些。

res=np.zeros(WF.shape[1])
for i in range(WF.shape[1]):
  a=np.copy(WF[:,i])
  r=np.dot(FW,a)
  res[i] = np.sum(r)

点积数组的每个元素都小于15。是的,我确实需要点积。尽管输出数组的大小比您的预测要小,但其大小表明解决问题的另一种方法,可能是使用分区矩阵。 - N.Borges

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