在 Cython 中使用 NumPy 函数进行数组元素的最小二乘拟合



我需要编写一个脚本,该脚本将逐像素地对 4 个类似的 500x500 图像堆栈进行最小二乘拟合。例如,我需要将所有四个图像上特定像素位置的值拟合到长度为三的向量中,对每个像素使用相同的 4x3 矩阵。

如果不通过每个像素进行嵌套的 for 循环迭代,我看不到一种方法可以做到这一点,所以我认为 cython 可以加快速度。我以前从未使用过cython,但我根据文档示例编写了以下代码。

问题是,这比纯python实现(~25 s(运行得慢或慢(~27 s(。

有没有人看到是什么在减慢速度?谢谢!

import numpy as np
cimport numpy as np
cimport cython
npint = np.int16
npfloat = np.float64
ctypedef np.int16_t npint_t
ctypedef np.float64_t npfloat_t

@cython.boundscheck(False)
@cython.wraparound(False)
def fourbythree(np.ndarray[npfloat_t, ndim=2] U_mat, np.ndarray[npint_t, ndim=3] G):
    assert U_mat.dtype == npfloat and G.dtype == npint
    cdef unsigned int z = G.shape[0]
    cdef unsigned int rows = G.shape[1]
    cdef unsigned int cols = G.shape[2]
    cdef np.ndarray[npfloat_t, ndim= 3] a  = np.empty((z - 1, rows, cols), dtype=npfloat)
    cdef npfloat_t resid
    cdef unsigned int rank
    cdef Py_ssize_t row, col
    cdef np.ndarray s
    for row in range(rows):
        for col in range(cols):
            a[:, row, col] = np.linalg.lstsq(U_mat, G[:, row, col])[0]
    return a

你不需要迭代 - 你可以在一次调用lstsq中完成所有操作。 lstsq允许第二个参数为 2D,在这种情况下,结果也是 2D。您的数组是 3D 的,但是您可以轻松地将其重塑为 2D,然后将输出重新塑造回来(并且重塑基本上是免费的 - 它不需要复制数据(:

a = np.linalg.lstsq(U_mat, G.reshape((G.shape[0],-1)))[0]
a = a.reshape((a.shape[0],G.shape[1],G.shape[2]))

这都是非类型化的纯Python代码,因为这不是真正的任何索引,所以我不希望Cython提供帮助。

我从中得到了大约 400 倍的加速(尽管其中一些是因为"一次调用"版本似乎并行运行,而 Cython 版本没有(。我认为加速的主要原因是重复调用 Python 函数的开销(考虑到它正在处理非常小的数组(。

最新更新