文档
注册

快速入门

本章节以开发一个Add算子为例,带您快速体验CANN算子开发的流程。Add算子的功能是实现两个数的加法操作,并将结果返回。

了解开发过程

全新开发算子的流程如下图所示。

每一个算子交付件的含义如下:
  • 算子原型定义:定义算子输入、输出、属性。
  • 算子代码实现:描述算子的运算逻辑,完成特定的计算功能。
  • 算子信息库定义:描述算子在昇腾AI处理器上的实现限制,包含算子输入输出的dtype、format、shape信息。算子编译时,会根据算子信息库匹配到算子实现。
  • 算子适配插件开发:用于进行第三方框架的适配,让第三方框架的算子可以映射到CANN算子。

此处,您不需要深入了解每一个交付件的含义,本章节旨在让您快速了解算子开发流程。您可以通过后续章节进行深入了解。

环境准备

请参见环境准备部署软件环境,并配置相关的环境变量。

准备好CANN软件基础环境后,进行算子开发操作前,你需要了解如下基本概念,以便更好的理解后续操作。

  • 开发环境:指编译开发代码的环境。
  • 运行环境:指运行算子、推理程序、训练程序等的环境。运行环境必须带昇腾AI处理器
  • 开发环境与运行环境合设场景:指带昇腾AI处理器的机器既作为开发环境又作为运行环境。此种场景下,代码开发与代码运行在同一台机器上。
  • 开发环境与运行环境分设场景:开发环境和运行环境不在同一台机器上,开发者使用带有昇腾AI处理器的机器作为运行环境;使用其他独立机器进行代码开发与编译,作为开发环境。

为了简化操作流程,本快速入门以开发环境与运行环境合设的场景为例。

针对开发环境与运行环境分设的场景,区别在于基于msopst工具进行ST测试,详细区别可参见算子包部署基于msopst工具

算子分析

下面进行Add算子的详细规格分析:

  • 明确算子的数学表达式
    y=x1+x2
  • 明确输入输出

    算子有两个输入与一个输出,支持的数据类型都为float16,数据排布格式为NCHW,要求两个输入的shape相同。

  • 确定使用的计算接口

    计算过程涉及加法操作,本样例通过DSL方式实现,查看TBE DSL API,分析可使用tbe.dsl.vadd。

  • 明确算子实现文件名称、算子实现函数名称以及算子的类型

    为了区别于CANN内置的Add算子,我们将此样例算子的OpType命名为AddDSL,算子实现文件及实现函数名称命名为add_dsl。

工程创建

  1. 定义AddDSL算子的原型定义json文件,用于生成AddDSL的算子开发工程。
    例如,定义的json文件的名字为add_dsl.json,存储路径为: $HOME/sample,文件内容如下:
    [
    {
            "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"
                    ]
            }
            ]
    }
    ]
  2. 使用msopgen工具生成AddDSL算子的开发工程。

    ${INSTALL_DIR}/python/site-packages/bin/msopgen gen -i $HOME/sample/add_dsl.json -f tf -c ai_core-<soc_version> -out $HOME/sample/AddDsl

    ${INSTALL_DIR}为CANN软件安装后文件存储路径;“-f tf”参数代表选择的原始框架为TensorFlow;“-c ai_core-<soc_version>”代表算子在AI Core上执行,<soc_version>昇腾AI处理器的型号。

    此命令执行完后,会在$HOME/sample/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
                └── <soc_version>
                    └── add_dsl.ini

    上述目录结构中的粗体文件为后续算子开发过程中需要修改的文件,其他文件无需修改。

算子开发过程

  1. 实现AddDSL算子的原型定义。
    算子原型定义文件包含算子注册代码的头文件(*.h)以及实现基本校验、Shape推导的实现文件(*.cc)。
    • msopgen工具根据add_dsl.json文件在“op_proto/add_dsl.h”中生成了算子注册代码,开发者需要检查自动生成的代码逻辑是否正确,一般无需修改。
    • 修改“op_proto/add_dsl.cc”文件,实现算子的输出描述推导函数及校验函数。
      • 在IMPLEMT_COMMON_INFERFUNC(AddDSLInferShape)函数中,填充推导输出描述的代码,针对AddDSL算子,输出Tensor的描述信息与输入Tensor的描述信息相同,所以直接将任意一个输入Tensor的描述赋给输出Tensor即可。
        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)函数中,填充算子参数校验代码。
        IMPLEMT_VERIFIER(AddDSL, AddDSLVerify)
        {
            // 校验算子的两个输入的数据类型是否一致,若不一致,则返回失败。
            if (op.GetInputDescByName("x1").GetDataType() != op.GetInputDescByName("x2").GetDataType()) {
                return GRAPH_FAILED;
            }
            return GRAPH_SUCCESS;
        }
  2. 实现AddDSL算子的计算逻辑。

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

    add_dsl_compute函数的实现代码如下:

    @register_op_compute("add_dsl")
    def add_dsl_compute(x1, x2, y, kernel_name="add_dsl"):
        # 调用dsl的vadd计算接口
        res = tbe.vadd(x1, x2)
        return res
  3. 配置算子信息库。

    算子信息库的路径为“tbe/op_info_cfg/ai_core/<soc_version>/add_dsl.ini”,包含了算子的类型,输入输出的名称、数据类型、数据排布格式等信息,该样例中,msopgen工具已经根据add_dsl.json文件将上述内容自动填充,开发者无需修改。

    AddDSL算子的信息库如下:

    [AddDSL]                    // 算子的类型 
    input0.name=x1              // 第一个输入的名称
    input0.dtype=float16        // 第一个输入的数据类型
    input0.paramType=required   // 代表此输入必选,且仅有一个
    input0.format=NCHW          // 第一个输入的数据排布格式
    input1.name=x2              // 第二个输入的名称
    input1.dtype=float16        // 第二个输入的数据类型
    input1.paramType=required   // 代表此输入必选,且仅有一个
    input1.format=NCHW          // 第二个输入的数据排布格式
    output0.name=y              // 算子输出的名称
    output0.dtype=float16       // 算子输出的数据类型
    output0.paramType=required  // 代表此输出必选,有且仅有一个
    output0.format=NCHW         // 算子输出的数据排布格式
    opFile.value=add_dsl        // 算子实现文件的名称
    opInterface.value=add_dsl   // 算子实现函数的名称
  4. 实现算子适配插件。

    算子适配插件实现文件的路径为“framework/tf_plugin/tensorflow_add_dsl_plugin.cc”,针对原始框架为TensorFlow的算子,CANN提供了自动解析映射接口“AutoMappingByOpFn”,如下所示:

    #include "register/register.h"
    
    namespace domi {
    // register op info to GE
    REGISTER_CUSTOM_OP("AddDSL")     // CANN算子的类型
        .FrameworkType(TENSORFLOW)   // type: CAFFE, TENSORFLOW
        .OriginOpType("AddDSL")      // 原始框架模型中的算子类型
        .ParseParamsByOperatorFn(AutoMappingByOpFn);   //解析映射函数
    }  // namespace domi

    以上为工程自动生成的代码,开发者仅需要修改.OriginOpType("AddDSL")中的算子类型即可。此处我们仅展示算子开发流程,不涉及原始模型,我们不做任何修改。

    至此,AddDSL算子的所有交付件都已开发完毕。

算子编译部署

  1. 算子工程编译。
    1. 修改build.sh脚本,配置算子编译所需环境变量。

      将build.sh中环境变量ASCEND_TENSOR_COMPILER_INCLUDE配置为CANN软件头文件所在路径。

      修改前,环境变量配置的原有代码行如下:

      # export ASCEND_TENSOR_COMPILER_INCLUDE=/usr/local/Ascend/ascend-toolkit/latest/compiler/include
      修改后,新的代码行如下:
      export ASCEND_TENSOR_COMPILER_INCLUDE=${INSTALL_DIR}/include

      ${INSTALL_DIR}请替换为CANN软件安装后文件存储路径。例如,若安装的Ascend-cann-toolkit软件包,则安装后文件存储路径为:$HOME/Ascend/ascend-toolkit/latest。

    2. 在算子工程目录下执行如下命令,进行算子工程编译。

      ./build.sh

      编译成功后,会在当前目录下创建build_out目录,并在build_out目录下生成自定义算子安装包custom_opp_<target os>_<target architecture>.run

  2. 自定义算子安装包部署。

    进入算子工程目录下的build_out目录,以运行用户执行如下命令,安装自定义算子包。

    ./custom_opp_<target os>_<target architecture>.run

    命令执行成功后,自定义算子包中的相关文件部署到CANN算子库中。

ST测试

  1. 创建ST测试用例定义文件“*.json”,用于生成测试用例。

    例如,定义的json文件的名字为add_dsl.json,存储路径为: $HOME/sample/st,文件内容如下:

    [
          {
            "case_name":"Test_AddDSL_001",
            "op": "AddDSL",                     
            "input_desc": [ 
                {                 
                    "name": "x1",
                    "format": [
                        "NCHW"
                    ],
                    "type": [ 
                        "float16"
                    ],
                    "shape": [8,16],
                    "data_distribute": [ 
                        "uniform"                 
                    ],
                    "value_range": [ 
                        [
                            1.0,
                            384.0
                        ]
                    ]
                },
                {           
                    "name": "x2",
                    "format": [
                        "NCHW"
                    ],
                     "type": [
                        "float16"
                    ],
                    "shape": [8,16],
                    "data_distribute": [
                        "uniform"
                    ],
                    "value_range": [
                        [
                            1.0,
                            384.0
                        ]
                    ]
                }
            ],  
            "output_desc": [            
                {
                    "name": "y",
                    "format": [
                        "NCHW"
                    ],
                    "type": [
                        "float16"
                    ],
                    "shape": [8,16]
              }
            ]
        }
    ]
  2. 配置ST测试用例编译所需环境变量。
    ST测试用例的主要功能为:使用AscendCL接口加载单算子模型文件并执行,所以生成并编译ST测试用例前需要配置AscendCL应用编译所需环境变量,如下所示:
    export DDK_PATH=${INSTALL_DIR}
    export NPU_HOST_LIB=${INSTALL_DIR}/runtime/lib64/stub

    ${INSTALL_DIR}请替换为CANN软件安装后文件存储路径。例如,若安装的Ascend-cann-toolkit软件包,则安装后文件存储路径为:$HOME/Ascend/ascend-toolkit/latest。

  3. 生成并执行ST测试用例。

    ${INSTALL_DIR}/python/site-packages/bin/msopst run -i $HOME/sample/st/add_dsl.json -soc <soc_version> -out $HOME/sample/st/out

    ${INSTALL_DIR}为CANN软件安装后文件存储路径;“-i”为ST测试用例定义json文件的路径,“-soc”为AI处理器型号,“-out”为输出文件存储路径。

    执行后出现类似"Case 'Test_AddDSL_001_case_001' run successfully."的提示信息,代表ST测试用例生成并测试成功。

    至此,您已经完成了第一个自定义算子的开发及测试。

搜索结果
找到“0”个结果

当前产品无相关内容

未找到相关内容,请尝试其他搜索词