【问题标题】:Why does Cython expect 0 dimensions?为什么 Cython 期望 0 维?
【发布时间】:2020-02-18 17:08:28
【问题描述】:

我已将我的问题归结为一个可重现的小测试用例:

在文件 1 (custom_cython.pyx) 文件中,我有以下内容:

import numpy as np
cimport numpy as np
cimport cython

ctypedef np.uint8_t DTYPE_B_t
ctypedef np.uint16_t CELL_ID_t
ctypedef np.int64_t DTYPE_INT64_t


cdef struct LOOKUPMEM_t:
    DTYPE_B_t filled_flag
    CELL_ID_t key_i
    CELL_ID_t key_j
    CELL_ID_t key_k
    DTYPE_INT64_t offset
    DTYPE_INT64_t num_elements  


cdef LOOKUPMEM_t[:] lookup_memory


my_dtype = [("filled_flag", np.uint8, 1),
            ("ijk", np.uint16, 3),
            ("offset_and_num", np.int64, 2)]

input_numpy_dtype = np.dtype(my_dtype, align=True)

lookup_memory = np.zeros(5000, dtype=input_numpy_dtype)

在文件 2 (custom_cython_test.py) 中,我有以下内容:

from custom_cython import lookup_memory

print(lookup_memory)

当我运行 python custom_cython_test.py 时,我最终得到 ValueError: Expected 0 dimension(s), got 1 在线 lookup_memory = np.zeros(5000, dtype=input_numpy_dtype)

在我的结构定义中,我尝试在 dtype 创建中使用cdef packed struct LOOKUPMEM_talign=False,这会产生相同的错误。

我在 Python 3.7.3 上使用 Cython 版本 0.29.12 和 Numpy 1.16.4。

我之前已经成功地将 cython memoryviews 分配给 1-D numpy 数组,所以我很困惑为什么我明显的 1d cdef LOOKUPMEM_t[:] lookup_memory 期望为 0 维。谁能告诉我这是怎么回事?

【问题讨论】:

  • 不管怎样,我能够使用 Python 3.6.8 和 Cython 0.29.15 进行复制。还不知道问题出在哪里。
  • 谢谢你,至少我知道我没疯!
  • 有问题的错误似乎源于 Cython 生成的代码,该代码来自一个名为 __Pyx_ValidateAndInit_memviewslice 的相当复杂的函数。我对 Cython 的 Typed Memoryview 区域并不是很熟悉,所以如果不仔细阅读该代码,我仍然不清楚这意味着什么......
  • 有趣的是,如果你把它改成lookup_memory = np.zeros(5000, dtype=input_numpy_dtype).reshape(1,5000),它就会变成ValueError: Buffer has wrong number of dimensions (expected 1, got 2),这与之前的错误格式略有不同,奇怪吗?
  • 不奇怪;后一个错误是因为实际上将形状设置为 (1, 5000) 使其成为二维数组,因此您需要声明 cdef LOOKUPMEM_t[:, :] lookup_memory 以便它是二维的。如果你这样做,第一个错误仍然会发生。

标签: python numpy cython memoryview


【解决方案1】:

问题似乎是你结构的这一部分:

    CELL_ID_t key_i
    CELL_ID_t key_j
    CELL_ID_t key_k

结合你的 dtype 的这一部分:

("ijk", np.uint16, 3)

对于您的组合 offset_and_num 字段也是如此。

问题在于,当 memoryview 接口看到像 ("ijk", np.uint16, 3) 这样的类似元组的字段时,它想将其解压缩为 3 个元素的一维数组,但结构中的下一个键只是 CELL_ID_t key_i,一个0-D 标量。

如果我将您的结构更改为更紧密地匹配 Numpy dtype 它可以工作:

cdef struct LOOKUPMEM_t:
    DTYPE_B_t filled_flag
    CELL_ID_t ijk[3]
    DTYPE_INT64_t offset_num_elements[2]

因此,对于如何继续,您有几个选择。如果您真的想以相同的方式保持结构,您可以这样做,并以不同的方式格式化 dtype。由于很容易查看具有不同 dtype 的 Numpy 数组,如果您想为其他用例保留现有的 dtype 格式,您还可以使用不同的 dtype 进行 memoryview 初始化。

【讨论】:

    猜你喜欢
    • 2019-11-28
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    • 1970-01-01
    相关资源
    最近更新 更多