【问题标题】:Interaction between numpy arrays of pyOpenCL vector types and numpy arrays of floatspyOpenCL 向量类型的 numpy 数组和浮点数的 numpy 数组之间的交互
【发布时间】:2021-02-18 17:48:19
【问题描述】:

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

但是我发现某些行为不方便。例如给出:

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 的答案是正确的,因为如果我在 shape=(2,) 上使用显式 dtype=float2,它将被转换为 dtype=float2 的 shape=(1,)。 然而,我的实际问题更笼统,关于如何从说一个数组(shape=(foo,bar,N),dtype=np.float32)变成一个数组(shape=(foo,bar),dtype=cltp.floatN ) N=2,3,4。

刚刚出现的后续问题:是否一定会出现实际副本,还是可以“就地”转换?乍一看,实际的内存布局看起来是兼容的。

【问题讨论】:

  • structured arrays 文档页面指向 recfunctions 包。其中有一个unstructured_to_structured 函数。许多recfunctions 通过逐个字段复制值来工作。或者,数据作为元组列表提供给结构化 dtype,就像显示数组一样。

标签: numpy pyopencl


【解决方案1】:
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')})

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

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

虽然您的数组是 2 元素 int。使用这种构造,元组的使用不会改变任何东西。

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 到 1d 结构化:

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)

【讨论】:

  • 谢谢,我编辑了这个问题,因为我意识到我把它过分简化了,为此道歉。不幸的是,这在更一般的情况下不起作用,但我仍然很感激。
猜你喜欢
  • 1970-01-01
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-13
  • 2021-02-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多