2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "CircleExpContract.h"
19 #include <luci/Importer.h>
20 #include <luci_interpreter/Interpreter.h>
33 void readDataFromFile(const std::string &filename, char *data, size_t data_size)
35 std::ifstream fs(filename, std::ifstream::binary);
37 throw std::runtime_error("Cannot open file \"" + filename + "\".\n");
38 if (fs.read(data, data_size).fail())
39 throw std::runtime_error("Failed to read data from file \"" + filename + "\".\n");
42 void writeDataToFile(const std::string &filename, const char *data, size_t data_size)
44 std::ofstream fs(filename, std::ofstream::binary);
46 throw std::runtime_error("Cannot open file \"" + filename + "\".\n");
47 if (fs.write(data, data_size).fail())
49 throw std::runtime_error("Failed to write data to file \"" + filename + "\".\n");
53 std::unique_ptr<luci::Module> importModel(const std::string &filename)
55 std::ifstream fs(filename, std::ifstream::binary);
58 throw std::runtime_error("Cannot open model file \"" + filename + "\".\n");
60 std::vector<char> model_data((std::istreambuf_iterator<char>(fs)),
61 std::istreambuf_iterator<char>());
62 return luci::Importer().importModule(circle::GetModel(model_data.data()));
65 template <typename NodeT> size_t getTensorSize(const NodeT *node)
67 uint32_t tensor_size = loco::size(node->dtype());
68 for (uint32_t i = 0; i < node->rank(); ++i)
69 tensor_size *= node->dim(i).value();
76 * @brief EvalTester main
78 * Driver for testing luci-inerpreter
81 int entry(int argc, char **argv)
86 << "Usage: " << argv[0]
87 << " <path/to/circle/model> <num_inputs> <path/to/input/prefix> <path/to/output/file>\n";
91 const char *filename = argv[1];
92 const int32_t num_inputs = atoi(argv[2]);
93 const char *input_prefix = argv[3];
94 const char *output_file = argv[4];
95 const std::string intermediate_filename = std::string(filename) + ".inter.circle";
97 // Load model from the file
98 std::unique_ptr<luci::Module> initial_module = importModel(filename);
99 if (initial_module == nullptr)
101 std::cerr << "ERROR: Failed to load '" << filename << "'" << std::endl;
105 // Export to a Circle file
106 luci::CircleExporter exporter;
107 CircleExpContract contract(initial_module.get(), intermediate_filename);
108 if (!exporter.invoke(&contract))
110 std::cerr << "ERROR: Failed to export '" << intermediate_filename << "'" << std::endl;
114 // Import model again
115 std::unique_ptr<luci::Module> module = importModel(intermediate_filename);
116 if (module == nullptr)
118 std::cerr << "ERROR: Failed to load '" << intermediate_filename << "'" << std::endl;
122 // Create interpreter.
123 luci_interpreter::Interpreter interpreter(module.get());
126 // Data for n'th input is read from ${input_prefix}n
127 // (ex: Add.circle.input0, Add.circle.input1 ..)
128 const auto input_nodes = loco::input_nodes(module->graph());
129 assert(num_inputs == input_nodes.size());
130 for (int32_t i = 0; i < num_inputs; i++)
132 const auto *input_node = loco::must_cast<const luci::CircleInput *>(input_nodes[i]);
133 std::vector<char> input_data(getTensorSize(input_node));
134 readDataFromFile(std::string(input_prefix) + std::to_string(i), input_data.data(),
136 interpreter.writeInputTensor(input_node, input_data.data(), input_data.size());
140 interpreter.interpret();
143 const auto output_nodes = loco::output_nodes(module->graph());
144 for (int i = 0; i < module->graph()->outputs()->size(); i++)
146 const auto *output_node = loco::must_cast<const luci::CircleOutput *>(output_nodes[i]);
147 std::vector<char> output_data(getTensorSize(output_node));
148 interpreter.readOutputTensor(output_node, output_data.data(), output_data.size());
150 // Output data is written in ${output_file}
151 // (ex: Add.circle.output0)
152 // Output shape is written in ${output_file}.shape
153 // (ex: Add.circle.output0.shape)
154 writeDataToFile(std::string(output_file) + std::to_string(i), output_data.data(),
156 // In case of Tensor output is Scalar value.
157 // The output tensor with rank 0 is treated as a scalar with shape (1)
158 if (output_node->rank() == 0)
160 writeDataToFile(std::string(output_file) + std::to_string(i) + ".shape", "1", 1);
164 auto shape_str = std::to_string(output_node->dim(0).value());
165 for (int j = 1; j < output_node->rank(); j++)
168 shape_str += std::to_string(output_node->dim(j).value());
170 writeDataToFile(std::string(output_file) + std::to_string(i) + ".shape", shape_str.c_str(),