【问题标题】:Memory allocation for numpy.array with copy=False?复制=假的numpy.array的内存分配?
【发布时间】:2014-12-22 19:45:24
【问题描述】:

如果 X 的类型是 numpy.arraydtype='f4'

那么下面一行的内存行为是什么:

X = array(X, dtype=double, copy=False, order='C', subok=True)

是否为X分配新的内存空间(内存使用*2)?

【问题讨论】:

    标签: python memory numpy


    【解决方案1】:

    NumPy docarray 构造函数的 copy 参数有这样的说法:

    如果为 true(默认),则复制对象。否则,仅当 array 返回副本、obj 是嵌套序列或需要副本以满足任何其他要求(dtype、顺序等)时才会生成副本。

    您提供了“其他要求”之一的示例,dtype。所以答案是,在这种情况下,copy=False 会被忽略,因为必须制作一个副本 才能将 float32 内容转换为更高的精度。

    【讨论】:

    • 这可以通过查看X.flags前后来验证。
    • @frank128791 我认为这是任何系统上的默认设置,但 OP 指定数组的起始 dtype'f4',它是 'float32' 的同义词。
    【解决方案2】:

    我喜欢做一些小实验,看看我的系统中“真正”发生了什么。这是一个简单的脚本:

    import numpy as np
    import numpy.random as rand
    @profile
    def test_size(N=20e6):
        x = np.zeros(N, dtype=np.float32)
        x[0] = 200
        x[N-1] = 123.555
        x[0:N] = rand.rand(N)
        x = np.array(x, copy=False, dtype=np.double, order='C', subok=True)
        x[0:N] = rand.rand(N)
        y = np.zeros(N, dtype=np.float32)
        y[0] = 500.0
        y[1000] = 123.4
        y[0:N] = rand.rand(N)
        del(x)
        del(y)
    
        if __name__ == '__main__':
            test_size()
    

    使用python -m memory_profiler ./testProc.py 进行分析时的输出是:

        Line #    Mem usage    Increment   Line Contents
    ================================================
         3   17.699 MiB    0.000 MiB   @profile
         4                             def test_size(N=20e6):
         5   17.707 MiB    0.008 MiB       x = np.zeros(N, dtype=np.float32)
         6   17.711 MiB    0.004 MiB       x[0] = 200
         7   17.719 MiB    0.008 MiB       x[N-1] = 123.555
         8   94.031 MiB   76.312 MiB       x[0:N] = rand.rand(N)
         9  170.332 MiB   76.301 MiB       x = np.array(x, copy=False, dtype=np.double, order='C', subok=True)
        10  170.340 MiB    0.008 MiB       x[0:N] = rand.rand(N)
        11  170.344 MiB    0.004 MiB       y = np.zeros(N, dtype=np.float32)
        12  170.344 MiB    0.000 MiB       y[0] = 500.0
        13  170.344 MiB    0.000 MiB       y[1000] = 123.4
        14  246.164 MiB   75.820 MiB       y[0:N] = rand.rand(N)
        15   93.582 MiB -152.582 MiB       del(x)
        16   17.285 MiB  -76.297 MiB       del(y)
    

    正如 Joe 所指出的,内存分析器的结果看起来令人惊讶。分析器在每行之后显示内存分配。内存占用在填充数组的行之后扩大,并在删除它们时缩小。在 shell 中运行 ps 的结果是相似的。

    进程删除的内存是否真的返回系统堆栈是另一回事。

    【讨论】:

    • 分析器出了点问题。 x is 的内存分配给您调用 zeros(对于 20e6 float32 应该是 ~76MB),当您调用 np.array(x, copy=False, dtype=np.double) 时,由于 dtype 的差异( float32 不是 float64)。
    • @JoeKington:是的,内存已分配,但这并不一定意味着进程占用空间会立即扩大。我已经扩展到示例以显示内存占用的行为方式。我认为这是一张合理的图片,它显示了对系统的影响。
    • 是的,这就是为什么逐行内存更改与任何事情无关的原因。这是非常具有误导性的。例如,尽管rand.rand(N) 在将它们分配给x 之前 创建了一个全新的浮点数组,但您的结果显示第10 行没有内存变化。 (第 8 行和第 10 行完全等同于 temp = np.random.rand(N); x[:] = temp。)
    猜你喜欢
    • 1970-01-01
    • 2020-11-28
    • 2018-05-05
    • 1970-01-01
    • 2018-09-06
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 2012-03-24
    相关资源
    最近更新 更多