如何构建此OpenCL强制代码

时间:2011-08-31 14:56:45

标签: python algorithm opencl brute-force

我刚开始玩OpenCL,我一直坚持如何以合理有效的方式构建程序(主要是避免大量数据传输到GPU或从GPU传输数据或工作在哪里完成)

我想做的是,给出:

v = r*i + b*j + g*k

..我知道vrgb的各种值,但ij和{{1}是未知的。我想通过强力计算k / i / j的合理值

换句话说,我有一堆“原始”RGB像素值,我有这些颜色的去饱和版本。我不知道使用的权重(i / j / k)计算了去饱和值。

我最初的计划是:

  1. 将数据加载到CL缓冲区(因此输入r / g / b值和输出)

  2. 有一个内核,它接受三个可能的矩阵值,以及各种像素数据缓冲区。

    然后执行k,并将v = r*i + b*j + g*k的值减去已知值,并将其存储在“得分”缓冲区中

  3. 另一个内核计算该值的RMS误差(如果所有输入值的差值为零,则i / j / k的值为“正确”)

  4. 我有这个工作(使用Python和PyCL编写,the code is here),但我想知道如何更多地并行化这一部分工作(通过一次尝试多个i / j / k值)

    我问的是,我有4个只读缓冲区(3个用于输入值,1个用于期望值),但我需要为每个i / j / k组合单独的“得分”缓冲区

    另一个问题是RMS计算是最慢的部分,因为它实际上是单线程的(总计“得分”中的所有值和总数的sqrt())

    基本上,我想知道是否有一种合理的方式来构建这样的程序。

    这似乎是一个非常适合OpenCL的任务 - 希望我的目标描述不是太复杂!如上所述,my current code is here,如果它更清楚,这是我正在尝试做的Python版本:

    v

2 个答案:

答案 0 :(得分:1)

i,j,k是否独立?我认为是的。很少有事情会伤害你的表现:

  1. 运行太多小内核
  2. 使用全局内存进行score_matrix和rm_to_rms之间的通信
  3. 您可以将两个内核重写为一个,并进行以下更改:

    1. 使一个OpenCL工作组可以在不同的i,j,k上工作 - 你可以在CPU上预先生成它
    2. 为了做1,你需要用一个线程处理多个数组元素,你可以这样做:

      int i = get_thread_id(0);
      float my_sum = 0;
      
      for (; i < array_size; i += get_local_size(0)){
          float val = in_r[i] * mtx_r + in_g[i] * mtx_g + in_b[i] * mtx_b;
          my_sum += pow(fabs(expect_r[i] - val), 2);
      }
      
    3. 之后你将每个线程的my_sum写入本地内存并用reduce(O(log(n))算法加以总结。

    4. 将结果保存到全局内存中

    5. 或者,如果你需要按顺序计算i,j,k,你可以在OpenCL规范中查找屏障和内存栅栏函数,这样你就可以使用它们而不是运行两个内核,只需记住在第一步中总结一切,写进去全局同步所有线程,然后再次总结

答案 1 :(得分:1)

有两个潜在的问题:

  1. 如果处理每个图像所需的工作量很小,则内核启动开销可能会很大。这是您将通过在单个内核中组合多个i,j,k值的评估来解决的问题。
  2. RMSE的总和计算的序列化。目前这可能是一个更大的问题。
  3. 要解决(2),请注意求和可以并行计算,但它并不像在输入中的每个像素上单独映射函数那么简单。这是因为求和需要在相邻元素之间传递值,而不是独立地处理所有元素。此模式通常称为 reduction

    PyOpenCL包含对common reductions的高级支持。你想要的是减少总和:pyopencl.array.sum(array)

    进一步研究如何在原始OpenCL中实现这一点,Apple的OpenCL文档包括example并行减少总和。与您要执行的操作最相关的部分是the kernel以及host C program which runs the reductionmaincreate_reduction_pass_counts函数。