小能豆

numpy.as_strided 的结果是否取决于输入的数据类型?

py

结果是否numpy.lib.stride_tricks.as_strided取决于 NumPy 数组的 dtype?

这个问题源于 的定义.strides,即

遍历数组时在每个维度中要步进的字节元组。

以我在其他问题中使用过的以下函数为例。它接受一维或二维数组并创建长度为 的重叠窗口window。结果将比输入大一维。

def rwindows(a, window):
    if a.ndim == 1:
        a = a.reshape(-1, 1)
    shape = a.shape[0] - window + 1, window, a.shape[-1]
    strides = (a.strides[0],) + a.strides
    windows = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
    return np.squeeze(windows)

# examples
# rwindows(np.arange(5), window=2)
# rwindows(np.arange(20).reshape((5,4)), window=2)

由于步幅的定义,并且因为,例如,否则 dtype的等效数组将具有不同的步幅float32``float64,这会破坏rwindows上面的函数吗?

我曾尝试进行测试,但测试方式并不详尽,我正在寻找一个答案,该答案可以(1)解释函数文档中的免责声明/警告是否与我在此处询问的内容有关,以及(2)解释为什么或为什么不具有不同 dtypes 和 strides 的等效数组会在上述内容中产生不同的结果。


阅读 7

收藏
2024-10-28

共1个答案

小能豆

不,警告针对的as_strided是两个问题,实际上与数据大小无关,更多是因写入结果视图而导致的。

  1. 首先,没有保护措施来确保view = as_strided(a . . . ) 指向 中的内存a。这就是为什么在调用 之前要做这么多精心准备工作as_strided。如果您的算法不正确,您很容易指向view中不存在的内存a,而这些内存可能确实被寻址到垃圾、其他变量或您的操作系统。如果您随后写入该视图,您的数据可能会丢失、放错位置、损坏……或导致您的计算机崩溃。

对于您的具体示例,其安全性在很大程度上取决于您使用的输入。您已设置,strides因此它a.strides是动态的。您可能希望assert不是像这样奇怪的东西。dtype``a``object

如果您确定总会a一个大于的二维数组window,那么您的算法可能就没问题了,但您也可以assert这样做以确保这一点。如果不是,您可能需要确保as_strided输出适用于 nda数组。例如:

shape = a.shape[0] - window + 1, window, a.shape[-1]

应该

shape = (a.shape[0] - window + 1, window) + a.shape[1:]

以便接受 nd 输入。就引用错误内存而言,这可能shape永远不会成为问题,但是如果您有更多维度,则当前将引用错误的数据a

  1. 其次,创建的视图多次引用相同的数据块。如果您随后对该视图进行并行写入(通过view = foobar( . . ., out = view)),结果可能不可预测,并且可能不是您所期望的。

也就是说,如果您担心出现问题并且不需要写入视图as_strided(因为在大多数常用的卷积应用程序中您不需要写入视图),您可以随时将其设置为writable = False,即使您的strides和/或shape不正确,这也可以防止出现这两个问题。

编辑:正如@hpaulj 指出的那样,除了这两个问题之外,如果你对 a 做了一些view复制(比如.flatten()或想索引它的一大块),它可能会导致MemoryError

2024-10-28