python - 为什么使用 numpy 进行矩阵乘法比使用 Python 中的 ctypes 更快?

标签 python c benchmarking matrix-multiplication

我试图找出最快的矩阵乘法方法并尝试了 3 种不同的方法:

  • 纯 python 实现:这里没有惊喜。
  • 使用 numpy.dot(a, b)
  • 实现 Numpy
  • 在 Python 中使用 ctypes 模块与 C 交互。

这是转换为共享库的 C 代码:

#include <stdio.h>
#include <stdlib.h>

void matmult(float* a, float* b, float* c, int n) {
    int i = 0;
    int j = 0;
    int k = 0;

    /*float* c = malloc(nay * sizeof(float));*/

    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            int sub = 0;
            for (k = 0; k < n; k++) {
                sub = sub + a[i * n + k] * b[k * n + j];
            }
            c[i * n + j] = sub;
        }
    }
    return ;
}

以及调用它的 Python 代码:

def C_mat_mult(a, b):
    libmatmult = ctypes.CDLL("./matmult.so")

    dima = len(a) * len(a)
    dimb = len(b) * len(b)

    array_a = ctypes.c_float * dima
    array_b = ctypes.c_float * dimb
    array_c = ctypes.c_float * dima

    suma = array_a()
    sumb = array_b()
    sumc = array_c()

    inda = 0
    for i in range(0, len(a)):
        for j in range(0, len(a[i])):
            suma[inda] = a[i][j]
            inda = inda + 1
        indb = 0
    for i in range(0, len(b)):
        for j in range(0, len(b[i])):
            sumb[indb] = b[i][j]
            indb = indb + 1

    libmatmult.matmult(ctypes.byref(suma), ctypes.byref(sumb), ctypes.byref(sumc), 2);

    res = numpy.zeros([len(a), len(a)])
    indc = 0
    for i in range(0, len(sumc)):
        res[indc][i % len(a)] = sumc[i]
        if i % len(a) == len(a) - 1:
            indc = indc + 1

    return res

我敢打赌,使用 C 的版本会更快……我会输的!下面是我的基准测试,它似乎表明我要么做错了,要么 numpy 太快了:

benchmark

我想了解为什么 numpy 版本比 ctypes 版本快,我什至不谈论纯 Python 实现,因为它有点很明显。

最佳答案

NumPy 使用高度优化、仔细调整的 BLAS 方法进行矩阵乘法(另请参见:ATLAS)。这种情况下的具体功能是 GEMM(用于通用矩阵乘法)。您可以通过搜索 dgemm.f(在 Netlib 中)来查找原始文件。

顺便说一句,优化超越了编译器优化。上面,菲利普提到了 Coppersmith-Winograd。如果我没记错的话,这是用于 ATLAS 中大多数矩阵乘法的算法(尽管评论者指出它可能是 Strassen 的算法)。

换句话说,您的 matmult 算法是简单的实现。有更快的方法来做同样的事情。

关于python - 为什么使用 numpy 进行矩阵乘法比使用 Python 中的 ctypes 更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10442365/

相关文章:

python - google-app-engine:如何将对象列表作为另一个类中的属性?

python - 我如何使用 __.init__ 并为 python 进行 OOP

c++ - 创建一个简单的可移植位掩码并使用它

Java 8 流矩阵乘法比 For 循环慢 10 倍?

C# - 为什么此循环的第一次迭代比其余循环运行得慢?

python - 您将如何设置具有多个虚拟主机的 Python Web 服务器?

python - 是否可以使 sqlite3 表中的集合成为 python 上的变量?

c - TCC 调用返回 double 值的函数

c - 我的简单程序中的 "value is neither array nor pointer nor vector"

performance - 基准 Nodejs 项目