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

时间:2017-11-21 04:57:58

标签: python numpy cython least-squares

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

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

问题是,这比纯python实现(~25秒)运行缓慢或慢(~27秒)。

有谁看到什么减慢了这个?谢谢!

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

1 个答案:

答案 0 :(得分:0)

您不应该需要迭代 - 您可以通过一次调用enum RoutineName { case crunches(name: String) } 来完成所有操作。 lstsq允许第二个参数为2D,在这种情况下,结果也是2D。您的阵列是3D,但您可以轻松地将其重新整形为2D,然后重新整形输出(并且重塑基本上是免费的 - 它不需要复制数据):

lstsq

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

我从中获得了400倍的加速(虽然其中一些是因为“一个调用”版本似乎并行运行而Cython版本没有)。我认为加速的主要原因是重复调用Python函数的开销(假设它在很小的数组上工作)。