2 * Copyright (c) 2019 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.
18 #include "nnfw_experimental.h"
26 #define NNPR_ENSURE_STATUS(a) \
29 if ((a) != NNFW_STATUS_NO_ERROR) \
35 extern "C" void FillFromEval(nnfw_custom_kernel_params *params, char *userdata,
36 size_t userdata_size);
38 const nnfw_custom_eval custom_func_ptr_list[] = {FillFromEval};
39 const char *custom_func_name_list[] = {"FillFrom"};
40 int custom_func_list_size = 1;
42 void register_custom_operations(nnfw_session *session)
44 for (int i = 0; i < custom_func_list_size; ++i)
46 auto name = custom_func_name_list[i];
47 custom_kernel_registration_info info;
48 info.eval_function = custom_func_ptr_list[i];
49 NNPR_ENSURE_STATUS(nnfw_register_custom_op_info(session, name, &info));
55 auto time_point = std::chrono::high_resolution_clock::now();
56 auto since_epoch = time_point.time_since_epoch();
57 // default precision of high resolution clock is 10e-9 (nanoseconds)
58 return std::chrono::duration_cast<std::chrono::microseconds>(since_epoch).count();
61 uint64_t num_elems(const nnfw_tensorinfo *ti)
64 for (uint32_t i = 0; i < ti->rank; ++i)
66 assert(ti->dims[i] >= 0);
72 // TODO replace with data import
73 // Valid only for model FillFrom.tflite
74 // FillFrom(idx=3, val=1.1)
75 static const float in_data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
76 static const float ref_data[10] = {1, 2, 3, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1};
78 std::vector<float> genData(uint64_t size)
80 assert(size == sizeof(in_data) / sizeof(in_data[0]));
81 std::cout << "Warning: runner uses hardcoded data form in_data" << std::endl;
82 std::vector<float> vec(size);
83 for (uint64_t i = 0; i < size; i++)
88 template <typename InIter1, typename InIter2>
89 static auto findMaxDifference(InIter1 first1, InIter1 last1, InIter2 first2)
90 -> decltype(*first1 - *first2)
92 auto max_difference = std::abs(*first1 - *first2);
93 for (; first1 != last1; ++first1, ++first2)
95 auto diff = std::abs(*first1 - *first2);
96 if (diff > max_difference)
98 max_difference = diff;
101 return max_difference;
104 std::string dirFilename(const std::string &str)
106 std::size_t found = str.find_last_of("/\\");
107 // Finished with '/' or '\' to merge
108 return str.substr(0, found + 1);
111 int main(const int argc, char **argv)
113 std::string dir = dirFilename(argv[0]);
114 std::string model_path = dir + "nnpkgs/FillFrom";
118 std::cout << "[WARNING] Use default package path\n";
122 model_path = argv[1];
126 std::cerr << "[ERROR] Invalid argument\n";
129 nnfw_session *session = nullptr;
130 NNPR_ENSURE_STATUS(nnfw_create_session(&session));
132 register_custom_operations(session);
134 NNPR_ENSURE_STATUS(nnfw_load_model_from_file(session, model_path.c_str()));
137 NNPR_ENSURE_STATUS(nnfw_input_size(session, &num_inputs));
139 // verify input and output
143 std::cerr << "[ ERROR ] "
144 << "No inputs in model => execution is not possible" << std::endl;
148 auto verifyInputTypes = [session]() {
150 NNPR_ENSURE_STATUS(nnfw_input_size(session, &sz));
151 for (uint32_t i = 0; i < sz; ++i)
154 NNPR_ENSURE_STATUS(nnfw_input_tensorinfo(session, i, &ti));
155 if (ti.dtype != NNFW_TYPE_TENSOR_FLOAT32)
157 std::cerr << "Only float 32bit is supported." << std::endl;
163 auto verifyOutputTypes = [session]() {
165 NNPR_ENSURE_STATUS(nnfw_output_size(session, &sz));
167 for (uint32_t i = 0; i < sz; ++i)
170 NNPR_ENSURE_STATUS(nnfw_output_tensorinfo(session, i, &ti));
171 if (ti.dtype != NNFW_TYPE_TENSOR_FLOAT32)
173 std::cerr << "Only float 32bit is supported." << std::endl;
184 uint64_t prepare_ms = NowMicros();
185 NNPR_ENSURE_STATUS(nnfw_prepare(session));
186 prepare_ms = NowMicros() - prepare_ms;
189 std::vector<std::vector<float>> inputs(num_inputs);
191 auto generateInputs = [session, num_inputs, &inputs]() {
192 // generate random data
194 for (uint32_t i = 0; i < num_inputs; ++i)
197 NNPR_ENSURE_STATUS(nnfw_input_tensorinfo(session, i, &ti));
198 auto input_num_elements = num_elems(&ti);
199 inputs[i] = genData(input_num_elements);
200 NNPR_ENSURE_STATUS(nnfw_set_input(session, i, NNFW_TYPE_TENSOR_FLOAT32, inputs[i].data(),
201 sizeof(float) * input_num_elements));
202 NNPR_ENSURE_STATUS(nnfw_set_input_layout(session, i, NNFW_LAYOUT_CHANNELS_LAST));
209 uint32_t num_outputs = 0;
210 NNPR_ENSURE_STATUS(nnfw_output_size(session, &num_outputs));
211 std::vector<std::vector<float>> outputs(num_outputs);
213 for (uint32_t i = 0; i < num_outputs; i++)
216 NNPR_ENSURE_STATUS(nnfw_output_tensorinfo(session, i, &ti));
217 auto output_num_elements = num_elems(&ti);
218 outputs[i].resize(output_num_elements);
219 NNPR_ENSURE_STATUS(nnfw_set_output(session, i, NNFW_TYPE_TENSOR_FLOAT32, outputs[i].data(),
220 sizeof(float) * output_num_elements));
221 NNPR_ENSURE_STATUS(nnfw_set_output_layout(session, i, NNFW_LAYOUT_CHANNELS_LAST));
224 uint64_t run_ms = NowMicros();
225 NNPR_ENSURE_STATUS(nnfw_run(session));
226 run_ms = NowMicros() - run_ms;
228 const float tolerance = 0.01f;
229 auto max_difference =
230 findMaxDifference(outputs[0].begin(), outputs[0].end(), std::begin(ref_data));
233 if (max_difference > tolerance)
235 std::cout << "Max difference is more than tolerance" << std::endl;
236 std::cout << "Max difference is " << max_difference << std::endl;
240 std::cout << "nnfw_prepare takes " << prepare_ms / 1e3 << " sec" << std::endl;
241 std::cout << "nnfw_run takes " << run_ms / 1e3 << " sec" << std::endl;
243 NNPR_ENSURE_STATUS(nnfw_close_session(session));