有什么方法可以将 Funds 组合成一个具有更多维度的 Function 吗?
Is there any way to combine Funcs into a Func has one more dimension?
我从上个月开始学习Halide。
终于遇到大问题了
我正在尝试在 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 处实现这个 Funcs 数组指向列头的指针,我可以获得一个图像。但是如果我想把它传给下一个Func呢?
这些天我查看了整个 Halide 示例(测试、应用程序)。但我认为没有类似的例子。
你可能已经注意到我对英语的不适,实际上我是日本人。所以如果这个问题有有用的例子,我很抱歉。如果是这样,请告诉我它在哪里。如果还有其他好的实现思路,请教教我。不管怎样,我需要别人的帮助!
感谢您的阅读。
[编辑 2]
编辑 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) 时,Halide 计算从 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 可以表达这个代码吗?
这里的algorithm1和algorithm2部分我不是很清楚。我理解最初的问题陈述并且英语看起来不错,所以我会努力提供一些帮助来回答我认为你问的问题。我将通过说明一些您可能不知道或在这里使用起来不明显的 Halide 机制来做到这一点。希望这会有所帮助。
首先,要将 Halide Func 的维度映射到不同的表达式,您几乎必须使用 select 语句:
Var x, y, n;
Func f_0, f_1, f_both;
f_0(x, y) = ...;
f_1(x, y) = ...;
f_both(x, y, n) = select(n == 0, f_zero, f_one);
这可以通过向 select
添加参数来扩展到更多情况。这对于分段计算比递归结构更有用,但似乎是标题中问题的最直接答案。
第二种机制是Tuple
。这允许 Func 具有多个值,这些值可以用编译时常量进行索引。我认为这不是您正在寻找的答案,但我在 tutorial/lesson_13_tuples.cpp .
中找到了答案
最后,Halide 支持归约,旨在处理第一个代码示例中的情况。看起来像这样:
Var x, y;
Func f, g;
RDom range(0, 3, 0, 3); // Form is min/extent, not start/end
f(x, y) = 0; // Initial condition
f(range.x, range.y) = f(range.x - 1, range.y - 1) + 1;
g(x, y) = f(x, y);
Buffer<int32t> result = g.realize(3, 3);
这应该会产生第一个示例的输出。减少,或 "update definitions" 包含在 tutorial/lesson_09_update_definitions.cpp .
中
我从上个月开始学习Halide。 终于遇到大问题了
我正在尝试在 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 处实现这个 Funcs 数组指向列头的指针,我可以获得一个图像。但是如果我想把它传给下一个Func呢?
这些天我查看了整个 Halide 示例(测试、应用程序)。但我认为没有类似的例子。 你可能已经注意到我对英语的不适,实际上我是日本人。所以如果这个问题有有用的例子,我很抱歉。如果是这样,请告诉我它在哪里。如果还有其他好的实现思路,请教教我。不管怎样,我需要别人的帮助!
感谢您的阅读。
[编辑 2]
编辑 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) 时,Halide 计算从 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 可以表达这个代码吗?
这里的algorithm1和algorithm2部分我不是很清楚。我理解最初的问题陈述并且英语看起来不错,所以我会努力提供一些帮助来回答我认为你问的问题。我将通过说明一些您可能不知道或在这里使用起来不明显的 Halide 机制来做到这一点。希望这会有所帮助。
首先,要将 Halide Func 的维度映射到不同的表达式,您几乎必须使用 select 语句:
Var x, y, n;
Func f_0, f_1, f_both;
f_0(x, y) = ...;
f_1(x, y) = ...;
f_both(x, y, n) = select(n == 0, f_zero, f_one);
这可以通过向 select
添加参数来扩展到更多情况。这对于分段计算比递归结构更有用,但似乎是标题中问题的最直接答案。
第二种机制是Tuple
。这允许 Func 具有多个值,这些值可以用编译时常量进行索引。我认为这不是您正在寻找的答案,但我在 tutorial/lesson_13_tuples.cpp .
最后,Halide 支持归约,旨在处理第一个代码示例中的情况。看起来像这样:
Var x, y;
Func f, g;
RDom range(0, 3, 0, 3); // Form is min/extent, not start/end
f(x, y) = 0; // Initial condition
f(range.x, range.y) = f(range.x - 1, range.y - 1) + 1;
g(x, y) = f(x, y);
Buffer<int32t> result = g.realize(3, 3);
这应该会产生第一个示例的输出。减少,或 "update definitions" 包含在 tutorial/lesson_09_update_definitions.cpp .
中