- 在 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 的公共成员变量。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 Library 安装位置为 ~/.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 graph,如下所示。
% 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"
注释: 将 /tmp/lib 添加到搜索路径 LD_LIBRARY_PATH 中,以便 CPU 运行器找到您编写的共享库。重要: 共享库的名称必须为 libvart_op_imp_<YOUR_OP_TYPE>.so。CPU 运行器使用此命名方案来查找自定义的 xir::Op 实现。您也可以使用 xdputil run_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