diff options
author | Kevin Cheng <kevin.cheng@arm.com> | 2021-06-03 15:00:34 -0700 |
---|---|---|
committer | Kevin Cheng <kevin.cheng@arm.com> | 2021-06-04 16:38:40 -0700 |
commit | cd79f0e06bf53c2c0fee39ee916bb6d79f177b57 (patch) | |
tree | 367078aeef8fd376711abfe6e52de7bfe491e527 | |
parent | 571f7182a10a974f1ce993d83b01070153f142cc (diff) | |
download | reference_model-cd79f0e06bf53c2c0fee39ee916bb6d79f177b57.tar.gz |
Rewrite model frontend to be json-driven.
Change-Id: Iac786eff96183938d2fd11cde9313c6e8e1270a5
40 files changed, 340 insertions, 125 deletions
diff --git a/.gitmodules b/.gitmodules index c112866..e06268d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "thirdparty/serialization_lib"] path = thirdparty/serialization_lib url = https://review.mlplatform.org/tosa/serialization_lib +[submodule "thirdparty/json"] + path = thirdparty/json + url = https://github.com/nlohmann/json.git @@ -29,8 +29,12 @@ tools: * GCC (tested with 7.5.0) or Clang C++ compiler (tested with clang-9) with C++17 support -The model includes the TOSA Serialization Library and Eigen 3.3.7 -as git submodules. The model is written using +The model includes the following git submodules: +* TOSA Serialization Library +* JSON for Modern C++ - 3.8.0 +* Eigen 3.3.7 + +The model is written using C++17 and has been primarily tested on Ubuntu x86_64 18.04 LTS Linux systems. @@ -71,26 +75,61 @@ rebuilt simply using `make`. # Usage The inputs to the *TOSA Reference Model* consist of a FlatBuffers file -containing the serialized subgraph, a sequence of placeholder node -name/input tensor NumPy file pairs (produced by an external tool), and -a prefix for output tensor NumPy files (produced by the reference model). +containing the serialized subgraph, a JSON test descriptor that describes +a sequence of name, shape and numpy file for each input and output tensor. + +The JSON test descriptor must have the following field: +* tosa_file: + type: string. + TOSA flatbuffer file location. +* ifm_name: + type: list(string). + Input placeholder tensor names. +* ifm_file: + type: list(string). + Input numpy array file location. +* ofm_name: + type: list(string). + Output placeholder tensor names. +* ofm_file: + type: list(string). + Output numpy array file location. +* expected_failure: + type: boolean. + Is this test expected to fail in runtime. + +Note by default, all the files specified by "tosa_file", "ifm_file", +"ofm_file" are relative to desc.json. This could be overwritten by +-Cflatbuffer_dir=, if desired. An example command is shown below: ``` bash -$ mkdir -p examples_out/test_add_1x4x4x4_f32 $ ./build/reference_model/tosa_reference_model \ - -Csubgraph_dir=examples/test_add_1x4x4x4_f32/flatbuffer-tflite \ - -Csubgraph_file=test_add_1x4x4x4_f32.tosa \ - -Cinput_dir=examples/test_add_1x4x4x4_f32/ \ - -Coutput_dir=examples_out/test_add_1x4x4x4_f32/ \ - -Coutput_tensor_prefix=ref_model_tflite_ \ - -Cinput_tensor=InputTensor-tflite0:InputTensor-tflite0.npy,InputTensor-tflite1:InputTensor-tflite1.npy + -Ctest_desc=examples/test_add_1x4x4x4_f32/flatbuffer-tflite/desc.json ``` +Instead of drive model by JSON test descriptor, user can also drive model +with -Ctosa_file=, -Cifm_name=, -Cifm_file=, -Cofm_name=, -Cofm_file= +options directly. + +In case where -Ctest_desc= and other options are specified at the same time, +JSON test descriptor will be initialized first. All other options +(-Ctosa_file=, -Cifm_name=, -Cifm_file=, -Cofm_name=, -Cofm_file=) will +overwrite whatever specified by JSON descriptor. + On a successful execution, the output tensors will be written in NumPy -format into output tensors in -Coutput_dir and prefixed with --Coutput_tensor_prefix. +format into output tensors specified by "ofm_file". + +For example, you can generate new output .npy by: +``` bash +$ ./build/reference_model/tosa_reference_model \ + -Ctest_desc=examples/test_add_1x4x4x4_f32/flatbuffer-tflite/desc.json + -Cofm_file=out.npy +``` + +In this case, the "ofm_file" field in desc.json will be ignored, and the +one specified by -Cofm_file= will be picked. When using JSON-formatted FlatBuffers input (.json extension), the FlatBuffers schema file from the TOSA Serialization library must be diff --git a/examples/test_add_1x4x4x4_f32/InputTensor-tf0.npy b/examples/test_add_1x4x4x4_f32/InputTensor-tf0.npy Binary files differdeleted file mode 100644 index 1b3effb..0000000 --- a/examples/test_add_1x4x4x4_f32/InputTensor-tf0.npy +++ /dev/null diff --git a/examples/test_add_1x4x4x4_f32/InputTensor-tf1.npy b/examples/test_add_1x4x4x4_f32/InputTensor-tf1.npy Binary files differdeleted file mode 100644 index f233cd4..0000000 --- a/examples/test_add_1x4x4x4_f32/InputTensor-tf1.npy +++ /dev/null diff --git a/examples/test_add_1x4x4x4_f32/InputTensor-tflite0.npy b/examples/test_add_1x4x4x4_f32/InputTensor-tflite0.npy Binary files differdeleted file mode 100644 index 1b3effb..0000000 --- a/examples/test_add_1x4x4x4_f32/InputTensor-tflite0.npy +++ /dev/null diff --git a/examples/test_add_1x4x4x4_f32/InputTensor-tflite1.npy b/examples/test_add_1x4x4x4_f32/InputTensor-tflite1.npy Binary files differdeleted file mode 100644 index f233cd4..0000000 --- a/examples/test_add_1x4x4x4_f32/InputTensor-tflite1.npy +++ /dev/null diff --git a/examples/test_add_1x4x4x4_f32/flatbuffer-tf/desc.json b/examples/test_add_1x4x4x4_f32/flatbuffer-tf/desc.json new file mode 100644 index 0000000..1a86713 --- /dev/null +++ b/examples/test_add_1x4x4x4_f32/flatbuffer-tf/desc.json @@ -0,0 +1,18 @@ +{ + "tosa_file": "test_add_1x4x4x4_f32.tosa", + "ifm_name": [ + "InputTensor-tf0", + "InputTensor-tf1" + ], + "ifm_file": [ + "../placeholder_0.npy", + "../placeholder_1.npy" + ], + "ofm_name": [ + "Result0" + ], + "ofm_file": [ + "ref_model_Result0.npy" + ], + "expected_failure": false +}
\ No newline at end of file diff --git a/examples/test_add_1x4x4x4_f32/flatbuffer-tf/ref_model_Result0.npy b/examples/test_add_1x4x4x4_f32/flatbuffer-tf/ref_model_Result0.npy Binary files differnew file mode 100644 index 0000000..60baeac --- /dev/null +++ b/examples/test_add_1x4x4x4_f32/flatbuffer-tf/ref_model_Result0.npy diff --git a/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/desc.json b/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/desc.json new file mode 100644 index 0000000..30a447b --- /dev/null +++ b/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/desc.json @@ -0,0 +1,18 @@ +{ + "tosa_file": "test_add_1x4x4x4_f32.tosa", + "ifm_name": [ + "InputTensor-tflite0", + "InputTensor-tflite1" + ], + "ifm_file": [ + "../placeholder_0.npy", + "../placeholder_1.npy" + ], + "ofm_name": [ + "Result0" + ], + "ofm_file": [ + "ref_model_Result0.npy" + ], + "expected_failure": false +}
\ No newline at end of file diff --git a/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/ref_model_Result0.npy b/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/ref_model_Result0.npy Binary files differnew file mode 100644 index 0000000..60baeac --- /dev/null +++ b/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/ref_model_Result0.npy diff --git a/examples/test_add_1x4x4x4_f32/model.pb b/examples/test_add_1x4x4x4_f32/model.pb index c2570bf..930928d 100644 --- a/examples/test_add_1x4x4x4_f32/model.pb +++ b/examples/test_add_1x4x4x4_f32/model.pb @@ -70,7 +70,7 @@ node { } node { name: "result" - op: "Add" + op: "AddV2" input: "placeholder_0" input: "placeholder_1" attr { @@ -92,5 +92,5 @@ node { } } versions { - producer: 714 + producer: 772 } diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/InputTensor-tf0.npy b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/InputTensor-tf0.npy Binary files differdeleted file mode 100644 index 328dbd8..0000000 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/InputTensor-tf0.npy +++ /dev/null diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/InputTensor-tflite0.npy b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/InputTensor-tflite0.npy Binary files differdeleted file mode 100644 index 328dbd8..0000000 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/InputTensor-tflite0.npy +++ /dev/null diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/desc.json b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/desc.json new file mode 100644 index 0000000..b62c528 --- /dev/null +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/desc.json @@ -0,0 +1,16 @@ +{ + "tosa_file": "test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa", + "ifm_name": [ + "InputTensor-tf0" + ], + "ifm_file": [ + "../placeholder_0.npy" + ], + "ofm_name": [ + "Result0" + ], + "ofm_file": [ + "ref_model_Result0.npy" + ], + "expected_failure": false +}
\ No newline at end of file diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/layer_1.npy b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/layer_1.npy Binary files differindex ec9d526..42ff6d7 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/layer_1.npy +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/layer_1.npy diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/layer_2.npy b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/layer_2.npy Binary files differindex 42ff6d7..ec9d526 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/layer_2.npy +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/layer_2.npy diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/ref_model_Result0.npy b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/ref_model_Result0.npy Binary files differnew file mode 100644 index 0000000..d57e8da --- /dev/null +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/ref_model_Result0.npy diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa Binary files differindex ea794c8..0204756 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/desc.json b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/desc.json new file mode 100644 index 0000000..2849934 --- /dev/null +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/desc.json @@ -0,0 +1,16 @@ +{ + "tosa_file": "test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa", + "ifm_name": [ + "InputTensor-tflite0" + ], + "ifm_file": [ + "../placeholder_0.npy" + ], + "ofm_name": [ + "Result0" + ], + "ofm_file": [ + "ref_model_Result0.npy" + ], + "expected_failure": false +}
\ No newline at end of file diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/layer_1.npy b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/layer_1.npy Binary files differindex 207be76..ec9d526 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/layer_1.npy +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/layer_1.npy diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/layer_2.npy b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/layer_2.npy Binary files differindex ec9d526..207be76 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/layer_2.npy +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/layer_2.npy diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/ref_model_Result0.npy b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/ref_model_Result0.npy Binary files differnew file mode 100644 index 0000000..d57e8da --- /dev/null +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/ref_model_Result0.npy diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa Binary files differindex dfc7c9c..f549d12 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.pb b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.pb index 500cc08..6e8a215 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.pb +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.pb @@ -137,5 +137,5 @@ node { } } versions { - producer: 714 + producer: 772 } diff --git a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/InputTensor-tflite0.npy b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/InputTensor-tflite0.npy Binary files differdeleted file mode 100644 index a61baf4..0000000 --- a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/InputTensor-tflite0.npy +++ /dev/null diff --git a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/desc.json b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/desc.json new file mode 100644 index 0000000..c935e0a --- /dev/null +++ b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/desc.json @@ -0,0 +1,16 @@ +{ + "tosa_file": "test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa", + "ifm_name": [ + "InputTensor-tflite0" + ], + "ifm_file": [ + "../placeholder_0.npy" + ], + "ofm_name": [ + "Result0" + ], + "ofm_file": [ + "ref_model_Result0.npy" + ], + "expected_failure": false +}
\ No newline at end of file diff --git a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/layer_1.npy b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/layer_1.npy Binary files differindex 7494934..67c2421 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/layer_1.npy +++ b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/layer_1.npy diff --git a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/layer_2.npy b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/layer_2.npy Binary files differindex 67c2421..7494934 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/layer_2.npy +++ b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/layer_2.npy diff --git a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/ref_model_Result0.npy b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/ref_model_Result0.npy Binary files differnew file mode 100644 index 0000000..5c9ff1d --- /dev/null +++ b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/ref_model_Result0.npy diff --git a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa Binary files differindex 1e21d49..248dace 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa +++ b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa diff --git a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/model.tflite b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/model.tflite Binary files differindex 4c6f35e..840fdb9 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/model.tflite +++ b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/model.tflite diff --git a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/test.json b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/test.json index f7a007d..5124ff9 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/test.json +++ b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/test.json @@ -1,7 +1,7 @@ { "tflite_model_filename": "model.tflite", "tflite_result_npy_filename": "tflite_result.npy", - "tflite_result_name": "Identity_int8", + "tflite_result_name": "Identity", "ifm_file": [ "placeholder_0.npy" ], diff --git a/reference_model/CMakeLists.txt b/reference_model/CMakeLists.txt index 153a5bd..ac1a2c4 100644 --- a/reference_model/CMakeLists.txt +++ b/reference_model/CMakeLists.txt @@ -71,6 +71,7 @@ target_link_libraries(tosa_reference_model PRIVATE tosa_serialization_lib flatbuffers + nlohmann_json::nlohmann_json ) install (TARGETS tosa_reference_model DESTINATION bin) diff --git a/reference_model/src/func_config.def b/reference_model/src/func_config.def index 004cf36..8270dbb 100644 --- a/reference_model/src/func_config.def +++ b/reference_model/src/func_config.def @@ -63,17 +63,18 @@ // macro processing rules only allow stringification of macro parameters. Unfortunately, // Other tokens that are NOT passed in as macro parameters cannot be stringified. -DEF_OPTION_STR(operator_fbs, "Flat buffer syntax file", FOF_STR_LEN, "../serialization/tosa.fbs") -DEF_OPTION_STR(subgraph_dir, "Subgraph directory to load", FOF_STR_LEN, ".") -DEF_OPTION_STR(subgraph_file, "Subgraph file to load", FOF_STR_LEN, "") -DEF_OPTION_STR(input_dir, "Input directory path for dumps/files", FOF_STR_LEN, ".") -DEF_OPTION_STR(input_tensor, "A list of pairs <name0>:<npy0>,<name1>:<npy1>", FOF_STR_LEN, "") -DEF_OPTION_STR(output_dir, "Output directory path for output dumps/files", FOF_STR_LEN, ".") +DEF_OPTION_STR(operator_fbs, "Flat buffer syntax file", FOF_STR_LEN, "tosa.fbs") +DEF_OPTION_STR(test_desc, "Json test descriptor", FOF_STR_LEN, "desc.json") +DEF_OPTION_STR(flatbuffer_dir, "Flatbuffer directory to load. If not specified, it will be overwritten by dirname(test_desc)", FOF_STR_LEN, "") +DEF_OPTION_STR(tosa_file, "Flatbuffer file. Support .json or .tosa. Specifying this will overwrite the one initialized by -Ctest_desc.", FOF_STR_LEN, "") +DEF_OPTION_STR(ifm_name, "Input tensor name. Comma(,) seperated. Specifying this will overwrite the one initialized by -Ctest_desc.", FOF_STR_LEN, "") +DEF_OPTION_STR(ifm_file, "Input tensor numpy Comma(,) seperated. file to initialize with placeholder. Specifying this will overwrite the one initialized by -Ctest_desc.", FOF_STR_LEN, "") +DEF_OPTION_STR(ofm_name, "Output tensor name. Comma(,) seperated. Specifying this will overwrite the one initialized by -Ctest_desc.", FOF_STR_LEN, "") +DEF_OPTION_STR(ofm_file, "Output tensor numpy file to be generated. Comma(,) seperated. Specifying this will overwrite the one initialized by -Ctest_desc.", FOF_STR_LEN, "") DEF_OPTION(eval, "Evaluate the network (0/1)", uint32_t, FOF_DEC, 1) DEF_OPTION(validate_only, "Validate the network, but do not read inputs or evaluate (0/1)", uint32_t, FOF_DEC, 0) DEF_OPTION(output_tensors, "Output tensors to a file (0/1)", uint32_t, FOF_DEC, 1) DEF_OPTION(tosa_profile, "Set TOSA profile (0 = Base Inference, 1 = Main Inference, 2 = Main Training)", uint32_t, FOF_DEC, 1) -DEF_OPTION_STR(output_tensor_prefix, "Optional output tensor prefix", FOF_STR_LEN, "output_") DEF_OPTION(dump_intermediates, "Dump intermediate tensors (0/1)", uint32_t, FOF_DEC, 0) DEF_OPTION_STR(fp_format, "Floating-point number dump format string (printf-style format, e.g. 0.5)", FOF_STR_LEN, "0.5") // Example of a hierarchical option diff --git a/reference_model/src/main.cpp b/reference_model/src/main.cpp index 240d913..0d6d8a3 100644 --- a/reference_model/src/main.cpp +++ b/reference_model/src/main.cpp @@ -22,16 +22,21 @@ #include <Eigen/CXX11/Tensor> #include <iostream> +#include <fstream> +#include <nlohmann/json.hpp> + using namespace TosaReference; using namespace tosa; +using json = nlohmann::json; // Global instantiation of configuration and debug objects func_config_t g_func_config; func_debug_t g_func_debug; -int readInputTensors(SubgraphTraverser& gt); -int writeFinalTensors(SubgraphTraverser& gt); -int loadGraph(TosaSerializationHandler& tsh); +int initTestDesc(json& test_desc); +int readInputTensors(SubgraphTraverser& gt, json test_desc); +int writeFinalTensors(SubgraphTraverser& gt, json test_desc); +int loadGraph(TosaSerializationHandler& tsh, json test_desc); int main(int argc, const char** argv) { @@ -46,7 +51,15 @@ int main(int argc, const char** argv) return 1; } - if (loadGraph(tsh)) + json test_desc; + + // Initialize test descriptor + if (initTestDesc(test_desc)) + { + SIMPLE_FATAL_ERROR("Unable to load test json"); + } + + if (loadGraph(tsh, test_desc)) { SIMPLE_FATAL_ERROR("Unable to load graph"); } @@ -74,7 +87,7 @@ int main(int argc, const char** argv) goto done; } - if (readInputTensors(main_gt)) + if (readInputTensors(main_gt, test_desc)) { SIMPLE_FATAL_ERROR("Unable to read input tensors"); } @@ -113,7 +126,7 @@ int main(int argc, const char** argv) if (g_func_config.output_tensors) { - if (writeFinalTensors(main_gt)) + if (writeFinalTensors(main_gt, test_desc)) { WARNING("Errors encountered in saving output tensors"); } @@ -127,16 +140,17 @@ done: return 0; } -int loadGraph(TosaSerializationHandler& tsh) +int loadGraph(TosaSerializationHandler& tsh, json test_desc) { char graph_fullname[1024]; - snprintf(graph_fullname, sizeof(graph_fullname), "%s/%s", g_func_config.subgraph_dir, g_func_config.subgraph_file); + snprintf(graph_fullname, sizeof(graph_fullname), "%s/%s", g_func_config.flatbuffer_dir, + test_desc["tosa_file"].get<std::string>().c_str()); if (strlen(graph_fullname) <= 2) { func_model_print_help(stderr); - SIMPLE_FATAL_ERROR("Missing required argument: Check -Csubgraph_file="); + SIMPLE_FATAL_ERROR("Missing required argument: Check \"tosa_file\" in .json specified by -Ctosa_desc="); } const char JSON_EXT[] = ".json"; @@ -163,131 +177,223 @@ int loadGraph(TosaSerializationHandler& tsh) if (tsh.LoadFileJson(graph_fullname)) { - SIMPLE_FATAL_ERROR("\nError loading JSON graph file: %s\nCheck -Csubgraph_file= and -Csubgraph_dir=", - graph_fullname); + SIMPLE_FATAL_ERROR( + "\nError loading JSON graph file: %s\nCheck -Ctest_desc=, -Ctosa_file= and -Cflatbuffer_dir=", + graph_fullname); } } else { if (tsh.LoadFileTosaFlatbuffer(graph_fullname)) { - SIMPLE_FATAL_ERROR("\nError loading TOSA flatbuffer file: %s\nCheck -Csubgraph_file= and -Csubgraph_dir=", - graph_fullname); + SIMPLE_FATAL_ERROR( + "\nError loading TOSA flatbuffer file: %s\nCheck -Ctest_desc=, -Ctosa_file= and -Cflatbuffer_dir=", + graph_fullname); } } return 0; } -int readInputTensors(SubgraphTraverser& gt) +int readInputTensors(SubgraphTraverser& gt, json test_desc) { int tensorCount = gt.getNumInputTensors(); Tensor* tensor; char filename[1024]; - // assuming filename doesn't have colons(:) - std::map<std::string, std::string> input_tensor_map; - std::string raw_str(g_func_config.input_tensor); - std::string name, npy; - bool last_pair = false; - - std::string::size_type pair_start = 0, pair_end, colons_pos; - do + try { - pair_end = raw_str.find(',', pair_start); - if (pair_end == std::string::npos) - last_pair = true; + if ((tensorCount != (int)test_desc["ifm_name"].size()) || (tensorCount != (int)test_desc["ifm_file"].size())) + { + WARNING("Number of input tensors(%d) doesn't match name(%ld)/file(%ld)in test descriptor.", tensorCount, + test_desc["ifm_name"].size(), test_desc["ifm_file"].size()); + return 1; + } - colons_pos = raw_str.find(':', pair_start); + for (int i = 0; i < tensorCount; i++) + { + tensor = gt.getInputTensorByName(test_desc["ifm_name"][i].get<std::string>()); + if (!tensor) + { + WARNING("Unable to find input tensor %s", test_desc["ifm_name"][i].get<std::string>().c_str()); + return 1; + } - name = raw_str.substr(pair_start, colons_pos - pair_start); - npy = raw_str.substr(colons_pos + 1, pair_end - colons_pos - 1); + snprintf(filename, sizeof(filename), "%s/%s", g_func_config.flatbuffer_dir, + test_desc["ifm_file"][i].get<std::string>().c_str()); - // Empty strings can make it to here - if (name.length() == 0 || npy.length() == 0) - break; + DEBUG_MED(GT, "Loading input tensor %s from filename: %s", tensor->getName().c_str(), filename); - input_tensor_map[name] = npy; + if (tensor->allocate()) + { + WARNING("Fail to allocate tensor %s", tensor->getName().c_str()); + return 1; + } - pair_start = pair_end + 1; // skip colons - } while (!last_pair); + if (tensor->readFromNpyFile(filename)) + { + WARNING("Unable to read input tensor %s from filename: %s", tensor->getName().c_str(), filename); + tensor->dumpTensorParams(g_func_debug.func_debug_file); + return 1; + } - if ((size_t)tensorCount != input_tensor_map.size()) + // Push ready consumers to the next node list + for (auto gn : tensor->getConsumers()) + { + if (gn->hasAllInputsReady() && !gn->getOnNextNodeList()) + { + gt.addToNextNodeList(gn); + } + } + } + } + catch (nlohmann::json::type_error& e) { - WARNING("graph has %lu input placeholders, but %lu initialized", tensorCount, input_tensor_map.size()); + WARNING("Fail accessing test descriptor: %s", e.what()); return 1; } - for (auto& tensor_pair : input_tensor_map) + if (DEBUG_ENABLED(DEBUG_VERB_HIGH, GT)) { - tensor = gt.getInputTensorByName(tensor_pair.first); - if (!tensor) - { - WARNING("Unable to find input tensor %s", tensor_pair.first.c_str()); - return 1; - } + gt.dumpNextNodeList(g_func_debug.func_debug_file); + } - snprintf(filename, sizeof(filename), "%s/%s", g_func_config.input_dir, tensor_pair.second.c_str()); + return 0; +} - DEBUG_MED(GT, "Loading input tensor %s from filename: %s", tensor->getName().c_str(), filename); +int writeFinalTensors(SubgraphTraverser& gt, json test_desc) +{ + int tensorCount = gt.getNumOutputTensors(); + const Tensor* tensor; + char filename[1024]; - if (tensor->allocate()) + try + { + if ((tensorCount != (int)test_desc["ofm_name"].size()) || (tensorCount != (int)test_desc["ofm_file"].size())) { - WARNING("Fail to allocate tensor %s", tensor->getName().c_str()); + WARNING("Number of output tensors(%d) doesn't match name(%ld)/file(%ld) in test descriptor.", tensorCount, + test_desc["ofm_name"].size(), test_desc["ofm_file"].size()); return 1; } - if (tensor->readFromNpyFile(filename)) + for (int i = 0; i < tensorCount; i++) { - WARNING("Unable to read input tensor %s from filename: %s", tensor->getName().c_str(), filename); - tensor->dumpTensorParams(g_func_debug.func_debug_file); - return 1; - } + tensor = gt.getOutputTensorByName(test_desc["ofm_name"][i].get<std::string>()); + if (!tensor) + { + WARNING("Unable to find output tensor %s", test_desc["ofm_name"][i].get<std::string>().c_str()); + return 1; + } - // Push ready consumers to the next node list - for (auto gn : tensor->getConsumers()) - { - if (gn->hasAllInputsReady() && !gn->getOnNextNodeList()) + snprintf(filename, sizeof(filename), "%s/%s", g_func_config.flatbuffer_dir, + test_desc["ofm_file"][i].get<std::string>().c_str()); + + DEBUG_MED(GT, "Writing output tensor[%d] %s to filename: %s", i, tensor->getName().c_str(), filename); + + if (tensor->writeToNpyFile(filename)) { - gt.addToNextNodeList(gn); + WARNING("Unable to write output tensor[%d] %s to filename: %s", i, tensor->getName().c_str(), filename); + return 1; } } } - - if (DEBUG_ENABLED(DEBUG_VERB_HIGH, GT)) + catch (nlohmann::json::type_error& e) { - gt.dumpNextNodeList(g_func_debug.func_debug_file); + WARNING("Fail accessing test descriptor: %s", e.what()); + return 1; } return 0; } -int writeFinalTensors(SubgraphTraverser& gt) +// Read "foo,bar,..." and return std::vector({foo, bar, ...}) +std::vector<std::string> parseFromString(std::string raw_str) { - int tensorCount = gt.getNumOutputTensors(); - const Tensor* tensor; - char filename[1024]; + bool last_pair = false; + std::string::size_type start = 0, end; + std::string name; - for (int i = 0; i < tensorCount; i++) + std::vector<std::string> result; + do { - tensor = gt.getOutputTensor(i); - if (!tensor) - { - WARNING("Unable to find output tensor[%d]", i); - return 1; - } + end = raw_str.find(',', start); + if (end == std::string::npos) + last_pair = true; + + name = raw_str.substr(start, end); - snprintf(filename, sizeof(filename), "%s/%s%s.npy", g_func_config.output_dir, - g_func_config.output_tensor_prefix, tensor->getName().c_str()); + result.push_back(name); - DEBUG_MED(GT, "Writing output tensor[%d] %s to filename: %s", i, tensor->getName().c_str(), filename); + start = end + 1; // skip comma + } while (!last_pair); + + return result; +} + +int initTestDesc(json& test_desc) +{ + std::ifstream ifs(g_func_config.test_desc); - if (tensor->writeToNpyFile(filename)) + if (ifs.good()) + { + try + { + test_desc = nlohmann::json::parse(ifs); + } + catch (nlohmann::json::parse_error& e) { - WARNING("Unable to write output tensor[%d] %s to filename: %s", i, tensor->getName().c_str(), filename); + WARNING("Error parsing test descriptor json: %s", e.what()); return 1; } } + // Overwrite g_func_config.flatbuffer_dir with dirname(g_func_config.test_desc) if it's not specified. + std::string flatbuffer_dir_str(g_func_config.flatbuffer_dir); + if (flatbuffer_dir_str.empty()) + { + std::string test_path(g_func_config.test_desc); + std::string test_dir = test_path.substr(0, test_path.find_last_of("/\\")); + strncpy(g_func_config.flatbuffer_dir, test_dir.c_str(), 1024); + } + + // Overwrite test_desc["tosa_file"] if -Ctosa_file= specified. + std::string tosa_file_str(g_func_config.tosa_file); + if (!tosa_file_str.empty()) + { + test_desc["tosa_file"] = tosa_file_str; + } + + // Overwrite test_desc["ifm_name"] if -Cifm_name= specified. + std::string ifm_name_str(g_func_config.ifm_name); + if (!ifm_name_str.empty()) + { + std::vector<std::string> ifm_name_vec = parseFromString(ifm_name_str); + test_desc["ifm_name"] = ifm_name_vec; + } + + // Overwrite test_desc["ifm_file"] if -Cifm_file= specified. + std::string ifm_file_str(g_func_config.ifm_file); + if (!ifm_file_str.empty()) + { + std::vector<std::string> ifm_file_vec = parseFromString(ifm_file_str); + test_desc["ifm_file"] = ifm_file_vec; + } + + // Overwrite test_desc["ofm_name"] if -Cofm_name= specified. + std::string ofm_name_str(g_func_config.ofm_name); + if (!ofm_name_str.empty()) + { + std::vector<std::string> ofm_name_vec = parseFromString(ofm_name_str); + test_desc["ofm_name"] = ofm_name_vec; + } + + // Overwrite test_desc["ofm_file"] if -Cofm_file= specified. + std::string ofm_file_str(g_func_config.ofm_file); + if (!ofm_file_str.empty()) + { + std::vector<std::string> ofm_file_vec = parseFromString(ofm_file_str); + test_desc["ofm_file"] = ofm_file_vec; + } + return 0; } diff --git a/reference_model/src/subgraph_traverser.cc b/reference_model/src/subgraph_traverser.cc index 1995b5c..b615feb 100644 --- a/reference_model/src/subgraph_traverser.cc +++ b/reference_model/src/subgraph_traverser.cc @@ -235,7 +235,7 @@ int SubgraphTraverser::initializeGraph() } bzero(tensor_fullname, sizeof(tensor_fullname)); - snprintf(tensor_fullname, sizeof(tensor_fullname), "%s/%s", g_func_config.subgraph_dir, + snprintf(tensor_fullname, sizeof(tensor_fullname), "%s/%s", g_func_config.flatbuffer_dir, ts->GetNpyFilePtr().c_str()); if (tensor->readFromNpyFile(tensor_fullname)) { diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 66b72b9..320e434 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -5,3 +5,4 @@ set(CMAKE_INSTALL_PREFIX "./thirdparty" CACHE PATH "..." FORCE) project(thirdparty LANGUAGES CXX) add_subdirectory(serialization_lib) +add_subdirectory(json) diff --git a/thirdparty/json b/thirdparty/json new file mode 160000 +Subproject e7452d87783fbf6e9d320d515675e26dfd1271c diff --git a/verif/tosa_ref_run.py b/verif/tosa_ref_run.py index 26c64da..098f39b 100644 --- a/verif/tosa_ref_run.py +++ b/verif/tosa_ref_run.py @@ -14,6 +14,7 @@ import os # See the License for the specific language governing permissions and # limitations under the License. +import os import json import shlex import subprocess @@ -31,24 +32,9 @@ class TosaRefRunner(TosaTestRunner): ref_cmd = [ args.ref_model_path, - "-Csubgraph_file={}".format(self.testDesc["tosa_file"]), - "-Csubgraph_dir={}".format(self.testDir), - "-Cinput_dir={}".format(self.testDir), - "-Coutput_dir={}".format(self.testDir), - "-Coutput_tensor_prefix=ref-", # Naming agreement with TosaSerializer + "-Ctest_desc={}".format(os.path.join(self.testDir, "desc.json")), ] - # Build up input tensor_name/filename list - inputTensors = [] - for i in range(len(self.testDesc["ifm_placeholder"])): - inputTensors.append( - "{}:{}".format( - self.testDesc["ifm_placeholder"][i], self.testDesc["ifm_file"][i] - ) - ) - - ref_cmd.append("-Cinput_tensor={}".format(",".join(inputTensors))) - if args.ref_debug: ref_cmd.extend(["-dALL", "-l{}".format(args.ref_debug)]) diff --git a/verif/tosa_serializer.py b/verif/tosa_serializer.py index 5ed9877..3b03252 100644 --- a/verif/tosa_serializer.py +++ b/verif/tosa_serializer.py @@ -645,30 +645,24 @@ class TosaSerializer: test_desc["tosa_file"] = tosa_filename ifm_name = [] - ifm_shape = [] ifm_file = [] ofm_name = [] ofm_file = [] - ofm_shape = [] for b in self.basicBlocks: if b.name == "main": for i in b.inputs: ifm_name.append(i) - ifm_shape.append(b.tensors[i].shape) ifm_file.append(b.tensors[i].placeholderFilename) for o in b.outputs: ofm_name.append(o) - ofm_shape.append(b.tensors[o].shape) # Make up an OFM filename here. One isn't generated until the reference tool is # run, so any name is a good name ofm_file.append("ref-{}.npy".format(o)) - test_desc["ifm_placeholder"] = ifm_name + test_desc["ifm_name"] = ifm_name test_desc["ifm_file"] = ifm_file - test_desc["ifm_shape"] = ifm_shape test_desc["ofm_name"] = ofm_name - test_desc["ofm_shape"] = ofm_shape test_desc["ofm_file"] = ofm_file test_desc["expected_failure"] = self.expectedFailure if self.expectedFailureDesc: |