【发布时间】:2017-04-02 13:27:43
【问题描述】:
我从上个月开始学习卤化物。 终于遇到了大问题。
我正在尝试在 Halide 中实现类似 C 类代码的功能。
for( int y = 0; y < 3; ++y ){
for( int x = 0; x < 3; ++x ){
out(x, y) = out(x-1, y-1) + 1;
}
}
所以假设初始图像如下。
0 0 0
0 0 0
0 0 0
输出图像将是……(0 超出范围)
1 1 1
1 2 2
1 2 3
所以我想到了两种可能的解决方案。
・解决方案1
将上述算法定义为这样的递归函数。
Func algorithm1(Func input, int n)
{
Func src, clamped, dst;
Var x, y;
if(n == 1){
src = input;
}else{
src = algorithm1(input, n-1);
src.compute_root();
}
clamped = BoundaryConditions::constant_exterior(src, 0, 0, SIZE, 0, SIZE);
dst(x, y) = clamped(x-1, y-1) + 1;
return dst;
}
并像下面的代码一样使用上面的函数。
Func input, output;
input(x, y) = src(x, y);
output = algorithm1(input, SIZE);
output.realize(src);
这个实现几乎没有用。但显然是退票。 因为每个阶段(Func)的大部分计算结果都与最终结果不匹配,尽管每个 Func 都在整个图像上进行计算。 我需要处理更多的大(正常)图像。 所以我想到了另一种可能的解决方案。
・解决方案2
第二个解决方案的第一个。
声明一个函数来定义一列和另一列之间的关系。
Func algorithm2(Func src)
{
Func clamped, dst;
Var x;
clamped = BoundaryConditions::constant_exterior(src, 0, 0, SIZE);
dst(x) = clamped(x-1) + 1;
return dst;
}
那么,让我们把这个结合起来吧。
Func output[3];
output[0](x) = cast<uint32_t>(0);
for(int i = 1; i < SIZE; ++i){
output[i] = algorithm2(output[i-1]);
}
好吧...问题来了。如何将这组 Func 组合成一个 Func?
当然,如果我在每个函数中实现这个函数数组指向列头的指针,我可以获得一个图像。但是如果我想将它传递给下一个 Func 怎么办?
这些天,我查看了整个 Halide 示例(测试、应用程序)。但我认为没有类似的例子。 你可能已经注意到我对英语的不适,实际上我是日本人。所以如果有这个问题的有用例子,我很抱歉提前。如果是这样,请告诉我它在哪里。如果还有其他好的实现思路,请教我。无论如何,我需要别人的帮助!
感谢您的阅读。
[编辑 2]
edit 1 是我的愚蠢问题。我可以安排它compute_root()。 我决定把它们留在这里,虽然真的很尴尬。 我希望这对另一个愚蠢的人有所帮助。
[编辑 1]
衷心感谢您快速而详细的回复!
很抱歉回复晚了,我想在成功实现我的算法后回复你。但是,我的 Halide 代码仍然无法正常工作,并且需要确认一些事情。
首先,我想告诉你,感谢你,我意识到我对 Halide 的误解。在我的算法实现步骤的第一步,我只使用纯“Var”来编写定义。 所以我得到了以下错误。
All of a functions recursive references to itself must contain the same pure variables in the same places as on the left-hand-side.
我认为发生此错误是因为日程安排的灵活性。如果允许这样的定义并且调度它分裂,这意味着调度改变算法。这种理解正确吗?从这样的理解来看,虽然我已经阅读了教程和模糊示例的缩减部分,但我误解了我无法访问所有 Func 定义中的相邻像素。我不知道为什么。
由于同样的原因,无法拆分归约域。我想我现在明白了。
这是您的代码的另一个问题。感谢您的 Halide 实施示例,我几乎成功地实施了我想做的事而不加考虑。但是,尽管我正在处理 20x20 的裁剪图像以便于调试,但这个实现速度非常慢。
我认为这种缓慢是由缩减域引起的。在您的示例中,例如在计算值 g(10, 10) 时,卤化物计算被安排从 f(0, 0) 到 f(0, 0) 并最终获得该值。另一方面,C 实现只是加载 g(9, 9) 处的值并增加它。我们可以通过打印循环嵌套来确认这样的计算。
produce g:
for y:
for x:
produce f:
for y:
for x:
f(...) = ...
for range:
for range:
f(...) = ...
consume f:
g(...) = ...
我想确认避免这种重新计算是不可能的?所以你建议的?
我想问你另一个简单的问题。如果有这样的反向依赖,
for( int y = 2; y > 0; --y ){
for( int x = 2; x > 0; --x ){
out(x, y) = out(x+1, y+1) + 1;
}
}
Halide 能表达这个代码吗?
【问题讨论】:
标签: halide