pyOpenCL向量类型的numpy数组与浮点数的numpy数组之间的交互



我发现同时使用结构体和np非常方便。ndarray使用dtypes,如pyopencl.cltypes.float2。这是一种清晰且自我记录的方式,可以将结构化数据传递给我的内核,而不仅仅是一堆浮点数。

然而,我发现某些行为不方便。例如给定:

import numpy as np
import pyopencl.cltypes as cltp
a = np.zeros((3,5), dtype=cltp.float2)

>>> a
array([[(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)],
[(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)],
[(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)]],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])

在将数据结构传递给内核之前,我可以分段地构建数据结构,例如:

a[:,1] = (42,-42)
>>> a
array([[( 0.,   0.), (42., -42.), ( 0.,   0.), ( 0.,   0.), ( 0.,   0.)],
[( 0.,   0.), (42., -42.), ( 0.,   0.), ( 0.,   0.), ( 0.,   0.)],
[( 0.,   0.), (42., -42.), ( 0.,   0.), ( 0.,   0.), ( 0.,   0.)]],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])

很好。然而,我也想将大小为2的数组赋值给float2,但这失败了。

a[:,1] = np.array((42,-42))
ValueError: could not broadcast input array from shape (2) into shape (3)

,我不得不求助于这个

a[:,1]['x'] = 42
a[:,1]['y'] = -42

可以工作,但是有点违背了整个事情的目的。

我错过了一些明显的语法差异,还是这个功能只是不应该这样使用?

编辑:在我试图给出最简单的例子时,我过度简化了这个问题。hpaulj的答案是正确的,因为如果我在形状=(2)的东西上使用显式dtype=float2,它将被转换为形状=(1,)的dtype=float2。然而,我的实际问题更一般,关于如何从一个数组(shape=(foo, bar, N), dtype=np.float32)到一个数组(shape=(foo, bar), dtype=cltp.floatN), N=2,3,4。

刚才出现的后续问题:是否需要进行实际的复制,或者是否可以"就地"转换?实际的内存布局乍一看是兼容的。

In [99]: a=np.array([[(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)],
...:        [(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)],
...:        [(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)]],
...:        dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
In [100]: a.dtype
Out[100]: dtype([(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
In [101]: a.dtype.fields
Out[101]: 
mappingproxy({'s0': (dtype('float32'), 0, 'x'),
'x': (dtype('float32'), 0, 'x'),
's1': (dtype('float32'), 4, 'y'),
'y': (dtype('float32'), 4, 'y')})

看一下预期的目标,一个3个元素的数组,复合dtype:

In [102]: a[:,1]
Out[102]: 
array([(0., 0.), (0., 0.), (0., 0.)],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])

当你的数组是2个元素的整型时。对于这种结构,使用元组不会改变任何东西。

In [103]: np.array((42,-42))
Out[103]: array([ 42, -42])

但是如果指定了正确的dtype,则创建了一个0d数组:

In [104]: np.array((42,-42), a.dtype)
Out[104]: array((42., -42.), dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])

现在赋值是没有问题的

In [105]: a[:,1] = np.array((42,-42), a.dtype)

编辑

In [3]: dt = a.dtype
In [4]: dt
Out[4]: dtype([(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])

使用最近的recfunctions添加,我们可以从形状适当的非结构化数组中生成结构化数组:

In [5]: import numpy.lib.recfunctions as rf    

2d to 1d structured:

In [7]: rf.unstructured_to_structured(np.arange(1,7).reshape(3,2), dtype=dt)
Out[7]: 
array([(1., 2.), (3., 4.), (5., 6.)],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])

3d到2d结构:

In [8]: rf.unstructured_to_structured(np.arange(24).reshape(4,3,2), dtype=dt)
Out[8]: 
array([[( 0.,  1.), ( 2.,  3.), ( 4.,  5.)],
[( 6.,  7.), ( 8.,  9.), (10., 11.)],
[(12., 13.), (14., 15.), (16., 17.)],
[(18., 19.), (20., 21.), (22., 23.)]],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])

或者从元组列表创建数组:

In [10]: np.array([(0,1),(2,3)], dt)
Out[10]: 
array([(0., 1.), (2., 3.)],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])

recfunctions经常使用逐字段设置:

In [16]: for name in a.dtype.names:
...:     a[name][:] = np.arange(15).reshape(3,5)

最新更新