gpt4 book ai didi

python - 预测 ufunc 输出的内存布局

转载 作者:行者123 更新时间:2023-12-03 16:48:23 28 4
gpt4 key购买 nike

使用 numpy ndarray大多数时候我们不需要担心内存布局的问题,因为结果并不依赖于它。
除非他们这样做。例如,考虑这种设置 3x2 矩阵对角线的稍微过度设计的方法

>>> a = np.zeros((3,2))
>>> a.reshape(2,3)[:,0] = 1
>>> a
array([[1., 0.],
[0., 1.],
[0., 0.]])
只要我们控制 a的内存布局这可以。但是,如果我们不这样做,那就是一个错误,更糟糕的是,这是一个令人讨厌的无声错误:
>>> a = np.zeros((3,2),order='F')
>>> a.reshape(2,3)[:,0] = 1
>>> a
array([[0., 0.],
[0., 0.],
[0., 0.]])
这足以表明内存布局不仅仅是一个实现细节。
为了了解数组布局,人们可能合理地要求的第一件事是新数组是什么样的?工厂 empty , ones , zeros , identity等。默认返回 C 连续布局。
但是,此规则并未扩展到 numpy 分配的每个新数组。例如:
>>> a = np.arange(8).reshape(2,2,2).transpose(1,0,2)
>>> aa = a*a
产品 aa是 ufunc 分配的新数组 np.multiply .它是 C 连续的吗?不:
>>> aa.strides
(16, 32, 8)
我的猜测是,这是优化的结果,该优化认识到可以在平面线性阵列上完成此操作,这将解释为什么输出具有与输入相同的内存布局。
事实上,这甚至可能很有用,不像下面的废话函数。它显示了一个方便的习惯用法来实现轴参数,同时仍然保持索引简单。
>>> def symmetrize_along_axis(a,axis=0):
... aux = a.swapaxes(0,axis)
... out = aux + aux[::-1]
... return out.swapaxes(0,axis)
稍微令人惊讶但显然是可取的事情是,只要输入是连续的,就会产生连续的输出。
>>> a = np.arange(8).reshape(2,2,2)
>>> symmetrize_along_axis(a,1).flags.contiguous
True
这足以表明了解 ufunc 返回的布局非常有用。因此我的问题是:
鉴于 ufunc 参数的布局,是否有关于输出布局的任何规则或保证?

最佳答案

a = np.zeros((3,2),order='F')案例,a.reshape(2,3)创建一个副本,而不是一个 View 。这就是分配失败的原因,而不是内存布局本身。
查看相同形状的数组:

In [123]: a = np.arange(6).reshape(3,2)                                                              
In [124]: a
Out[124]:
array([[0, 1],
[2, 3],
[4, 5]])
In [125]: a.reshape(2,3)
Out[125]:
array([[0, 1, 2],
[3, 4, 5]])
In [127]: a.reshape(2,3)[:,0]
Out[127]: array([0, 3])
在 [125] 中,值仍然按顺序 C 流动。
和一个 F 阶数组:
In [128]: b = np.arange(6).reshape(3,2, order='F')                                                   
In [129]: b
Out[129]:
array([[0, 3], # values flow in order F
[1, 4],
[2, 5]])
In [130]: b.reshape(2,3)
Out[130]:
array([[0, 3, 1], # values are jumbled
[4, 2, 5]])
In [131]: b.reshape(2,3)[:,0]
Out[131]: array([0, 4])
如果我保持订单 F 的形状:
In [132]: b.reshape(2,3, order='F')                                                                  
Out[132]:
array([[0, 2, 4], # values still flow in order F
[1, 3, 5]])
In [133]: b.reshape(2,3, order='F')[:,0]
Out[133]: array([0, 1])
确认分配:
In [135]: a.reshape(2,3)[:,0]=10                                                                     
In [136]: a
Out[136]:
array([[10, 1],
[ 2, 10],
[ 4, 5]])
不赋值:
In [137]: b.reshape(2,3)[:,0]=10                                                                     
In [138]: b
Out[138]:
array([[0, 3],
[1, 4],
[2, 5]])
但这里的分配工作:
In [139]: b.reshape(2,3, order='F')[:,0]=10                                                          
In [140]: b
Out[140]:
array([[10, 3],
[10, 4],
[ 2, 5]])
或者我们可以使用订单 A保持秩序:
In [143]: b.reshape(2,3, order='A')[:,0]                                                             
Out[143]: array([10, 10])
In [144]: b.reshape(2,3, order='A')[:,0] = 20
In [145]: b
Out[145]:
array([[20, 3],
[20, 4],
[ 2, 5]])
ufunc 命令
怀疑 ufunc (大部分)是用 nditer 实现的(C 版),我检查了 np.nditer` 文档 - 可以在几个地方指定顺序。并且教程演示了顺序对迭代的影响。
我没看到 order记录于 ufunc ,但是,它被 kwargs 接受.
In [171]: c = np.arange(8).reshape(2,2,2)                                                            
In [172]: d = c.transpose(1,0,2)
In [173]: d.strides
Out[173]: (16, 32, 8)
In [174]: np.multiply(d,d,order='K').strides
Out[174]: (16, 32, 8)
In [175]: np.multiply(d,d,order='C').strides
Out[175]: (32, 16, 8)
In [176]: np.multiply(d,d,order='F').strides
Out[176]: (8, 16, 32)

关于python - 预测 ufunc 输出的内存布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62988794/

28 4 0
文章推荐: angular - typescript :将 json 从 api 调用转换为 Array