在 MATLAB 中将两个非常大的稀疏矩阵相乘时出现内存不足错误
Out of memory error when multiplying two very large sparse matrices in MATLAB
我有一个非常大的稀疏高 matrixA
尺寸(M x N
, M
>>>>> N
)
和大小 N x 1
的其他 matrixB
我想做
MatrixA*MatrixB
并获得 M x 1
输出。但是我遇到了内存不足的错误。这些矩阵只有 100 个非零元素。解决这个问题的方法是什么?
正如 @patrik 在现已删除的答案中指出的那样,问题在于 MATLAB 按列而不是按元素存储稀疏矩阵。这意味着稀疏矩阵的空列占用的内存很少,而 大量 的空列占用过多的内存,即使整个非零元素合理很少。来自您的评论之一的相应引用:
whos
for one of the variables is MatrixA 31679201751184x290953480 double sparse
我相信我说的“巨大”有点轻描淡写。
由于您在评论中注意到您的矩阵,尤其是第二个矩阵,包含 非常 几个非零元素,它可能更快,但绝对可行并且内存效率更高自己实现矩阵乘积。
使用 find
选择矩阵的非零索引,然后遍历矩阵的这些非零索引以构造矩阵乘积。您唯一需要的是(使用一些基于数学的伪代码)
[MatrixA * MatrixB](m,l) = sum_k MatrixA(m,k)*MatrixB(k,l)
你需要的索引全部来自向量
[kvec, lvec] = find(MatrixB);
[mvec, ~] = find(MatrixA);
特别是在您的情况下,lvec
一侧会非常轻。在进行一些预分配之后,循环 mvec
和 lvec
应该很简单,在整个过程中总结与 kvec
的元素相关的必要项。
如果你的matrixB
确实只是一个列向量,那么你的工作就更简单了:那么你需要
[MatrixA * MatrixB](m,1) = sum_k MatrixA(m,k)*MatrixB(k,1)
您基本上需要
k1vec = find(MatrixB);
[mvec, k2vec] = find(MatrixA);
%// choose those 'k' indices which are nonzero in both matrices
both_k = intersect(k1vec,k2vec);
inds_A = ismember(k2vec,both_k);
inds_B = ismember(k1vec,both_k);
mvec = mvec(inds_A);
k2vec = k2vec(inds_A);
k1vec = k1vec(inds_B);
然后在预分配后构建乘积向量。
仅供参考:如果您的 N 足够小,我发现此实现速度更快
function out = sparseMult(MatrixA, MatrixB)
out = sparse(size(a,1),1);
k1vec = find(b');
for i = k1vec
out = out + a(:,i).*b(i);
end
end
我有一个非常大的稀疏高 matrixA
尺寸(M x N
, M
>>>>> N
)
和大小 N x 1
matrixB
我想做
MatrixA*MatrixB
并获得 M x 1
输出。但是我遇到了内存不足的错误。这些矩阵只有 100 个非零元素。解决这个问题的方法是什么?
正如 @patrik 在现已删除的答案中指出的那样,问题在于 MATLAB 按列而不是按元素存储稀疏矩阵。这意味着稀疏矩阵的空列占用的内存很少,而 大量 的空列占用过多的内存,即使整个非零元素合理很少。来自您的评论之一的相应引用:
whos
for one of the variables isMatrixA 31679201751184x290953480 double sparse
我相信我说的“巨大”有点轻描淡写。
由于您在评论中注意到您的矩阵,尤其是第二个矩阵,包含 非常 几个非零元素,它可能更快,但绝对可行并且内存效率更高自己实现矩阵乘积。
使用 find
选择矩阵的非零索引,然后遍历矩阵的这些非零索引以构造矩阵乘积。您唯一需要的是(使用一些基于数学的伪代码)
[MatrixA * MatrixB](m,l) = sum_k MatrixA(m,k)*MatrixB(k,l)
你需要的索引全部来自向量
[kvec, lvec] = find(MatrixB);
[mvec, ~] = find(MatrixA);
特别是在您的情况下,lvec
一侧会非常轻。在进行一些预分配之后,循环 mvec
和 lvec
应该很简单,在整个过程中总结与 kvec
的元素相关的必要项。
如果你的matrixB
确实只是一个列向量,那么你的工作就更简单了:那么你需要
[MatrixA * MatrixB](m,1) = sum_k MatrixA(m,k)*MatrixB(k,1)
您基本上需要
k1vec = find(MatrixB);
[mvec, k2vec] = find(MatrixA);
%// choose those 'k' indices which are nonzero in both matrices
both_k = intersect(k1vec,k2vec);
inds_A = ismember(k2vec,both_k);
inds_B = ismember(k1vec,both_k);
mvec = mvec(inds_A);
k2vec = k2vec(inds_A);
k1vec = k1vec(inds_B);
然后在预分配后构建乘积向量。
仅供参考:如果您的 N 足够小,我发现此实现速度更快
function out = sparseMult(MatrixA, MatrixB)
out = sparse(size(a,1),1);
k1vec = find(b');
for i = k1vec
out = out + a(:,i).*b(i);
end
end