Ascend C算子开发能力认证(中级):是开发者在Ascend C算子设计、实现与框架调用能力的权威认证。通过该认证,您将展示您在深度学习框架中的Ascend C算子开发能力,为业界所认可。
Ascend C算子开发能力认证考试伴侣-昇腾Ascend C编程入门教程,在昇腾社区的地址:https://www.hiascend.com/forum/thread-0239124507827469022-1-1.html
Ascend C算子开发视频学习课程:在线课程详情
Ascend C算子开发配套视频学习课程的资料:
1、在线文档:https://hiascend.com/document/redirect/CannCommunityOpdevAscendC
2、课程示例代码:https://gitee.com/ascend/samples/tree/master/operator/ascendc/0_introduction/1_add_frameworklaunch
4、环境搭建:参考Ascend C环境准备帖进行环境搭建
视频学习课程非常详细,但是有时候静不下心来学,在线文档非常详细,但是内容太多了,看不过来。如果想快速通过Ascend C算子开发能力认证考试,那么还可以看下昇腾社区的这篇文档:昇腾Ascend C编程入门教程。
op_kernel代码学习
以下代码来源于昇腾Ascend C编程入门教程,文件位置:op_kernel/add_custom.cpp
初始化
cpp
__aicore__ inline void Init(GM_ADDR x, GM_ADDR y, uint32_t totalLength, uint32_t tileNum, float scalar)
{
ASSERT(GetBlockNum() != 0 && "block dim can not be zero!");
this->blockLength = totalLength / GetBlockNum();
this->tileNum = tileNum;
this->scalar = static_cast<half>(scalar);
ASSERT(tileNum != 0 && "tile num can not be zero!");
this->tileLength = this->blockLength / tileNum / BUFFER_NUM;
// get start index for current core, core parallel
xGm.SetGlobalBuffer((__gm__ half*)x + this->blockLength * get_block_idx(), this->blockLength);
yGm.SetGlobalBuffer((__gm__ half*)y + this->blockLength * get_block_idx(), this->blockLength);
// pipe alloc memory to queue, the unit is Bytes
pipe.InitBuffer(inQueueX, BUFFER_NUM, this->tileLength * sizeof(half));
pipe.InitBuffer(outQueueY, BUFFER_NUM, this->tileLength * sizeof(half));
}
Process函数
主要实现三个CopyIn、Compute、CopyOut这三stage。
cpp
__aicore__ inline void Process()
{
// loop count need to be doubled, due to double buffer
int32_t loopCount = this->tileNum * BUFFER_NUM;
// tiling strategy, pipeline parallel
for (int32_t i = 0; i < loopCount; i++) {
CopyIn(i);
Compute(i);
CopyOut(i);
}
}
CopyIn函数
cpp
__aicore__ inline void CopyIn(int32_t progress)
{
// alloc tensor from queue memory
LocalTensor<half> xLocal = inQueueX.AllocTensor<half>();
// copy progress_th tile from global tensor to local tensor
DataCopy(xLocal, xGm[progress * tileLength], tileLength);
// enque input tensors to VECIN queue
inQueueX.EnQue(xLocal);
}
Compute函数
负责从Queue中取出数据,进行计算,并将结果放入Queue
cpp
__aicore__ inline void Compute(int32_t progress)
{
// deque input tensors from VECIN queue
LocalTensor<half> xLocal = inQueueX.DeQue<half>();
LocalTensor<half> yLocal = outQueueY.AllocTensor<half>();
// call LeakyRelu instr for computation
LeakyRelu(yLocal, xLocal, scalar, tileLength);
// enque the output tensor to VECOUT queue
outQueueY.EnQue<half>(yLocal);
// free input tensors for reuse
inQueueX.FreeTensor(xLocal);
}
当然,认证考试可能是其它的算子,需要自己写相关的计算代码部分。
CopyOut函数
负责从Queue中将数据取出,并将数据从Local Memory拷贝到Global Memory。
cpp
__aicore__ inline void CopyOut(int32_t progress)
{
// deque output tensor from VECOUT queue
LocalTensor<half> yLocal = outQueueY.DeQue<half>();
// copy progress_th tile from local tensor to global tensor
DataCopy(yGm[progress * tileLength], yLocal, tileLength);
// free output tensor for reuse
outQueueY.FreeTensor(yLocal);
}
补充init和process函数调用内容
cpp
extern "C" __global__ __aicore__ void leakyrelu_custom(GM_ADDR x, GM_ADDR y, GM_ADDR workspace, GM_ADDR tiling)
{
GET_TILING_DATA(tilingData, tiling);
KernelLeakyRelu op;
op.Init(x, y, tilingData.totalLength, tilingData.tileNum, tilingData.scalar);
op.Process();
}
自定义成员变量
cpp
uint32_t blockLength;
uint32_t tileNum;
uint32_t tileLength;
op_host代码学习
以下代码来自于代码示例:https://gitee.com/ascend/samples/tree/master/operator/ascendc/0_introduction/1_add_frameworklaunch/AddCustom
填充tiling结构体
文件位置:op_host/add_custom.cpp ,以下为AddCustom算子的示例
cpp
static ge::graphStatus TilingFunc(gert::TilingContext *context)
{
TilingData tiling;
uint32_t totalLength = context->GetInputShape(0)->GetOriginShape().GetShapeSize(); //输入数据长度
context->SetBlockDim(BLOCK_DIM); //设置block大小
tiling.set_totalLength(totalLength); //设置输入数据长度
tiling.set_tileNum(TILE_NUM); //设置tiling数量
tiling.SaveToBuffer(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity()); //将tiling数据保存到buffer中
context->GetRawTilingData()->SetDataSize(tiling.GetDataSize()); //设置tiling数据大小
size_t *currentWorkspace = context->GetWorkspaceSizes(1); //获取工作空间大小
currentWorkspace[0] = 0; //设置工作空间大小
return ge::GRAPH_SUCCESS; //返回成功
}
} // namespace optiling
自行定义tiling结构体成员变量
文件位置op_host/add_custom_tiling.h ,以下为AddCustom算子的示例
cpp
namespace optiling {
BEGIN_TILING_DATA_DEF(TilingData)
TILING_DATA_FIELD_DEF(uint32_t, totalLength); //输入张量长度
TILING_DATA_FIELD_DEF(uint32_t, tileNum); //输入张量分块个数
END_TILING_DATA_DEF;
REGISTER_TILING_DATA_CLASS(AddCustom, TilingData)
} // namespace optiling