DSL简介
为了方便开发者进行自定义算子开发,TBE(Tensor Boost Engine)提供了一套计算接口供开发者用于组装算子的计算逻辑,这套计算接口称之为DSL(Domain-Specific Language)。基于DSL开发的算子,可以直接使用TBE提供的Auto Schedule机制,自动完成调度过程,省去最复杂的调度编写过程。
DSL功能框架
TBE DSL算子的功能框架如图1所示。
- 开发者调用TBE提供的DSL接口进行计算逻辑的描述,指明算子的计算方法和步骤。
- 计算逻辑开发完成后,开发者可调用Auto Schedule接口,启动自动调度,自动调度时TBE会根据计算类型自动选择合适的调度模板,完成数据切块和数据流向的划分,确保在硬件执行上达到最优。
- Auto Schedule调度完成后,会生成类似于TVM的IR(Intermediate Representation)的中间表示。
- 编译优化(Pass)会对算子生成的IR进行编译优化,优化的方式有双缓冲(Double Buffer)、流水线(Pipeline)同步、内存分配管理、指令映射、分块适配矩阵计算单元等。
- 算子经Pass处理后,由CodeGen生成类C代码的临时文件,这个临时代码文件可通过编译器生成算子的实现文件,可被网络模型直接加载调用。
代码示例如下所示:
//初始化输入tensor,为输入tensor进行占位 data_x = tvm.placeholder(shape_x, name="data_1", dtype=input_data_type) data_y = tvm.placeholder(shape_y, name="data_2", dtype=input_data_type) //调用计算接口实现data_x + data_y res = tbe.dsl.vadd(data_x, data_y) //调用auto_schedule接口实现自动调度 with tvm.target.cce(): schedule = tbe.dsl.auto_schedule(res) //配置编译参数并进行编译 config = {"name": kernel_name, "tensor_list": (data_x, data_y, res)} tbe.dsl.build(schedule, config)
Auto Schedule介绍
算子的计算逻辑实现完后,如果要让计算逻辑在硬件中执行,还需要考虑如下问题:
- 计算指令在硬件中按照什么顺序执行?
- 数据如何在硬件内存中存储?
Schedule(调度)就是为了解决如上问题,通过调整计算逻辑、优化计算过程,使得计算更加高效,并保证计算过程中占用的硬件存储空间不会超过上限。
TBE DSL提供了Auto Schedule机制,以上Schedule操作无需用户关注。用户通过组合DSL接口表达算子的计算逻辑后,直接调用Auto Schedule接口即可实现自动调度,完成数据切块和数据流向的划分。Auto Schedule机制是TBE底层的默认Schedule调优机制,开发者无法在算子开发代码过程中进行控制,下面简要介绍Auto Schedule的原理。
如下是基于DSL进行算子开发的示例,实现对x取指数,然后在轴0上进行累加降维,再取倒数的功能。
x = tvm.placeholder((512, 1024), "float16") exp_x = tbe.dsl.vexp(x) reduce_exp_x = tbe.dsl.sum(exp_x, axis = 0) res = tbe.dsl.vrec(reduce_exp_x) with tvm.target.cce(): sch = tbe.dsl.auto_schedule(res)
开发者调用tbe.dsl.auto_schedule接口开启TBE的自动调度,自动调度的总体流程如图2所示。
- 调用Auto Schedule接口的时候,就是传递了一个compute的语法树,TBE中每一个compute语句在进行编译的时候都会被加上tag_scope标志,如下所示。
with tvm.tag_scope(op): tmp = tvm.compute(shape, lambda_func, name=name)
如图3所示,左侧的compute语法树,也叫抽象语法树(Abstract Syntax Tree: AST),编译过程中,会对每一个compute语句加上tag_scope标志。 - 根据scope标识,识别出对应pattern,TBE当前支持的pattern类型有:elewise、reduce、segment、concat、conv、depthwise、pooling2d等。TBE会按照pattern规则对AST进行切分,例如最简单的一条pattern规则是elewise可以和其他的pattern连在一起,reduce、segment、concat不能在一个AST子图内。
- 完成AST子图切分后,TBE会创建并初始化Schedule对象。
- Schedule执行过程中首先找到AST子图的边界,然后对每一个子图根据其pattern选择一个合适的Schedule模板进行调度。调度过程主要包括数据流管理、tiling以及指令映射等。
父主题: 算子代码实现(TBE DSL)