如何在python中有效地计算(稀疏)位矩阵的矩阵乘积

Posted

技术标签:

【中文标题】如何在python中有效地计算(稀疏)位矩阵的矩阵乘积【英文标题】:How to calculate matrix product on (sparse) bit matrix efficiently in python 【发布时间】:2016-10-01 03:52:50 【问题描述】:

位数组之间的普通矩阵乘积:

           1, 0, 0
Matrix A = 1, 1, 1
           0, 0, 1

                 1, 1, 0
Transpose of A = 0, 1, 0
                 0, 1, 1

C = Matrix A times (Transpose of Matrix A)

    1, 1, 0
C = 1, 3, 1
    0, 1, 1

A 是 1 和 0 的位数组。实际矩阵 A 很大,大约有 0.25% 的 1 项和 99.75% 的零项。

C 是一个整数数组。

如何在不占用大量内存的情况下快速计算?

目前,我正在使用 scipy 的稀疏矩阵乘法例程来处理 python 中浮点 1.0 和 0.0 的压缩稀疏行矩阵。我也在尝试直接调用 mkl 库中的 c 函数来减少内存使用。

【问题讨论】:

多大? 1000 x 1000 矩阵需要多长时间? 计算一个 750,000 x b 矩阵与其转置的乘积。 b 至少为 10,000。 b 越大越好。但是每个 cpu 核心的内存是有限的。 对不起,我的意思是一个形状为 b x 750,000 的矩阵 A。所以 A 的 A 次转置应该是 b x b 的形状。 @rxu 给出 750000 和 0.25%,你的 C 有 99% 的非零元素。您可能希望以密集格式存储它。 这取决于 b 行是否倾向于在同一列有 1。 【参考方案1】:

MKL 等现有性能库始终使用 float/double 作为数据类型。与将 A 转换为浮点 CSR 然后调用 .dot() 或一些 MKL 例程相比,您可能会发现编写自己的 bit-mat-mul 代码更快。你甚至不需要乘法运算。它只是计算位数。

编辑

在了解您的问题背景后,我会建议以下程序。

    将数组 A 转换为 CSR 格式并仅存储 col 索引和行 ptr; 对于 A 的每一行 i 和 j 行,计算公共 col 索引的数量并将结果存储在 C(i, j) 中,其中 i

稠密矩阵 C 就是你想要的。

给定你的 A 的大小 (b x 750,000) 和密度 (0.25%),C 的密度是 99.1%;每个 col 索引的平均长度为 1875。

所以你的问题变成了计算 2 个 1875-D 向量的公共元素的数量 b*(b+1)/2 次。

for 循环的速度似乎是唯一剩下的问题。

【讨论】:

@rxu 之前的问题暗示数据可能存储为gmpy2.mpz 类型。如果正确,gmpy2.hamdist(row & col, 0) 应该很快。 让我试试。我担心开销 python 循环和从 python 调用 c++ 会使事情变慢......实际上我写了一个版本来使用 python 的集合和交集一次。对于稀疏矩阵,那个比 scipy 的点要慢得多。即使构建稀疏矩阵需要时间。组合时间仍然比设置版本快得多。在程序的前一部分中,我使用 mpz 和 python 循环非常快速地计算了logical_and。效果很好,而 scipy 做不到那么快,而且会占用大量内存。 在密集位数组的程序工作的第一部分。现在我必须在程序的第二部分使用稀疏数组。 set 版本也占用大量内存。这使得 b 很小。 另一件事是我必须在计算产品之前将该 b x 750,000 矩阵压缩到内存中。在我的例子中,稀疏矩阵在内存效率上大大优于密集矩阵。

以上是关于如何在python中有效地计算(稀疏)位矩阵的矩阵乘积的主要内容,如果未能解决你的问题,请参考以下文章

如何对稀疏矩阵列表求和?

有效地找到稀疏矩阵的最小列的索引

尝试在python中有效地计算相关矩阵

在给定稀疏矩阵数据的情况下,Python 中计算余弦相似度的最快方法是啥?

如何计算 scipy 稀疏矩阵行列式而不将其变为密集?

使用 scipy 在 python 中构建和更新稀疏矩阵