TBE Add 算子开发入门

举报
jackwangcumt 发表于 2024/04/12 18:51:59 2024/04/12
【摘要】 TBE(Tensor Boost Engine,即张量加速引擎),是一款华为自研的算子开发工具,用于开发能够运行在NPU芯片上的算子,该工具是在业界著名的开源项目TVM(Tensor Virtual Machine)基础上扩展的,提供了一套Python API来进行开发。借助TBE算子开发框架,开发者可以基于Python语言开发自定义算子,从而降低了入门的难度,对于算子的业务逻辑比较简单的场景

1 TBE概述

      TBE(Tensor Boost Engine,即张量加速引擎),是一款华为自研的算子开发工具,用于开发能够运行在NPU芯片上的算子,该工具是在业界著名的开源项目TVM(Tensor Virtual Machine)基础上扩展的,提供了一套Python API来进行开发。借助TBE算子开发框架,开发者可以基于Python语言开发自定义算子,从而降低了入门的难度,对于算子的业务逻辑比较简单的场景,适合用TBE进行算子开发。一般来说,TBE进行算子开发的方式有两种:DSL开发和TIK开发。DSL开发方式比较简单,通过算子定义文件,借助相关工具自动生成Python代码,并在编译时,自动生成特定目标的代码。

2  Add算子分析

      Add算子实现两个张量x1,x2的和,数学表达式是 y = x1 + x2 。Add算子有两个输入与一个输出,支持的数据类型都为float16,数据排布格式为NCHW,要求两个输入的shape相同。本文以DSL方式实现算子,通过查看TBE DSL API,得知可以使用 tbe.dsl.vadd方法来实现业务逻辑 。这里将Add算子的OpType命名为AddDSL,算子实现文件及实现函数名称命名为add_dsl 。

3 Add算子实现

     定义AddDSL算子的原型定义json文件add_dsl.json,用于生成AddDSL的算子开发工程。add_dsl.json文件的内容如下所示:

[
{
        "op":"AddDSL",                
        "input_desc":[
        {                                
                "name":"x1",            
                "param_type":"required", 
                "format":[            
                        "NCHW"
                ],
                "type":[            
                        "fp16"
                ]
        },
        {                         
                "name":"x2",
                "param_type":"required",
                "format":[
                        "NCHW"
                ],
                "type":[
                        "fp16"
                ]
        }
        ],
        "output_desc":[     
        {                     
                "name":"y",
                "param_type":"required",
                "format":[
                        "NCHW"
                ],
                "type":[
                        "fp16"
                ]
        }
        ]
}
]
使用msopgen工具生成AddDSL算子的开发工程,命令如下所示 :
root@atlas500ai:/home/kzroot/mysoft/myAscendC/opdsl# ${INSTALL_DIR}/python/site-packages/bin/msopgen gen 
-i ./add_dsl.json 
-f tf 
-c ai_core-Ascend310P3 
-out ./AddDsl

其中的 ${INSTALL_DIR} 为 /usr/local/Ascend/ascend-toolkit/latest 。执行成功显示如下所示:

QQ截图20240412165654.png

AddDsl目录下生成算子工程,工程中包含各交付件的模板文件,编译脚本等,如下所示:

AddDsl
├── build.sh                           // 编译入口脚本
├── cmake                              // 编译解析脚本存放目录
├── CMakeLists.txt                     
├── framework                          // 算子适配插件相关文件存放目录
│   ├── CMakeLists.txt
│   └── tf_plugin
│       ├── CMakeLists.txt
│       └── tensorflow_add_dsl_plugin.cc   // 算子适配插件实现文件
├── op_proto                      // 算子原型定义相关文件存放目录
│   ├── add_dsl.cc
│   ├── add_dsl.h
│   └── CMakeLists.txt
├── op_tiling
│   └── CMakeLists.txt
├── scripts               // 自定义算子工程打包脚本存放目录
└── tbe
    ├── CMakeLists.txt
    ├── impl              // 算子代码实现
    │   └── add_dsl.py
    └── op_info_cfg       // 算子信息库存放目录
        └── ai_core
            └── ascend310p
                └── add_dsl.ini

修改 op_proto/add_dsl.cc文件,实现算子的输出描述推导函数及校验函数。具体如下所示:

#include "add_dsl.h"
namespace ge {

IMPLEMT_COMMON_INFERFUNC(AddDSLInferShape)
{
    // 获取输出数据描述
    TensorDesc tensordesc_output = op.GetOutputDescByName("y");
    tensordesc_output.SetShape(op.GetInputDescByName("x1").GetShape());
    tensordesc_output.SetDataType(op.GetInputDescByName("x1").GetDataType());
    tensordesc_output.SetFormat(op.GetInputDescByName("x1").GetFormat());
    // 直接将输入x1的Tensor描述信息赋给输出
    (void)op.UpdateOutputDesc("y", tensordesc_output);

    return GRAPH_SUCCESS;
}

IMPLEMT_VERIFIER(AddDSL, AddDSLVerify)
{
    // 校验算子的两个输入的数据类型是否一致,若不一致,则返回失败。
    if (op.GetInputDescByName("x1").GetDataType() != op.GetInputDescByName("x2").GetDataType()) {
        return GRAPH_FAILED;
    }
    return GRAPH_SUCCESS;
}

COMMON_INFER_FUNC_REG(AddDSL, AddDSLInferShape);
VERIFY_FUNC_REG(AddDSL, AddDSLVerify);

}  // namespace ge

实现AddDSL算子的计算逻辑。修改 tbe/impl/add_dsl.py 文件,其中已经自动生成了算子代码的框架,开发者需要在此文件中修改add_dsl_compute函数,实现此算子的计算逻辑。代码如下所示:

import tbe.dsl as tbe
from tbe import tvm
from tbe.common.register import register_op_compute
from tbe.common.utils import para_check


@register_op_compute("add_dsl")
def add_dsl_compute(x1, x2, y, kernel_name="add_dsl"):
    """
    To do: Implement the operator by referring to the
           TBE Operator Development Guide.
    """

    # res = tbe.XXX(x1, x2)
    # 调用dsl的vadd计算接口
    res = tbe.vadd(x1, x2)
    return res

@para_check.check_op_params(para_check.REQUIRED_INPUT, para_check.REQUIRED_INPUT, para_check.REQUIRED_OUTPUT, para_check.KERNEL_NAME)
def add_dsl(x1, x2, y, kernel_name="add_dsl"):
    """
    To do: Implement the operator by referring to the
           TBE Operator Development Guide.
    """
    data_x1 = tvm.placeholder(x1.get("shape"), dtype=x1.get("dtype"), name="data_x1")
    data_x2 = tvm.placeholder(x2.get("shape"), dtype=x2.get("dtype"), name="data_x2")

    res = add_dsl_compute(data_x1, data_x2, y, kernel_name)

    # auto schedule
    with tvm.target.cce():
        schedule = tbe.auto_schedule(res)

    # operator build
    config = {"name": kernel_name,
              "tensor_list": [data_x1, data_x2, res]}
    tbe.build(schedule, config)
    

至此,AddDSL算子的所有交付件都已开发完毕。下面就可以进行编译工程了,修改build.sh脚本,配置算子编译所需环境变量ASCEND_TENSOR_COMPILER_INCLUDE ,将其设置为CANN软件头文件所在路径。执行如下命令可设置:

export ASCEND_TENSOR_COMPILER_INCLUDE=/usr/local/Ascend/ascend-toolkit/latest/include

在算子工程目录下执行如下命令,进行算子工程编译。编译成功后,会在当前目录下创建build_out目录,并在build_out目录下生成自定义算子安装包 custom_opp_ubuntu_aarch64.run 。然后可以执行安装。

root@atlas500ai:/home/kzroot/mysoft/myAscendC/opdsl/AddDsl# ./build.sh
root@atlas500ai:/home/kzroot/mysoft/myAscendC/opdsl/AddDsl# ./build_out/custom_opp_ubuntu_aarch64.run

命令执行成功后,自定义算子包中的相关文件部署到CANN算子库中。下面编写测试用例。创建一个st目录,并创建一个测试用例的定义文件add_dsl.json ,具体内容如下所示:

[
    {
      "case_name":"Test_AddDSL_001",
      "op": "AddDSL", 
      "error_threshold":[0.0001,0.0001],
      "calc_expect_func_file":"./check_add.py:test_add",                    
      "input_desc": [ 
          {                 
              "name": "x1",
              "format": [
                  "NCHW"
              ],
              "type": [ 
                  "float16"
              ],
              "shape": [8,16],
              "data_distribute": [ 
                  "uniform"                 
              ],
              "value_range": [ 
                  [
                      -10.0,
                      10.0
                  ]
              ]
          },
          {           
              "name": "x2",
              "format": [
                  "NCHW"
              ],
               "type": [
                  "float16"
              ],
              "shape": [8,16],
              "data_distribute": [
                  "uniform"
              ],
              "value_range": [
                  [
                      -10.0,
                      10.0
                  ]
              ]
          }
      ],  
      "output_desc": [            
          {
              "name": "y",
              "format": [
                  "NCHW"
              ],
              "type": [
                  "float16"
              ],
              "shape": [8,16]
        }
      ]
  }
]

其中的"calc_expect_func_file":"./check_add.py:test_add" 定义测试的校验函数,check_add.py文件内容如下所示:

def test_add(x1,x2,y):
    res = x1['value'] + x2['value']
    return [res,]

配置ST测试用例编译所需环境变量。ST测试用例的主要功能为:使用AscendCL接口加载单算子模型文件并执行,所以生成并编译ST测试用例前需要配置AscendCL应用编译所需环境变量:

root@atlas500ai:/home/kzroot/mysoft/myAscendC/opdsl/st# export DDK_PATH=${INSTALL_DIR}
root@atlas500ai:/home/kzroot/mysoft/myAscendC/opdsl/st# export NPU_HOST_LIB=${INSTALL_DIR}/runtime/lib64/stub
root@atlas500ai:/home/kzroot/mysoft/myAscendC/opdsl/st# ${INSTALL_DIR}/python/site-packages/bin/msopst run 
-i ./add_dsl.json 
-soc Ascend310P3 
-out ./out

执行测试通过后,显示如下所示:

QQ截图20240412184953.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。