我刚开始玩OpenCL,我一直坚持如何以合理有效的方式构建程序(主要是避免大量数据传输到GPU或从GPU传输数据或工作在哪里完成)
我想做的是,给出:
v = r*i + b*j + g*k
..我知道v
有r
,g
和b
的各种值,但i
,j
和{{1}是未知的。我想通过强力计算k
/ i
/ j
的合理值
换句话说,我有一堆“原始”RGB像素值,我有这些颜色的去饱和版本。我不知道使用的权重(i / j / k)计算了去饱和值。
我最初的计划是:
将数据加载到CL缓冲区(因此输入r / g / b值和输出)
有一个内核,它接受三个可能的矩阵值,以及各种像素数据缓冲区。
然后执行k
,并将v = r*i + b*j + g*k
的值减去已知值,并将其存储在“得分”缓冲区中
另一个内核计算该值的RMS误差(如果所有输入值的差值为零,则i / j / k的值为“正确”)
我有这个工作(使用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
答案 0 :(得分:1)
i,j,k是否独立?我认为是的。很少有事情会伤害你的表现:
您可以将两个内核重写为一个,并进行以下更改:
为了做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);
}
之后你将每个线程的my_sum写入本地内存并用reduce(O(log(n))算法加以总结。
将结果保存到全局内存中
或者,如果你需要按顺序计算i,j,k,你可以在OpenCL规范中查找屏障和内存栅栏函数,这样你就可以使用它们而不是运行两个内核,只需记住在第一步中总结一切,写进去全局同步所有线程,然后再次总结
答案 1 :(得分:1)
有两个潜在的问题:
i,j,k
值的评估来解决的问题。要解决(2),请注意求和可以并行计算,但它并不像在输入中的每个像素上单独映射函数那么简单。这是因为求和需要在相邻元素之间传递值,而不是独立地处理所有元素。此模式通常称为 reduction 。
PyOpenCL包含对common reductions的高级支持。你想要的是减少总和:pyopencl.array.sum(array)
。
进一步研究如何在原始OpenCL中实现这一点,Apple的OpenCL文档包括example并行减少总和。与您要执行的操作最相关的部分是the kernel以及host C program which runs the reduction的main
和create_reduction_pass_counts
函数。