转移numpy d的所有权

2024-04-20 10:45:58 发布

您现在位置:Python中文网/ 问答频道 /正文

在我的previous question中,我学会了适当地调整子类ndarray的大小。整洁。不幸的是,当我要调整大小的数组是计算的结果时,这种方法不再有效:

import numpy as np

class Foo(np.ndarray):
    def __new__(cls,shape,dtype=np.float32,buffer=None,offset=0,
                strides=None,order=None):
        return np.ndarray.__new__(cls,shape,dtype,buffer,offset,strides,order)

    def __array_prepare__(self,output,context):
        print output.flags['OWNDATA'],"PREPARE",type(output)
        return np.ndarray.__array_prepare__(self,output,context)

    def __array_wrap__(self,output,context=None):
        print output.flags['OWNDATA'],"WRAP",type(output)

        return np.ndarray.__array_wrap__(self,output,context)

a = Foo((32,))
#resizing a is no problem
a.resize((24,),refcheck=False)

b = Foo((32,))
c = Foo((32,))

d = b+c
#Cannot resize `d`
d.resize((24,),refcheck=False)

准确的输出(包括回溯)是:

^{pr2}$

我认为这是因为numpy创建了一个新的ndarray,并将其传递给__array_prepare__。但在某个时候,似乎“output” array得到view-casted to my ^{} type,尽管文档在这一点上似乎不是100%清晰/准确。在任何情况下,在视图转换之后,输出不再拥有数据,因此不可能在适当的位置进行重塑(据我所知)。在

有没有什么方法,通过某种新巫术(__array_prepare____array__)等,将数据的所有权转移到我的子类实例中?在


Tags: 方法selfnoneoutputreturnfoodeftype
3条回答

怎么样:

def resize(arr, shape):
    np.require(arr, requirements=['OWNDATA'])
    arr.resize(shape, refcheck=False)

它似乎成功地调整了大小(并减少了内存消耗):

^{pr2}$

收益率

print(change_in_memory())
# 0

d = b+c
d = np.require(d, requirements=['OWNDATA'])

print(change_in_memory())
# 39136

resize(d, (24,))   # Increases memory by 200 KiB
time.sleep(1)
print(change_in_memory())
# -39116

这不是一个令人满意的答案,但它也不适合评论。。。您可以使用ufunc的out参数来解决数据的拥有问题。一个愚蠢的例子:

>>> a = Foo((5,))
>>> b = Foo((5,))
>>> c = a + b # BAD
True PREPARE <type 'numpy.ndarray'>
False WRAP <class '__main__.Foo'>
>>> c.flags.owndata
False

>>> c = Foo((5,))
>>> c[:] = a + b # BETTER
True PREPARE <type 'numpy.ndarray'>
False WRAP <class '__main__.Foo'>
>>> c.flags.owndata
True

>>> np.add(a, b, out=c) # BEST
True PREPARE <class '__main__.Foo'>
True WRAP <class '__main__.Foo'>
Foo([  1.37754085e-38,   1.68450356e-20,   6.91042737e-37,
         1.74735556e-04,   1.48018885e+29], dtype=float32)
>>> c.flags.owndata
True

我认为上面的输出与c[:] = a + b获得数据的所有权是一致的,但代价是将数据从临时数组复制到c。但是在使用out参数时,不应该发生这种情况。

由于您已经担心数学表达式中的中间存储,所以对如何处理它进行微管理可能不是一件坏事。也就是说,更换

^{pr2}$

g = foo_like(d) # you'll need to write this function!
np.multiply(d, d, out=g)
g += e * e
g += f * f
np.sqrt(g, out=g)
g += b
g += a

你可以保存一些你自己的数据。它确实把“可读性很重要”的咒语抛到了窗外,但是。。。

At some point along the way though, it seems that the "output" array gets view-casted to my Foo type

是的,ndarray.__array_prepare__调用output.view,这将返回一个不拥有其数据的数组。

我做了一点实验,但找不到一个简单的方法。

虽然我同意这种行为并不理想,但至少在您的用例中,我认为d不拥有其数据是可以接受的。Numpy广泛使用视图,如果您坚持在使用Numpy数组时避免创建任何视图,那么您的生活将非常艰难。

我还认为,根据我的经验,resize一般应该避免。如果避免使用resize,那么使用创建的视图应该不会有任何问题。它有一种骇人听闻的感觉,而且很难使用它(正如您可能开始理解的那样,在使用它时遇到了两个经典错误之一:it does not own its data。另一个是cannot resize an array that has been referenced)。(另一个问题在quesion中描述。)

由于您使用resize的决定来自于对另一个问题的回答,所以我将把剩下的答案there张贴出来。

相关问题 更多 >