Halide示例学习二

Halide代码优化思想简述 Halide是一种编程语言,主要在图片处理和矩阵计算时具有方便快捷高性能的特点。它不是一种独立语言,而是基于C++的DSL(Domain Specified Language),主要应用在算法的底层加... 阅读详情

默认的维度计算顺序

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    // 该示例演示了如何观察计算的维度变化顺序以及如何改变计算顺序
    Var x("x"), y("y");
    // 首先来观察一个默认的计算顺序
    Func gradient("gradient");
    gradient(x, y) = x + y;
    gradient.trace_stores();

    /* 一般地,图像中x表示列,y表示行
        那么一般是先遍历一行,也就是从左往右,从上往下的遍历顺序
        columns-列,rows-行
        行-列遍历计算顺序
    */
    printf("Evaluating gradient row-major\n");
    Buffer<int> output = gradient.realize({4, 4});
    // 等价的C代码如下所示:
    printf("Equivalent C:\n");
    for (int y = 0; y < 4; y++) {
        for (int x = 0; x < 4; x++) {
            printf("Evaluating at x = %d, y = %d: %d\n", x, y, x + y);
        }
    }
    printf("\n\n");

    // 使用print_loop_nest函数可以打印出怎样的调度信息和循环嵌套
    printf("Pseudo-code for the schedule:\n");
    gradient.print_loop_nest();
    printf("\n");
    // 上述将会打印出如下所示的调度信息
    // compute gradient:
    //   for y:
    //     for x:
    //       gradient(...) = ...
    return 0;
}
# 运行结果如下所示:
Begin pipeline gradient.0()
Tag gradient.0() tag = "func_type_and_dim: 1 0 32 1 2 0 4 0 4"
Store gradient.0(0, 0) = 0
Store gradient.0(1, 0) = 1
Store gradient.0(2, 0) = 2
Store gradient.0(3, 0) = 3
Store gradient.0(0, 1) = 1
Store gradient.0(1, 1) = 2
Store gradient.0(2, 1) = 3
Store gradient.0(3, 1) = 4
Store gradient.0(0, 2) = 2
Store gradient.0(1, 2) = 3
Store gradient.0(2, 2) = 4
Store gradient.0(3, 2) = 5
Store gradient.0(0, 3) = 3
Store gradient.0(1, 3) = 4
Store gradient.0(2, 3) = 5
Store gradient.0(3, 3) = 6
End pipeline gradient.0()
Evaluating gradient row-major
Equivalent C:
Evaluating at x = 0, y = 0: 0
Evaluating at x = 1, y = 0: 1
Evaluating at x = 2, y = 0: 2
Evaluating at x = 3, y = 0: 3
Evaluating at x = 0, y = 1: 1
Evaluating at x = 1, y = 1: 2
Evaluating at x = 2, y = 1: 3
Evaluating at x = 3, y = 1: 4
Evaluating at x = 0, y = 2: 2
Evaluating at x = 1, y = 2: 3
Evaluating at x = 2, y = 2: 4
Evaluating at x = 3, y = 2: 5
Evaluating at x = 0, y = 3: 3
Evaluating at x = 1, y = 3: 4
Evaluating at x = 2, y = 3: 5
Evaluating at x = 3, y = 3: 6


Pseudo-code for the schedule:
produce gradient:
  for y:
    for x:
      gradient(...) = ...

维度顺序重排操作

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    Func gradient("gradient_col_major");
    Var x,y;
    gradient(x, y) = x + y;
    gradient.trace_stores();

    // 我们可以通过reorder类方法来进行调度的重排
    gradient.reorder(y, x);
    // 上述交换了x和y这两个轴的计算先后顺序
    // 也就是说现在是列-行的计算顺序
    printf("Evaluating gradient column-major\n");
    Buffer<int> output = gradient.realize({4, 4});
    // 以下是等效的C代码
    printf("Equivalent C:\n");
    for (int x = 0; x < 4; x++) {
        for (int y = 0; y < 4; y++) {
            printf("Evaluating at x = %d, y = %d: %d\n", x, y, x + y);
        }
    }
    printf("\n");
    printf("Pseudo-code for the schedule:\n");
    gradient.print_loop_nest();
    printf("\n");
    return 0;
}

#运行结果如下所示
Begin pipeline gradient_col_major.0()
Tag gradient_col_major.0() tag = "func_type_and_dim: 1 0 32 1 2 0 4 0 4"
Store gradient_col_major.0(0, 0) = 0
Store gradient_col_major.0(0, 1) = 1
Store gradient_col_major.0(0, 2) = 2
Store gradient_col_major.0(0, 3) = 3
Store gradient_col_major.0(1, 0) = 1
Store gradient_col_major.0(1, 1) = 2
Store gradient_col_major.0(1, 2) = 3
Store gradient_col_major.0(1, 3) = 4
Store gradient_col_major.0(2, 0) = 2
Store gradient_col_major.0(2, 1) = 3
Store gradient_col_major.0(2, 2) = 4
Store gradient_col_major.0(2, 3) = 5
Store gradient_col_major.0(3, 0) = 3
Store gradient_col_major.0(3, 1) = 4
Store gradient_col_major.0(3, 2) = 5
Store gradient_col_major.0(3, 3) = 6
End pipeline gradient_col_major.0()

Evaluating gradient column-major
Equivalent C:
Evaluating at x = 0, y = 0: 0
Evaluating at x = 0, y = 1: 1
Evaluating at x = 0, y = 2: 2
Evaluating at x = 0, y = 3: 3
Evaluating at x = 1, y = 0: 1
Evaluating at x = 1, y = 1: 2
Evaluating at x = 1, y = 2: 3
Evaluating at x = 1, y = 3: 4
Evaluating at x = 2, y = 0: 2
Evaluating at x = 2, y = 1: 3
Evaluating at x = 2, y = 2: 4
Evaluating at x = 2, y = 3: 5
Evaluating at x = 3, y = 0: 3
Evaluating at x = 3, y = 1: 4
Evaluating at x = 3, y = 2: 5
Evaluating at x = 3, y = 3: 6

Pseudo-code for the schedule:
produce gradient_col_major:
  for x:
    for y:
      gradient_col_major(...) = ...

维度拆分

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    Var x,y;
    Func gradient("gradient_split");
    gradient(x, y) = x + y;
    gradient.trace_stores();
    // 以下的split进行了单层循环到多层循环嵌套的变化
    Var x_outer, x_inner;
    gradient.split(x, x_outer, x_inner, 2);
    /* 以下的C代码展示了相应的循环嵌套转换结果
        原始的x_dim=x_outer*factor+x_inner
    */
    printf("Evaluating gradient with x split into x_outer and x_inner \n");
    Buffer<int> output = gradient.realize({4, 4});

    printf("Equivalent C:\n");
    for (int y = 0; y < 4; y++) {
        for (int x_outer = 0; x_outer < 2; x_outer++) {
            for (int x_inner = 0; x_inner < 2; x_inner++) {
                int x = x_outer * 2 + x_inner;
                printf("Evaluating at x = %d, y = %d: %d\n", x, y, x + y);
            }
        }
    }
    printf("\n");

    printf("Pseudo-code for the schedule:\n");
    /* 打印出来的结果如下所示:
    produce gradient_split:
    for y:
        for x.v0:
        for x.v1 in [0, 1]:
            gradient_split(...) = ...
    */
    gradient.print_loop_nest();
    printf("\n");
    /*
    说明:尽管进行了维度拆分,但是并没有影响那个像素点的计算顺序
    */
    return 0;
}

#运行结果如下所示
Begin pipeline gradient_split.0()
Tag gradient_split.0() tag = "func_type_and_dim: 1 0 32 1 2 0 4 0 4"
Store gradient_split.0(0, 0) = 0
Store gradient_split.0(1, 0) = 1
Store gradient_split.0(2, 0) = 2
Store gradient_split.0(3, 0) = 3
Store gradient_split.0(0, 1) = 1
Store gradient_split.0(1, 1) = 2
Store gradient_split.0(2, 1) = 3
Store gradient_split.0(3, 1) = 4
Store gradient_split.0(0, 2) = 2
Store gradient_split.0(1, 2) = 3
Store gradient_split.0(2, 2) = 4
Store gradient_split.0(3, 2) = 5
Store gradient_split.0(0, 3) = 3
Store gradient_split.0(1, 3) = 4
Store gradient_split.0(2, 3) = 5
Store gradient_split.0(3, 3) = 6
End pipeline gradient_split.0()

Evaluating gradient with x split into x_outer and x_inner 
Equivalent C:
Evaluating at x = 0, y = 0: 0
Evaluating at x = 1, y = 0: 1
Evaluating at x = 2, y = 0: 2
Evaluating at x = 3, y = 0: 3
Evaluating at x = 0, y = 1: 1
Evaluating at x = 1, y = 1: 2
Evaluating at x = 2, y = 1: 3
Evaluating at x = 3, y = 1: 4
Evaluating at x = 0, y = 2: 2
Evaluating at x = 1, y = 2: 3
Evaluating at x = 2, y = 2: 4
Evaluating at x = 3, y = 2: 5
Evaluating at x = 0, y = 3: 3
Evaluating at x = 1, y = 3: 4
Evaluating at x = 2, y = 3: 5
Evaluating at x = 3, y = 3: 6

Pseudo-code for the schedule:
produce gradient_split:
  for y:
    for x.v0:
      for x.v1 in [0, 1]:
        gradient_split(...) = ...

维度融合

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    Var x,y;
    Func gradient("gradient_fused");
    gradient(x, y) = x + y;

    // 维度拆分的反例就是维度融合
    // 通过融合可以把双循环变成单循环,同时像素点的计算顺序不变
    Var fused;
    gradient.fuse(x, y, fused);
    printf("Evaluating gradient with x and y fused\n");
    Buffer<int> output = gradient.realize({4, 4});
    printf("Equivalent C:\n");
    for (int fused = 0; fused < 4 * 4; fused++) {
        int y = fused / 4;
        int x = fused % 4;
        printf("Evaluating at x = %d, y = %d: %d\n", x, y, x + y);
    }
    printf("\n");
    printf("Pseudo-code for the schedule:\n");
    gradient.print_loop_nest();
    printf("\n");
    return 0;
}

#运行结果如下所示
Evaluating gradient with x and y fused
Equivalent C:
Evaluating at x = 0, y = 0: 0
Evaluating at x = 1, y = 0: 1
Evaluating at x = 2, y = 0: 2
Evaluating at x = 3, y = 0: 3
Evaluating at x = 0, y = 1: 1
Evaluating at x = 1, y = 1: 2
Evaluating at x = 2, y = 1: 3
Evaluating at x = 3, y = 1: 4
Evaluating at x = 0, y = 2: 2
Evaluating at x = 1, y = 2: 3
Evaluating at x = 2, y = 2: 4
Evaluating at x = 3, y = 2: 5
Evaluating at x = 0, y = 3: 3
Evaluating at x = 1, y = 3: 4
Evaluating at x = 2, y = 3: 5
Evaluating at x = 3, y = 3: 6

Pseudo-code for the schedule:
produce gradient_fused:
  for x.v2:
    gradient_fused(...) = ...

维度平铺

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    //平铺操作,类似于取一个图像中相邻的几个像素点的操作,比较像卷积操作
    Var x,y;
    Func gradient("gradient_tiled");
    gradient(x, y) = x + y;
    gradient.trace_stores();

    // 平铺可以是维度拆分+循环重排的组合技能
    Var x_outer, x_inner, y_outer, y_inner;
    gradient.split(x, x_outer, x_inner, 4);
    gradient.split(y, y_outer, y_inner, 4);
    gradient.reorder(x_inner, y_inner, x_outer, y_outer);
    // 使用tile接口就是如下所示的操作
    // gradient.tile(x, y, x_outer, y_outer, x_inner, y_inner, 4, 4);
    printf("Evaluating gradient in 4x4 tiles\n");
    Buffer<int> output = gradient.realize({8, 8});
    // 示意图可以查看lesson_05_tiled.gif
    printf("Equivalent C:\n");
    for (int y_outer = 0; y_outer < 2; y_outer++) {
        for (int x_outer = 0; x_outer < 2; x_outer++) {
            for (int y_inner = 0; y_inner < 4; y_inner++) {
                for (int x_inner = 0; x_inner < 4; x_inner++) {
                    int x = x_outer * 4 + x_inner;
                    int y = y_outer * 4 + y_inner;
                    printf("Evaluating at x = %d, y = %d: %d\n", x, y, x + y);
                }
            }
        }
    }
    printf("\n");
    printf("Pseudo-code for the schedule:\n");
    gradient.print_loop_nest();
    printf("\n");
    return 0;
}

结果的动态展示图如下所示:

在这里插入图片描述

#运行结果如下所示
Begin pipeline gradient_tiled.0()
Tag gradient_tiled.0() tag = "func_type_and_dim: 1 0 32 1 2 0 8 0 8"
Store gradient_tiled.0(0, 0) = 0
Store gradient_tiled.0(1, 0) = 1
Store gradient_tiled.0(2, 0) = 2
Store gradient_tiled.0(3, 0) = 3
Store gradient_tiled.0(0, 1) = 1
Store gradient_tiled.0(1, 1) = 2
Store gradient_tiled.0(2, 1) = 3
Store gradient_tiled.0(3, 1) = 4
Store gradient_tiled.0(0, 2) = 2
Store gradient_tiled.0(1, 2) = 3
Store gradient_tiled.0(2, 2) = 4
Store gradient_tiled.0(3, 2) = 5
Store gradient_tiled.0(0, 3) = 3
Store gradient_tiled.0(1, 3) = 4
Store gradient_tiled.0(2, 3) = 5
Store gradient_tiled.0(3, 3) = 6
Store gradient_tiled.0(4, 0) = 4
Store gradient_tiled.0(5, 0) = 5
Store gradient_tiled.0(6, 0) = 6
Store gradient_tiled.0(7, 0) = 7
Store gradient_tiled.0(4, 1) = 5
Store gradient_tiled.0(5, 1) = 6
Store gradient_tiled.0(6, 1) = 7
Store gradient_tiled.0(7, 1) = 8
Store gradient_tiled.0(4, 2) = 6
Store gradient_tiled.0(5, 2) = 7
Store gradient_tiled.0(6, 2) = 8
Store gradient_tiled.0(7, 2) = 9
Store gradient_tiled.0(4, 3) = 7
Store gradient_tiled.0(5, 3) = 8
Store gradient_tiled.0(6, 3) = 9
Store gradient_tiled.0(7, 3) = 10
Store gradient_tiled.0(0, 4) = 4
Store gradient_tiled.0(1, 4) = 5
Store gradient_tiled.0(2, 4) = 6
Store gradient_tiled.0(3, 4) = 7
Store gradient_tiled.0(0, 5) = 5
Store gradient_tiled.0(1, 5) = 6
Store gradient_tiled.0(2, 5) = 7
Store gradient_tiled.0(3, 5) = 8
Store gradient_tiled.0(0, 6) = 6
Store gradient_tiled.0(1, 6) = 7
Store gradient_tiled.0(2, 6) = 8
Store gradient_tiled.0(3, 6) = 9
Store gradient_tiled.0(0, 7) = 7
Store gradient_tiled.0(1, 7) = 8
Store gradient_tiled.0(2, 7) = 9
Store gradient_tiled.0(3, 7) = 10
Store gradient_tiled.0(4, 4) = 8
Store gradient_tiled.0(5, 4) = 9
Store gradient_tiled.0(6, 4) = 10
Store gradient_tiled.0(7, 4) = 11
Store gradient_tiled.0(4, 5) = 9
Store gradient_tiled.0(5, 5) = 10
Store gradient_tiled.0(6, 5) = 11
Store gradient_tiled.0(7, 5) = 12
Store gradient_tiled.0(4, 6) = 10
Store gradient_tiled.0(5, 6) = 11
Store gradient_tiled.0(6, 6) = 12
Store gradient_tiled.0(7, 6) = 13
Store gradient_tiled.0(4, 7) = 11
Store gradient_tiled.0(5, 7) = 12
Store gradient_tiled.0(6, 7) = 13
Store gradient_tiled.0(7, 7) = 14
End pipeline gradient_tiled.0()

Evaluating gradient in 4x4 tiles
Equivalent C:
Evaluating at x = 0, y = 0: 0
Evaluating at x = 1, y = 0: 1
Evaluating at x = 2, y = 0: 2
Evaluating at x = 3, y = 0: 3
Evaluating at x = 0, y = 1: 1
Evaluating at x = 1, y = 1: 2
Evaluating at x = 2, y = 1: 3
Evaluating at x = 3, y = 1: 4
Evaluating at x = 0, y = 2: 2
Evaluating at x = 1, y = 2: 3
Evaluating at x = 2, y = 2: 4
Evaluating at x = 3, y = 2: 5
Evaluating at x = 0, y = 3: 3
Evaluating at x = 1, y = 3: 4
Evaluating at x = 2, y = 3: 5
Evaluating at x = 3, y = 3: 6
Evaluating at x = 4, y = 0: 4
Evaluating at x = 5, y = 0: 5
Evaluating at x = 6, y = 0: 6
Evaluating at x = 7, y = 0: 7
Evaluating at x = 4, y = 1: 5
Evaluating at x = 5, y = 1: 6
Evaluating at x = 6, y = 1: 7
Evaluating at x = 7, y = 1: 8
Evaluating at x = 4, y = 2: 6
Evaluating at x = 5, y = 2: 7
Evaluating at x = 6, y = 2: 8
Evaluating at x = 7, y = 2: 9
Evaluating at x = 4, y = 3: 7
Evaluating at x = 5, y = 3: 8
Evaluating at x = 6, y = 3: 9
Evaluating at x = 7, y = 3: 10
Evaluating at x = 0, y = 4: 4
Evaluating at x = 1, y = 4: 5
Evaluating at x = 2, y = 4: 6
Evaluating at x = 3, y = 4: 7
Evaluating at x = 0, y = 5: 5
Evaluating at x = 1, y = 5: 6
Evaluating at x = 2, y = 5: 7
Evaluating at x = 3, y = 5: 8
Evaluating at x = 0, y = 6: 6
Evaluating at x = 1, y = 6: 7
Evaluating at x = 2, y = 6: 8
Evaluating at x = 3, y = 6: 9
Evaluating at x = 0, y = 7: 7
Evaluating at x = 1, y = 7: 8
Evaluating at x = 2, y = 7: 9
Evaluating at x = 3, y = 7: 10
Evaluating at x = 4, y = 4: 8
Evaluating at x = 5, y = 4: 9
Evaluating at x = 6, y = 4: 10
Evaluating at x = 7, y = 4: 11
Evaluating at x = 4, y = 5: 9
Evaluating at x = 5, y = 5: 10
Evaluating at x = 6, y = 5: 11
Evaluating at x = 7, y = 5: 12
Evaluating at x = 4, y = 6: 10
Evaluating at x = 5, y = 6: 11
Evaluating at x = 6, y = 6: 12
Evaluating at x = 7, y = 6: 13
Evaluating at x = 4, y = 7: 11
Evaluating at x = 5, y = 7: 12
Evaluating at x = 6, y = 7: 13
Evaluating at x = 7, y = 7: 14

Pseudo-code for the schedule:
produce gradient_tiled:
  for y.v5:
    for x.v3:
      for y.v6 in [0, 3]:
        for x.v4 in [0, 3]:
          gradient_tiled(...) = ...

向量化操作

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    // 向量化操作
    Var x,y;
    Func gradient("gradient_in_vectors");
    gradient(x, y) = x + y;
    gradient.trace_stores();

    // 使用向量化操作,在x86平台上可以使用SSE指令集进行长度为4的向量加速
    Var x_outer, x_inner;
    gradient.split(x, x_outer, x_inner, 4);
    gradient.vectorize(x_inner);
    // 可以使用以下操作等效上述两个语句
    // gradient.vectorize(x, 4);
    printf("Evaluating gradient with x_inner vectorized \n");
    Buffer<int> output = gradient.realize({8, 4});
    // 动态图可见lesson_05_vectors.gif
    printf("Equivalent C:\n");
    for (int y = 0; y < 4; y++) {
        for (int x_outer = 0; x_outer < 2; x_outer++) {
            // 内部的循环已经被指令集加速进行替换
            int x_vec[] = {x_outer * 4 + 0,
                            x_outer * 4 + 1,
                            x_outer * 4 + 2,
                            x_outer * 4 + 3};
            int val[] = {x_vec[0] + y,
                            x_vec[1] + y,
                            x_vec[2] + y,
                            x_vec[3] + y};
            printf("Evaluating at <%d, %d, %d, %d>, <%d, %d, %d, %d>:"
                    " <%d, %d, %d, %d>\n",
                    x_vec[0], x_vec[1], x_vec[2], x_vec[3],
                    y, y, y, y,
                    val[0], val[1], val[2], val[3]);
        }
    }
    printf("\n");
    printf("Pseudo-code for the schedule:\n");
    gradient.print_loop_nest();
    printf("\n");
    return 0;
}

向量化的示意图如下所示:

在这里插入图片描述

#运行结果如下所示
Begin pipeline gradient_in_vectors.0()
Tag gradient_in_vectors.0() tag = "func_type_and_dim: 1 0 32 1 2 0 8 0 4"
Store gradient_in_vectors.0(<0, 1, 2, 3>, <0, 0, 0, 0>) = <0, 1, 2, 3>
Store gradient_in_vectors.0(<4, 5, 6, 7>, <0, 0, 0, 0>) = <4, 5, 6, 7>
Store gradient_in_vectors.0(<0, 1, 2, 3>, <1, 1, 1, 1>) = <1, 2, 3, 4>
Store gradient_in_vectors.0(<4, 5, 6, 7>, <1, 1, 1, 1>) = <5, 6, 7, 8>
Store gradient_in_vectors.0(<0, 1, 2, 3>, <2, 2, 2, 2>) = <2, 3, 4, 5>
Store gradient_in_vectors.0(<4, 5, 6, 7>, <2, 2, 2, 2>) = <6, 7, 8, 9>
Store gradient_in_vectors.0(<0, 1, 2, 3>, <3, 3, 3, 3>) = <3, 4, 5, 6>
Store gradient_in_vectors.0(<4, 5, 6, 7>, <3, 3, 3, 3>) = <7, 8, 9, 10>
End pipeline gradient_in_vectors.0()

Evaluating gradient with x_inner vectorized 
Equivalent C:
Evaluating at <0, 1, 2, 3>, <0, 0, 0, 0>: <0, 1, 2, 3>
Evaluating at <4, 5, 6, 7>, <0, 0, 0, 0>: <4, 5, 6, 7>
Evaluating at <0, 1, 2, 3>, <1, 1, 1, 1>: <1, 2, 3, 4>
Evaluating at <4, 5, 6, 7>, <1, 1, 1, 1>: <5, 6, 7, 8>
Evaluating at <0, 1, 2, 3>, <2, 2, 2, 2>: <2, 3, 4, 5>
Evaluating at <4, 5, 6, 7>, <2, 2, 2, 2>: <6, 7, 8, 9>
Evaluating at <0, 1, 2, 3>, <3, 3, 3, 3>: <3, 4, 5, 6>
Evaluating at <4, 5, 6, 7>, <3, 3, 3, 3>: <7, 8, 9, 10>

Pseudo-code for the schedule:
produce gradient_in_vectors:
  for y:
    for x.v7:
      vectorized x.v8 in [0, 3]:
        gradient_in_vectors(...) = ...

循环展开

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    Var x,y;
    Func gradient("gradient_unroll");
    gradient(x, y) = x + y;
    gradient.trace_stores();
    // 循环展开就指被指定的那层循环用重复代码进行替换,消除掉该层
    Var x_outer, x_inner;
    gradient.split(x, x_outer, x_inner, 2);
    gradient.unroll(x_inner);
    // 上述可以用unroll一个语句代替,如下所示
    // gradient.unroll(x, 2);
    printf("Evaluating gradient unrolled by a factor of two\n");
    Buffer<int> result = gradient.realize({4, 4});
    printf("Equivalent C:\n");
    for (int y = 0; y < 4; y++) {
        for (int x_outer = 0; x_outer < 2; x_outer++) {
            // 循环展开如下所示
            {
                int x_inner = 0;
                int x = x_outer * 2 + x_inner;
                printf("Evaluating at x = %d, y = %d: %d\n", x, y, x + y);
            }
            {
                int x_inner = 1;
                int x = x_outer * 2 + x_inner;
                printf("Evaluating at x = %d, y = %d: %d\n", x, y, x + y);
            }
        }
    }
    printf("\n");
    printf("Pseudo-code for the schedule:\n");
    gradient.print_loop_nest();
    printf("\n");
    return 0;
}

#运行结果如下所示
Begin pipeline gradient_unroll.0()
Tag gradient_unroll.0() tag = "func_type_and_dim: 1 0 32 1 2 0 4 0 4"
Store gradient_unroll.0(0, 0) = 0
Store gradient_unroll.0(1, 0) = 1
Store gradient_unroll.0(2, 0) = 2
Store gradient_unroll.0(3, 0) = 3
Store gradient_unroll.0(0, 1) = 1
Store gradient_unroll.0(1, 1) = 2
Store gradient_unroll.0(2, 1) = 3
Store gradient_unroll.0(3, 1) = 4
Store gradient_unroll.0(0, 2) = 2
Store gradient_unroll.0(1, 2) = 3
Store gradient_unroll.0(2, 2) = 4
Store gradient_unroll.0(3, 2) = 5
Store gradient_unroll.0(0, 3) = 3
Store gradient_unroll.0(1, 3) = 4
Store gradient_unroll.0(2, 3) = 5
Store gradient_unroll.0(3, 3) = 6
End pipeline gradient_unroll.0()

Evaluating gradient unrolled by a factor of two
Equivalent C:
Evaluating at x = 0, y = 0: 0
Evaluating at x = 1, y = 0: 1
Evaluating at x = 2, y = 0: 2
Evaluating at x = 3, y = 0: 3
Evaluating at x = 0, y = 1: 1
Evaluating at x = 1, y = 1: 2
Evaluating at x = 2, y = 1: 3
Evaluating at x = 3, y = 1: 4
Evaluating at x = 0, y = 2: 2
Evaluating at x = 1, y = 2: 3
Evaluating at x = 2, y = 2: 4
Evaluating at x = 3, y = 2: 5
Evaluating at x = 0, y = 3: 3
Evaluating at x = 1, y = 3: 4
Evaluating at x = 2, y = 3: 5
Evaluating at x = 3, y = 3: 6

Pseudo-code for the schedule:
produce gradient_unroll:
  for y:
    for x.v9:
      unrolled x.v10 in [0, 1]:
        gradient_unroll(...) = ...

维度拆分split的特殊情况

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    Var x,y;
    Func gradient("gradient_split_7x2");
    gradient(x, y) = x + y;
    gradient.trace_stores();
    // 此时进行拆分,那么将会出现没有维度溢出的情况
    Var x_outer, x_inner;
    gradient.split(x, x_outer, x_inner, 3);

    printf("Evaluating gradient over a 7x2 box with x split by three \n");
    Buffer<int> output = gradient.realize({7, 2});
    // 示意图可以见lesson_05_split_7_by_3.gif
    printf("Equivalent C:\n");
    for (int y = 0; y < 2; y++) {
        for (int x_outer = 0; x_outer < 3; x_outer++) {  // Now runs from 0 to 2
            for (int x_inner = 0; x_inner < 3; x_inner++) {
                int x = x_outer * 3;
                // 在计算前,为了防止溢出7之外,这里使用判断进行溢出处理
                // 这样的判断导致了不会溢出,最多到6下标这个点
                if (x > 4) x = 4;
                x += x_inner;
                printf("Evaluating at x = %d, y = %d: %d\n", x, y, x + y);
            }
        }
    }
    printf("\n");
    printf("Pseudo-code for the schedule:\n");
    gradient.print_loop_nest();
    printf("\n");
    // The general rule is: If we require x from x_min to x_min + x_extent, and
    // we split by a factor 'factor', then:
    //
    // x_outer runs from 0 to (x_extent + factor - 1)/factor
    // x_inner runs from 0 to factor
    // x = min(x_outer * factor, x_extent - factor) + x_inner + x_min
    // In our example, x_min was 0, x_extent was 7, and factor was 3.
    return 0;
}

维度拆分的特殊情况的示意图如下所示:

在这里插入图片描述

#运行结果如下所示
Begin pipeline gradient_split_7x2.0()
Tag gradient_split_7x2.0() tag = "func_type_and_dim: 1 0 32 1 2 0 7 0 2"
Store gradient_split_7x2.0(0, 0) = 0
Store gradient_split_7x2.0(1, 0) = 1
Store gradient_split_7x2.0(2, 0) = 2
Store gradient_split_7x2.0(3, 0) = 3
Store gradient_split_7x2.0(4, 0) = 4
Store gradient_split_7x2.0(5, 0) = 5
Store gradient_split_7x2.0(4, 0) = 4
Store gradient_split_7x2.0(5, 0) = 5
Store gradient_split_7x2.0(6, 0) = 6
Store gradient_split_7x2.0(0, 1) = 1
Store gradient_split_7x2.0(1, 1) = 2
Store gradient_split_7x2.0(2, 1) = 3
Store gradient_split_7x2.0(3, 1) = 4
Store gradient_split_7x2.0(4, 1) = 5
Store gradient_split_7x2.0(5, 1) = 6
Store gradient_split_7x2.0(4, 1) = 5
Store gradient_split_7x2.0(5, 1) = 6
Store gradient_split_7x2.0(6, 1) = 7
End pipeline gradient_split_7x2.0()

Evaluating gradient over a 7x2 box with x split by three 
Equivalent C:
Evaluating at x = 0, y = 0: 0
Evaluating at x = 1, y = 0: 1
Evaluating at x = 2, y = 0: 2
Evaluating at x = 3, y = 0: 3
Evaluating at x = 4, y = 0: 4
Evaluating at x = 5, y = 0: 5
Evaluating at x = 4, y = 0: 4
Evaluating at x = 5, y = 0: 5
Evaluating at x = 6, y = 0: 6
Evaluating at x = 0, y = 1: 1
Evaluating at x = 1, y = 1: 2
Evaluating at x = 2, y = 1: 3
Evaluating at x = 3, y = 1: 4
Evaluating at x = 4, y = 1: 5
Evaluating at x = 5, y = 1: 6
Evaluating at x = 4, y = 1: 5
Evaluating at x = 5, y = 1: 6
Evaluating at x = 6, y = 1: 7

Pseudo-code for the schedule:
produce gradient_split_7x2:
  for y:
    for x.v11:
      for x.v12 in [0, 2]:
        gradient_split_7x2(...) = ...

融合、平铺、并行化组合技

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    Var x,y;
    // 有时候为了进行并行化操作,我们需要使用融合和平铺来跨维度进行并行化操作
    Func gradient("gradient_fused_tiles");
    gradient(x, y) = x + y;
    gradient.trace_stores();
    // 平铺->外部循环融合->外部循环并行
    Var x_outer, y_outer, x_inner, y_inner, tile_index;
    gradient.tile(x, y, x_outer, y_outer, x_inner, y_inner, 4, 4);
    gradient.fuse(x_outer, y_outer, tile_index);
    gradient.parallel(tile_index);
    // 能够使用如下的链式表达式进行上述的替代
    // gradient
    //     .tile(x, y, x_outer, y_outer, x_inner, y_inner, 4, 4)
    //     .fuse(x_outer, y_outer, tile_index)
    //     .parallel(tile_index);
    printf("Evaluating gradient tiles in parallel\n");
    Buffer<int> output = gradient.realize({8, 8});
    // 如此一来,每个瓦片都是并行运行的
    printf("Equivalent (serial) C:\n");
    // 外部循环应该进行展开
    // C中使用 # omp for
    for (int tile_index = 0; tile_index < 4; tile_index++) {
        int y_outer = tile_index / 2;
        int x_outer = tile_index % 2;
        for (int y_inner = 0; y_inner < 4; y_inner++) {
            for (int x_inner = 0; x_inner < 4; x_inner++) {
                int y = y_outer * 4 + y_inner;
                int x = x_outer * 4 + x_inner;
                printf("Evaluating at x = %d, y = %d: %d\n", x, y, x + y);
            }
        }
    }
    printf("\n");
    printf("Pseudo-code for the schedule:\n");
    gradient.print_loop_nest();
    printf("\n");
    return 0;
}

三个组合技的示意图如下所示:

在这里插入图片描述

#运行结果如下所示
Begin pipeline gradient_fused_tiles.0()
Tag gradient_fused_tiles.0() tag = "func_type_and_dim: 1 0 32 1 2 0 8 0 8"
Store gradient_fused_tiles.0(0, 0) = 0
Store gradient_fused_tiles.0(1, 0) = 1
Store gradient_fused_tiles.0(2, 0) = 2
Store gradient_fused_tiles.0(3, 0) = 3
Store gradient_fused_tiles.0(0, 1) = 1
Store gradient_fused_tiles.0(1, 1) = 2
Store gradient_fused_tiles.0(2, 1) = 3
Store gradient_fused_tiles.0(3, 1) = 4
Store gradient_fused_tiles.0(0, 2) = 2
Store gradient_fused_tiles.0(1, 2) = 3
Store gradient_fused_tiles.0(2, 2) = 4
Store gradient_fused_tiles.0(3, 2) = 5
Store gradient_fused_tiles.0(0, 3) = 3
Store gradient_fused_tiles.0(1, 3) = 4
Store gradient_fused_tiles.0(2, 3) = 5
Store gradient_fused_tiles.0(3, 3) = 6
Store gradient_fused_tiles.0(4, 0) = 4
Store gradient_fused_tiles.0(4, 4) = 8
Store gradient_fused_tiles.0(0, 4) = 4
Store gradient_fused_tiles.0(5, 0) = 5
Store gradient_fused_tiles.0(1, 4) = 5
Store gradient_fused_tiles.0(5, 4) = 9
Store gradient_fused_tiles.0(6, 0) = 6
Store gradient_fused_tiles.0(2, 4) = 6
Store gradient_fused_tiles.0(6, 4) = 10
Store gradient_fused_tiles.0(7, 0) = 7
Store gradient_fused_tiles.0(3, 4) = 7
Store gradient_fused_tiles.0(4, 1) = 5
Store gradient_fused_tiles.0(7, 4) = 11
Store gradient_fused_tiles.0(0, 5) = 5
Store gradient_fused_tiles.0(5, 1) = 6
Store gradient_fused_tiles.0(1, 5) = 6
Store gradient_fused_tiles.0(4, 5) = 9
Store gradient_fused_tiles.0(2, 5) = 7
Store gradient_fused_tiles.0(5, 5) = 10
Store gradient_fused_tiles.0(6, 1) = 7
Store gradient_fused_tiles.0(3, 5) = 8
Store gradient_fused_tiles.0(6, 5) = 11
Store gradient_fused_tiles.0(7, 1) = 8
Store gradient_fused_tiles.0(0, 6) = 6
Store gradient_fused_tiles.0(7, 5) = 12
Store gradient_fused_tiles.0(4, 2) = 6
Store gradient_fused_tiles.0(1, 6) = 7
Store gradient_fused_tiles.0(4, 6) = 10
Store gradient_fused_tiles.0(5, 2) = 7
Store gradient_fused_tiles.0(5, 6) = 11
Store gradient_fused_tiles.0(2, 6) = 8
Store gradient_fused_tiles.0(6, 2) = 8
Store gradient_fused_tiles.0(6, 6) = 12
Store gradient_fused_tiles.0(3, 6) = 9
Store gradient_fused_tiles.0(7, 2) = 9
Store gradient_fused_tiles.0(7, 6) = 13
Store gradient_fused_tiles.0(0, 7) = 7
Store gradient_fused_tiles.0(4, 3) = 7
Store gradient_fused_tiles.0(1, 7) = 8
Store gradient_fused_tiles.0(4, 7) = 11
Store gradient_fused_tiles.0(5, 3) = 8
Store gradient_fused_tiles.0(2, 7) = 9
Store gradient_fused_tiles.0(6, 3) = 9
Store gradient_fused_tiles.0(5, 7) = 12
Store gradient_fused_tiles.0(3, 7) = 10
Store gradient_fused_tiles.0(7, 3) = 10
Store gradient_fused_tiles.0(6, 7) = 13
Store gradient_fused_tiles.0(7, 7) = 14
End pipeline gradient_fused_tiles.0()

Evaluating gradient tiles in parallel
Equivalent (serial) C:
Evaluating at x = 0, y = 0: 0
Evaluating at x = 1, y = 0: 1
Evaluating at x = 2, y = 0: 2
Evaluating at x = 3, y = 0: 3
Evaluating at x = 0, y = 1: 1
Evaluating at x = 1, y = 1: 2
Evaluating at x = 2, y = 1: 3
Evaluating at x = 3, y = 1: 4
Evaluating at x = 0, y = 2: 2
Evaluating at x = 1, y = 2: 3
Evaluating at x = 2, y = 2: 4
Evaluating at x = 3, y = 2: 5
Evaluating at x = 0, y = 3: 3
Evaluating at x = 1, y = 3: 4
Evaluating at x = 2, y = 3: 5
Evaluating at x = 3, y = 3: 6
Evaluating at x = 4, y = 0: 4
Evaluating at x = 5, y = 0: 5
Evaluating at x = 6, y = 0: 6
Evaluating at x = 7, y = 0: 7
Evaluating at x = 4, y = 1: 5
Evaluating at x = 5, y = 1: 6
Evaluating at x = 6, y = 1: 7
Evaluating at x = 7, y = 1: 8
Evaluating at x = 4, y = 2: 6
Evaluating at x = 5, y = 2: 7
Evaluating at x = 6, y = 2: 8
Evaluating at x = 7, y = 2: 9
Evaluating at x = 4, y = 3: 7
Evaluating at x = 5, y = 3: 8
Evaluating at x = 6, y = 3: 9
Evaluating at x = 7, y = 3: 10
Evaluating at x = 0, y = 4: 4
Evaluating at x = 1, y = 4: 5
Evaluating at x = 2, y = 4: 6
Evaluating at x = 3, y = 4: 7
Evaluating at x = 0, y = 5: 5
Evaluating at x = 1, y = 5: 6
Evaluating at x = 2, y = 5: 7
Evaluating at x = 3, y = 5: 8
Evaluating at x = 0, y = 6: 6
Evaluating at x = 1, y = 6: 7
Evaluating at x = 2, y = 6: 8
Evaluating at x = 3, y = 6: 9
Evaluating at x = 0, y = 7: 7
Evaluating at x = 1, y = 7: 8
Evaluating at x = 2, y = 7: 9
Evaluating at x = 3, y = 7: 10
Evaluating at x = 4, y = 4: 8
Evaluating at x = 5, y = 4: 9
Evaluating at x = 6, y = 4: 10
Evaluating at x = 7, y = 4: 11
Evaluating at x = 4, y = 5: 9
Evaluating at x = 5, y = 5: 10
Evaluating at x = 6, y = 5: 11
Evaluating at x = 7, y = 5: 12
Evaluating at x = 4, y = 6: 10
Evaluating at x = 5, y = 6: 11
Evaluating at x = 6, y = 6: 12
Evaluating at x = 7, y = 6: 13
Evaluating at x = 4, y = 7: 11
Evaluating at x = 5, y = 7: 12
Evaluating at x = 6, y = 7: 13
Evaluating at x = 7, y = 7: 14

Pseudo-code for the schedule:
produce gradient_fused_tiles:
  parallel x.v13.v17:
    for y.v16 in [0, 3]:
      for x.v15 in [0, 3]:
        gradient_fused_tiles(...) = ...

所有循环优化的手段组合运用

#include "Halide.h"
#include <algorithm>
#include <stdio.h>
using namespace Halide;

int main(int argc, char **argv) {
    Var x,y;
    Func gradient_fast("gradient_fast");
    gradient_fast(x, y) = x + y;

    // 首先进行了大循环平铺->外循环融合->外循环并行化
    Var x_outer, y_outer, x_inner, y_inner, tile_index;
    gradient_fast
        .tile(x, y, x_outer, y_outer, x_inner, y_inner, 64, 64)
        .fuse(x_outer, y_outer, tile_index)
        .parallel(tile_index);
    // 然后对平铺的瓦片进行平铺->向量化->循环展开
    Var x_inner_outer, y_inner_outer, x_vectors, y_pairs;
    gradient_fast
        .tile(x_inner, y_inner, x_inner_outer, y_inner_outer, x_vectors, y_pairs, 4, 2)
        .vectorize(x_vectors)
        .unroll(y_pairs);
    // 这里没有用到维度分割和维度变化操作,因为使用了其他操作进行替换,但是这两种可以组合成其他操作
    Buffer<int> result = gradient_fast.realize({350, 250});

    // See figures/lesson_05_fast.mp4 for a visualization.

    printf("Checking Halide result against equivalent C...\n");
    for (int tile_index = 0; tile_index < 6 * 4; tile_index++) {
        int y_outer = tile_index / 4;
        int x_outer = tile_index % 4;
        for (int y_inner_outer = 0; y_inner_outer < 64 / 2; y_inner_outer++) {
            for (int x_inner_outer = 0; x_inner_outer < 64 / 4; x_inner_outer++) {
                // We're vectorized across x
                int x = std::min(x_outer * 64, 350 - 64) + x_inner_outer * 4;
                int x_vec[4] = {x + 0,
                                x + 1,
                                x + 2,
                                x + 3};

                // And we unrolled across y
                int y_base = std::min(y_outer * 64, 250 - 64) + y_inner_outer * 2;
                {
                    // y_pairs = 0
                    int y = y_base + 0;
                    int y_vec[4] = {y, y, y, y};
                    int val[4] = {x_vec[0] + y_vec[0],
                                    x_vec[1] + y_vec[1],
                                    x_vec[2] + y_vec[2],
                                    x_vec[3] + y_vec[3]};

                    // Check the result.
                    for (int i = 0; i < 4; i++) {
                        if (result(x_vec[i], y_vec[i]) != val[i]) {
                            printf("There was an error at %d %d!\n",
                                    x_vec[i], y_vec[i]);
                            return -1;
                        }
                    }
                }
                {
                    // y_pairs = 1
                    int y = y_base + 1;
                    int y_vec[4] = {y, y, y, y};
                    int val[4] = {x_vec[0] + y_vec[0],
                                    x_vec[1] + y_vec[1],
                                    x_vec[2] + y_vec[2],
                                    x_vec[3] + y_vec[3]};

                    // Check the result.
                    for (int i = 0; i < 4; i++) {
                        if (result(x_vec[i], y_vec[i]) != val[i]) {
                            printf("There was an error at %d %d!\n",
                                    x_vec[i], y_vec[i]);
                            return -1;
                        }
                    }
                }
            }
        }
    }
    printf("\n");
    printf("Pseudo-code for the schedule:\n");
    gradient_fast.print_loop_nest();
    printf("\n");
    return 0;
}

所有的组合技叠加的效果:

在这里插入图片描述

#运行结果如下所示
Checking Halide result against equivalent C...

Pseudo-code for the schedule:
produce gradient_fast:
  parallel x.v18.v22:
    for y.v21.v24 in [0, 31]:
      for x.v20.v23 in [0, 15]:
        unrolled y.v21.v26 in [0, 1]:
          vectorized x.v20.v25 in [0, 3]:
            gradient_fast(...) = ...
Halide简介 Halide是用C++作为宿主语言的一个图像处理相关的DSL(Domain Specified Language)语言,全称领域专用语言。主要的作用为在软硬层面上(与算法本身的设计无关)实现对算法的底层加速,我们有必要对其有一定的了解。因为不论是 传统的图像处理方法亦或是深度学习应用 都使用到了halide的思想。 来自 https://www.codercto.com/a/67796.html ... 阅读详情

相关推荐

Halide 构建

hello halide 随着人工智能,VR等领域的发展,我们对于高性能图像处理程序的需求越来越大;当前编程工具开发的高性能图像处理程序牺牲了程序的可读性,模块性,可移植性等;其主要原因是,当前程序将算法描述, 数据存储以及计算糅杂在一起。同时手工编写高性能图像处理程序开发效率较低,难以快速构建大量高性能图像处理代码。 在这样的背景下,MIT的研究人员专门为图像处理设计了一种程序语言——Halid...

2Know的博客 1765

Halide示例学习一

Halide示例学习一示例学习基本变量和概念操控图片操作debug操作1 示例学习 基本变量和概念 // 使用Halide,我们只需要包含Halide.h这个头文件就可以了 #include "Halide.h" #include <stdio.h> int main(int argc, char **argv) { // Halide::Func代表了一个计算图,代表了每一个像素值需要进行的计算操作 Halide::Func gradient; // Halide::

Pengcode的博客 763

windows安装Halide

https://github.com/halide/Halide/releases 下载Halide压缩包,解压 添加环境变量,C:\Opencv3.4\halide\Debug;C:\Opencv3.4\halide\Release ①Linker>general>Adiditional Library Directories release C:\lib\halide\Releas...

勉強 1711

Halide示例学习四

Halide示例学习四多阶段计算图多计算图组合示例compute_at使用方法store_root配合compute_at使用方法tile配合compute_at使用方法compute_at和store_at以及之前的混合技使用方法 多阶段计算图 #include "Halide.h" #include <stdio.h> using namespace Halide; int main(int argc, char **argv) { Var x("x"), y("y");

Pengcode的博客 437

Halide编译安装与基本数据结构

Overview Halide是为了在现代计算机上编写更高性能的图像处理代码而设计的一种编程语言。目前只吃的目标为: CPU架构:X86, ARM, MIPS, Hexagon, PowerPC 操作系统:Linux, Windows, macOS, Andriod, IOS, Qualcomm QuRT GPU计算API: CUDA,OpenGL, OpenCL, Apple Metal, Microsoft Direction X 12 Halide不是独立的一种编程语言,而是嵌入在C++中,这

亦梦云烟的博客 1745

OpenCV如何启用Halide后端以提高效率

OpenCV如何启用Halide后端以提高效率如何启用Halide后端以提高效率介绍要求LLVM编译器Halide语言使用Halide后端构建OpenCV将Halide设置为首选后端 如何启用Halide后端以提高效率 介绍 本教程指导如何使用Halide语言后端在OpenCV深度学习模块中运行模型。Halide是一个开源项目,可以让我们以易于阅读的格式编写图像处理算法,根据特定设备安排计算时间,并以相当高的效率对其进行评估。 要求 LLVM编译器 LLVM编译可能需要很长时间。 从http://relea

希望我的博客,能帮上你解决学习中工作中所遇到的问题 1006

快速入门Halide

Halide代码流程: 声明函数,变量,表达式 用变量、表达式等实现算法 使用调度策略对算法进行调度调优 调用函数的realize成员函数,对函数进行实现 写出数据 example 1: Halide::Func gradient; // Func对象表示了一个pipeline阶段。它是一个纯函数,定义了每个像素点对应的值。 Halide::Var x, y; // Var对象是Func的定义域,或者说是Func的参数。它们本身没有任何意义。Var用来索引 Halide::Expr e = x

Time_remember的专栏 1290

使用Halide后端提高OpenCV效率的方法

通过上述步骤,我们成功地在OpenCV中启用了Halide后端,并使用Halide后端进行了高斯滤波操作。通过上述步骤,我们成功地在OpenCV中启用了Halide后端,并使用Halide后端进行了高斯滤波操作。通过使用Halide后端,你可以进一步优化和并行化你的图像处理算法,以实现更高的性能。通过使用Halide后端,你可以进一步优化和并行化你的图像处理算法,以实现更高的性能。要启用OpenCV的Halide后端,首先确保已经正确安装了OpenCV和Halide,并配置了正确的编译环境。

PixelNovaO的博客 314

Halide学习

目的:在现代机器上完成高性能的图像处理。 编译器目标:x86/SSE, ARM V7/NEON, CUDA, Native Client, OpenCL, and Metal. 大致流程:用Halide::Var, Halide::Expr, Halide::Func类型的对象完成c++程序,然后调用Halide::Func::compile_to_file来生成对象文件和头文件。或者调用Halide::Func::realize即时编译(JIT)并即刻运行整套pipeline,这有利于测试小的程序。

u011994454的博客 742

Halide:一种用于快速,便携式数据并行计算的语言

卤化物 Halide是一种编程语言,旨在使在现代机器上编写高性能图像和数组处理代码更加容易。 卤化物目前的目标是: CPU体系结构:X86,ARM,MIPS,Hexagon,PowerPC 操作系统:Linux,Windows,Mac OS X,Android,iOS,Qualcomm QuRT GPU计算API:CUDA,OpenCL,OpenGL计算着色器,Apple Metal,Microsoft Direct X 12 Halide并不是独立的编程语言,而是嵌入C ++中。 这意味着您编写的C ++代码使用Halide的C ++ API构建了Halide管道的内存中表示形式。 然后,您可以将该表示形式编译为目标文件,或对其进行JIT编译并在同一过程中运行。 Halide还提供了Python绑定,该绑定提供了对编写无需C ++的Python中嵌入的Halide的完全支持。 有关Halide是什么的更多详细信息,请参见 。 有关API文档,请参见 要查看一些示例代码,请查看tutorials目录。 如果您已获取完整的源代码发行版并希望构建Halide,请参阅的。 卤

重带电粒子的能量歧离(energy straggling)

能量歧离,Bethe-Bloch

G751888629的博客 2298

为Halide安装opencl支持

打开TargetOpenCL开关,我们可以看到使用opencl进行推理的时候,计算时调用的openclapi是如何的。展示的测速结果如下所示,这里可以看出来,虽然都是使用了cpu进行计算,但是还是intel-cpu-opencl速度更快些。compile_jit进行处理操作。查看主机平台支持的设备平台。设置kernel参数。...

Pengcode的博客 715

快手商业化风控内容审核场景下的大模型早期探索与应用

在处理大量的自动语音识别(ASR)输出时,面临的主要挑战之一是文本的冗长和格式混乱,这严重影响了审核人员的阅读效率。为了解决这一问题,我们利用大模型的理解能力对文本进行智能总结,可以显著优化文本内容,使其更加清晰并且具有可读性。该方式极大地提高了审核过程的效率,审核人员可以更快地处理信息,减少了处理时间和劳动强度。

kuaishoutech的博客 2739

Halide示例学习五

Halide示例学习四函数重定义操作RDom下标使用使用RDom计算直方图调度函数更新多阶段重定义操作使用归化函数进行模糊操作内置的归化函数sum使用归约函数的一个复杂例子 函数重定义操作 #include "Halide.h" #include <stdio.h> using namespace Halide; int main(int argc, char **argv) { Var x("x"), y("y"); Buffer<uint8_t> input

Pengcode的博客 520

Redhawk:toggle rate从哪来?

redhwak中toggle rate的相关设置

m0_61544122的博客 8115

基于pytorch cnn ResNets卷积网络的模糊图像检测 完整代码数据直接运行

基于pytorch cnn ResNets卷积网络的模糊图像检测 完整代码数据直接运行

730

Halide示例学习三

Halide示例学习三改变维度遍历起点多计算图组合示例 改变维度遍历起点 #include "Halide.h" #include <stdio.h> using namespace Halide; int main(int argc, char **argv) { Func gradient("gradient"); Var x("x"), y("y"); gradient(x, y) = x + y; gradient.trace_stores();

Pengcode的博客 296

OpenCV实例(一)人脸检测

计算机视觉使很多任务成为现实,其中两项任务就是人脸检测(在图像中定位人脸)和人脸识别(将人脸识别为特定的人)。OpenCV实现了一些人脸检测和识别的算法。从安全到娱乐,这些技术在现实环境中都有应用。介绍OpenCV的一些人脸检测和识别功能,并定义特定类型的可跟踪物体的数据文件。具体来说,将研究Haar级联分类器,通过分析相邻图像区域之间的对比度,确定给定图像或子图像是否与已知类型匹配。

小幽余生不加糖 5004

(深度学习优化大师)TVM的前辈,介绍下什么是HALIDE

在开始学习之前推荐大家可以多在FlyAI竞赛服务平台多参加训练和竞赛,以此来提升自己的能力。FlyAI是为AI开发者提供数据竞赛并支持GPU离线训练的一站式服务平台。每周免费提供项目开源算法样例,支持算法能力变现以及快速的迭代算法模型。 前言 前几天又用到了TVM,想着是否能够间接替代TensorRT作为GPU服务器部署的一个后端。TensorRT在自家的GPU上确实强大,也是老黄家重点关照的”开源项目“。但TensorRT还是有一点点小缺点的: 经过infer优化后的模型与特定GPU绑定,...

iFlyAI的博客 3284

VB.net:VB.net编程语言学习之基于VS软件利用VB.net语言实现对SolidWorks进行二次开发的案例应用(启动SolidWorks代码/直接驱动模型代码/路径下模型驱动代码/创建两个文

VB.net:VB.net编程语言学习之基于VS软件利用VB.net语言实现对SolidWorks进行二次开发的案例应用(启动SolidWorks代码/直接驱动模型代码/路径下模型驱动代码/创建两个文件夹对话框代码/重新生成三维图代码/导出工程图代码)之详细攻略 目录 基于VS软件利用VB.net语言实现对SolidWorks进行二次开发的案例应用 1、调用SW的模型,并进行参数修改 1.1、VB按钮之SW的三维零件之间切换思想 1.2、调用SW 2、基础案例经验 2.1、设计SW的拉

头部AI社区如有邀博主AI主题演讲请私信—心比天高,仗剑走天涯,保持热爱,奔赴向梦想!低调,专注,谦虚,自律,反思,成长,还算比较正能量的博主,公益免费传播…内心特别想在AI界做出一些可以推进历史进程影响力的技术(兴趣使然,有点小情怀,也有点使命感呀 3036

【SpringBoot 3.x 第92节】Spring Modulith:构建模块化单体架构(基于 Spring Boot 3),一文带你搞透(超详细)!

🏆本文收录于《滚雪球学SpringBoot 3.x》,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。    该专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。 如果想快速定位学习,可以看这篇【SpringBoot3教程导航帖】,你想学习的都被收集在内,快速投入学习!!两不误。

**My Coding Family** 998

如何为 Halide 后端安排网络

介绍我们使用的每台设备都是一样的卤化物代码。但是为了达到令人满意的效率,我们应该正确地安排计算。在本教程中,我们将介绍在 OpenCV 深度学习模块中使用 Halide 后端调度网络的方法。为了更好地理解 Halide 调度,您可能需要阅读教程 @。如果这是你第一次在 OpenCV 中与 Halide 会面,我们建议从开始。配置文件您可以通过编写文本配置文件来计划卤化物管道的计算。这意味着您可以轻松地矢量化、并行化和管理层计算的循环顺序。

2301_81888214的博客 927

SAP 实施:Waterfall vs. Agile —— 一场“结构性矛盾“的深刻比较先说结论:在 SAP 世界里,这从来不是“谁更好“的宗教问题,而是“你的项目 DNA 是什么“的战略选择。​

SAP 实施:Waterfall vs. Agile —— 一场"结构性矛盾"的深刻比较 先说结论:在 SAP 世界里,这从来不是"谁更好"的宗教问题,而是"你的项目 DNA 是什么"的战略选择。​ SAP 早已用 SAP Activate​ 给出了官方态度——它不是纯 Agile,也不是回头去搞旧 Waterfall,而是一个带质量门的混合架构。 1. 先回到本质:两者解决的是不同维度的风险 维度 Waterfall(传统 ASAP 路线)​ Agile(SCRUM/Kanban 式迭代)​

金牌架构师 336

Halide源码编译

Halide源码编译Halide为何要源码编译?源码编译LLVM库源码编译Halide测试Halide是否编译成功生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 Halide   Halide 算是一种编程模式,主要用于在现代机器上来进行高性能的图像和数组处理。其寄生在C++编程语言中,作为DSL编程语言(特定域语言)来实现高

Pengcode的博客 1942

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Halide编程

免责申明:本文所用的材料来自于网络,仅供个人学习和交流之用。如果用作其他用途,那么请自行承担法律负责。 Halide是一种特定领域的编程语言(DSL),专门用于加速图像处理,当前已支持x86 SSE,ARM v7 NEON,CUDA,OpenCL等。Halide的主要特点在于分开算法描述和调度描述。一个算法的Halide算法描述不依赖于硬件,其调度描述使用并行化、向量化(SIMD指令)和处理本地化(block)等函数(为便于表述,本文使用了原语),通过这些原语的某种特定组合,使得算法描述可在选定的硬件计算平

serpentine的博客 633

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

halide编程技术指南(连载二)

本文是halide编程指南的连载,已同步至公众号 目录 第二章 图像处理 第三章 检查生成的代码 第四章 使用tracing, print, 和print_when进行调试 第五章 Vectorize, parallelize, unroll and tile 你的代码 第二章 图像处理 本章演示如何传递输入图像并进行操作。 // halide提供了对应方法用于导入png图像...

Aoulun的博客 1381

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

上一篇: Halide示例学习一
下一篇: Halide示例学习三
慷仔
博客等级 码龄9年 88粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值