numpy.shares_memory和numpy.may_share_memory有什么区别?

时间:2017-07-01 20:43:49

标签: python numpy

为什么numpy.may_share_memory存在?
给出确切结果的挑战是什么?

是否已弃用numpy.may_share_memory方法?
numpy.may_share_memory可能会给出误报,但不会给出假阴性。

numpy.shares_memory是否给出任何假阳性且没有假阴性?

我使用numpy版本1.11.2

请参阅:

  1. numpy.may_share_memory
  2. numpy.shares_memory
  3. version 1.11.2 source on github

2 个答案:

答案 0 :(得分:9)

引用release notes for 1.11.0

  

添加了一个新函数np.shares_memory,可以准确检查两个数组是否有内存重叠。 np.may_share_memory现在也可以选择花更多的精力来减少误报。

从语义上讲,这表明较旧的may_share_memory测试旨在让人们猜测内存是否在数组之间共享。如果肯定不是,那么可以相应地进行。如果有阳性检测(可能是假阳性),则必须小心。另一方面,新的shares_memory函数允许精确检查。这需要更多的计算时间,但从长远来看可能是有益的,因为没有误报可以使用更多可能的优化。对may_share_memory进行更宽松的检查可能只能保证不会返回错误的否定

may_share_memoryshares_memory的文档而言,两者都有一个关键字参数,告诉numpy用户想要检查的严格程度。

may_share_memory

max_work : int, optional

    Effort to spend on solving the overlap problem. See shares_memory for details. Default for may_share_memory is to do a bounds check.

shares_memory

max_work : int, optional

    Effort to spend on solving the overlap problem (maximum number of candidate solutions to consider). The following special values are recognized:

    max_work=MAY_SHARE_EXACT (default)

        The problem is solved exactly. In this case, the function returns True only if there is an element shared between the arrays.
    max_work=MAY_SHARE_BOUNDS

        Only the memory bounds of a and b are checked.

根据文档判断,这表明这两个函数可能会调用相同的底层机制,但may_share_memory使用不太严格的默认设置进行检查。

让我们看一看at the implementation

static PyObject *
array_shares_memory(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
{
    return array_shares_memory_impl(args, kwds, NPY_MAY_SHARE_EXACT, 1);
}


static PyObject *
array_may_share_memory(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
{
    return array_shares_memory_impl(args, kwds, NPY_MAY_SHARE_BOUNDS, 0);
}

使用签名

调用相同的基础函数
static PyObject *
array_shares_memory_impl(PyObject *args, PyObject *kwds, Py_ssize_t default_max_work,
                         int raise_exceptions)
{}

在没有深入研究源代码的情况下,我认为shares_memory是对may_share_memory的改进,它可以使用适当的关键字参数进行与后者相同的松散检查。旧功能可用于方便和向后兼容。

免责声明:这是我第一次查看源代码的这一部分,而我没有进一步调查array_shares_memory_impl,所以我的印象可能完全错误。

至于两个方法之间差异的具体示例(使用默认参数调用):在上面的链接中解释了may_share_memory仅检查数组绑定索引。如果它们与两个阵列不相交,那么没有机会它们可以共享内存。但如果它们不相交,那么数组仍然可以是独立的!

简单示例:通过切片对连续的内存块进行不相交的分区:

>>> import numpy as np
>>> v = np.arange(6)
>>> x = v[::2]
>>> y = v[1::2]
>>> np.may_share_memory(x,y)
True
>>> np.shares_memory(x,y)
False
>>> np.may_share_memory(x,y,max_work=np.MAY_SHARE_EXACT)
False

如您所见,xy是同一数组的两个不相交的切片。因此,它们的数据范围在很大程度上重叠(它们几乎相同,在内存中保存一个整数)。但是,它们的元素实际上都不相同:一个包含偶数,另一个包含原始连续块的奇数元素。所以may_share_memory正确断言数组可以共享内存,但是在更严格的检查中发现它们没有。

至于准确计算重叠的额外难度,工作可以追溯到名为solve_may_share_memory的工作人员,该工作人员还包含许多关于正在进行的有用的评论。简而言之,那就是

  1. a quick check and return如果界限没有重叠,否则
  2. return with MEM_OVERLAP_TOO_HARD如果我们要求进行宽松检查(例如may_share_memory使用默认参数),handled on the calling side为"我们不知道,所以返回{ {1}}"
  3. 否则我们实际上解决了问题映射到starting here
  4. 的丢番图方程

    因此,上面第3点的工作是True需要额外完成的工作(或者通常是严格的检查案例)。

答案 1 :(得分:3)

在阅读以下内容之前,请阅读:

http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html
http://www.scipy-lectures.org/advanced/advanced_numpy/

实际上问题是找到两个跨步数组ab的内存重叠:

请参阅Implementatation NumPy(阅读标题中的评论非常重要。)

此问题相当于:

"找到具有正系数的有界丢番图方程的解法"

以1D阵列为例:

import numpy as np

x = np.arange(8, dtype=np.int8)
a = x[::3]
b = x[1::2]

在记忆中我们有:

1D array

1D数组是内存中的连续结构。我想我们的存储器具有64位地址(在8个字节上),并且我们的数组的每个元素具有一个字节的大小(0 <= np.int8 <256)。

要解决重叠问题,a的一个元素的可能内存地址为:

base_a + stride_a * x_a其中x_a是一个变量(数组索引从0开始)。

我们对b

也一样

base_b + stride_b * x_b其中x_b是一个变量(数组索引从0开始)。

当且仅当:

时才有重叠

base_a + stride_a * x_a = base_b + stride_b * x_b

我们有:

stride_a * x_a - stride_b * x_b = base_b - base_a

0 <= x_a < shape_a0 <= x_b < shape_b

我们可以转换所有负系数,而不是阅读b 从上到下,我们可以通过变量从下到上阅读:

x_b' = shape_b - 1 - x_b

我们获得:

stride_a * x_a + stride_b * x_b = base_b + stride_b * (shape_b - 1) - base_a

这里:

3 x_a + 2 x_b = 7 (= 1 + 2 * (4 - 1))

0 <= x_a < 30 <= x_b < 4

一个解决方案是x_a = 1x_b = 2(从x_b的底部读取)。

....

我们可以很容易地推断出对于2D数组然后是XD数组,并且每个数组元素需要多于一个字节(例如4个字节,所有数组元素都是内存中常见的大小)。

这是naive solution on my github and comparaison performance with NumPy implementation

...