Numpy:每个操作的内存分配?

hli*_*117 5 python numpy

numpy 是否为您在矩阵上执行的每个操作分配新矩阵?

例如:

A = np.random.rand(10, 20)
A = 2 * A  # Operation 1: Is a copy of A made, and a reference assigned to A?
B = 2 * A  # Operation 2: Does B get a completely different copy of A?
C = A      # Operation 3: Does C get a reference to A?
Run Code Online (Sandbox Code Playgroud)

和切片操作:

A[0, :] = 3
Run Code Online (Sandbox Code Playgroud)

链式操作怎么样?

D = A * B * C  # Elementwise multiplication, if A * B allocates memory, does 
               # (A * B) * C allocate another patch of memory?
Run Code Online (Sandbox Code Playgroud)

Numpy 是一个很棒的图书馆,但我只想知道幕后发生了什么。我的直觉是切片操作会就地修改内存视图,但我不知道分配。

hpa*_*ulj 4

请记住,numpy 数组是一个 Python 对象。Python 不断创建和删除对象。该数组具有.FLAGS.__array_interface__字典中显示的属性,例如shapedtype。占用(可能)大量内存的属性是数据缓冲区。它可能是几个字节长,也可能是MB。

在可能的情况下,numpy 操作会尝试避免复制数据缓冲区。建立索引时,如果可能的话会返回 a view。我认为文档很好地比较了视图和副本。

但视图与 Python 引用不同。共享引用意味着两个变量(或列表或字典中的指针)指向同一个 Python 对象。Aview是一个不同的数组对象,但与另一个数组共享数据缓冲区。副本有自己的数据缓冲区。

在你的例子中:

A = np.random.rand(10, 20)
Run Code Online (Sandbox Code Playgroud)

A是一个指向数组对象的变量。该对象有一个包含 200 个浮点数(200*8 字节)的数据缓冲区。

A = 2 * A  # Operation 1: Is a copy of A made, and a reference assigned to A?
Run Code Online (Sandbox Code Playgroud)

2*A使用新的数据缓冲区创建一个新对象。它的任何数据值都不能与原始数据共享AA=...重新分配A变量。旧A对象“丢失”,最终内存被垃圾收集。

B = 2 * A  # Operation 2: Does B get a completely different copy of A?
Run Code Online (Sandbox Code Playgroud)

2*A对新A数组进行操作。该对象被分配给B. A保持不变。

C = A      # Operation 3: Does C get a reference to A?
Run Code Online (Sandbox Code Playgroud)

是的,这只是普通的 Python 作业。 C指的是与 相同的对象Aid(C)==id(A)

B = A[1,:]  #  B is a view
Run Code Online (Sandbox Code Playgroud)

B是对新数组对象的引用。但该对象与 共享数据缓冲区A。这是因为只需从不同的点开始并使用不同的shape.

A[0, :] = 3
Run Code Online (Sandbox Code Playgroud)

此 LHS 切片将更改 的值的子集A。它类似于:

B = A[0, :]
B = 3
Run Code Online (Sandbox Code Playgroud)

但 LHS 和 RHS 切片之间存在细微的差异。在 LHS 上,当您获得副本而不是视图时,您必须更加注意。我尤其在诸如 之类的表达式中看到过这一点A[idx1,:][:,idx2] = 3

D = A * B * C 
Run Code Online (Sandbox Code Playgroud)

在这样的计算中生成了多少个中间副本的详细信息隐藏在 numpy C 代码中。最安全的假设是它会执行以下操作:

temp1 = A*B
temp2 = temp1*C
D = temp2
(temp1 goes to garbage)
Run Code Online (Sandbox Code Playgroud)

对于普通计算来说,不值得担心这些细节。如果你真的追求速度,你可以做一个timeit替代方案。有时我们会收到有关捐赠运营的问题memory errors。进行搜索以获取有关这些内容的更多详细信息。