具有numpy的大型稀疏矩阵的余弦相似性

2024-03-29 13:43:13 发布

您现在位置:Python中文网/ 问答频道 /正文

下面的代码会导致系统在完成之前耗尽内存。

你能建议一种更有效的方法来计算大矩阵上的余弦相似性吗,比如下面的一个?

我想计算原始矩阵中65000行的余弦相似性(mat)相对于所有其他行的余弦相似性,因此结果是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)

在运行完最后一行代码后,我总是内存不足,程序要么冻结,要么崩溃。无论是在8 gb本地RAM上运行还是在64 gb EC2实例上运行,都会发生这种情况。


Tags: 方法内存代码fromimportnp矩阵相似性
3条回答

我会像这样把它切成块

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 

内存不足,因为您试图存储65000x6500矩阵。请注意,您正在构造的矩阵根本不是稀疏矩阵。^{}生成一个介于0和1之间的随机数。所以没有足够的零来让csr_matrix真正压缩数据。实际上,这里根本没有almost surely零。

如果仔细查看MemoryError回溯,可以看到^{}尝试使用稀疏点积(如果可能):

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,而在于你的矩阵。尝试初始化实际稀疏矩阵(例如,稀疏度为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.]])

同样的问题。我有一个很大的非稀疏矩阵。它很适合内存,但是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

对我来说没有崩溃;YMMV。尝试不同的批量以加快速度。我以前一次只比较一行,在我的机器上花了大约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))

相关问题 更多 >