当前位置: 首页 > 工具软件 > Halide > 使用案例 >

Halide 初步使用

赵俊晤
2023-12-01

最近开始使用Halide做点事情,说找点资料,结果网上基本都是翻译下官方教程,还得自己摸索。
Halide的目的是更方便地做优化,即不牺牲代码可读性的情况下利用硬件加速代码执行。更详细的说明参考原始论文。这里直接说怎么上手的事情。

Halide的文档确实不如OpenCV,这就是差距吧。就比如说,首先应当介绍下核心的数据结构以及围绕这些数据结构有哪些关键API,《Learning OpenCV》这方面就做得比较好。所以 这篇文章大致按照这个套路来,而不是上来就直奔有哪些优化操作。

看了Tutorial的第一个例子,感觉 它的Func的用法更像是函数式编程语言,或者说 像 Tensorflow的计算图,先定义好运算步骤,然后再进行实际运算。

我只需要对数组进行操作,并不一定是图像,所以先要把自己的数据转换成 Halide的Buffer,但Halide的前几个教程并没说怎么把自己内存中的数据转出它的Buffer类型,只有读图片的API,在网上找了会儿,后面又看到很靠后Tutorial里面 有 这样的写法:

 Halide::Runtime::Buffer<uint8_t> planar_input(1024, 768, 3);

原来挺简单, Halide::Buffer也能这么创建,创建好以后访问就比较简单了

	Halide::Buffer<float> input(10, 1, 3); // w * h * 3
	for (int j = 0; j < input.height(); j++) {
		for (int i = 0; i < input.width(); i++) {
			for (int k = 0; k < 3; k++) {
				input(i, j, k) = 1;
			}
		}
	}

接下来是怎么写Func操作的问题, 主要是输出结果为多通道的情况。Halide的例子有个增强亮度,问题是它那里对每个通道的操作是一样的,但不是每个需求都这样。我需要把每个通道拿出来做特定运算,然后自己试图照猫画虎,直接写了如下代码,编译没问题,运行报错:

	Halide::Func transformColod;


	Halide::Var x, y;

	Halide::Var c;
	Halide::Expr xCoor = input(x, y, 0);
	Halide::Expr yCoor = input(x, y, 1);
	Halide::Expr zCoor = input(x, y, 2);

	xCoor = Halide::cast<float>(xCoor);
	yCoor = Halide::cast<float>(yCoor);
	zCoor = Halide::cast<float>(zCoor);

	std::cout << "aa\n";
	std::cout << " input.channels() " << input.channels() << std::endl;
	xCoor += 10;
	yCoor += 20;
	zCoor += 30;

	transformColod(x, y, 0) = xCoor;
	transformColod(x, y, 1) = yCoor;
	transformColod(x, y, 2) = zCoor;

验证了下,如果不是3通道,transformColod(x, y) = xx, 也就是输出 只有一个通道是没问题的。然后在网上搜怎么写输出多通道的Func,居然没搜到,倒是看到官方文档说用tuple,但自己的需求还没这么复杂啊。

然后在 tutorial中看到 第13课 说了这方面的问题,原来很简单:

transformColod(x, y, c) = mux(c, { xCoor , yCoor, zCoor });

不过这样写要注意 调用bound和unroll,不然影响效率
这样写即可,运行没问题,全部代码如下


#include "Halide.h"

// We'll also include stdio for printf.
#include <stdio.h>

int mytest() {
	// test code
	Halide::Buffer<float> input(10, 1, 3); // w * h * 3
	for (int j = 0; j < input.height(); j++) {
		for (int i = 0; i < input.width(); i++) {
			for (int k = 0; k < 3; k++) {
				input(i, j, k) = 1;
			}
		}
	}

	for (int j = 0; j < input.height(); j++) {
		for (int i = 0; i < input.width(); i++) {
			for (int k = 0; k < 3; k++) {
				printf(" %d ", input(i, j, k));
			}
			printf(" \n");
		}
		printf(" \n");
	}

	Halide::Func transformColod;


	Halide::Var x, y;

	Halide::Var c;
	Halide::Expr xCoor = input(x, y, 0);
	Halide::Expr yCoor = input(x, y, 1);
	Halide::Expr zCoor = input(x, y, 2);

	xCoor = Halide::cast<float>(xCoor);
	yCoor = Halide::cast<float>(yCoor);
	zCoor = Halide::cast<float>(zCoor);

	std::cout << "aa\n";
	std::cout << " input.channels() " << input.channels() << std::endl;
	xCoor += 10;
	yCoor += 20;
	zCoor += 30;


	// 2) It requires a select, which can impact performance if not
	// bounded and unrolled:
	// brighter.bound(c, 0, 3).unroll(c);
	
	// 参考 lesson 13
	// TODO: 这个操作要求 bound 和 循环展开!
	// 2) It requires a select, which can impact performance if not
	// bounded and unrolled:
	// brighter.bound(c, 0, 3).unroll(c);

	transformColod(x, y, c) = mux(c, { xCoor , yCoor, zCoor });

	Halide::Buffer<float> output2 =
		transformColod.realize(input.width(), input.height(), 3);
	//transformColod.realize(output2);

	std::cout << "bb\n";
	for (int j = 0; j < output2.height(); j++) {
		for (int i = 0; i < output2.width(); i++) {
			for (int k = 0; k < output2.channels(); k++) {
				printf(" %f ", output2(i, j, k));
			}
			printf(" \n");
		}
		printf(" \n");
	}
	return 0;
}


Visual Studio里面的配置 就配置下头文件目录、库文件目录,链接器选项里面加上lib文件即可。

 类似资料: