【问题标题】:Convert OpenCL Image to pyOpenCL Array or numpy ndarray将 OpenCL 图像转换为 pyOpenCL 数组或 numpy ndarray
【发布时间】:2015-10-16 20:28:25
【问题描述】:

我正在尝试使用 Python 和 PyOpenCL 为我在网上找到的代码中的图像实现高斯过滤器。我的原始图像是 numpy 数组,但我很困惑应该使用哪个将图像传递给 GPU。

最初,内核接收 OpenCL 图像作为输入。这工作正常,内核运行正常,但是,我还没有找到将 GPU 计算(也是 OpenCL 图像)的输出转换为 numpy 数组的方法。这是必需的,因为在运行 GPU 过滤器后我必须执行其他计算。

我尝试使用 pyOpenCL Array,但在这种情况下遇到了 2 个问题:

  1. 不知道如何告诉内核输入将是一个数组,因为它是一个 pyOpenCL 数据结构,而不是 OpenCL 数据结构。
  2. 找不到在 pyOpenCL 数组上使用的 read_imagef 等效项,我在内核中使用了该函数。
  3. 无法将 GPU 结果复制回主机。我会不断收到“cl_array 没有模块 get()”错误。

我想知道:

  1. 有没有办法告诉内核它将接收一个数组,就像我使用image2d_t 说输入是一个图像一样?
  2. 对于 pyOpenCL 数组,我可以使用什么来等效于 OpenCL 的 read_imagef

提前非常感谢。内核代码如下:

内核:

__kernel void gaussian(__read_only image2d_t inputImage,
                        __read_only image2d_t filterImage,
                        __write_only image2d_t outputImage,
                        const int nInWidth,
                        const int nFilterWidth){

const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;

const int xOut = get_global_id(0);
const int yOut = get_global_id(1);

float4 sum = (float4)(0.0, 0.0, 0.0, 1.0);

for(int r = 0; r < nFilterWidth; r++){
    for(int c = 0; c < nFilterWidth; c++){

        int2 location = (xOut + r, yOut + c);

        float4 filterVal = read_imagef(filterImage, sampler, location);
        float4 inputVal = read_imagef(inputImage, sampler, location);

        sum.x += filterVal.x * inputVal.x;
        sum.y += filterVal.y * inputVal.y;
        sum.z += filterVal.z * inputVal.z;
        sum.w = 1.0;
    }
}

int2 outLocation = (xOut, yOut);
write_imagef(outputImage, outLocation, sum);
}

【问题讨论】:

    标签: numpy opencl pyopencl


    【解决方案1】:

    这是一个复杂的问题,因为我遇到了同样的问题,所以我想尝试详细回答它们。让我们将您的问题分解为更小的部分,看看发生了什么。

    数据类型

    您似乎混淆了一些相互混淆的数据类型。 OpenCL 本身使用 imagesarrays,一个 pyopenCL 数组 映射到 OpenCL 中的一个数组,pyopenCL 图像也是如此> 到 OpenCL 图像。将这两者混合在某些特殊情况下会起作用,但总的来说,这不是一个好主意。

    数据访问

    OpenCL 中的图像需要一个采样器才能从中读取。数组可以通过简单的坐标访问来访问,就像在 python 中一样。 (有关我在那里遇到的问题的更多信息,请参阅herehere...)。

    运动

    使用 pyopencl 在 OpenCL 中移动的所有内容都有自己的复制功能。因此,要将图像或数组从设备移动到主机,请务必将相应的复制函数排入您的上下文中的队列中。

    【讨论】:

      【解决方案2】:

      pyopencl.Array 的底层 OpenCl 数据结构是所谓的缓冲区。您可以通过数组的base_data 属性检索缓冲区对象(请参阅the docs)。缓冲区可以在内核调用中传递,但是必须调整内核以处理缓冲区而不是图像(将内核参数类型更改为__global float* inputImage 等,访问元素就像在常规多维数组索引中一样)。

      无论如何,PyOpenCL Array 类旨在使用 numpy 样式编写将在设备上执行的代码。这不再需要您自己编写任何内核代码。相反,您可以这样做:

      import pyopencl as cl
      input_array = cl.array.to_device(queue, input_numpy_array)
      filter_array = cl.array.to_device(queue, filter_numpy_array)
      output_array = cl.array.zeros_like(input_array)
      # half height and half width of filter
      fhh, fhw = filter_array.shape[0] // 2, filter_array.shape[1] // 2
      for y in range(input_array.shape[0]):
          for x in range(input_array.shape[1]):
                  patch = input_array[y-fhh:y+fhh+1, x-fhw:x+fhw+1]
              sum = cl.array.sum(patch * filter_array)
              output_array[y, x] = sum
      output_numpy_array = output_array.get()
      

      请注意,我假设使用的是单通道(灰色)图像。我也没有测试上面的代码,但我认为实现非常无效。边缘处理不包括在内。

      最后,考虑到您的内核,您应该考虑使用 PyOpenCl 数组。从您的 numpy 数组创建 pyopencl.Image 对象并将它们传递给内核调用。这样,您不必修改内核。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-10-05
        • 2018-08-22
        • 2017-06-25
        • 1970-01-01
        • 1970-01-01
        • 2017-12-14
        • 2015-08-07
        相关资源
        最近更新 更多