【TBE算子开发】TIk算子开发总结
TIk算子开发总结
tik算子开发时可以采用当前我们DSL的开发框架进行,当变量过多时可以以class形式来开发
tik算子开发只需要在算子接口处进行shape、dtype等的验证,但tik不需要定义tvm.placeholder,直接定义TIK的DSL容器,语句如下
1 2 | import tik tik_instacnce = tik.Tik(tik.Dprofile( "v100" , "cloud" )) |
目前只支持v100下cloud和mini,其中tik.Tik用于创建TIK的DSL的容器,tik.Dprofile用于指定编程时针对的编程环境
一旦创建了TIK容器,所有的语句都是基于tik_instacnce进行语句开发,不能出现普通的python语句
当前tik语句支持的数据类型有:int8,uint8, int16, uint16, int32, uint32, float16, float32,uint1(bool),比如在cloud形式下,除了输入输出的gm类型局限在fp32、fp16、int8、int32、uint8,tik中的数据类型都可以采用上述的数据类型;
定义Scalar方法:
1 | x = tik_instance.Scalar( "int64" ) |
相当于定义了一个uint64的Scalar变量x;
定义tensor方法:
1 | x = tik_instance.Tensor(name = "X" , dtype = "float32" , shape = [ 1 ,], scope = tik.scope_gm) |
其中scope表示tensor定义的区域;
Scalar和tensor的生命周期:在定义语句时创建,到定义语句所在代码块(if,else,for)的结束并释放,只有在存在期间可以被访问,,所以要根据需要去确定定义的范围
分支结构:采用if_scope进行分支判断(else部分为可选),实现如下:
1 2 3 4 | with tik_instance.if_scope(x> 1 ): #some method with tik_instance.else_scope: #some method |
For语句:
1 | tik_instance.for_range(begint,endt,name = "i" , thread_num = 1 ,block_num = 1 ,dtype = "int32" ) as i |
等同于 for i in range(begint, endt),里面的begint, endt可以使用常量,不一定要tik定义的scalar
thread_num可以选择1或者2,默认为1,当选择2时,为开启pingpong,在该for循环语句下,每个buf会double
block_num:分核数,默认值为1,只能在一个for循环中设置该值,建议在最外循环外设置该值;
tik.Tik.BuildCCE(kernel_name, inputs,outpus):用于将DSL容器中语句编译成CCEC代码
inputs:List型变量,List中存放程序的输入Tensor(需要是global memory的存储类型)
outputs,List型变量,List中存放程序的输出Tensor(需要是global memory的存储类型)
以上为tik开发最基本的语句
下面给出一个简单的例子:使用tik语句实现a+b:
a:fp32 [1024, 1024,1024]
b : fp32 [1024, 1024,1024]
add属于vector操作,需要把a和b的数据从gm搬到ub中,在然后进行add操作,最后再从搬出来
考虑到a+b的结果可以复写到a中,因此考虑在ub中定义两个tensor,分别用于存放a和b;另外由于a和b的shape比较大,在考虑分核的同时,还需要考虑DB使能,因此a和b可以分到的UB为UB总大小的1/4(记为a_ub和b_ub).
UB大小为256K,a_ub=b_ub=64k,相当于64*1024/4=16*1024个fp32数据,因此每次可以从gm往ub中搬运16*1024个数据
vector一拍可以处理64个fp32数据,因此repeat=1024*16/64=256(repeat 上限是255,考虑分两次执行,每次128)
具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # 定义tik容器,这里定义为cloud环境下 tik_instance = tik.Tik(tik.Dprofile( "v100" , "cloud" )) # 定义输入输出的gm input_x_gm = tik_instance.Tensor( "float32" , [ 1024 , 1024 , 1024 ], name = "input_x" , scope = tik.scope_gm) input_y_gm = tik_instance.Tensor( "float32" , [ 1024 , 1024 , 1024 ], name = "input_y" , scope = tik.scope_gm) output_gm = tik_instance.Tensor( "float32" , [ 1024 , 1024 , 1024 ], name = "ioutput" , scope = tik.scope_gm) # 最外面循环进行分核,cloud下最大为32核 with tik_instance.for_range( 0 , 32 , block_num = 32 ) as out: # db循环,循环次数为1024^3/32/16/1024=2048,该循环内定义的ub都会自动double with tik_instance.for_range( 0 , 2048 , thread_num = 2 ) as db_out: # 定义ub_a和ub_b a_ub = tik_instance.Tensor( "float32" , ( 16 , 1024 ), name = "a_ub" , scope = tik.scope_ubuf) b_ub = tik_instance.Tensor( "float32" , ( 16 , 1024 ), name = "b_ub" , scope = tik.scope_ubuf) # 搬运数据 tik_instance.data_move(a_ub, input_x_gm[out * 32 + db_out * 16 % 1024 , db_out * 16 % 1024 , 0 ], 0 , 1 , 16 * 1024 * 4 / / 32 , 0 , 0 ) tik_instance.data_move(y_ub, input_y_gm[out * 32 + db_out * 16 % 1024 , db_out * 16 % 1024 , 0 ], 0 , 1 , 16 * 1024 * 4 / / 32 , 0 , 0 ) # 数据运算 tik_instance.vadd( 64 , a_ub, a_ub, b_ub, 128 , 1 , 1 , 1 , 8 , 8 , 8 ) tik_instance.vadd( 64 , a_ub[ 8 , 0 ], a_ub[ 8 , 0 ], b_ub[ 8 , 0 ], 128 , 1 , 1 , 1 , 8 , 8 , 8 ) # 搬运数据 tik_instance.data_move(input_x_gm[out * 32 + db_out * 16 % 1024 , db_out * 16 % 1024 , 0 ], a_ub, 0 , 1 , 16 * 1024 * 4 / / 32 , 0 , 0 ) tik_instance.BuildCCE(kernel_name = "add" , inputs = [input_x_gm, input_y_gm], outputs = [output_gm,]) |
- 点赞
- 收藏
- 关注作者
评论(0)