单算子模型执行

完成自定义算子的开发和部署后,您可以参考本章节对算子进行运行验证,主要验证步骤为:先将自定义算子转换为单算子离线模型文件(*.om),然后通过AscendCL接口加载单算子模型文件并运行。

环境要求

准备验证代码工程

代码工程目录结构如下,您可以单击LINK,获取样例工程的完整样例:
├──input                                                 // 存放脚本生成的输入数据目录
├──output                                                // 存放算子运行输出数据和真值数据的目录
├── inc                           // 头文件目录 
│   ├── common.h                 // 声明公共方法类,用于读取二进制文件 
│   ├── operator_desc.h          // 算子描述声明文件,包含算子输入/输出,算子类型以及输入描述与输出描述 
│   ├── op_runner.h              // 算子运行相关信息声明文件,包含算子输入/输出个数,输入/输出大小等 
├── src 
│   ├── CMakeLists.txt    // 编译规则文件
│   ├── common.cpp         // 公共函数,读取二进制文件函数的实现文件
│   ├── main.cpp    // 将单算子编译为om文件并加载om文件执行
│   ├── operator_desc.cpp     // 构造算子的输入与输出描述 
│   ├── op_runner.cpp   // 单算子编译与运行函数实现文件
├── scripts
│   ├── verify_result.py    // 真值对比文件
│   ├── gen_data.py    // 输入数据和真值数据生成脚本文件
│   ├── acl.json    // acl配置文件
│   ├── add_custom_static_shape.json  // 算子描述文件,用于构造静态shape单算子模型文件
│   ├── add_custom_dynamic_shape.json // 算子描述文件,用于构造动态shape单算子模型文件

生成单算子离线模型文件

  1. 构造静态shape单算子描述文件add_custom_static_shape.json,描述算子的输入、输出及属性等信息。

    Add静态shape算子的描述文件示例如下:
    [
        {
            "op": "AddCustom",
            "input_desc": [
                {
                    "name": "x",
                    "param_type": "required",
                    "format": "ND",
                    "shape": [8, 2048],
                    "type": "float16"
                },
                {
                    "name": "y",
                    "param_type": "required",
                    "format":"ND",
                    "shape": [8, 2048],
                    "type": "float16"
                }
            ],
            "output_desc": [
                {
                    "name": "z",
                    "param_type": "required",
                    "format":  "ND",
                    "shape": [8, 2048],
                    "type": "float16"
                }
            ]
        }
    ]
    Add动态shape算子的描述文件示例如下:
    [
        {
            "op": "AddCustom",
            "input_desc": [
                {
                    "name": "x",
                    "param_type": "required",
                    "format": "ND",
                    "shape": [-1, -1],
                    "shape_range": [[1,-1],[1,-1]],
                    "type": "float16"
                },
                {
                    "name": "y",
                    "param_type": "required",
                    "format":"ND",
                    "shape": [-1, -1],
                    "shape_range": [[1,-1],[1,-1]],
                    "type": "float16"
                }
            ],
            "output_desc": [
                {
                    "name": "z",
                    "param_type": "required",
                    "format":  "ND",
                    "shape": [-1, -1],
                    "shape_range": [[1,-1],[1,-1]],
                    "type": "float16"
                }
            ]
        }
    ]

  2. 使用ATC工具,将该算子描述文件编译成单算子模型文件(*.om文件)

    ATC工具的命令示例如下:

    atc --singleop=$HOME/op_verify/run/out/test_data/config/add_custom_static_shape.json --output=op_models/ --soc_version=<soc_version>

    关键参数解释如下(详细参数说明,请参见ATC工具使用指南。):

    • --singleop:单算子描述文件(json格式)的路径。
    • --output:存放om模型文件的目录。
    • --soc_version:配置为AI处理器的型号,请根据实际环境进行替换。

      如果无法确定具体的<soc_version>,则在安装昇腾AI处理器的服务器执行npu-smi info命令进行查询,在查询到的“Name”前增加Ascend信息,例如“Name”对应取值为xxxyy,实际配置的<soc_version>值为Ascendxxxyy

    以上命令执行后,会在output参数指定路径下生成*.om后缀的离线模型文件。

生成测试数据

在样例工程目录下,执行如下命令:

python3 scripts/gen_data.py

会在input目录下生成两个shape为(8,2048),数据类型为float16的数据文件input_0.bin与input_1.bin,用于进行AddCustom算子的验证。

代码样例如下:

import numpy as np
a = np.random.randint(100, size=(8, 2048,)).astype(np.float16)
b = np.random.randint(100, size=(8, 2048,)).astype(np.float16)
a.tofile('input_0.bin')
b.tofile('input_1.bin')

编写验证代码

您可以参考如下样例编写单算子加载、执行的代码逻辑。

以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考,调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。

// 1.AscendCL初始化
aclRet = aclInit("../scripts/acl.json");

// 2.运行管理资源申请
int deviceId = 0;
aclRet = aclrtSetDevice(deviceid);
// 获取软件栈的运行模式,不同运行模式影响后续的接口调用流程(例如是否进行数据传输等)
aclrtRunMode runMode;
bool g_isDevice = false;
aclError aclRet = aclrtGetRunMode(&runMode);
g_isDevice = (runMode == ACL_DEVICE);

// 3.加载单算子模型文件(*.om文件)
// 该目录相对可执行文件所在的目录,例如,编译出来的可执行文件存放在output目录下,此处就表示工程目录下的op_models目录
aclRet = aclopSetModelDir("../op_models");

// 4.设置算子的输入,申请内存,然后读取输入数据input_0.bin与input_1.bin并保存至申请的内存中
// ......

// 5.创建Stream流
aclrtStream stream = nullptr;
aclrtCreateStream(&stream)

// 6.执行算子
// opType表示算子类型名称,例如AddCustom
// numInputs表示算子输入个数,例如AddCustom算子是2个输入
// inputDesc表示算子输入tensor描述的数组,描述每个输入的format、shape、数据类型
// inputs表示算子输入tensor数据
// numOutputs表示算子输出个数,例如AddCustom算子是1个输出
// outputDesc表示算子输出tensor描述的数组,描述每个输出的format、shape、数据类型
// outputs表示算子输出tensor数据
// attr表示算子属性,如果算子没有属性,也需要调用aclopCreateAttr接口创建aclopAttr类型的数据
// stream用于维护一些异步操作的执行顺序

aclopExecuteV2(opType, numInputs, inputDesc, inputs,                 
               numOutputs, outputDesc, outputs, attr, nullptr);


// 7.阻塞应用运行,直到指定Stream中的所有任务都完成
aclrtSynchronizeStream(stream);

// 8.处理执行算子后的输出数据,例如在屏幕上显示、写入文件等,由用户根据实际情况自行实现,本示例会将结果写入output_z.bin文件中
// ......

// 9.释放stream流
aclrtDestroyStream(stream);

// 10.释放运行管理资源
aclRet = aclrtResetDevice(deviceid);
aclRet = aclFinalize();

// ....

运行和验证

  1. 开发环境上,设置环境变量,配置AscendCL单算子验证程序编译依赖的头文件与库文件路径,如下为设置环境变量的示例。${INSTALL_DIR}表示CANN软件安装目录,例如,$HOME/Ascend/ascend-toolkit/latest。{arch-os}为运行环境的架构和操作系统,arch表示操作系统架构,os表示操作系统,例如x86_64-linux。
    export DDK_PATH=${INSTALL_DIR}
    export NPU_HOST_LIB=${INSTALL_DIR}/{arch-os}/devlib
  2. 编译样例工程,生成单算子验证可执行文件。
    1. 切换到样例工程根目录,然后在样例工程根目录下执行如下命令创建目录用于存放编译文件,例如,创建的目录为“build”

      mkdir -p build

    2. 进入build目录,执行cmake编译命令,生成编译文件

      命令示例如下所示:

      cd build

      cmake ../src

    3. 执行如下命令,生成可执行文件。

      make

      会在工程目录的output目录下生成可执行文件execute_add_custom

  3. 执行单算子
    1. 以运行用户(例如HwHiAiUser)拷贝开发环境中样例工程output下的execute_add_custom到运行环境任一目录。

      说明: 若您的开发环境即为运行环境,此拷贝操作可跳过。

    2. 在运行环境中,执行execute_add_custom文件,验证单算子模型文件。

      chmod +x execute_add_custom

      ./execute_add_custom

      会有如下屏显信息:

      [INFO]  static op will be called
      [INFO]  Set device[0] success
      [INFO]  Get RunMode[1] success
      [INFO]  aclopSetModelDir op model success
      [INFO]  Init resource success
      [INFO]  Set input success
      [INFO]  Copy input[0] success
      [INFO]  Copy input[1] success
      [INFO]  Create stream success
      [INFO]  Execute AddCustom success
      [INFO]  Synchronize stream success
      [INFO]  Copy output[0] success
      [INFO]  Write output success
      [INFO]  Run op success
      [INFO]  Reset Device success
      [INFO]  Destory resource success

      如果有Run op success,表明执行成功,会在outout目录下生成输出文件output_z.bin。

  4. 比较真值文件

    切换到样例工程根目录,然后执行如下命令:

    python3 scripts/verify_result.py output/output_z.bin output/golden.bin
    会有如下屏显信息,可见AddCustom算子验证结果正确。
    test pass