カスタム OP の登録 - 2.5 日本語

Vitis AI ユーザー ガイド (UG1414)

Document ID
UG1414
Release Date
2022-06-15
Version
2.5 日本語

カスタム op を登録する前に、最新の Netron プログラムを使用してコンパイル済みモデルをチェックできます。次のグラフからわかるように、PPScatter は CPU に割り当てられています。PPScatter OP を実装し、登録する必要があります。

図 1. CPU サブグラフの PPScatter OP

手順

  1. Netron を使用してコンパイル済みモデルを開き、op 情報を使用して CPU サブグラフ内のカスタム OP を見つけます。
    図 2. PPScatter Op の入力と出力

    上記のモデル構造図から、OP タイプが PPScatterV2 であることがわかります。この名前のカスタム OP を作成する必要があります。

    xdputil を使用して OP の詳細情報をチェックすることもできます。次のコマンドを実行して、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_OP_Demo/pytorch_example/op_registration/python/ を参照してください。

    注記: Vitis-AI/examples/Custom_OP_Demo/op_add ディレクトリには、カスタム op の詳細な実装手順を記述した README.mdファイルがあります。カスタム OP の実装および登録方法については、このファイルを参照してください。
    1. my_PPScatter_op.cpp ソース ファイルを作成し、新規フォルダー op_PPScatter に置きます。

      次に示すように、既存の op をコピーして名前を適宜変更することもできます。次に、my_tanh_op.cpp のファイル名を my_PPScatter_op.cpp に変更します。

      cp - r Vitis-AI/src/Vitis-AI-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 内で、construct 関数を使用して変数を初期化します。この例では、初期化が必要な変数はありません。

      calculate() 関数に、独自のロジックを実装します。このロジックは、主に「inputs」変数から入力データを取得し、ロジックを計算し、「output」変数に出力データを書き込みます。

      次に、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. 次に示すように、xdputilrun_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 の実装が正常に完了すると、次の結果が表示されます。