TIK(Tensor Iterator Kernel)是一种基于Python语言的动态编程框架,呈现为一个Python模块。
开发者可以通过调用TIK提供的API基于Python语言编写自定义算子,然后TIK编译器会编译为适配昇腾AI处理器应用程序的二进制文件。
TIK算子开发方式是一种灵活的开发方式。TIK代码在算子开发效率和算子性能自动优化上有着一定的优势:
图1是使用TIK进行编程的过程示意图,用户调用TIK API编写算子对应的Python程序后,TIK会将其转化为TIK DSL(TIK DSL是一种DSL语言,它可以在比CCE更高的抽象层次上定义CCEC程序的行为),经过编译器编译后生成CCEC文件(CCEC代码目前对于TIK编程人员无法感知),再经过CCE编译器编译后生成可运行在昇腾AI处理器上的应用程序。
基于TIK API编写Python程序的通用步骤,如图2所示。
下面以一个简单的例子描述TIK程序的编写步骤:
from tbe import tik
“tbe.tik”:提供了所有TIK相关的python函数,具体请参考CANN软件安装后文件存储路径的“python/site-packages/tbe/tik”。
from tbe import tik tik_instance = tik.Tik()
data_A = tik_instance.Tensor("float16", (128,), name="data_A", scope=tik.scope_gm) data_B = tik_instance.Tensor("float16", (128,), name="data_B", scope=tik.scope_gm) data_C = tik_instance.Tensor("float16", (128,), name="data_C", scope=tik.scope_gm) data_A_ub = tik_instance.Tensor("float16", (128,), name="data_A_ub", scope=tik.scope_ubuf) data_B_ub = tik_instance.Tensor("float16", (128,), name="data_B_ub", scope=tik.scope_ubuf) data_C_ub = tik_instance.Tensor("float16", (128,), name="data_C_ub", scope=tik.scope_ubuf)
tik_instance.data_move(data_A_ub, data_A, 0, 1, 128 //16, 0, 0) tik_instance.data_move(data_B_ub, data_B, 0, 1, 128 //16, 0, 0)
tik_instance.vec_add(128, data_C_ub[0], data_A_ub[0], data_B_ub[0], 1, 8, 8, 8)
tik_instance.data_move(data_C, data_C_ub, 0, 1, 128 //16, 0, 0)
tik_instance.BuildCCE(kernel_name="simple_add",inputs=[data_A,data_B],outputs=[data_C])
其中,
编译产生文件的存储位置默认为”./kernel_meta”,也可以通过BuildCCE中的output_files_path参数指定。
上述TIK实例中,将data_A和data_B从外部存储分别搬运到Unified Buffer中,并通过TIK计算接口vec_add()相加,存放到data_C_ub中,然后将data_C_ub中的数据搬到外部存储data_C中。运行该用例,如果输入data_A和data_B分别为128个float16类型的数字1的一维矩阵,则输出data_C为:
data_C: [2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.]
以上仅对大致编程过程进行展示,后续会对上述实例中各接口、各参数的含义进行详细描述。
在入门学习章节,您已经熟悉了AI Core架构,TIK是基于AI Core架构研发出来的动态编程架构,其面向的存储模型即为AI Core架构的存储模块。
AI Core内的存储介质称为内部存储,对程序员可见的内部存储包括L1 Buffer、L0A Buffer、L0B Buffer、L0C Buffer、Unified Buffer、Scalar Buffer、GPR、SPR等。而AI Core外的存储介质称为外部存储。只有将存储在外部存储内的数据加载到内部存储中,AI Core才能完成相应的计算。详细介绍可参考存储单元,下表简要介绍各内部存储:
存储单元 |
描述 |
TIK标识符 |
---|---|---|
L1 Buffer |
通用内部存储,AI Core内比较大的一块数据中转区,可暂存AI Core中需要反复使用的一些数据从而减少从总线读写的次数。 某些MTE的数据格式转换功能,要求源数据必须位于L1 Buffer,例如3D图像转2D矩阵(Img2Col)操作。 |
scope_cbuf |
L0A Buffer / L0B Buffer |
Cube指令的左/右矩阵输入。 |
scope_ca/scope_cb |
L0C Buffer |
Cube指令的输出,但进行累加计算的时候,也是输入的一部分。 |
scope_cc |
Unified Buffer |
向量和标量计算的输入和输出。 |
scope_ubuf |
Scalar Buffer |
标量计算的通用Buffer,作为GPR不足时的补充。 |
NA |
GPR |
General-Purpose Register,标量计算的输入和输出。 应用开发工程师不需要具体关注这些寄存器,由系统内部实现封装,程序访问Scalar Buffer并执行标量计算的时候,系统内部自动实现Scalar Buffer和GPR之间的同步。 |
NA |
SPR |
Special-Purpose Register,AI Core的一组配置寄存器。 通过修改SPR的内容可以修改AI Core的部分计算行为。 例如,在Tik中可通过调用sys_set/get()函数实现对应配置的修改,这些配置修改后,有可能改变其他函数的行为。 |
NA |
由于各型号芯片的存储单元大小有所不同,TIK用户在编程时可以通过get_soc_spec查阅各存储单元的大小,便于在编程时决定如何安排程序,实现最高效的执行过程。