From c22bb18a27e5d4cea682cb8daac92d0c04eb6298 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Wed, 29 Apr 2020 12:09:06 +0900 Subject: [PATCH] test: avoid code from duplicated This patch moves common code from test files to a new file, inference_enigne_test_common.cpp, to avoid code from duplicated. Change-Id: Id516b91298bc9fbef779d6568de449b9538ecba6 Signed-off-by: Inki Dae --- test/src/CMakeLists.txt | 2 + test/src/inference_engine_tc.cpp | 244 +------------- test/src/inference_engine_test.cpp | 377 +-------------------- test/src/inference_engine_test_common.cpp | 387 ++++++++++++++++++++++ test/src/inference_engine_test_common.h | 55 +++ 5 files changed, 447 insertions(+), 618 deletions(-) create mode 100644 test/src/inference_engine_test_common.cpp create mode 100644 test/src/inference_engine_test_common.h diff --git a/test/src/CMakeLists.txt b/test/src/CMakeLists.txt index 7bd4400..12dec3a 100644 --- a/test/src/CMakeLists.txt +++ b/test/src/CMakeLists.txt @@ -23,6 +23,7 @@ file(GLOB INFER_GTEST_INC_LIST "${PROJECT_SOURCE_DIR}/*.h") add_executable(${INFERENCE_TEST} ${INFER_GTEST_INC_LIST} ${PROJECT_SOURCE_DIR}/inference_engine_test.cpp + ${PROJECT_SOURCE_DIR}/inference_engine_test_common.cpp ) target_link_libraries(${INFERENCE_TEST} ${GTEST_LIBRARY} @@ -34,6 +35,7 @@ target_link_libraries(${INFERENCE_TEST} ${GTEST_LIBRARY} add_executable(${INFERENCE_ENGINE_TEST_CASE} ${INFER_GTEST_INC_LIST} ${PROJECT_SOURCE_DIR}/inference_engine_tc.cpp + ${PROJECT_SOURCE_DIR}/inference_engine_test_common.cpp ) target_link_libraries(${INFERENCE_ENGINE_TEST_CASE} ${GTEST_LIBRARY} diff --git a/test/src/inference_engine_tc.cpp b/test/src/inference_engine_tc.cpp index 78f2b67..5aa508a 100644 --- a/test/src/inference_engine_tc.cpp +++ b/test/src/inference_engine_tc.cpp @@ -26,8 +26,7 @@ #include "inference_engine_error.h" #include "inference_engine_common_impl.h" - -using namespace InferenceEngineInterface::Common; +#include "inference_engine_test_common.h" typedef std::tuple ParamType_Bind; typedef std::tuple> ParamType_Load; @@ -37,30 +36,6 @@ class InferenceEngineTestCase_G1 : public testing::TestWithParam class InferenceEngineTestCase_G2 : public testing::TestWithParam { }; class InferenceEngineTestCase_G3 : public testing::TestWithParam { }; -std::map Model_Formats = { - { "caffemodel", INFERENCE_MODEL_CAFFE }, - { "pb", INFERENCE_MODEL_TF }, - { "tflite", INFERENCE_MODEL_TFLITE }, - { "t7", INFERENCE_MODEL_TORCH }, - { "weights", INFERENCE_MODEL_DARKNET }, - { "xml", INFERENCE_MODEL_DLDT }, - { "onnx", INFERENCE_MODEL_ONNX } -}; - -std::map Target_Formats = { - { INFERENCE_TARGET_CPU, "cpu" }, - { INFERENCE_TARGET_GPU, "gpu" }, - { INFERENCE_TARGET_CUSTOM, "custom" } -}; - -enum { - TEST_IMAGE_CLASSIFICATION = 0, - TEST_OBJECT_DETECTION, - TEST_FACE_DETECTION, - TEST_FACIAL_LANDMARK_DETECTION, - TEST_POSE_ESTIMATION -}; - TEST_P(InferenceEngineTestCase_G1, Bind_P) { std::string backend_name; @@ -94,166 +69,6 @@ TEST_P(InferenceEngineTestCase_G1, Bind_P) delete engine; } -int GetModelInfo(std::vector &model_paths, std::vector &models) -{ - std::string model_path = model_paths[0]; - std::string ext_str = model_path.substr(model_path.find_last_of(".") + 1); - std::map::iterator key = Model_Formats.find(ext_str); - int ret = key != Model_Formats.end() ? key->second : -1; - EXPECT_NE(ret, -1); - - if (ret == -1) { - return ret; - } - - switch (ret) { - case INFERENCE_MODEL_CAFFE: - case INFERENCE_MODEL_TF: - case INFERENCE_MODEL_DARKNET: - case INFERENCE_MODEL_DLDT: - case INFERENCE_MODEL_ONNX: - models.push_back(model_paths[0]); - models.push_back(model_paths[1]); - break; - case INFERENCE_MODEL_TFLITE: - case INFERENCE_MODEL_TORCH: - models.push_back(model_paths[0]); - break; - default: - break; - } - - return ret; -} - -int PrepareTensorBuffers(InferenceEngineCommon *engine, std::vector &inputs, - std::vector &outputs) -{ - int ret = engine->GetInputTensorBuffers(inputs); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - if (inputs.empty()) { - inference_engine_layer_property input_property; - ret = engine->GetInputLayerProperty(input_property); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - // If backend is OpenCV then the buffers will be allocated out of this function. - if (input_property.tensor_infos.empty()) { - return INFERENCE_ENGINE_ERROR_NONE; - } - - for (int i = 0; i < (int)input_property.tensor_infos.size(); ++i) { - inference_engine_tensor_info tensor_info = input_property.tensor_infos[i]; - inference_engine_tensor_buffer tensor_buffer; - if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) { - tensor_buffer.buffer = (void *)(new float[tensor_info.size]); - tensor_buffer.size = tensor_info.size * 4; - } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { - tensor_buffer.buffer = (void *)(new unsigned char[tensor_info.size]); - tensor_buffer.size = tensor_info.size; - } - - EXPECT_TRUE(tensor_buffer.buffer); - tensor_buffer.owner_is_backend = 0; - tensor_buffer.data_type = tensor_info.data_type; - inputs.push_back(tensor_buffer); - } - } - - ret = engine->GetOutputTensorBuffers(outputs); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - if (outputs.empty()) { - inference_engine_layer_property output_property; - ret = engine->GetOutputLayerProperty(output_property); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - // If backend is OpenCV then the buffers will be allocated out of this function. - if (output_property.tensor_infos.empty()) { - return INFERENCE_ENGINE_ERROR_NONE; - } - - for (int i = 0; i < (int)output_property.tensor_infos.size(); ++i) { - inference_engine_tensor_info tensor_info = output_property.tensor_infos[i]; - inference_engine_tensor_buffer tensor_buffer; - if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) { - tensor_buffer.buffer = (void *)(new float[tensor_info.size]); - tensor_buffer.size = tensor_info.size * 4; - } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { - tensor_buffer.buffer = (void *)(new unsigned char[tensor_info.size]); - tensor_buffer.size = tensor_info.size; - } - - EXPECT_TRUE(tensor_buffer.buffer); - tensor_buffer.owner_is_backend = 0; - tensor_buffer.data_type = tensor_info.data_type; - outputs.push_back(tensor_buffer); - } - } - - return INFERENCE_ENGINE_ERROR_NONE; -} - -void CleanupTensorBuffers(std::vector &inputs, std::vector &outputs) -{ - if (!inputs.empty()) { - std::vector::iterator iter; - for (iter = inputs.begin(); iter != inputs.end(); iter++) { - inference_engine_tensor_buffer tensor_buffer = *iter; - - // If tensor buffer owner is a backend then skip to release the tensor buffer. - // This tensor buffer will be released by the backend. - if (tensor_buffer.owner_is_backend) { - continue; - } - - if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) - delete[] (float *)tensor_buffer.buffer; - else - delete[] (unsigned char *)tensor_buffer.buffer; - } - std::vector().swap(inputs); - } - - if (!outputs.empty()) { - std::vector::iterator iter; - for (iter = outputs.begin(); iter != outputs.end(); iter++) { - inference_engine_tensor_buffer tensor_buffer = *iter; - - // If tensor buffer owner is a backend then skip to release the tensor buffer. - // This tensor buffer will be released by the backend. - if (tensor_buffer.owner_is_backend) { - continue; - } - - if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) - delete[] (float *)tensor_buffer.buffer; - else - delete[] (unsigned char *)tensor_buffer.buffer; - } - std::vector().swap(outputs); - } -} - -void CopyFileToMemory(const char *file_name, inference_engine_tensor_buffer &buffer, unsigned int size) -{ - int fd = open(file_name, O_RDONLY); - if (fd == -1) { - ASSERT_NE(fd, -1); - return; - } - - int num = read(fd, buffer.buffer, size); - if (num == -1) { - close(fd); - ASSERT_NE(num, -1); - return; - } - - close(fd); -} - - TEST_P(InferenceEngineTestCase_G2, Load_P) { std::string backend_name; @@ -302,63 +117,6 @@ TEST_P(InferenceEngineTestCase_G2, Load_P) delete engine; } -void FillOutputResult(InferenceEngineCommon *engine, std::vector &outputs, tensor_t &outputData) -{ - inference_engine_layer_property property; - int ret = engine->GetOutputLayerProperty(property); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - for (int i = 0; i < (int)property.tensor_infos.size(); ++i) { - inference_engine_tensor_info tensor_info = property.tensor_infos[i]; - - std::vector tmpDimInfo; - for (int i = 0; i < (int)tensor_info.shape.size(); i++) { - tmpDimInfo.push_back(tensor_info.shape[i]); - } - - outputData.dimInfo.push_back(tmpDimInfo); - - // Normalize output tensor data converting it to float type in case of quantized model. - if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { - unsigned char *ori_buf = (unsigned char *)outputs[i].buffer; - float *new_buf = new float[tensor_info.size]; - ASSERT_TRUE(new_buf); - - for (int j = 0; j < (int)tensor_info.size; j++) { - new_buf[j] = (float)ori_buf[j] / 255.0f; - } - - // replace original buffer with new one, and release origin one. - outputs[i].buffer = new_buf; - if (!outputs[i].owner_is_backend) { - delete[] ori_buf; - } - } - - outputData.data.push_back((void *)outputs[i].buffer); - } -} - -int VerifyImageClassificationResults(tensor_t &outputData, int answer) -{ - std::vector> inferDimInfo(outputData.dimInfo); - std::vector inferResults(outputData.data.begin(), outputData.data.end()); - - int idx = -1; - int count = inferDimInfo[0][1]; - float value = 0.0f; - - float *prediction = reinterpret_cast(inferResults[0]); - for (int i = 0; i < count; ++i) { - if (value < prediction[i]) { - value = prediction[i]; - idx = i; - } - } - - return idx == answer; -} - TEST_P(InferenceEngineTestCase_G3, Inference) { std::string backend_name; diff --git a/test/src/inference_engine_test.cpp b/test/src/inference_engine_test.cpp index db50a80..61d195b 100644 --- a/test/src/inference_engine_test.cpp +++ b/test/src/inference_engine_test.cpp @@ -26,8 +26,7 @@ #include "inference_engine_error.h" #include "inference_engine_common_impl.h" - -using namespace InferenceEngineInterface::Common; +#include "inference_engine_test_common.h" typedef std::tuple, int, int, int, std::vector, std::vector, std::vector, std::vector> ParamType_Infer; @@ -35,378 +34,6 @@ class InferenceEngineTfliteTest : public testing::TestWithParam class InferenceEngineCaffeTest : public testing::TestWithParam { }; class InferenceEngineDldtTest : public testing::TestWithParam { }; -std::map Model_Formats = { - { "caffemodel", INFERENCE_MODEL_CAFFE }, - { "pb", INFERENCE_MODEL_TF }, - { "tflite", INFERENCE_MODEL_TFLITE }, - { "t7", INFERENCE_MODEL_TORCH }, - { "weights", INFERENCE_MODEL_DARKNET }, - { "xml", INFERENCE_MODEL_DLDT }, - { "onnx", INFERENCE_MODEL_ONNX } -}; - -std::map Target_Formats = { - { INFERENCE_TARGET_CPU, "cpu" }, - { INFERENCE_TARGET_GPU, "gpu" }, - { INFERENCE_TARGET_CUSTOM, "custom" } -}; - -enum { - TEST_IMAGE_CLASSIFICATION = 0, - TEST_OBJECT_DETECTION, - TEST_FACE_DETECTION, - TEST_FACIAL_LANDMARK_DETECTION, - TEST_POSE_ESTIMATION -}; - -int GetModelInfo(std::vector &model_paths, std::vector &models) -{ - std::string model_path = model_paths[0]; - std::string ext_str = model_path.substr(model_path.find_last_of(".") + 1); - std::map::iterator key = Model_Formats.find(ext_str); - int ret = key != Model_Formats.end() ? key->second : -1; - EXPECT_NE(ret, -1); - - if (ret == -1) { - return ret; - } - - switch (ret) { - case INFERENCE_MODEL_CAFFE: - case INFERENCE_MODEL_TF: - case INFERENCE_MODEL_DARKNET: - case INFERENCE_MODEL_DLDT: - case INFERENCE_MODEL_ONNX: - models.push_back(model_paths[0]); - models.push_back(model_paths[1]); - break; - case INFERENCE_MODEL_TFLITE: - case INFERENCE_MODEL_TORCH: - models.push_back(model_paths[0]); - break; - default: - break; - } - - return ret; -} - -int PrepareTensorBuffers(InferenceEngineCommon *engine, std::vector &inputs, - std::vector &outputs) -{ - int ret = engine->GetInputTensorBuffers(inputs); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - if (inputs.empty()) { - inference_engine_layer_property input_property; - ret = engine->GetInputLayerProperty(input_property); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - // If backend is OpenCV then the buffers will be allocated out of this function. - if (input_property.tensor_infos.empty()) { - return INFERENCE_ENGINE_ERROR_NONE; - } - - for (int i = 0; i < (int)input_property.tensor_infos.size(); ++i) { - inference_engine_tensor_info tensor_info = input_property.tensor_infos[i]; - inference_engine_tensor_buffer tensor_buffer; - if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) { - tensor_buffer.buffer = (void *)(new float[tensor_info.size]); - tensor_buffer.size = tensor_info.size * 4; - } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { - tensor_buffer.buffer = (void *)(new unsigned char[tensor_info.size]); - tensor_buffer.size = tensor_info.size; - } - - EXPECT_TRUE(tensor_buffer.buffer); - tensor_buffer.owner_is_backend = 0; - tensor_buffer.data_type = tensor_info.data_type; - inputs.push_back(tensor_buffer); - } - } - - ret = engine->GetOutputTensorBuffers(outputs); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - if (outputs.empty()) { - inference_engine_layer_property output_property; - ret = engine->GetOutputLayerProperty(output_property); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - // If backend is OpenCV then the buffers will be allocated out of this function. - if (output_property.tensor_infos.empty()) { - return INFERENCE_ENGINE_ERROR_NONE; - } - - for (int i = 0; i < (int)output_property.tensor_infos.size(); ++i) { - inference_engine_tensor_info tensor_info = output_property.tensor_infos[i]; - inference_engine_tensor_buffer tensor_buffer; - if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) { - tensor_buffer.buffer = (void *)(new float[tensor_info.size]); - tensor_buffer.size = tensor_info.size * 4; - } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { - tensor_buffer.buffer = (void *)(new unsigned char[tensor_info.size]); - tensor_buffer.size = tensor_info.size; - } - - EXPECT_TRUE(tensor_buffer.buffer); - tensor_buffer.owner_is_backend = 0; - tensor_buffer.data_type = tensor_info.data_type; - outputs.push_back(tensor_buffer); - } - } - - return INFERENCE_ENGINE_ERROR_NONE; -} - -void CleanupTensorBuffers(std::vector &inputs, std::vector &outputs) -{ - if (!inputs.empty()) { - std::vector::iterator iter; - for (iter = inputs.begin(); iter != inputs.end(); iter++) { - inference_engine_tensor_buffer tensor_buffer = *iter; - - // If tensor buffer owner is a backend then skip to release the tensor buffer. - // This tensor buffer will be released by the backend. - if (tensor_buffer.owner_is_backend) { - continue; - } - - if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) - delete[] (float *)tensor_buffer.buffer; - else - delete[] (unsigned char *)tensor_buffer.buffer; - } - std::vector().swap(inputs); - } - - if (!outputs.empty()) { - std::vector::iterator iter; - for (iter = outputs.begin(); iter != outputs.end(); iter++) { - inference_engine_tensor_buffer tensor_buffer = *iter; - - // If tensor buffer owner is a backend then skip to release the tensor buffer. - // This tensor buffer will be released by the backend. - if (tensor_buffer.owner_is_backend) { - continue; - } - - if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) - delete[] (float *)tensor_buffer.buffer; - else - delete[] (unsigned char *)tensor_buffer.buffer; - } - std::vector().swap(outputs); - } -} - -void CopyFileToMemory(const char *file_name, inference_engine_tensor_buffer &buffer, unsigned int size) -{ - int fd = open(file_name, O_RDONLY); - if (fd == -1) { - ASSERT_NE(fd, -1); - return; - } - - int num = read(fd, buffer.buffer, size); - if (num == -1) { - close(fd); - ASSERT_NE(num, -1); - return; - } - - close(fd); -} - -void FillOutputResult(InferenceEngineCommon *engine, std::vector &outputs, tensor_t &outputData) -{ - inference_engine_layer_property property; - int ret = engine->GetOutputLayerProperty(property); - EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); - - for (int i = 0; i < (int)property.tensor_infos.size(); ++i) { - inference_engine_tensor_info tensor_info = property.tensor_infos[i]; - - std::vector tmpDimInfo; - for (int i = 0; i < (int)tensor_info.shape.size(); i++) { - tmpDimInfo.push_back(tensor_info.shape[i]); - } - - outputData.dimInfo.push_back(tmpDimInfo); - - // Normalize output tensor data converting it to float type in case of quantized model. - if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { - unsigned char *ori_buf = (unsigned char *)outputs[i].buffer; - float *new_buf = new float[tensor_info.size]; - ASSERT_TRUE(new_buf); - - for (int j = 0; j < (int)tensor_info.size; j++) { - new_buf[j] = (float)ori_buf[j] / 255.0f; - } - - // replace original buffer with new one, and release origin one. - outputs[i].buffer = new_buf; - if (!outputs[i].owner_is_backend) { - delete[] ori_buf; - } - } - - outputData.data.push_back((void *)outputs[i].buffer); - } -} - -int VerifyImageClassificationResults(tensor_t &outputData, int answer) -{ - std::vector> inferDimInfo(outputData.dimInfo); - std::vector inferResults(outputData.data.begin(), outputData.data.end()); - - int idx = -1; - int count = inferDimInfo[0][1]; - float value = 0.0f; - - float *prediction = reinterpret_cast(inferResults[0]); - for (int i = 0; i < count; ++i) { - if (value < prediction[i]) { - value = prediction[i]; - idx = i; - } - } - - return idx == answer; -} - -int VerifyObjectDetectionResults(tensor_t &outputData, std::vector &answers, int height, int width) -{ - std::vector> inferDimInfo(outputData.dimInfo); - std::vector inferResults(outputData.data.begin(), outputData.data.end()); - - float* boxes = nullptr; - float* classes = nullptr; - float* scores = nullptr; - int num_of_detections = 0; - - if (outputData.dimInfo.size() == 1) { - // there is no way to know how many objects are detect unless the number of objects aren't - // provided. In the case, each backend should provide the number of results manually. - // For example, in OpenCV, MobilenetV1-SSD doesn't provide it so the number of objects are - // written to the 1st element i.e., outputData.data[0] (the shape is 1x1xNx7 and the 1st of 7 - // indicats the image id. But it is useless if a batch mode isn't supported. - // So, use the 1st of 7. - - num_of_detections = (int)(*reinterpret_cast(outputData.data[0])); - - boxes = new float[num_of_detections * 4]; - classes = new float[num_of_detections]; - scores = new float[num_of_detections]; - - for (int idx = 0; idx < num_of_detections; ++idx) { - classes[idx] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 1]; - scores[idx] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 2]; - - boxes[idx*4] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 4]; - boxes[idx*4 + 1] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 3]; - boxes[idx*4 + 2] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 6]; - boxes[idx*4 + 3] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 5]; - } - } else { - boxes = reinterpret_cast(inferResults[0]); - classes = reinterpret_cast(inferResults[1]); - scores = reinterpret_cast(inferResults[2]); - num_of_detections = (int)(*reinterpret_cast(inferResults[3])); - } - - int left = 0, top = 0, right = 0, bottom = 0; - float max_score = 0.0f; - - for (int i = 0; i < num_of_detections; ++i) { - if (max_score < scores[i]) { - max_score = scores[i]; - - left = (int)(boxes[i * 4 + 1] * width); - top = (int)(boxes[i * 4 + 0] * height); - right = (int)(boxes[i * 4 + 3] * width); - bottom = (int)(boxes[i * 4 + 2] * height); - } - } - - if (outputData.dimInfo.size() == 1) { - delete [] boxes; - delete [] classes; - delete [] scores; - } - - return (answers[0] == left && answers[1] == top && answers[2] == right && answers[3] == bottom); -} - -int VerifyFacialLandmarkDetectionResults(tensor_t &outputData, std::vector &answers, int height, int width) -{ - std::vector> inferDimInfo(outputData.dimInfo); - std::vector inferResults(outputData.data.begin(), outputData.data.end()); - std::vector result_x, result_y; - - long number_of_detections = inferDimInfo[0][1]; - float* loc = reinterpret_cast(inferResults[0]); - - for (int idx = 0; idx < number_of_detections; idx+=2) { - result_x.push_back((int)(loc[idx] * width)); - result_y.push_back((int)(loc[idx+1] * height)); - } - - int ret = 1; - for (int i = 0; i < (number_of_detections>>1); i++) { - if (result_x[i] != answers[i*2] || result_y[i] != answers[i*2 + 1]) { - ret = 0; - break; - } - } - - return ret; -} - -int VerifyPoseEstimationResults(tensor_t &outputData, std::vector &answers, int height, int width) -{ - std::vector> inferDimInfo(outputData.dimInfo); - std::vector inferResults(outputData.data.begin(), outputData.data.end()); - std::vector result_x, result_y; - - const int heat_map_width = 96, heat_map_height = 96; - int num_of_pose = inferDimInfo[0][3]; - float *data = static_cast(inferResults[0]); - - float ratio_x = (float)width / (float)inferDimInfo[0][2]; - float ratio_y = (float)height / (float)inferDimInfo[0][1]; - - for (int idx = 0; idx < num_of_pose; ++idx) { - float max_score = 0.0f; - int max_x = 0, max_y = 0; - - for (int y = 0; y < heat_map_height; ++y) { - for (int x = 0; x < heat_map_width; ++x) { - // head_map[Yy][Xx][Kidx] = (Yy * heat_map_height * num_of_pose) + (Xx * num_of_pose) + Kidx - float score = data[(y * heat_map_width * num_of_pose) + (x * num_of_pose) + idx]; - if (score > max_score) { - max_score = score; - max_x = x; - max_y = y; - } - } - } - - result_x.push_back((int)((float)(max_x + 1) * ratio_x)); - result_y.push_back((int)((float)(max_y + 1) * ratio_y)); - } - - int ret = 1; - for (int i = 0; i < num_of_pose; ++i) { - if (result_x[i] != answers[i] || result_y[i] != answers[num_of_pose + i]) { - ret = 0; - break; - } - } - - return ret; -} - TEST_P(InferenceEngineTfliteTest, Inference) { std::string backend_name; @@ -1044,4 +671,4 @@ INSTANTIATE_TEST_CASE_P(Prefix, InferenceEngineDldtTest, // DLDT ParamType_Infer("dldt", INFERENCE_TARGET_CUSTOM, TEST_IMAGE_CLASSIFICATION, 10, INFERENCE_TENSOR_DATA_TYPE_FLOAT32, { "/opt/usr/images/dldt_banana_classification.bin" }, 224, 224, 3, { "data" }, { "prob" }, { "/usr/share/capi-media-vision/models/IC/dldt/googlenet-v1.xml", "/usr/share/capi-media-vision/models/IC/dldt/googlenet-v1.bin" }, { 954 }) ) -); \ No newline at end of file +); diff --git a/test/src/inference_engine_test_common.cpp b/test/src/inference_engine_test_common.cpp new file mode 100644 index 0000000..9a2791e --- /dev/null +++ b/test/src/inference_engine_test_common.cpp @@ -0,0 +1,387 @@ +/** + * Copyright (c) 2020 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 +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "inference_engine_error.h" +#include "inference_engine_common_impl.h" +#include "inference_engine_test_common.h" + +static std::map Model_Formats = { + { "caffemodel", INFERENCE_MODEL_CAFFE }, + { "pb", INFERENCE_MODEL_TF }, + { "tflite", INFERENCE_MODEL_TFLITE }, + { "t7", INFERENCE_MODEL_TORCH }, + { "weights", INFERENCE_MODEL_DARKNET }, + { "xml", INFERENCE_MODEL_DLDT }, + { "onnx", INFERENCE_MODEL_ONNX } +}; + +int GetModelInfo(std::vector &model_paths, std::vector &models) +{ + std::string model_path = model_paths[0]; + std::string ext_str = model_path.substr(model_path.find_last_of(".") + 1); + std::map::iterator key = Model_Formats.find(ext_str); + int ret = key != Model_Formats.end() ? key->second : -1; + EXPECT_NE(ret, -1); + + if (ret == -1) { + return ret; + } + + switch (ret) { + case INFERENCE_MODEL_CAFFE: + case INFERENCE_MODEL_TF: + case INFERENCE_MODEL_DARKNET: + case INFERENCE_MODEL_DLDT: + case INFERENCE_MODEL_ONNX: + models.push_back(model_paths[0]); + models.push_back(model_paths[1]); + break; + case INFERENCE_MODEL_TFLITE: + case INFERENCE_MODEL_TORCH: + models.push_back(model_paths[0]); + break; + default: + break; + } + + return ret; +} + +int PrepareTensorBuffers(InferenceEngineCommon *engine, std::vector &inputs, + std::vector &outputs) +{ + int ret = engine->GetInputTensorBuffers(inputs); + EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); + + if (inputs.empty()) { + inference_engine_layer_property input_property; + ret = engine->GetInputLayerProperty(input_property); + EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); + + // If backend is OpenCV then the buffers will be allocated out of this function. + if (input_property.tensor_infos.empty()) { + return INFERENCE_ENGINE_ERROR_NONE; + } + + for (int i = 0; i < (int)input_property.tensor_infos.size(); ++i) { + inference_engine_tensor_info tensor_info = input_property.tensor_infos[i]; + inference_engine_tensor_buffer tensor_buffer; + if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) { + tensor_buffer.buffer = (void *)(new float[tensor_info.size]); + tensor_buffer.size = tensor_info.size * 4; + } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { + tensor_buffer.buffer = (void *)(new unsigned char[tensor_info.size]); + tensor_buffer.size = tensor_info.size; + } + + EXPECT_TRUE(tensor_buffer.buffer); + tensor_buffer.owner_is_backend = 0; + tensor_buffer.data_type = tensor_info.data_type; + inputs.push_back(tensor_buffer); + } + } + + ret = engine->GetOutputTensorBuffers(outputs); + EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); + + if (outputs.empty()) { + inference_engine_layer_property output_property; + ret = engine->GetOutputLayerProperty(output_property); + EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); + + // If backend is OpenCV then the buffers will be allocated out of this function. + if (output_property.tensor_infos.empty()) { + return INFERENCE_ENGINE_ERROR_NONE; + } + + for (int i = 0; i < (int)output_property.tensor_infos.size(); ++i) { + inference_engine_tensor_info tensor_info = output_property.tensor_infos[i]; + inference_engine_tensor_buffer tensor_buffer; + if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) { + tensor_buffer.buffer = (void *)(new float[tensor_info.size]); + tensor_buffer.size = tensor_info.size * 4; + } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { + tensor_buffer.buffer = (void *)(new unsigned char[tensor_info.size]); + tensor_buffer.size = tensor_info.size; + } + + EXPECT_TRUE(tensor_buffer.buffer); + tensor_buffer.owner_is_backend = 0; + tensor_buffer.data_type = tensor_info.data_type; + outputs.push_back(tensor_buffer); + } + } + + return INFERENCE_ENGINE_ERROR_NONE; +} + +void CleanupTensorBuffers(std::vector &inputs, std::vector &outputs) +{ + if (!inputs.empty()) { + std::vector::iterator iter; + for (iter = inputs.begin(); iter != inputs.end(); iter++) { + inference_engine_tensor_buffer tensor_buffer = *iter; + + // If tensor buffer owner is a backend then skip to release the tensor buffer. + // This tensor buffer will be released by the backend. + if (tensor_buffer.owner_is_backend) { + continue; + } + + if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) + delete[] (float *)tensor_buffer.buffer; + else + delete[] (unsigned char *)tensor_buffer.buffer; + } + std::vector().swap(inputs); + } + + if (!outputs.empty()) { + std::vector::iterator iter; + for (iter = outputs.begin(); iter != outputs.end(); iter++) { + inference_engine_tensor_buffer tensor_buffer = *iter; + + // If tensor buffer owner is a backend then skip to release the tensor buffer. + // This tensor buffer will be released by the backend. + if (tensor_buffer.owner_is_backend) { + continue; + } + + if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) + delete[] (float *)tensor_buffer.buffer; + else + delete[] (unsigned char *)tensor_buffer.buffer; + } + std::vector().swap(outputs); + } +} + +void CopyFileToMemory(const char *file_name, inference_engine_tensor_buffer &buffer, unsigned int size) +{ + int fd = open(file_name, O_RDONLY); + if (fd == -1) { + ASSERT_NE(fd, -1); + return; + } + + int num = read(fd, buffer.buffer, size); + if (num == -1) { + close(fd); + ASSERT_NE(num, -1); + return; + } + + close(fd); +} + +void FillOutputResult(InferenceEngineCommon *engine, std::vector &outputs, tensor_t &outputData) +{ + inference_engine_layer_property property; + int ret = engine->GetOutputLayerProperty(property); + EXPECT_EQ(ret, INFERENCE_ENGINE_ERROR_NONE); + + for (int i = 0; i < (int)property.tensor_infos.size(); ++i) { + inference_engine_tensor_info tensor_info = property.tensor_infos[i]; + + std::vector tmpDimInfo; + for (int i = 0; i < (int)tensor_info.shape.size(); i++) { + tmpDimInfo.push_back(tensor_info.shape[i]); + } + + outputData.dimInfo.push_back(tmpDimInfo); + + // Normalize output tensor data converting it to float type in case of quantized model. + if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) { + unsigned char *ori_buf = (unsigned char *)outputs[i].buffer; + float *new_buf = new float[tensor_info.size]; + ASSERT_TRUE(new_buf); + + for (int j = 0; j < (int)tensor_info.size; j++) { + new_buf[j] = (float)ori_buf[j] / 255.0f; + } + + // replace original buffer with new one, and release origin one. + outputs[i].buffer = new_buf; + if (!outputs[i].owner_is_backend) { + delete[] ori_buf; + } + } + + outputData.data.push_back((void *)outputs[i].buffer); + } +} + +int VerifyImageClassificationResults(tensor_t &outputData, int answer) +{ + std::vector> inferDimInfo(outputData.dimInfo); + std::vector inferResults(outputData.data.begin(), outputData.data.end()); + + int idx = -1; + int count = inferDimInfo[0][1]; + float value = 0.0f; + + float *prediction = reinterpret_cast(inferResults[0]); + for (int i = 0; i < count; ++i) { + if (value < prediction[i]) { + value = prediction[i]; + idx = i; + } + } + + return idx == answer; +} + +int VerifyObjectDetectionResults(tensor_t &outputData, std::vector &answers, int height, int width) +{ + std::vector> inferDimInfo(outputData.dimInfo); + std::vector inferResults(outputData.data.begin(), outputData.data.end()); + + float* boxes = nullptr; + float* classes = nullptr; + float* scores = nullptr; + int num_of_detections = 0; + + if (outputData.dimInfo.size() == 1) { + // there is no way to know how many objects are detect unless the number of objects aren't + // provided. In the case, each backend should provide the number of results manually. + // For example, in OpenCV, MobilenetV1-SSD doesn't provide it so the number of objects are + // written to the 1st element i.e., outputData.data[0] (the shape is 1x1xNx7 and the 1st of 7 + // indicats the image id. But it is useless if a batch mode isn't supported. + // So, use the 1st of 7. + + num_of_detections = (int)(*reinterpret_cast(outputData.data[0])); + + boxes = new float[num_of_detections * 4]; + classes = new float[num_of_detections]; + scores = new float[num_of_detections]; + + for (int idx = 0; idx < num_of_detections; ++idx) { + classes[idx] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 1]; + scores[idx] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 2]; + + boxes[idx*4] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 4]; + boxes[idx*4 + 1] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 3]; + boxes[idx*4 + 2] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 6]; + boxes[idx*4 + 3] = (reinterpret_cast(outputData.data[0]))[idx*inferDimInfo[0][3] + 5]; + } + } else { + boxes = reinterpret_cast(inferResults[0]); + classes = reinterpret_cast(inferResults[1]); + scores = reinterpret_cast(inferResults[2]); + num_of_detections = (int)(*reinterpret_cast(inferResults[3])); + } + + int left = 0, top = 0, right = 0, bottom = 0; + float max_score = 0.0f; + + for (int i = 0; i < num_of_detections; ++i) { + if (max_score < scores[i]) { + max_score = scores[i]; + + left = (int)(boxes[i * 4 + 1] * width); + top = (int)(boxes[i * 4 + 0] * height); + right = (int)(boxes[i * 4 + 3] * width); + bottom = (int)(boxes[i * 4 + 2] * height); + } + } + + if (outputData.dimInfo.size() == 1) { + delete [] boxes; + delete [] classes; + delete [] scores; + } + + return (answers[0] == left && answers[1] == top && answers[2] == right && answers[3] == bottom); +} + +int VerifyFacialLandmarkDetectionResults(tensor_t &outputData, std::vector &answers, int height, int width) +{ + std::vector> inferDimInfo(outputData.dimInfo); + std::vector inferResults(outputData.data.begin(), outputData.data.end()); + std::vector result_x, result_y; + + long number_of_detections = inferDimInfo[0][1]; + float* loc = reinterpret_cast(inferResults[0]); + + for (int idx = 0; idx < number_of_detections; idx+=2) { + result_x.push_back((int)(loc[idx] * width)); + result_y.push_back((int)(loc[idx+1] * height)); + } + + int ret = 1; + for (int i = 0; i < (number_of_detections>>1); i++) { + if (result_x[i] != answers[i*2] || result_y[i] != answers[i*2 + 1]) { + ret = 0; + break; + } + } + + return ret; +} + +int VerifyPoseEstimationResults(tensor_t &outputData, std::vector &answers, int height, int width) +{ + std::vector> inferDimInfo(outputData.dimInfo); + std::vector inferResults(outputData.data.begin(), outputData.data.end()); + std::vector result_x, result_y; + + const int heat_map_width = 96, heat_map_height = 96; + int num_of_pose = inferDimInfo[0][3]; + float *data = static_cast(inferResults[0]); + + float ratio_x = (float)width / (float)inferDimInfo[0][2]; + float ratio_y = (float)height / (float)inferDimInfo[0][1]; + + for (int idx = 0; idx < num_of_pose; ++idx) { + float max_score = 0.0f; + int max_x = 0, max_y = 0; + + for (int y = 0; y < heat_map_height; ++y) { + for (int x = 0; x < heat_map_width; ++x) { + // head_map[Yy][Xx][Kidx] = (Yy * heat_map_height * num_of_pose) + (Xx * num_of_pose) + Kidx + float score = data[(y * heat_map_width * num_of_pose) + (x * num_of_pose) + idx]; + if (score > max_score) { + max_score = score; + max_x = x; + max_y = y; + } + } + } + + result_x.push_back((int)((float)(max_x + 1) * ratio_x)); + result_y.push_back((int)((float)(max_y + 1) * ratio_y)); + } + + int ret = 1; + for (int i = 0; i < num_of_pose; ++i) { + if (result_x[i] != answers[i] || result_y[i] != answers[num_of_pose + i]) { + ret = 0; + break; + } + } + + return ret; +} diff --git a/test/src/inference_engine_test_common.h b/test/src/inference_engine_test_common.h new file mode 100644 index 0000000..bcd38cf --- /dev/null +++ b/test/src/inference_engine_test_common.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2020 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 +#include + +#include "inference_engine_common_impl.h" + +using namespace InferenceEngineInterface::Common; + +static std::map Target_Formats = { + { INFERENCE_TARGET_CPU, "cpu" }, + { INFERENCE_TARGET_GPU, "gpu" }, + { INFERENCE_TARGET_CUSTOM, "custom" } +}; + +enum { + TEST_IMAGE_CLASSIFICATION = 0, + TEST_OBJECT_DETECTION, + TEST_FACE_DETECTION, + TEST_FACIAL_LANDMARK_DETECTION, + TEST_POSE_ESTIMATION +}; + +int GetModelInfo(std::vector &model_paths, std::vector &models); + +int PrepareTensorBuffers(InferenceEngineCommon *engine, std::vector &inputs, + std::vector &outputs); + +void CleanupTensorBuffers(std::vector &inputs, std::vector &outputs); + +void CopyFileToMemory(const char *file_name, inference_engine_tensor_buffer &buffer, unsigned int size); + +void FillOutputResult(InferenceEngineCommon *engine, std::vector &outputs, tensor_t &outputData); + +int VerifyImageClassificationResults(tensor_t &outputData, int answer); + +int VerifyObjectDetectionResults(tensor_t &outputData, std::vector &answers, int height, int width); + +int VerifyFacialLandmarkDetectionResults(tensor_t &outputData, std::vector &answers, int height, int width); + +int VerifyPoseEstimationResults(tensor_t &outputData, std::vector &answers, int height, int width); \ No newline at end of file -- 2.34.1