[英]cosine similarity on large sparse matrix with numpy
下面的代码导致我的系统在完成之前耗尽内存。
你能否建议一种更有效的方法来计算大矩阵的余弦相似度,如下面的那个?
我希望在原始矩阵( mat
)中相对于所有其他行的65000行中的每一行计算余弦相似度,以便结果是65000 x 65000矩阵,其中每个元素是两行之间的余弦相似度。原始矩阵。
import numpy as np
from scipy import sparse
from sklearn.metrics.pairwise import cosine_similarity
mat = np.random.rand(65000, 10)
sparse_mat = sparse.csr_matrix(mat)
similarities = cosine_similarity(sparse_mat)
在运行最后一行之后,我总是耗尽内存,程序会因MemoryError冻结或崩溃。 无论我在8 gb本地RAM上运行还是在64 gb EC2实例上运行,都会发生这种情况。
同样的问题在这里 我有一个很大的非稀疏矩阵。 它在内存中很合适,但是cosine_similarity
因为任何未知原因而崩溃,可能是因为它们在某处复制了一次太多的矩阵。 所以我把它比作“左边”的小批量行而不是整个矩阵:
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
def cosine_similarity_n_space(m1, m2, batch_size=100):
assert m1.shape[1] == m2.shape[1]
ret = np.ndarray((m1.shape[0], m2.shape[0]))
for row_i in range(0, int(m1.shape[0] / batch_size) + 1):
start = row_i * batch_size
end = min([(row_i + 1) * batch_size, m1.shape[0]])
if end <= start:
break # cause I'm too lazy to elegantly handle edge cases
rows = m1[start: end]
sim = cosine_similarity(rows, m2) # rows is O(1) size
ret[start: end] = sim
return ret
对我没有崩溃; 因人而异。 尝试不同的批量大小,使其更快。 我以前只比较一行,我的机器上花了大约30倍。
愚蠢但有效的理智检查:
import random
while True:
m = np.random.rand(random.randint(1, 100), random.randint(1, 100))
n = np.random.rand(random.randint(1, 100), m.shape[1])
assert np.allclose(cosine_similarity(m, n), cosine_similarity_n_space(m, n))
由于您正在尝试存储65000x65000矩阵,因此内存不足。 请注意,您构建的矩阵根本不稀疏。 np.random.rand
生成一个介于0和1之间的随机数。因此, csr_matrix
没有足够的零来实际压缩数据。 事实上, 几乎肯定没有零。
如果仔细查看MemoryError
回溯,可以看到cosine_similarity
尝试使用稀疏点积(如果可能):
MemoryError Traceback (most recent call last)
887 Y_normalized = normalize(Y, copy=True)
888
--> 889 K = safe_sparse_dot(X_normalized, Y_normalized.T, dense_output=dense_output)
890
891 return K
所以问题不cosine_similarity
,而cosine_similarity
你的矩阵。 尝试初始化一个实际的稀疏矩阵(例如,稀疏度为1%),如下所示:
>>> a = np.zeros((65000, 10))
>>> i = np.random.rand(a.size)
>>> a.flat[i < 0.01] = 1 # Select 1% of indices and set to 1
>>> a = sparse.csr_matrix(a)
然后,在具有32GB RAM的机器上(8GB RAM对我来说还不够),以下运行时没有内存错误:
>>> b = cosine_similarity(a)
>>> b
array([[ 0., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.],
...,
[ 0., 0., 0., ..., 1., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 0., 0., 0.]])
我会像这样运行它
from sklearn.metrics.pairwise import cosine_similarity
# Change chunk_size to control resource consumption and speed
# Higher chunk_size means more memory/RAM needed but also faster
chunk_size = 500
matrix_len = your_matrix.shape[0] # Not sparse numpy.ndarray
def similarity_cosine_by_chunk(start, end):
if end > matrix_len:
end = matrix_len
return cosine_similarity(X=your_matrix[start:end], Y=your_matrix) # scikit-learn function
for chunk_start in xrange(0, matrix_len, chunk_size):
cosine_similarity_chunk = similarity_cosine_by_chunk(chunk_start, chunk_start+chunk_size)
# Handle cosine_similarity_chunk ( Write it to file_timestamp and close the file )
# Do not open the same file again or you may end up with out of memory after few chunks
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.