爱笑的小姐姐 · 2020年12月18日

【AutoKernel系列教程】三、Halide初体验

文章转载于: Tengine开发者社区
作者:小O妹

AutoKernel

系列教程

- Halide初体验 -

在深入了解Halide之前,我们先来体验一下Halide的黑魔法。

进入AutoKernel的docker, docker里已有Halide的python环境,直接运行

python data/03_halide_magic.py

可以得到输出

func_origin__ cost 0.510215 second
func_parallel cost 0.122265 second

以上这个脚本执行了一个简单的函数计算:func[x,y] = x + 10*y 对比了两个函数的运行时间:

  • func\_origin: 默认函数
  • func\_parallel: 添加了Halide的一个调度策略:func.parallel(y,4), 对y维度进行并行化,并行度为4

结果可以看到,第二个函数的耗时是第一个函数的四分之一。

这,就是Halide的魔法!

无需底层优化汇编知识,只需添加一行代码,就能得到比较好的优化效果。

Halide语言基础

要想调用Halide的调度策略,首先要掌握基本的Halide语言,用Halide语言来描述算子的计算。下面以简单的函数来演示Halide语言的基本数据结构。

  • 变量 Var:可以理解为函数的自变量,比如要描述一个图像的像素,需要两个变量x和y来描述 w维度和h维度的坐标。
  • 函数 Func:和数学上的函数类似,定义了一个计算过程。复杂的计算过程可以拆成多个小函数来实现。

示例一:

本例子的函数计算公式为:func(x,y)= 10*y + x 用Halide语言来描述这个函数:

Python:

import halide as hl

x, y = hl.Var("x"), hl.Var("y")
func = hl.Func("func")
func[x,y] = x + 10*y

C++:

#include "Halide.h"

#include "Halide.h"
using namespace Halide;

Var x("x"), y("y");
Func func("func");

func(x, y) = x + 10 * y;

Func的realize会计算函数在定义域的值并返回数值结果。调用了realize,函数才被即时编译(jit-compile),在这之前只是定义了函数的计算过程。

查看计算结果:

Python:

out = func.realize(3, 4)  # width, height = 3,4

for j in range(out.height()):
    for i in range(out.width()):
        print("out[x=%i,y=%i]=%i"%(i,j,out[i,j]))

C++:

Buffer<int32_t> out = func.realize(3, 4);

Buffer<int32_t> out = func.realize(3, 4);

for (int j = 0; j < out.height(); j++) {
    for (int i = 0; i < out.width(); i++) {
        printf("out[x=%d,y=%d]=%d",i,j,out(i,j));
        }
    }

这个函数的计算是:

                   wide = 3
                  x=0 x=1 x=2
                ------------
            y=0 |  0   1   2
hight = 4   y=1 | 10  11  12
            y=2 | 20  21  22
            y=3 | 30  31  32

完整的代码在data/03\_halide\_basic.py 可以直接运行:

python data/03_halide_basic.py

另外可以调用func.trace_stores()来跟踪函数的值

示例二:

本示例演示如何喂入输入数据,取出输出数据 完整的代码在data/03\_halide\_feed\_data.py

本示例的函数:

B(x,y)=A(x,y)+1

A是输入数据,可以定义Halide.Buffer,然后把numpy的array数据喂入buffer


# feed input
    input_data = np.ones((4,4),dtype=np.uint8)
    A = hl.Buffer(input_data)

定义函数B:


i,j = hl.Var("i"), hl.Var("j")
    B = hl.Func("B")
    B[i,j] = A[i,j] + 1

获取输出数据, 有以下几种方式:


# 1
        output = B.realize(4,4)
        print("out: \n",np.asanyarray(output))
# 2
        output = hl.Buffer(hl.UInt(8),[4,4])
        B.realize(output)
        print("out: \n",np.asanyarray(output))
# 3
        output_data = np.empty(input_data.shape, dtype=input_data.dtype,order="F")
        output = hl.Buffer(output_data)
        B.realize(output)
        print("out: \n",output_data)

可以直接运行完整代码:

python data/03_halide_feed_data.py

*开源网址:https://github.com/OAID/AutoK...

推荐阅读

更多Tengine相关内容请关注Tengine-边缘AI推理框架专栏。
推荐阅读
关注数
3393
内容数
68
Tengine是一款轻量级模块化高性能的神经网络推理引擎 ;欢迎体验Tengine,[链接] 《Tengine开发者入门资料包》[链接]
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息