0

侵食関数の実行時間を短縮しようとしていますが、図に示すようにタイルで問題を分割しようとすると、実際には実行が遅くなります。

浸食時間差

スケジューリングなしの私のコードは次のとおりです。

Halide::Image<uint8_t> erode(Halide::Image<uint8_t> input, int dimension) {
Halide::Var x("x"), y("y");
Halide::Image<uint8_t> output;
Halide::Func limit("limit"), e("e");
limit = Halide::BoundaryConditions::repeat_edge(input);
Halide::RDom r(dimension*-1 / 2, dimension, dimension*-1 / 2, dimension);
e(x, y) = limit(x, y);
e(x, y) = Halide::min(limit(x + r.x, y + r.y), e(x, y));
output = e.realize(input.width(), input.height());
return output;
}

タイリングを試みた私のコード(チュートリアルに示されている例を使用しようとしました):

Halide::Image<uint8_t> erodeTiling(Halide::Image<uint8_t> input, int dimension) {
Halide::Var x("x"), y("y"), x_outer, x_inner, y_outer, y_inner, tile_index;
Halide::Image<uint8_t> output;
Halide::Func limit("limit"), e("e");
limit = Halide::BoundaryConditions::repeat_edge(input);
Halide::RDom r(dimension*-1 / 2, dimension, dimension*-1 / 2, dimension);
e(x, y) = limit(x, y);
e(x, y) = Halide::min(limit(x + r.x, y + r.y), e(x, y));
e.tile(x, y, x_outer, y_outer, x_inner, y_inner, 64,64).fuse(x_outer, y_outer, tile_index).parallel(tile_index);
output = e.realize(input.width(), input.height());
return output;
}

私はまだこれに非常に慣れていないので、適切にスケジュールする方法に関するヒントは大歓迎です。

編集:時間を取得するために使用されるコード:

__int64 ctr1 = 0, ctr2 = 0, freq = 0;
output = erode(input, dimension);


if (QueryPerformanceCounter((LARGE_INTEGER *)&ctr1) != 0) {
    // Activity to be timed
    output = erode(input, dimension);
    QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
    QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
}
std::cout << "\nerosion " << dimension << "x" << dimension << ":" << ((ctr2 - ctr1) *1.0 / freq) << "..."; 
ctr1 = 0, ctr2 = 0, freq = 0;
4

1 に答える 1

1

ここでの大きな問題の 1 つは、イメージを侵食するたびにイメージング パイプラインを再コンパイルしていることです。入力に ​​ImageParam を使用し、ディメンションに Param を使用する場合、一度コンパイルするだけで、異なる画像で複数回実現できます。

それはさておき、スケジューリングは Func のステージごとに独立して行われます。Func には 2 つのステージがあり ("e(x, y) =" で始まる各行はステージです)、最初の (安い) ステージのみをスケジュールしています。次のようにして、初期化と更新の両方を同じ方法でスケジュールします。

e.tile(x, y, x_outer, y_outer, x_inner, y_inner, 64,64).fuse(x_outer, y_outer, tile_index).parallel(tile_index);
e.update(0).tile(x, y, x_outer, y_outer, x_inner, y_inner, 64,64).fuse(x_outer, y_outer, tile_index).parallel(tile_index);

次元が 3 より大きい場合は、おそらく分離可能な最小フィルターが必要です。私は次のように書きます:

Func minx, miny;
miny(x, y) = minimum(limit(x, y+r));
minx(x, y) = minimum(miny(x+r, y));

minx.parallel(y, 4).vectorize(x, 32);
miny.compute_at(minx, y).vectorize(x, 32);
于 2016-06-29T16:47:28.023 に答える