Size of numpy strided array/broadcast array in memory?

后端 未结 1 714
感情败类
感情败类 2020-12-18 11:49

I\'m trying to create efficient broadcast arrays in numpy, e.g. a set of shape=[1000,1000,1000] arrays that have only 1000 elements, but repeated 1e6 times. Th

相关标签:
1条回答
  • 2020-12-18 12:12

    One way would be to examine the .base attribute of the array, which references the object from which an array "borrows" its memory. For example:

    x = np.arange(1000)
    print(x.flags.owndata)      # x "owns" its data
    # True
    print(x.base is None)       # its base is therefore 'None'
    # True
    
    a = x.reshape(100, 10)      # a is a reshaped view onto x
    print(a.flags.owndata)      # it therefore "borrows" its data
    # False
    print(a.base is x)          # its .base is x
    # True
    

    Things are slightly more complicated with np.lib.stride_tricks:

    b = np.lib.stride_tricks.as_strided(x, [1000,100,100], strides=x.strides + (0, 0))
    
    print(b.flags.owndata)
    # False
    print(b.base)   
    # <numpy.lib.stride_tricks.DummyArray object at 0x7fb40c02b0f0>
    

    Here, b.base is a numpy.lib.stride_tricks.DummyArray instance, which looks like this:

    class DummyArray(object):
        """Dummy object that just exists to hang __array_interface__ dictionaries
        and possibly keep alive a reference to a base array.
        """
    
        def __init__(self, interface, base=None):
            self.__array_interface__ = interface
            self.base = base
    

    We can therefore examine b.base.base:

    print(b.base.base is x)
    # True
    

    Once you have the base array then its .nbytes attribute should accurately reflect the amount of memory it occupies.

    In principle it's possible to have a view of a view of an array, or to create a strided array from another strided array. Assuming that your view or strided array is ultimately backed by another numpy array, you could recursively reference its .base attribute. Once you find an object whose .base is None, you have found the underlying object from which your array is borrowing its memory:

    def find_base_nbytes(obj):
        if obj.base is not None:
            return find_base_nbytes(obj.base)
        return obj.nbytes
    

    As expected,

    print(find_base_nbytes(x))
    # 8000
    
    print(find_base_nbytes(y))
    # 8000
    
    print(find_base_nbytes(z))
    # 8000
    
    0 讨论(0)
提交回复
热议问题