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

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

Document ID
UG1414
Release Date
2023-09-28
Version
3.5 日本語
カスタム op を登録する前に、最新の Netron プログラムを使用してコンパイル済みモデルをチェックできます。次のグラフからわかるように、PPScatter は CPU に割り当てられています。PPScatter op を実装し、登録する必要があります。
図 1. CPU サブグラフの PPScatter Op

手順

  1. Netron を使用してコンパイル済みモデルを開き、op 情報を使用して 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 には、カスタム op を実装する手順を包括的に説明した「README.md」ファイルがあります。カスタム op の実装と登録に関するガイダンスと手順については、この「README.md」ファイルを参照してください。
    1. my_PPScatter_op.cpp ソース ファイルを作成し、新規フォルダー op_PPScatter に置きます。

      次に示すように、既存の 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() 関数に、独自のロジックを実装します。このロジックは、主に「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 の実装が正常に完了すると、次の結果が表示されます。