1.什么是Ascend C?
Ascend C是一门面向算子开发场景的编程语言,原生支持C和C++标准规范。
特点:
Ascend C基于C/C++ 与一个额外类库,支持原语编程
编程模型可以屏蔽硬件差异,用户无需关注
拥有多层计算api封装,可根据实际任务需要选用某一类api
孪生调试:可以在cpu侧模拟npu行为,便于快速调试
2.算子基础概念
基本概念:算子对应(神经)网络中层或节点的计算逻辑
数学含义:一个函数空间到另一个函数空间上的映射
算子的重要属性有:
算子名称:用于标志网络中某个算子,需要为唯一值。
算子类型:相同类型算子的实现逻辑相同
数据容器:张量(tensor),即为存储算子输入输出的容器
tensor的属性包括:名称(name)、形状(shape)、数据类型(dtype)、数据排布格式(format:也即数据的物理排布格式:在深度学习领域,多维数据是用多维数组存储的。因为数据在计算机中只能线性存储,因此需要按照不同的顺序存储数据。例如NCHW将同一通道的所有像素值顺序存储在一起、NHWC则将不同通道的同一位置的像素值顺序存储在一起)
轴(Axis): 张量中维度的下标 例如张量x shape为(5,6) axis=0即为x中的第一维
Ascend C算子即为Ascend c编程语言开发出的算子,其运行在npu的ai core上
3.硬件架构简介
Ai Core逻辑架构使用达芬奇架构
其主要部分包含:
计算单元(包括标量计算单元、向量计算单元、矩阵计算单元,负责输入数据的计算)
存储单元(负责管理ai core片上存储和数据通路)
控制单元(指令经过指令缓存->标量指令处理队列->指令发射模块送至三个运算队列以进一步控制计算任务的执行)
ai core硬件架构抽象
在进行编程实践时,主要基于硬件抽象架构进行编程。上图中Scalar计算单元主要负责指令分发给相应计算单元的指令队列和标量计算(为性能考虑,尽量让Scalar计算单元只进行指令分配的任务)。ai core内部数据处理基本流程是:搬运单元将输入数据从外部内存搬运至LocalMemory,各计算单元可从LocalMemory取数据进行计算与结果写回,最后搬运单元再将计算结果从LocalMemory搬回外部内存。
4.Ascend C矢量编程范式与案例实践
本次实践中应用到了矢量编程范式:即算子实现由数据搬入(CopyIn)、计算(Compute)、数据搬出(CopyOut)三个流水任务组成。在各个任务间使用queue进行同步管理,并且使用Pipe模块进行内存资源管理。
以sinh算子为例:
CopyIn负责搬入数据操作,将输入数据从GlobalMemory搬运到LocalMemory供给计算单元使用。
此部分主要使用的api包括:AllocTensor(通过队列申请内存)、DataCopy(数据搬运实现)、EnQue(数据送入队列)
__aicore__ inline void CopyIn(int32_t progress, uint32_t length) {
LocalTensor<DTYPE_X> xLocal = inQueueX.AllocTensor<DTYPE_X>();
DataCopy(xLocal, xGm[progress * this->tileLength], length);
inQueueX.EnQue(xLocal);
}
Compute负责矢量指令计算操作,通过调用相关计算api实现具体算法。
sinh算法:
__aicore__ inline void Compute(int32_t progress, uint32_t length) {
LocalTensor<DTYPE_X> xLocal = inQueueX.DeQue<DTYPE_X>();
LocalTensor<DTYPE_Y> yLocal = outQueueY.AllocTensor<DTYPE_Y>();
//sinh(x)=(exp(x)-exp(-x))/2
//exp(x)
Exp(yLocal, xLocal, this->tileLength);
//-x
Muls(xLocal, xLocal, (DTYPE_X)(-1), this->tileLength);
//exp(-x)
Exp(xLocal, xLocal, this->tileLength);
//exp(x) - exp(-x)
Sub(xLocal, yLocal, xLocal, this->tileLength);
//(exp(x)-exp(-x))/2
Muls(yLocal, xLocal, (DTYPE_X)(0.5), this->tileLength);
outQueueY.EnQue<DTYPE_Y>(yLocal);
inQueueX.FreeTensor(xLocal);
}
CopyOut负责搬出操作:完成队列出队后,将计算结果从LocalMemory搬运到GlobalMemory,流程类似数据搬入。
__aicore__ inline void CopyOut(int32_t progress, uint32_t length) {
LocalTensor<DTYPE_X> yLocal = outQueueY.DeQue<DTYPE_X>();
DataCopy(yGm[progress * this->tileLength], yLocal, length);
outQueueY.FreeTensor(yLocal);
}
5.参考资料
CANN社区版文档