自定义运算符寄存 - 3.5 简体中文

Vitis AI 用户指南 (UG1414)

Document ID
UG1414
Release Date
2023-09-28
Version
3.5 简体中文
执行自定义运算符寄存前,可使用最新 Netron 程序来检查编译的模型。在以下计算图中,PPScatter 分配给 CPU。您必须实现并寄存 PPScatter OP。
图 1. CPU 子计算图中的 PPScatter OP

步骤

  1. 使用 Netron 打开编译的模型,并利用运算符信息查找 CPU 子计算图中的自定义 OP。
    图 2. PPScatter OP 的输入和输出

    从先前模型结构图中可以观察发现,运算类型 (op type) 为 PPScatterV2。PPScatterV2 表示要创建的自定义运算 (op) 的名称。

    要获取有关自定义 OP 的详细信息,可使用 xdputil 工具。运行以下命令检查 custom_layer OP:
    xdputil xmodel pointpillars_custom_op.xmodel --op VoxelNet__VoxelNet_input_4
  2. 自行编写此 op 的实现。

    自定义 OP 寄存支持 C++ 和 Python。以下步骤显示了如何在 C++ 中实现 OP。如需了解有关 OP Python 实现的信息,请参阅 Vitis-AI/examples/custom_operator/pytorch_example/op_registration/python/

    注释:Vitis-AI/examples/custom_operator/op_add 中可以找到“README.md”文件,此文件全面描述了自定义 OP 的实现过程。如需获取有关实现和寄存自定义 OP 的指导信息和说明,请参阅此“README.md”文件。
    1. 创建 my_PPScatter_op.cpp 源文件,并将其置于新的 op_PPScatter 文件夹内。

      您也可以复制现有 OP,并将其重命名为自己 OP,然后将 my_tanh_op.cpp 重命名为 my_PPScatter_op.cpp

      cp - r Vitis-AI/src/vai_library/cpu_task/examples/op_tanh/  op_PPScatter 
    2. 创建 Makefile。
      
      OUTPUT_DIR = $(PWD)
      
      all: $(OUTPUT_DIR) $(OUTPUT_DIR)/libvart_op_imp_PPScatterV2.so
      
      $(OUTPUT_DIR):
      mkdir -p $@
      
      $(OUTPUT_DIR)/my_PPScatter_op.o: my_PPScatter_op.cpp
      $(CXX) -std=c++17 -fPIC -c -o $@ -I. -I=/install/Debug/include -Wall -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 $<
      
      $(OUTPUT_DIR)/libvart_op_imp_PPScatterV2.so: $(OUTPUT_DIR)/my_PPScatter_op.o
      $(CXX) -Wl,--no-undefined -shared -o $@ $+ -L=/install/Debug/lib -lglog -lvitis_ai_library-runner_helper -lvart-runner -lxir
    3. 编写 op 的实现。

      my_PPScatter_op.cpp 文件中,使用构造函数初始化任何必需的变量。在本例中,无需初始化任何变量。

      在“calculate()”函数中实现定制逻辑。此逻辑的主要目标是从 inputs 变量检索输入数据、执行必要的计算,并将输出数据写入 output 变量。

      在 calculate() 函数中,实现您自己的逻辑。该逻辑主要用于从“输入”变量获取输入数据,计算逻辑,并将输出数据写入“输出”变量。

      my_PPScatter_op.cpp 代码如下
      
      #include <vart/op_imp.h> 
      
      class MyPPScatterOp {
        public:
        MyPPScatterOp(const xir::Op* op1, xir::Attrs* attrs) : op{op1} {
        // op and attrs is not in use.
      }
      
      int calculate(vart::simple_tensor_buffer_t output,
                     std::vector<vart::simple_tensor_buffer_t<float>> inputs) {
        CHECK_EQ(inputs.size(), 2);
        auto input_data_shape = inputs[0].tensor->get_shape();
        auto input_coord_shape = inputs[1].tensor->get_shape();
        auto output_shape = output.tensor->get_shape();
        CHECK_EQ(input_data_shape.size(), 4); // 1 12000 1 64 --> 1 64 12000 1
        CHECK_EQ(input_coord_shape.size(), 3); // 1 12000 4
        CHECK_EQ(output_shape.size(), 4); // 1 496 432 64 ---> 1 64 496 432
      
        auto coord_numbers = input_coord_shape[1];
        auto coord_channel = input_coord_shape[2];
        CHECK_EQ(coord_numbers, input_data_shape[2]);
      
        auto batch = output_shape[0];
        auto height = output_shape[2];
        auto width = output_shape[3];
        auto channel = output_shape[1];
        CHECK_EQ(input_data_shape[0], batch);
        CHECK_EQ(channel, input_data_shape[1]);
      
        auto output_idx = 0;
        auto input_idx = 0;
        auto x_idx = 0;
      
        memset(output.data, 0, output_shape[0]*output_shape[1]*output_shape[2]*output_shape[3]*sizeof(float));
      
        for (auto n = 0; n < coord_numbers; n++) {
          auto x = (int)inputs[1].data[x_idx + 3];
          auto y = (int)inputs[1].data[x_idx + 2];
          if (x < 0) break; // stop copy data when coord x == -1 .
          for(int i=0; i < channel; i++) {
          output_idx =i*height*width + y*width+x;
          input_idx = n+i*coord_numbers;
          output.data[output_idx] = inputs[0].data[ input_idx ];
          }
          x_idx += coord_channel;
        }
        return 0;
      }
      
      
      public:
        const xir::Op* const op;
      };
      
      DEF_XIR_op_IMP(MyPPScatterOp)
      
    4. 构建库。目标目录为 $(HOME)/build/custom_op/。您可以修改 Makefile 中的路径。

      使用您提供的 Makefile 执行 make 命令时,自定义 OP 库将在以下目录中生成:$(HOME)/build/custom_op/

      文件名为“libvart_op_imp_PPScatterV2.so”。

    5. libvart_op_imp_PPScatterV2.so 复制到目标上的 /usr/lib
  3. 在目标上验证 Op。
    1. xdputil 中使用 run_op 命令来测试此 OP:
      xdputil run_op pointpillars_op.xmodel VoxelNet__VoxelNet_input_4 -r ref -d dump

      运行此命令前,请准备 OP 的参考输入。运行此命令后,就会生成 VoxelNet__VoxelNet_input_4.bin 文件。

    2. 将输出与黄金文件进行对比:
       xdputil comp_float ref/VoxelNet__VoxelNet_input_4.bin dump/VoxelNet__VoxelNet_input_4.bin
      如果 OP 实现成功,您将看到如下结果: