Halide::Generator生成器使用说明

  • 1、前言
  • 2、核心代码总览
  • 3、具体说明和注意事项
    • 3.1、生成器使用流程
    • 3.2、生成代码内容总览
  • 4、后续计划与安排

我们之前已经能够使用Halide去调用OpenCL后端了,但是我们的代码总是在建立计算图和调度后使用realize实例化进行运行。
这很明显对于我们AI模型优化核函数、推理运行时这些操作造成不小的影响。而且也无法剥离出Halide这个庞大的依赖库,导致
最终的推理时依赖过多引起的接口过于复杂。

1、前言

本次的主要工作就是尝试了Halide::Generator生成器去进行核函数生成以及如何使用不同后端的试验。
关键信息如下所示:

  • 多计算图
  • 调度gpu约束
  • 输入输出定义信息
  • 自动调度操作
  • 生成器调用示例

2、核心代码总览

#include <stdio.h>
#include "Halide.h"
#include "HalideBuffer.h"
#include "clock.h"
using namespace Halide;
using namespace Halide::Tools;
//尝试进行核函数生成操作。
class image_f4:public Halide::Generator<image_f4>{
public:// 定义输入buffer,图片数据,三维数据Input<Buffer<uint8_t>> input{"input", 3};// 定义输出buffer,图片数据,三维数据,两者shape完全一致。Output<Buffer<uint8_t>> output{"output", 3};void generate(){Var x, y, c, i, ii, xo, yo, xi, yi;Func lut;Func curved;Func padded;lut(i) = cast<uint8_t>(clamp(pow(i / 255.0f, 1.2f) * 255.0f, 0, 255));// Augment the input with a boundary condition.padded(x, y, c) = input(clamp(x, 0, input.width() - 1),clamp(y, 0, input.height() - 1), c);// Cast it to 16-bit to do the math.Func padded16;padded16(x, y, c) = cast<uint16_t>(padded(x, y, c));// Next we sharpen it with a five-tap filter.Func sharpen;sharpen(x, y, c) = (padded16(x, y, c) * 2 -(padded16(x - 1, y, c) +padded16(x, y - 1, c) +padded16(x + 1, y, c) +padded16(x, y + 1, c)) /4);curved(x, y, c) = lut(sharpen(x, y, c));lut.compute_root();Var block, thread;lut.split(i, block, thread, 16);lut.gpu_blocks(block).gpu_threads(thread);output(x, y, c) = curved(x, y, c);}void schedule(){/* THE SCHEDULE */// input.set_estimates({{0, 1024}, {0, 1024}, {1, 3}});// output.set_estimates({{0, 1024}, {0, 1024}, {1, 3}});}
};HALIDE_REGISTER_GENERATOR(image_f4, image_f4)int main(int argc, char **argv) {return Halide::Internal::generate_filter_main(argc, argv, std::cerr);
}

3、具体说明和注意事项

3.1、生成器使用流程

  • 1、建立基于父类Halide::Generator的核生成器
class image_f4:public Halide::Generator<image_f4>{}
  • 2、声明输出输入buffer信息
// 定义输入buffer,图片数据,三维数据
Input<Buffer<uint8_t>> input{"input", 3};
// 定义输出buffer,图片数据,三维数据,两者shape完全一致。
Output<Buffer<uint8_t>> output{"output", 3};
  • 3、声明核函数的halide计算图实现
    void generate(){Var x, y, c, i, ii, xo, yo, xi, yi;Func lut;Func curved;Func padded;lut(i) = cast<uint8_t>(clamp(pow(i / 255.0f, 1.2f) * 255.0f, 0, 255));// Augment the input with a boundary condition.padded(x, y, c) = input(clamp(x, 0, input.width() - 1),clamp(y, 0, input.height() - 1), c);// Cast it to 16-bit to do the math.Func padded16;padded16(x, y, c) = cast<uint16_t>(padded(x, y, c));// Next we sharpen it with a five-tap filter.Func sharpen;sharpen(x, y, c) = (padded16(x, y, c) * 2 -(padded16(x - 1, y, c) +padded16(x, y - 1, c) +padded16(x + 1, y, c) +padded16(x, y + 1, c)) /4);curved(x, y, c) = lut(sharpen(x, y, c));/*-----------自定义调度-----------*/lut.compute_root();Var block, thread;lut.split(i, block, thread, 16);lut.gpu_blocks(block).gpu_threads(thread);/*-----------自定义调度-----------*/output(x, y, c) = curved(x, y, c);}
  • 4、自动调度设置(可选)
    void schedule(){/* THE SCHEDULE */// input.set_estimates({{0, 1024}, {0, 1024}, {1, 3}});// output.set_estimates({{0, 1024}, {0, 1024}, {1, 3}});}
  • 5、注册生成代码操作
HALIDE_REGISTER_GENERATOR(image_f4, image_f4)//后续通过argv传参去生成image_f4核实现
int main(int argc, char **argv) {return Halide::Internal::generate_filter_main(argc, argv, std::cerr);
}
  • 6、命令行操作
if [ ! -d "./halide_generate_file" ]; thenmkdir halide_generate_file
elserm -rf halide_generate_file/*
fi
# 假设总览代码被编译成了test可执行程序
# target=x86-64-linux-opencl -r GPU这些参数的设置决定了目标平台必然会使用opencl实现
./test -g image_f4 -e c_header,c_source -o halide_generate_file target=x86-64-linux-opencl -r GPU
# 那么将在halide_generate_file文件夹下生成相关代码

3.2、生成代码内容总览

  • opencl核函数代码如下所示:
/* OpenCL C x86-64-linux-opencl*/
#pragma OPENCL FP_CONTRACT ON
inline float float_from_bits(unsigned int x) {return as_float(x);}
inline float nan_f32() { return NAN; }
inline float neg_inf_f32() { return -INFINITY; }
inline float inf_f32() { return INFINITY; }
inline bool is_nan_f32(float x) {return isnan(x); }
inline bool is_inf_f32(float x) {return isinf(x); }
inline bool is_finite_f32(float x) {return isfinite(x); }
#define sqrt_f32 sqrt
#define sin_f32 sin
#define cos_f32 cos
#define exp_f32 exp
#define log_f32 log
#define abs_f32 fabs
#define floor_f32 floor
#define ceil_f32 ceil
#define round_f32 round
#define trunc_f32 trunc
#define pow_f32 pow
#define asin_f32 asin
#define acos_f32 acos
#define tan_f32 tan
#define atan_f32 atan
#define atan2_f32 atan2
#define sinh_f32 sinh
#define asinh_f32 asinh
#define cosh_f32 cosh
#define acosh_f32 acosh
#define tanh_f32 tanh
#define atanh_f32 atanh
#define fast_inverse_f32 native_recip
#define fast_inverse_sqrt_f32 native_rsqrt
#define halide_unused(x)__kernel void _at_least_one_kernel(int x) { }
// Address spaces for _kernel_f0_s0_v3_v9___block_id_x
#define __address_space__f0 __global
__kernel void _kernel_f0_s0_v3_v9___block_id_x(__address_space__f0 uchar *restrict _f0,__local int16* __shared)
{int _f0_s0_v3_v9___block_id_x = get_group_id(0);int ___thread_id_x = get_local_id(0);int _0 = _f0_s0_v3_v9___block_id_x * 16;int _1 = _0 + ___thread_id_x;float _2 = (float)(_1);float _3 = float_from_bits(998277249 /* 0.00392157 */);float _4 = _2 * _3;float _5 = float_from_bits(1067030938 /* 1.2 */);float _6 = pow_f32(_4, _5);float _7 = float_from_bits(1065353216 /* 1 */);float _8 = min(_6, _7);float _9 = float_from_bits(0 /* 0 */);float _10 = max(_8, _9);float _11 = float_from_bits(1132396544 /* 255 */);float _12 = _10 * _11;uchar _13 = (uchar)(_12);_f0[_1] = _13;
} // kernel _kernel_f0_s0_v3_v9___block_id_x
#undef __address_space__f0

4、后续计划与安排

到了这一步,我们已经可以使用halide继续核函数的生成,但是还需要进行如何使用核函数的过程。

Halide::Generator生成器使用说明相关推荐

  1. MyBatis Generator 生成器把其他数据库的同名表生成下来的问题

    MyBatis Generator 生成器把其他数据库的同名表生成下来的问题 2018年10月23日 20:47:48 莫弹弹 阅读数:603 MyBatis Generator : Table Co ...

  2. python生成器yield原理_Python generator生成器和yield表达式详解

    前言 Python生成器(generator)并不是一个晦涩难懂的概念.相比于MetaClass和Closure等概念,其较为容易理解和掌握.但相对于程序结构:顺序.循环和分支而言其又不是特别的直观. ...

  3. python学习笔记-day6-函数的延续【汉字转拼音模块,函数返回多个值,匿名函数,列表生成式,generator生成器,三元运算符】...

    继续来说函数的后续知识点,主要是函数返回多个值,匿名函数,三元运算符,算是比较小的知识点. 一.汉字转拼音模的使用 1.安装模块 #install xpinyin 2.如果使用 结果: 二.函数返回多 ...

  4. 理解Generator生成器对象

    Generator 对象(理解为生成器函数更好) 注意,Generator函数,不可当作构造函数 首先声明一个Generator 函数,以下均以 gen 为例 function* gen(){yiel ...

  5. 3-4 第三天 Generator生成器

    Generator是ES6里面的新增规范,ES6其实就是ES2015.ES5.ES6.ES7这些术语大家上网一查就都明白了.JavaScript是一个范程,就是我们说的JS.ES就是ECMA Scri ...

  6. python generator输出_python 高级特性:Generator(生成器)

    格式对比: List Imprehensions 格式:[ 语句 for .. in ..] Generator 格式:(语句 for .. in ..) 区别:List存储的是具体内容,每个元素都占 ...

  7. Generator(生成器),入门初基,Coroutine(原生协程),登峰造极,Python3.10并发异步编程async底层实现

    普遍意义上讲,生成器是一种特殊的迭代器,它可以在执行过程中暂停并在恢复执行时保留它的状态.而协程,则可以让一个函数在执行过程中暂停并在恢复执行时保留它的状态,在Python3.10中,原生协程的实现手 ...

  8. Python中生成器generator和迭代器Iterator的使用方法

    一.生成器 1. 生成器的定义 把所需要值得计算方法储存起来,不会先直接生成数值,而是等到什么时候使用什么时候生成,每次生成一个,减少计算机占用内存空间 2. 生成器的创建方式 第一种只要把一个列表生 ...

  9. python生成器generator和迭代器Iterator测试

    为什么需要使用生成器? ''' generator生成器 通过列表推导式,我们可以创建一个新的列表,但是,受内存限制,列表的容量是有限的. 而且,创建一个包含100万个元素的列表,不仅占用很大存储空间 ...

最新文章

  1. 非托管资源在虚拟机中的管理
  2. xtrabackup 使用说明(续)
  3. 项目创建venv、_都2020年了,居然还有人没有在数据科学项目中使用Docker?
  4. 厦门大学和福州大学计算机专业哪个好,福州大学和厦门大学的土木工程哪个好...
  5. C++ 静态线性表的顺序存储结构(数组实现)
  6. Sql Server 2005中的快照隔离
  7. Beginning SDL 2.0(4) YUV加载及渲染
  8. 最全三大框架整合(使用映射)——applicationContext.xml里面的配置
  9. T-Sql备份还原数据库
  10. java周志第二周_第二周JAVA学习日志
  11. CVPR 2021 | 用于动作识别,即插即用、混合注意力机制的 ACTION 模块
  12. ehcache常用API整理
  13. oracle里的字符串类型,Oracle中的字符串類型及相關函數詳解
  14. rocketmq下单支付场景
  15. echarts 实现晶体球面投影
  16. python实现不重复排列组合_python 实现排列组合
  17. [编程题]雀魂启动!(java实现)
  18. 网络攻击更难预料,IoT到底是福是祸?
  19. 项目实训(树莓派)(十四)树莓派4B下的ubuntu系统下的vim的使用
  20. ubuntu16.04掉显卡驱动解决方法

热门文章

  1. 刘润对谈吴军:给腾讯和所有上进企业的4点建议
  2. Java分页查询详解
  3. 一个合格的中级前端工程师需要掌握的技能笔记(上)
  4. marve register license
  5. python计算圆周率代码_使用 Python 计算 π 值
  6. 【Linux】进程状态的理解
  7. 彻底关闭FF新闻资讯
  8. 中国石油大学(北京)-《外国文学作品选读》第一阶段在线作业
  9. (三十)arcpy开发pycharm导入arcpy
  10. Page Visibility(页面可见性) API介绍、微拓展