-
my_add_op.cpp に C++ クラスを作成します。ソース ファイルまたはクラスには命名規則の要件はありません。
// in my_add_op.cpp class MyAddOp { };
- 次のコード スニペットに示すようにコンストラクター関数を作成します。
#include <vart/op_imp.h> class MyAddOp { MyAddOp(const xir::Op* op1, xir::Attrs* attrs) : op{op1} { // op and attrs is not in use. } public: const xir::Op * const op; };
注記:MyAddOp
には、op という名前の public メンバー変数が必要です。op
は、コンストラクター関数の最初の入力引数 (例:op1
) で初期化されます。これは、DEF_XIR_OP_IMP
の要件です。 - 次のコード スニペットに示すようにメンバー関数 calculate を作成します。
class MyAddOp { ... int calculate(vart::simple_tensor_buffer_t output, std::vector<vart::simple_tensor_buffer_t<float>> inputs) { for (auto i = 0u; i < output.mem_size / sizeof(float); ++i) { output.data[i] = 0.0f; for (auto input : inputs) { output.data[i] = output.data[i] + input.data[i]; } } return 0; } ... }
- ソース ファイルをコンパイルします。
% g++ -fPIC -std=c++17 -c -o /tmp/my_add_op.o -Wall -Werror -I ~/.local/Ubuntu.18.04.x86_64.Debug/include/ my_add_op.cpp
注記: C++ 17 以降を使用してください。共有ライブラリをビルドするには、-fPIC
を有効にします。Vitis AI ライブラリは ~/.local/Ubuntu.18.04.x86_64.Debug にインストールされているものとします。 - 共有ライブラリにリンクするには、次のコードを使用します。
% mkdir -p /tmp/lib; % g++ -Wl,--no-undefined -shared -o /tmp/lib/libvart_op_imp_add.so /tmp/my_add_op.o -L ~/.local/Ubuntu.18.04.x86_64.Debug/lib -lglog -lvitis_ai_library-runner_helper -lvart-runner -lxir
Makefile を使用してライブラリのコンパイルとリンクを実行することもできます。次のコード スニペットに、makefile の例を示します。
OUTPUT_DIR = $(HOME)/build/customer_op all: $(OUTPUT_DIR) $(OUTPUT_DIR)/libvart_op_imp_add.so $(OUTPUT_DIR): mkdir -p $@ $(OUTPUT_DIR)/my_add_op.o: my_add_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_add.so: $(OUTPUT_DIR)/my_add_op.o $(CXX) -Wl,--no-undefined -shared -o $@ $+ -L=/install/Debug/lib -lglog -lvitis_ai_library-runner_helper -lvart-runner -lxir
- OP 実装をテストするため、次に示すサンプル XIR グラフを作成します。
% ipython; import xir g = xir.Graph("simple_graph") a = g.create_op("a", "data", {"shape": [1,2,2,4], "data_type": "FLOAT32"}); b = g.create_op("b", "data", {"shape": [1,2,2,4], "data_type": "FLOAT32"}); add = g.create_op("add_op", "add", {"shape": [1,2,2,4], "data_type": "FLOAT32"}, {"input": [a,b]}) root = g.get_root_subgraph() root.create_child_subgraph() user_subgraph = root.merge_children(set([g.get_leaf_subgraph(a), g.get_leaf_subgraph(b)])) cpu_subgraph = root.merge_children(set([g.get_leaf_subgraph(add)])) user_subgraph.set_attr("device", "USER") cpu_subgraph.set_attr("device", "CPU") g.serialize("/tmp/add.xmodel")
推奨: 複雑な Python コードを作成するのではなく、Xcompiler を使用して xmodel を作成します。詳細は、 『Vitis AI ユーザー ガイド』 (UG1414) を参照してくだい。 - サンプル入力ファイルを作成します。
% cd /tmp % mkdir -p ref % ipython import numpy as np a = np.arange(1, 17, dtype=np.float32) b = np.arange(1, 17, dtype=np.float32) a.tofile("ref/a.bin") b.tofile("ref/b.bin") c = a + b c.tofile("ref/c.bin")
% cd /tmp % mkdir -p /tmp/dump % env LD_LIBRARY_PATH=$HOME/.local/Ubuntu.18.04.x86_64.Debug/lib:/tmp/lib $HOME/.local/Ubuntu.18.04.x86_64.Debug/share/vitis_ai_library/test/cpu_task/test_op_imp --graph /tmp/add.xmodel --op "add_op"
注記: 作成した共有ライブラリを CPU ランナーが検出できるように、検索パス LD_LIBRARY_PATH に /tmp/lib を追加します。重要: 共有ライブラリの名前は libvart_op_imp_<YOUR_OP_TYPE>.so とする必要があります。CPU ランナーは、この命名規則を使用してカスタム xir::Op 実装を検出します。xdputil run_op を使用して op を検証することもできます。
root@xilinx-zcu102-2021_2:~/add_op# xdputil run_op add.xmodel add_op -r ref -d dump WARNING: Logging before InitGoogleLogging() is written to STDERR I1202 09:32:41.497661 1208 test_op_run.cpp:79] try to test op: add_op I1202 09:32:41.497745 1208 test_op_run.cpp:97] input op: a tensor: a I1202 09:32:41.497768 1208 test_op_run.cpp:97] input op: b tensor: b I1202 09:32:41.497865 1208 test_op_run.cpp:55] read ref/a.bin to 0xaaab17d605d0 size=64 I1202 09:32:41.497917 1208 test_op_run.cpp:55] read ref/b.bin to 0xaaab17c549b0 size=64 I1202 09:32:41.498561 1208 test_op_run.cpp:114] graph name:simple_graphtesting op: { {args: input= TensorBuffer{@0xaaab17ba9b90,tensor=xir::Tensor{name = a, type = FLOAT32, shape = {1, 2, 2, 4}},location=HOST_VIRT,data=[(Virt=0xaaab17d605d0, 64)]} TensorBuffer{@0xaaab17e2a860,tensor=xir::Tensor{name = b, type = FLOAT32, shape = {1, 2, 2, 4}},location=HOST_VIRT,data=[(Virt=0xaaab17c549b0, 64)]}} { I1202 09:32:41.499586 1208 test_op_run.cpp:68] write output to dump/add_op.bin from 0xaaab17de7090 size=64 test pass
- これをリファレンス結果と比較し、
op
が正しく実装されたかを検証します。% diff -u <(xxd ref/c.bin) <(xxd dump/add_op.bin) % xxd ref/c.bin % xxd dump/add_op.bin