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 <inference_engine_error.h>
18 #include "inference_engine_mlapi_private.h"
26 namespace InferenceEngineImpl
30 InferenceMLAPI::InferenceMLAPI(void) :
35 mDesignated_outputs(),
39 mOutputTensorBuffer(),
48 InferenceMLAPI::~InferenceMLAPI()
50 mDesignated_inputs.clear();
51 std::vector<std::string>().swap(mDesignated_inputs);
53 mDesignated_outputs.clear();
54 std::vector<std::string>().swap(mDesignated_outputs);
56 ml_single_close(mSingle);
59 int InferenceMLAPI::SetPrivateData(void *data)
63 inference_backend_type_e type =
64 *(static_cast<inference_backend_type_e *>(data));
66 if (INFERENCE_BACKEND_ONE != type && INFERENCE_BACKEND_MLAPI != type) {
67 LOGE("Invalid backend type.");
68 return INFERENCE_ENGINE_ERROR_NOT_SUPPORTED;
75 return INFERENCE_ENGINE_ERROR_NONE;
78 int InferenceMLAPI::SetTargetDevices(int types)
82 LOGI("Inference targets are, ");
83 if (types & INFERENCE_TARGET_CPU) {
84 mTargetDevice |= INFERENCE_TARGET_CPU;
88 if (types & INFERENCE_TARGET_GPU) {
89 mTargetDevice |= INFERENCE_TARGET_GPU;
93 if (types & INFERENCE_TARGET_CUSTOM) {
94 mTargetDevice |= INFERENCE_TARGET_CUSTOM;
100 return INFERENCE_ENGINE_ERROR_NONE;
103 int InferenceMLAPI::Load(std::vector<std::string> model_paths,
104 inference_model_format_e model_format)
108 std::string model_str(model_paths[0]);
110 // TODO. Set NNFW backend type and HW type properly.
112 ml_nnfw_type_e nnfw_type;
113 ml_nnfw_hw_e nnfw_hw;
115 switch (mPluginType) {
116 case INFERENCE_BACKEND_MLAPI:
117 // For now, backend type is MLAPI and target device type is CUSTOM then
118 // we will use Vivante NPU.
119 // TODO. other NPU should be considered later. I.e., SRNPU.
120 if ((mTargetDevice & INFERENCE_TARGET_CUSTOM) ==
121 INFERENCE_TARGET_CUSTOM) {
122 nnfw_type = ML_NNFW_TYPE_VIVANTE;
123 nnfw_hw = ML_NNFW_HW_ANY;
124 LOGI("Vivante tensor filter will be used.");
126 LOGE("Invalid target device type.");
127 return INFERENCE_ENGINE_ERROR_NOT_SUPPORTED;
130 if (access(model_str.c_str(), R_OK) ||
131 access(model_paths[1].c_str(), R_OK)) {
132 LOGE("model file path in [%s,%s]", model_str.c_str(),
133 model_paths[1].c_str());
134 return INFERENCE_ENGINE_ERROR_INVALID_PATH;
137 // ML Single API of MLAPI requires model_paths rule like below,
138 // "so library file path,nb model file path" or vise versa.
139 model_str += "," + model_paths[1];
141 case INFERENCE_BACKEND_ONE:
142 nnfw_type = ML_NNFW_TYPE_NNFW;
144 if (access(model_str.c_str(), R_OK)) {
145 LOGE("model file path in [%s]", model_str.c_str());
146 return INFERENCE_ENGINE_ERROR_INVALID_PATH;
149 if (mTargetDevice == INFERENCE_TARGET_CPU) {
150 nnfw_hw = ML_NNFW_HW_CPU_NEON;
151 LOGI("Target device is NEON.");
152 } else if (mTargetDevice == INFERENCE_TARGET_GPU) {
153 nnfw_hw = ML_NNFW_HW_GPU;
154 LOGI("Target device is GPU");
156 LOGE("Invalid inference target device type.");
157 return INFERENCE_ENGINE_ERROR_INVALID_PARAMETER;
160 LOGI("NNFW tensor filter will be used.");
164 LOGE("Invalid plugin type.");
165 return INFERENCE_ENGINE_ERROR_INVALID_PARAMETER;
168 LOGI("Model name = %s", model_str.c_str());
170 // TODO. create ml_tensor_info for input and output tensor and pass
171 // them as parameters of ml_single_open function.
173 int ret = ml_single_open(&mSingle, model_str.c_str(), NULL, NULL,
175 if (ret != ML_ERROR_NONE) {
176 LOGE("Failed to request ml_single_open(%d).", ret);
177 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
182 return INFERENCE_ENGINE_ERROR_NONE;
185 int InferenceMLAPI::GetInputTensorBuffers(
186 std::vector<inference_engine_tensor_buffer> &buffers)
190 // TODO. Implement this function according to a given ML Single API backend properly.
194 return INFERENCE_ENGINE_ERROR_NONE;
197 int InferenceMLAPI::GetOutputTensorBuffers(
198 std::vector<inference_engine_tensor_buffer> &buffers)
202 // TODO. Implement this function according to a given ML Single API backend properly.
206 return INFERENCE_ENGINE_ERROR_NONE;
209 int InferenceMLAPI::GetInputLayerProperty(
210 inference_engine_layer_property &property)
214 ml_tensors_info_h in_info = NULL;
216 // TODO. Need to check if model file loading is done.
218 int ret = ml_single_get_input_info(mSingle, &in_info);
219 if (ret != ML_ERROR_NONE) {
220 LOGE("Failed to request ml_single_get_input_info(%d).", ret);
221 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
225 ret = ml_tensors_info_get_count(in_info, &cnt);
226 if (ret != ML_ERROR_NONE) {
227 LOGE("Failed to request ml_tensors_info_get_count(%d).", ret);
228 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
231 LOGI("input tensor count = %u", cnt);
233 for (unsigned int i = 0; i < cnt; ++i) {
234 inference_engine_tensor_info tensor_info;
235 ml_tensor_type_e in_type;
236 unsigned int in_dim[ML_TENSOR_RANK_LIMIT];
237 char *in_name = NULL;
240 ret = ml_tensors_info_get_tensor_type(in_info, i, &in_type);
241 if (ret != ML_ERROR_NONE) {
242 LOGE("Failed to request ml_tensors_info_get_tensor_type(%d).",
244 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
247 LOGI("input tensor type = %d", in_type);
249 int type = ConvertTensorType(in_type);
251 return INFERENCE_ENGINE_ERROR_NOT_SUPPORTED;
254 ret = ml_tensors_info_get_tensor_dimension(in_info, i, in_dim);
255 if (ret != ML_ERROR_NONE) {
256 LOGE("Failed to request ml_tensors_info_get_tensor_dimension(%d).",
258 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
261 LOGI("Input tensor dimension:");
262 for (unsigned int shape_idx = 0; shape_idx < ML_TENSOR_RANK_LIMIT; ++shape_idx) {
263 tensor_info.shape.push_back(in_dim[shape_idx]);
264 in_size *= static_cast<size_t>(in_dim[shape_idx]);
265 LOGI("%u", in_dim[shape_idx]);
268 LOGI("input tensor size = %zu", in_size);
270 ret = ml_tensors_info_get_tensor_name(in_info, i, &in_name);
271 if (ret != ML_ERROR_NONE) {
272 LOGE("Failed to request ml_tensors_info_get_tensor_name(%d).",
274 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
277 LOGI("input tensor name = %s", in_name);
279 tensor_info.data_type = static_cast<inference_tensor_data_type_e>(type);
280 tensor_info.size = in_size;
282 property.tensor_infos.push_back(tensor_info);
284 // TODO. Compare tensor info from engine to one from a given property.
287 property.layer_names = mInputProperty.layer_names;
291 return INFERENCE_ENGINE_ERROR_NONE;
294 int InferenceMLAPI::GetOutputLayerProperty(
295 inference_engine_layer_property &property)
299 ml_tensors_info_h out_info = NULL;
301 // TODO. Need to check if model file loading is done.
303 int ret = ml_single_get_output_info(mSingle, &out_info);
304 if (ret != ML_ERROR_NONE) {
305 LOGE("Failed to request ml_single_get_output_info(%d).", ret);
306 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
310 ret = ml_tensors_info_get_count(out_info, &cnt);
311 if (ret != ML_ERROR_NONE) {
312 LOGE("Failed to request ml_tensors_info_get_count(%d).", ret);
313 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
316 LOGI("output tensor count = %u", cnt);
318 for (unsigned int i = 0; i < cnt; ++i) {
319 inference_engine_tensor_info tensor_info;
320 ml_tensor_type_e out_type;
321 unsigned int out_dim[ML_TENSOR_RANK_LIMIT];
322 char *out_name = NULL;
325 ret = ml_tensors_info_get_tensor_type(out_info, i, &out_type);
326 if (ret != ML_ERROR_NONE) {
327 LOGE("Failed to request ml_tensors_info_get_tensor_type(%d).",
329 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
332 LOGI("output tensor type = %d", out_type);
334 int type = ConvertTensorType(out_type);
336 return INFERENCE_ENGINE_ERROR_NOT_SUPPORTED;
339 ret = ml_tensors_info_get_tensor_dimension(out_info, i, out_dim);
340 if (ret != ML_ERROR_NONE) {
341 LOGE("Failed to request ml_tensors_info_get_tensor_dimension(%d).",
343 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
348 LOGI("Output tensor dimension:");
350 for (unsigned int shape_idx = 0; shape_idx < ML_TENSOR_RANK_LIMIT; ++shape_idx) {
351 out_size *= static_cast<size_t>(out_dim[shape_idx]);
353 if (out_dim[shape_idx] == 1 && shape_size == 0)
354 shape_size = shape_idx;
356 LOGI("%d", out_dim[shape_idx]);
359 LOGI("Shape size of output tensor : %d", shape_size);
360 LOGI("Reversed output tensor dimension:");
362 // Reverse shape order.
363 for (int idx = shape_size; idx >= 0; --idx) {
364 tensor_info.shape.push_back(out_dim[idx]);
365 LOGI("%u", out_dim[idx]);
368 LOGI("output tensor size = %zu", out_size);
370 ret = ml_tensors_info_get_tensor_name(out_info, i, &out_name);
371 if (ret != ML_ERROR_NONE) {
372 LOGE("Failed to request ml_tensors_info_get_tensor_name(%d).",
374 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
377 LOGI("output tensor name = %s", out_name);
379 tensor_info.data_type = static_cast<inference_tensor_data_type_e>(type);
380 tensor_info.size = out_size;
382 property.tensor_infos.push_back(tensor_info);
384 // TODO. Compare tensor info from engine to one from a given property.
387 property.layer_names = mOutputProperty.layer_names;
391 return INFERENCE_ENGINE_ERROR_NONE;
394 int InferenceMLAPI::SetInputLayerProperty(
395 inference_engine_layer_property &property)
399 std::vector<std::string>::iterator iter;
400 for (iter = property.layer_names.begin();
401 iter != property.layer_names.end(); iter++) {
402 std::string name = *iter;
403 LOGI("input layer name = %s", name.c_str());
406 mDesignated_inputs.clear();
407 std::vector<std::string>().swap(mDesignated_inputs);
409 // TODO. Request input property information to a given ML Single API of nnstreamer backend,
410 // and set it instead of user-given one,
412 mDesignated_inputs = property.layer_names;
413 mInputProperty = property;
417 return INFERENCE_ENGINE_ERROR_NONE;
420 int InferenceMLAPI::SetOutputLayerProperty(
421 inference_engine_layer_property &property)
425 std::vector<std::string>::iterator iter;
426 for (iter = property.layer_names.begin();
427 iter != property.layer_names.end(); iter++) {
428 std::string name = *iter;
429 LOGI("output layer name = %s", name.c_str());
432 mDesignated_outputs.clear();
433 std::vector<std::string>().swap(mDesignated_outputs);
435 // TODO. Request output property information to a given ML Single API of nnstreamer backend,
436 // and set it instead of user-given one,
438 mDesignated_outputs = property.layer_names;
439 mOutputProperty = property;
443 return INFERENCE_ENGINE_ERROR_NONE;
446 int InferenceMLAPI::GetBackendCapacity(inference_engine_capacity *capacity)
450 if (capacity == NULL) {
451 LOGE("Bad pointer.");
452 return INFERENCE_ENGINE_ERROR_INVALID_PARAMETER;
455 // TODO. flag supported accel device types according to a given ML Single API of nnstreamer backend.
456 if (mPluginType == INFERENCE_BACKEND_MLAPI) {
457 capacity->supported_accel_devices = INFERENCE_TARGET_CUSTOM;
459 capacity->supported_accel_devices = INFERENCE_TARGET_GPU |
460 INFERENCE_TARGET_CPU;
465 return INFERENCE_ENGINE_ERROR_NONE;
468 int InferenceMLAPI::CheckTensorBuffers(
469 std::vector<inference_engine_tensor_buffer> &input_buffers,
470 std::vector<inference_engine_tensor_buffer> &output_buffers)
476 return INFERENCE_ENGINE_ERROR_NONE;
479 int InferenceMLAPI::ConvertTensorType(int tensor_type)
483 switch (tensor_type) {
484 case ML_TENSOR_TYPE_FLOAT32:
485 return INFERENCE_TENSOR_DATA_TYPE_FLOAT32;
486 case ML_TENSOR_TYPE_UINT8:
487 return INFERENCE_TENSOR_DATA_TYPE_UINT8;
488 case ML_TENSOR_TYPE_UINT16:
489 return INFERENCE_TENSOR_DATA_TYPE_UINT16;
490 case ML_TENSOR_TYPE_INT64:
491 return INFERENCE_TENSOR_DATA_TYPE_INT64;
492 case ML_TENSOR_TYPE_UINT64:
493 return INFERENCE_TENSOR_DATA_TYPE_UINT64;
495 LOGE("Tensor type(%d) is invalid.", tensor_type);
496 return INFERENCE_ENGINE_ERROR_INVALID_PARAMETER;
504 int InferenceMLAPI::Run(
505 std::vector<inference_engine_tensor_buffer> &input_buffers,
506 std::vector<inference_engine_tensor_buffer> &output_buffers)
510 // Make sure to check if tensor buffer count and binding info one are same.
511 int err = CheckTensorBuffers(input_buffers, output_buffers);
512 if (err != INFERENCE_ENGINE_ERROR_NONE) {
516 ml_tensors_info_h in_info = NULL;
518 err = ml_single_get_input_info(mSingle, &in_info);
519 if (err != ML_ERROR_NONE) {
520 LOGE("Failed to request ml_single_get_input_info(%d).", err);
521 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
524 ml_tensors_data_h input_data = NULL;
525 err = ml_tensors_data_create(in_info, &input_data);
526 if (err != ML_ERROR_NONE) {
527 LOGE("Failed to request ml_tensors_data_create(%d).", err);
528 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
532 err = ml_tensors_info_get_count(in_info, &in_cnt);
533 if (err != ML_ERROR_NONE) {
534 LOGE("Failed to request ml_tensors_info_get_count(%d).", err);
535 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
538 ml_tensors_info_h out_info = NULL;
540 err = ml_single_get_output_info(mSingle, &out_info);
541 if (err != ML_ERROR_NONE) {
542 LOGE("Failed to request ml_single_get_output_info(%d).", err);
543 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
546 unsigned int out_cnt;
547 err = ml_tensors_info_get_count(out_info, &out_cnt);
548 if (err != ML_ERROR_NONE) {
549 LOGE("Failed to request ml_tensors_info_get_count(%d).", err);
550 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
553 for (unsigned int i = 0; i < in_cnt; ++i) {
554 LOGI("index(%d) : buffer = %p, size = %zu\n", i,
555 input_buffers[i].buffer, input_buffers[i].size);
556 err = ml_tensors_data_set_tensor_data(input_data, i,
557 input_buffers[i].buffer,
558 input_buffers[i].size);
559 if (err != ML_ERROR_NONE) {
560 LOGE("Failed to request ml_tensors_data_set_tensor_data(%d).",
562 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
566 ml_tensors_data_h output_data = NULL;
567 err = ml_single_invoke(mSingle, input_data, &output_data);
568 if (err != ML_ERROR_NONE) {
569 LOGE("Failed to request ml_single_invoke(%d).", err);
570 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
573 for (unsigned int i = 0; i < out_cnt; ++i) {
574 err = ml_tensors_data_get_tensor_data(
575 output_data, i, (void **) &output_buffers[i].buffer,
576 &output_buffers[i].size);
577 if (err != ML_ERROR_NONE) {
578 LOGE("Failed to request ml_tensors_data_get_tensor_data(%d).", err);
579 return INFERENCE_ENGINE_ERROR_INVALID_OPERATION;
581 LOGI("Output tensor[%u] = %zu", i, output_buffers[0].size);
586 return INFERENCE_ENGINE_ERROR_NONE;
591 class IInferenceEngineCommon *EngineCommonInit(void)
595 InferenceMLAPI *engine = new InferenceMLAPI();
602 void EngineCommonDestroy(class IInferenceEngineCommon *engine)
612 } /* InferenceEngineImpl */