summaryrefslogtreecommitdiff
path: root/compiler/embedded-import-value-test/src/TestDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/embedded-import-value-test/src/TestDriver.cpp')
-rw-r--r--compiler/embedded-import-value-test/src/TestDriver.cpp242
1 files changed, 242 insertions, 0 deletions
diff --git a/compiler/embedded-import-value-test/src/TestDriver.cpp b/compiler/embedded-import-value-test/src/TestDriver.cpp
new file mode 100644
index 000000000..63fd745eb
--- /dev/null
+++ b/compiler/embedded-import-value-test/src/TestDriver.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <luci_interpreter/GraphBuilderRegistry.h>
+#include <luci_interpreter/Interpreter.h>
+
+#include <luci/Importer.h>
+
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <string>
+#include <random>
+
+namespace
+{
+
+uint32_t tensor_size_of(const luci::CircleNode *node)
+{
+ uint32_t tensor_size = loco::size(node->dtype());
+ for (uint32_t i = 0; i < node->rank(); ++i)
+ tensor_size *= node->dim(i).value();
+ return tensor_size;
+}
+
+std::vector<uint8_t> random_data_for(const luci::CircleInput *node)
+{
+ // allocate data buffer
+ std::vector<uint8_t> inputs_data(tensor_size_of(node));
+ auto *buffer = inputs_data.data();
+
+ // define size of buffer in elements
+ const auto dtype = node->dtype();
+ assert(inputs_data.size() % loco::size(dtype) == 0); // FIX ME UNLESS
+ const auto element_count = inputs_data.size() / loco::size(dtype);
+
+ // random generator engine
+ std::random_device device;
+ std::mt19937 engine{device()};
+
+ // fill buffer with random data
+ switch (node->dtype())
+ {
+ case loco::DataType::FLOAT32:
+ {
+ auto element_buffer = reinterpret_cast<float *>(buffer);
+
+ std::uniform_real_distribution<float> distrib(-3, 3);
+ const auto generator = [&distrib, &engine]() { return distrib(engine); };
+ std::generate(element_buffer, element_buffer + element_count, generator);
+
+ break;
+ }
+ case loco::DataType::U8:
+ {
+ auto element_buffer = buffer;
+
+ std::uniform_int_distribution<uint8_t> distrib(100, 200);
+ const auto generator = [&distrib, &engine]() { return distrib(engine); };
+ std::generate(element_buffer, element_buffer + element_count, generator);
+
+ break;
+ }
+ case loco::DataType::S16:
+ {
+ auto element_buffer = reinterpret_cast<int16_t *>(buffer);
+
+ std::uniform_int_distribution<int16_t> distrib(0, 100);
+ const auto generator = [&distrib, &engine]() { return distrib(engine); };
+ std::generate(element_buffer, element_buffer + element_count, generator);
+
+ break;
+ }
+ case loco::DataType::S32:
+ {
+ auto element_buffer = reinterpret_cast<int32_t *>(buffer);
+
+ std::uniform_int_distribution<int32_t> distrib(0, 100);
+ const auto generator = [&distrib, &engine]() { return distrib(engine); };
+ std::generate(element_buffer, element_buffer + element_count, generator);
+
+ break;
+ }
+ case loco::DataType::BOOL:
+ {
+ // num of bool data type is equivalent to uint8_t num in [0, 1] range
+ auto element_buffer = buffer;
+
+ std::uniform_int_distribution<uint8_t> distrib(0, 1);
+ const auto generator = [&distrib, &engine]() { return distrib(engine); };
+ std::generate(element_buffer, element_buffer + element_count, generator);
+
+ break;
+ }
+ default:
+ // TODO Support other dtypes
+ throw std::runtime_error("Unsupported data type, yet!");
+ }
+
+ return inputs_data;
+}
+
+} // namespace
+
+int entry(int argc, char **argv)
+{
+ // check arguments
+ if (argc != 3 || std::string(argv[1]) != "--model")
+ {
+ std::cerr << "Usage: " << argv[0] << " --model <path/to/model>" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ // open file with model
+ const auto model_file = std::string(argv[2]);
+ std::ifstream fs(model_file, std::ifstream::binary);
+ if (fs.fail())
+ {
+ std::cerr << "Cannot open model file \"" << model_file << "\"." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ // create constant circle model
+ const std::vector<char> model_buffer((std::istreambuf_iterator<char>(fs)),
+ std::istreambuf_iterator<char>());
+ const auto circle_model = circle::GetModel(model_buffer.data());
+
+ // create random model's inputs
+ std::vector<std::vector<uint8_t>> inputs_data;
+ {
+ // model inputs
+ auto model = luci::Importer(nullptr).importModule(circle_model);
+ const auto inputs = loco::input_nodes(model->graph());
+
+ // create random data for each input
+ for (const auto *input : inputs)
+ {
+ const auto input_node = loco::must_cast<const luci::CircleInput *>(input);
+ inputs_data.emplace_back(random_data_for(input_node));
+ }
+ }
+
+ // interpret given module
+ const auto interpret_module_and_compute_output =
+ [&](const std::unique_ptr<luci::Module> &module) {
+ // create interpreter
+ luci_interpreter::Interpreter interpreter(module.get());
+
+ // model's input and output nodes
+ const auto input_nodes = loco::input_nodes(module->graph());
+ const auto output_nodes = loco::output_nodes(module->graph());
+
+ // set inputs
+ for (uint32_t i = 0; i < input_nodes.size(); ++i)
+ {
+ const auto input_node = loco::must_cast<const luci::CircleInput *>(input_nodes[i]);
+ const auto &data = inputs_data.at(i);
+ interpreter.writeInputTensor(input_node, data.data(), data.size());
+ }
+
+ // do inference
+ interpreter.interpret();
+
+ // read outputs
+ std::vector<std::vector<uint8_t>> outputs_data;
+ for (const auto *node : output_nodes)
+ {
+ const auto output_node = loco::must_cast<const luci::CircleOutput *>(node);
+
+ // allocate output buffer
+ outputs_data.emplace_back(tensor_size_of(output_node));
+
+ auto &data = outputs_data.back();
+ interpreter.readOutputTensor(output_node, data.data(), data.size());
+ }
+
+ return outputs_data;
+ };
+
+ // import with copying, execute and save
+ std::vector<std::vector<uint8_t>> outputs_data_1;
+ {
+ const auto default_source = &luci::GraphBuilderRegistry::get();
+ const auto module = luci::Importer(default_source).importModule(circle_model);
+ if (not module)
+ {
+ std::cerr << "Fail to import model with constant copying." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ outputs_data_1 = interpret_module_and_compute_output(module);
+ }
+
+ // import without copying, execute and save
+ std::vector<std::vector<uint8_t>> outputs_data_2;
+ {
+ const auto optimized_source = luci_interpreter::source_without_constant_copying();
+ const auto module = luci::Importer(optimized_source.get()).importModule(circle_model);
+ if (not module)
+ {
+ std::cerr << "Fail to import model without constant copying." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ outputs_data_2 = interpret_module_and_compute_output(module);
+ }
+
+ // check all tensors are equal
+ assert(outputs_data_1.size() == outputs_data_2.size());
+ for (uint32_t n = 0; n < outputs_data_1.size(); ++n)
+ {
+ const auto &output_1 = outputs_data_1.at(n);
+ const auto &output_2 = outputs_data_2.at(n);
+ assert(output_1.size() == output_2.size());
+
+ for (uint32_t o = 0; o < output_1.size(); ++o)
+ {
+ if (output_1[o] != output_2[o])
+ {
+ std::cerr << "Values mismatch in model's output number " << n << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ std::cout << "[TEST PASSED]" << std::endl;
+ return EXIT_SUCCESS;
+}