Halide教程Part01:build、语法、调度、流水线

Halide是一个将算法与执行解耦的图像处理库。本文详细介绍了如何构建Halide,其基本语法,包括定义函数、表达式、变量等。接着探讨了调度策略,如默认顺序、变量分割、合并、循环展开、向量化和多级流水线调度。通过不同的调度示例,展示了如何根据目标机器优化执行效率。
摘要由CSDN通过智能技术生成

About Halide

Halide的核心思路不在于其能够自动优化代码,而是将 算法的内容 和 算法的执行 解耦,编写时分开编写。程序猿可以很轻松的根据具体的目标机器,设计并尝试不同的优化策略,从中选择一个最优的策略。
Halide GitHub Repo

How to build Halide

  1. 安装llvm4.0以上版本,并配置环境变量

    可以在对应系统的包管理工具下安装llvm4.0以上版本:

    $ brew search llvm
    ==> Searching local taps...
    llvm@4
    ==> Searching taps on GitHub...
    ==> Searching blacklisted, migrated and deleted formulae...

    这里macOS选择使用brew作为包管理工具。

  2. 配置环境变量

    shell工具读取的配置目录文件中添加环境变量以下两条:

    export LLVM_CONFIG="/usr/local/opt/llvm@4/bin/llvm-config"
    export CLANG="/usr/local/opt/llvm@4/bin/clang"
  3. 直接make生成库在${workpath}/bin下,头文件在${workpath}/include以及${workpath}/tools目录下。

Halide 基本语法

  • Halide 关键字

    Algorithm部分:

    • Halide::func 对应图像流水线处理中的一个步骤。这个func定义了一个图像中每一个像素应该是什么值。这里只是一个定义。
    • Halide::Var 用于定义func的变量。
    • Halide::Expr 用于定义一个表达式。
    • Halide::cast 强制类型转换。
    • Halide::min
    • Halide::Buffer<T>用于定义缓存

    Schedule部分:Vectorizeparallelizeunroll

  • Halide在定义func的时候没有真正计算每个像素点的值,只有在调用funcrealize方法时才会真正执行。

  • Halide Debug手段

    • _.compile_to_lowered_stmt("_.html", {}, HTML)可以将中间结果生成html预览。
    • trace_stores用于跟踪执行过程。
    • func中直接print部分内容。
    • cout可以打印Expr的具体表达式内容。
    • _.print_loop_nest()可以将调度的伪代码打印出来。

Halide Schedule

Default ordering

没有添加任何调度代码的时候,也就是default ordering的调度时,所有的调度均是串行执行的:

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

示意图如下所示:

Reorder

func调用_.reorder(_,_);后,可以更改调度的顺序。

调度的伪代码如下:

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

Split a variable 分割变量

func调用

Var x_outer, x_inner;
gradient.split(x, x_outer, x_inner, 2);

后,会将第一个参数分为x_outerx_inner部分,然后再分别执行。最后一个参数是factor,该factor代表着inner的块的大小。见下面代码的x_inner in [0, 1]

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

Splitting by factors that don’t divide the extent

当不能整数分割的时候,会在临界的地方部分点重复计算(保证不越界)。

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

Fuse two variables into one 合并变量

func调用

Var fused;
gradient.fuse(x, y, fused);

可以将原来的多个合并成一个进行处理。下面的伪代码中原来的两次循环变成了一次循环。

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

Evaluating in tiles 分成一块块执行

将原来的图分割成不同的tiles,然后一块一块进行执行:

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值