python - Cython:融合类型的使用无效,类型不能被专门化

标签 python numpy cython cythonize

我有以下 MCVE:

import numpy as np

cimport numpy as np
cimport cython

from cython cimport floating


def func1(floating[:] X_data, floating alpha):
    if floating is double:
        dtype = np.float64
    else:
        dtype = np.float32

    cdef floating[:] prios = np.empty(12, dtype=dtype)
    cdef int ws_size = 10

    C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

    cdef int res = func2(X_data, alpha, C)


cpdef int func2(floating[:] X_data, floating alpha, int[:] C):
    cdef int epoch = 1
    return epoch

试图运行 cython test_fused.pyx给我:
Error compiling Cython file:
------------------------------------------------------------
...
    cdef floating[:] prios = np.empty(12, dtype=dtype)
    cdef int ws_size = 10

    C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

    cdef int res = func2(X_data, alpha, C)
                       ^
------------------------------------------------------------

test_fused.pyx:21:24: no suitable method found

    Error compiling Cython file:
    ------------------------------------------------------------
    ...
        cdef floating[:] prios = np.empty(12, dtype=dtype)
        cdef int ws_size = 10

        C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

        cdef int res = func2(X_data, alpha, C)
                           ^
    ------------------------------------------------------------

    test_fused.pyx:21:24: no suitable method found

    Error compiling Cython file:
    ------------------------------------------------------------
    ...
        cdef floating[:] prios = np.empty(12, dtype=dtype)
        cdef int ws_size = 10

        C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

        cdef int res = func2(X_data, alpha, C)
                      ^
    ------------------------------------------------------------

    test_fused.pyx:21:19: Invalid use of fused types, type cannot be specialized

    Error compiling Cython file:
    ------------------------------------------------------------
    ...
        cdef floating[:] prios = np.empty(12, dtype=dtype)
        cdef int ws_size = 10

        C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

        cdef int res = func2(X_data, alpha, C)
                      ^
    ------------------------------------------------------------

    test_fused.pyx:21:19: Invalid use of fused types, type cannot be specialized

我有一个更复杂的代码,它也传递了数组 C作为运行时定义的值,这不会导致任何问题。这个编译错误的原因是什么?

我很困惑,因为稍加修改(向 func1 添加一个虚拟关键字 arg 和向 func2 添加两个关键字 args)使代码编译:
def func1(floating[:] X_data, floating alpha,
          int dummy_variable=1):  # added dummy_variable here

    # same as before here

    cdef int res = func2(X_data, alpha, C,
                       dummy_variable=dummy_variable)


cpdef int func2(floating[:] X_data, floating alpha, int[:] C, 
    int K=6, int dummy_variable=1):  # added K and dummy variable here

    cdef int epoch = 1
    return epoch

最佳答案

让我们从一个较小的复制器开始:

%%cython
import numpy as np
from cython cimport floating

def func1(floating[:] X_data):
    C = np.empty(12, dtype=np.int_32)
    func2(X_data, C)

cpdef func2(floating[:] X_data, int[:] C):
    pass

它不编译。

一项重要观察:func2cpdef ,这意味着 Cython 将调用它作为来自 func1 的原始 C 函数.这两个 C 签名将由 Cython 生成用于融合 func2功能(一个用于 double 和一个用于 float ):
static PyObject *__pyx_fuse_0__pyx_f_4test_func2(__Pyx_memviewslice, __Pyx_memviewslice, int __pyx_skip_dispatch); /*proto*/
static PyObject *__pyx_fuse_1__pyx_f_4test_func2(__Pyx_memviewslice, __Pyx_memviewslice, int __pyx_skip_dispatch); /*proto*/

所以C预计是__Pyx_memviewslice ,但就 Cython 而言,它是一个 PyObjectfunc1 ,因此无法将函数称为 cdef .我不明白的是:为什么 Cython 不回退到 python-def版本?

C 签名有点误导,Cython 在编译过程中做了更多的类型检查,所以定义 C 无济于事。作为
cdef float[:] C

因为即使 C在这种情况下也是 __Pyx_memviewslice它没有正确的类型,只有
cdef int[:] C

会工作。

func2被定义为
cpdef func2(floating[:] X_data, C):

相应的两个 C 签名将是
static PyObject *__pyx_fuse_0__pyx_f_4test_func2(__Pyx_memviewslice, PyObject *, int __pyx_skip_dispatch); /*proto*/
static PyObject *__pyx_fuse_1__pyx_f_4test_func2(__Pyx_memviewslice, PyObject *, int __pyx_skip_dispatch); /*proto*/

所以可以通过C ,这是一个 PyObject到这些功能。

所以有两种方法可以解决编译问题:
  • 使用 cdef int[:] Cfunc1 , 或
  • int[:] Cfunc2 的签名中


  • 那么为什么要添加一个虚拟参数,即
    %%cython -a
    import numpy as np
    from cython cimport floating
    
    def func1(floating[:] X_data, int dummy_variable=1):
        C = np.empty(12, dtype=np.int_32)
        func2(X_data, C, dummy_variable=dummy_variable)
    
    cpdef func2(floating[:] X_data, int[:] C, int k=6, dummy_variable = 1):
        pass
    

    作品?

    实际上还有第三种方法可以编译代码:通过 func2仅适用于 Python def -功能。在这种情况下,类型为 C在编译时不起作用,将在运行时检查。

    问题是:对于您的虚拟变量,Cython 决定调用 func2作为 Python 函数而不是 C 函数,因此类型不匹配不起作用。

    通过检查带注释的 html 文件,您可以轻松看到这一点。

    但是,我不能说 Cython 回退到 Python 函数调用来解决您的问题的原因是什么。我只能说:不要为 k 提供值起着重要的作用。

    关于python - Cython:融合类型的使用无效,类型不能被专门化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51083070/

    相关文章:

    python - Cython bdist_egg 与 setuptools 创建无效包

    python - 在 python 中使用 coreNLP 的斯坦福类型依赖项

    performance - 为什么我的 Cython C 函数比它包装的内置函数慢 40 倍?

    python - 将 numpy 数组传递给 cython 中的 C 函数

    python - 零碎的 xpath : choose the ancestor node

    python - 如何从视频中提取 ROI - 将不相关的像素涂黑

    python - 任意长度的 Numpy 分段

    python - Pandas 使用多个条件在列中赋值 :

    python 位移位与 numpy

    python - 值错误 : ndarray is not C-contiguous in cython