【2024CANN训练营第二季】Ascend C API接口
Ascend C API接口概述
Ascend C算子采用标准C++语法和一组类库API进行编程,开发者根据自己的需求选择合适的API。
Ascend C API的操作数据类型:Tensor类型
- GlobalTensor
- LocalTensor,
类库API
- 高阶API
- 基础API
基础API
实现基础功能的API,包括计算类、数据搬运、内存管理和任务同步等。使用基础API自由度更高,可以通过API组合实现自己的算子逻辑。基础API是对计算能力的表达。
计算类API:标量计算API、向量计算API、矩阵计算API、分别实现调用Scalar计算单元、Vector计算单元、Cube计算单元
数据搬运API:基于Local Memory数据进行计算,数据需要先从Global Memory搬运至Local Memory,再使用计算接口完成计算,最后从Local Memory搬出至Global Memory。比如DataCopy接口
内存管理API:用于分配管理内存,比如AllocTensor、FreeTensor接口
任务同步API:完成任务间的通信和同步,比如EnQue、DeQue接口。不同的指令异步并行执行,为了保证不同指令队列间的指令按照正确的逻辑关系执行,需要向不同的组件发送同步指令
Ascend C API用于计算的基本数据类型都是Tensor:GlobalTensor和LocalTensor
计算API
命名 | 说明 |
---|---|
整个Tensor参与计算 | 通过运算符重载的方式实现,支持+,-,*,/,|,&,<,>,<=,>=,==,!=,实现计算的简化表述。例如:dst=src1+src2 |
Tensor前n个数据计算 | 针对源操作数的连续n个数据进行计算并连续写入目的操作数,解决一维Tensor的连续计算问题。例如:Add(dst,src1,src2,n) |
Tensor高维切分计算 | 功能灵活的计算API,充分发挥硬件优势,支持对每个操作数的Repeat Times(迭代次数)、Block Stride(单词迭代内不同block间地址步长)、Repeat Stride(相邻迭代间相同block的地址步长)、Mask(用于控制参与运算的计算单元)的操作 |
Tensor高维切分计算通用参数
- Repeat times:迭代次数
- Repeat stride:相邻迭代间相同block的地址步长
- Block stride:单词迭代内不同block的地址步长
- Mask:用于控制参与运算的计算单元
以上都是通用描述,其命名不一定与具体指令中的参数命名完全对应
比如:单词迭代内不同block间步长Block stride参数,在单目指令中,对应为dstBlkStride,srcBlkStride参数。在双目指令中,对应为dstBlkStride、src0BlkStride、src1BlkStride参数。
重复迭代次数-Repeat times
矢量计算单元,每次读取连续的8个block(每个block 32 Bytes,共256 Bytes)数据进行计算,为完成对输入数据的处理,必须通过多次迭代(repeat)才能完成所有数据的读取与计算。Repeat times表示迭代的次数
相邻迭代间相同block的地址步长-Repeat stride
当Repeat times>1,需要多次迭代完成矢量计算时,可以根据不同的使用场景合理设置相邻迭代间相同block的地址步长Repeat stride的值
连续计算场景:假设定义一个Tensor供目的操作数和源操作数同时使用(即地址重叠),Repeat stride取值为8。此时,矢量计算单元第一次迭代读取连续8个block,第二轮迭代读取下一个连续的8个block,通过多次迭代即可完成所有输入数据的计算
非连续计算场景:Repeat stride>8(如Repeat stide =10)时,则相邻迭代间矢量计算单元读取的数据在低智商不连续出现2个block的间隔。
反复计算场景:Repeat stride = 0时,矢量计算单元会对收个连续的8个block进行反复读取和计算。
同一迭代内不同block的地址步长-Block stride
如果需要控制单词迭代内,数据处理的步长,可以通过设置统一迭代内不同block的地址步长Block stride来实现
- 连续计算:Block stride=1,对同一迭代内的8个block数据连续进行处理。
- 非连续计算,Block stride>1(如Block stride=2),同一迭代内不同block之间在读取数据时出现一个block的间隔
Mask参数
mask用于控制每次迭代内参与计算的元素。可通过连续模式和逐比特模式两种方式进行设置
-
连续模式:表示前面连续的多少个元素参与计算,数据类型为uint64_t。取值范围和操作数的数据类型有关,数据类型不同,每次迭代内能够处理的元素个数最大值不同(当前数据类型单次迭代能处理的元素个数最大值为:256/sizeof(数据类型))。当操作数的数据类型占比特位16位时(如half,uint16_t),mask∈[1,128],当操作数为32位时(如float,int32_1),mask∈[1,64]
-
逐比特模式:可以按位控制哪些元素参与计算,比特位的值为1表示参与计算,0表示不参与。参数类型为长度为2的unit64_t类型数组。参数取值范围和操作数的数据类型有关,数据类型不同,每次迭代内能够处理的元素个数最大值不同。当操作数为16位时,mask[0]、mask[1]∈[0,(2^64)-1]、且mask[0]和mask[1]不可同时为0,当dst/src为32位时,msk[1]为0,msk[0]∈(0,(2^64)-1]
数据搬运API
定义
普通数据搬运2级接口:适用于连续数据搬运
template <typename T>
void DataCopy(const LocalTensor<T>& dstLocal, const GlobalTensor<T>& srcGlobal, const uint32_t calCount);
普通数据搬运0级接口:适用于连续和不连续搬运
template <typename T>
void DataCopy(const LocalTensor<T>& dstLocal, const GlobalTensor<T>& srcGlobal, const DataCopyParams& intriParams);
参数
blockCount:指定该指令包含的连续传输数据块的个数。
blockLen:指定该指令每个连续传输数据块长度,单位为datablock(32Bytes)。
srcStride:源操作数,相邻连续数据块的间隔(前面一个数据块的尾与后面数据块的头的间隔),单位为datablock(32Bytes)。
dstStride:目的操作数,相邻连续数据块间的间隔(前面一个数据块的尾与后面数据块的头的间隔),单位为datablock(32Bytes)
高阶API
封装常用算法逻辑的API,比如Matmul,Softmax等,可减少重复开发,提高开发者开发效率。使用高阶API可以快速的实现相对复杂的算法逻辑,高阶API是对于某种特定算法的表述。
举例:实现Matmul矩阵乘运算的步骤如下
- 创建Matmul对象
- 初始化
- 设置左矩阵A、右矩阵B、Bias
- 完成矩阵乘操作
代码:
// 1、创建Matmul对象
typedef MatmulType<TPosition::GM, CubeFormat::ND, half>aType;
typedef MatmulType<TPosition::GM, CubeFormat::ND, half>bType;
typedef MatmulType<TPosition::GM, CubeFormat::ND, float>cType;
typedef MatmulType<TPosition::GM, CubeFormat::ND, float>biasType;
MatMul<aType, bType, cType, biasType>mm;
mm.Init(&tiling, &tpipe); //初始化
//2、设置左矩阵A、右矩阵B、Bias
mm.SetTensorA(gm_a) //设置左矩阵A
mm.SetTensorB(gm_b) //设置右矩阵B
mm.SetBias(gm_bias) //设置Bias
//3、完成矩阵乘操作
while (mm.Iterate()){
mm.GetTensor(gm_c);
}
//mm.InterateALL(gm_c);
//4、结束矩阵操作
mm.End();
- 点赞
- 收藏
- 关注作者
评论(0)