更新到HyperLPR3版本
This commit is contained in:
@@ -0,0 +1,430 @@
|
||||
/* Copyright 2021 iwatake2222
|
||||
|
||||
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 ***/
|
||||
/* for general */
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
||||
/* for My modules */
|
||||
#include "inference_helper_log.h"
|
||||
#include "inference_helper.h"
|
||||
|
||||
#ifdef INFERENCE_HELPER_ENABLE_OPENCV
|
||||
#include "inference_helper_opencv.h"
|
||||
#endif
|
||||
#if defined(INFERENCE_HELPER_ENABLE_TFLITE) || defined(INFERENCE_HELPER_ENABLE_TFLITE_DELEGATE_XNNPACK) || defined(INFERENCE_HELPER_ENABLE_TFLITE_DELEGATE_GPU) || defined(INFERENCE_HELPER_ENABLE_TFLITE_DELEGATE_EDGETPU)
|
||||
#include "inference_helper_tensorflow_lite.h"
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_TENSORRT
|
||||
#include "inference_helper_tensorrt.h"
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_NCNN
|
||||
#include "inference_helper_ncnn.h"
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_MNN
|
||||
#include "inference_helper_mnn.h"
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_SNPE
|
||||
#include "inference_helper_snpe.h"
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_ARMNN
|
||||
#include "inference_helper_armnn.h"
|
||||
#endif
|
||||
#if defined(INFERENCE_HELPER_ENABLE_NNABLA) || defined(INFERENCE_HELPER_ENABLE_NNABLA_CUDA)
|
||||
#include "inference_helper_nnabla.h"
|
||||
#endif
|
||||
#if defined(INFERENCE_HELPER_ENABLE_ONNX_RUNTIME) || defined(INFERENCE_HELPER_ENABLE_ONNX_RUNTIME_CUDA)
|
||||
#include "inference_helper_onnx_runtime.h"
|
||||
#endif
|
||||
#if defined(INFERENCE_HELPER_ENABLE_LIBTORCH) || defined(INFERENCE_HELPER_ENABLE_LIBTORCH_CUDA)
|
||||
#include "inference_helper_libtorch.h"
|
||||
#endif
|
||||
#if defined(INFERENCE_HELPER_ENABLE_TENSORFLOW) || defined(INFERENCE_HELPER_ENABLE_TENSORFLOW_GPU)
|
||||
#include "inference_helper_tensorflow.h"
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_SAMPLE
|
||||
#include "inference_helper_sample.h"
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_RKNN
|
||||
#include "inference_helper_rknn.h"
|
||||
#endif
|
||||
|
||||
/*** Macro ***/
|
||||
#define TAG "InferenceHelper"
|
||||
#define PRINT(...) INFERENCE_HELPER_LOG_PRINT(TAG, __VA_ARGS__)
|
||||
#define PRINT_E(...) INFERENCE_HELPER_LOG_PRINT_E(TAG, __VA_ARGS__)
|
||||
|
||||
|
||||
InferenceHelper* InferenceHelper::Create(const InferenceHelper::HelperType helper_type)
|
||||
{
|
||||
InferenceHelper* p = nullptr;
|
||||
switch (helper_type) {
|
||||
#ifdef INFERENCE_HELPER_ENABLE_OPENCV
|
||||
case kOpencv:
|
||||
case kOpencvGpu:
|
||||
PRINT("Use OpenCV \n");
|
||||
p = new InferenceHelperOpenCV();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_TFLITE
|
||||
case kTensorflowLite:
|
||||
PRINT("Use TensorflowLite\n");
|
||||
p = new InferenceHelperTensorflowLite();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_TFLITE_DELEGATE_XNNPACK
|
||||
case kTensorflowLiteXnnpack:
|
||||
PRINT("Use TensorflowLite XNNPACK Delegate\n");
|
||||
p = new InferenceHelperTensorflowLite();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_TFLITE_DELEGATE_GPU
|
||||
case kTensorflowLiteGpu:
|
||||
PRINT("Use TensorflowLite GPU Delegate\n");
|
||||
p = new InferenceHelperTensorflowLite();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_TFLITE_DELEGATE_EDGETPU
|
||||
case kTensorflowLiteEdgetpu:
|
||||
PRINT("Use TensorflowLite EdgeTPU Delegate\n");
|
||||
p = new InferenceHelperTensorflowLite();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_TFLITE_DELEGATE_NNAPI
|
||||
case kTensorflowLiteNnapi:
|
||||
PRINT("Use TensorflowLite NNAPI Delegate\n");
|
||||
p = new InferenceHelperTensorflowLite();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_TENSORRT
|
||||
case kTensorrt:
|
||||
PRINT("Use TensorRT \n");
|
||||
p = new InferenceHelperTensorRt();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_NCNN
|
||||
case kNcnn:
|
||||
case kNcnnVulkan:
|
||||
PRINT("Use NCNN\n");
|
||||
p = new InferenceHelperNcnn();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_MNN
|
||||
case kMnn:
|
||||
PRINT("Use MNN\n");
|
||||
p = new InferenceHelperMnn();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_SNPE
|
||||
case kSnpe:
|
||||
PRINT("Use SNPE\n");
|
||||
p = new InferenceHelperSnpe();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_ARMNN
|
||||
case kArmnn:
|
||||
PRINT("Use ARMNN\n");
|
||||
p = new InferenceHelperArmnn();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_NNABLA
|
||||
case kNnabla:
|
||||
PRINT("Use NNabla\n");
|
||||
p = new InferenceHelperNnabla();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_NNABLA_CUDA
|
||||
case kNnablaCuda:
|
||||
PRINT("Use NNabla_CUDA\n");
|
||||
p = new InferenceHelperNnabla();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_ONNX_RUNTIME
|
||||
case kOnnxRuntime:
|
||||
PRINT("Use ONNX Runtime\n");
|
||||
p = new InferenceHelperOnnxRuntime();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_ONNX_RUNTIME_CUDA
|
||||
case kOnnxRuntimeCuda:
|
||||
PRINT("Use ONNX Runtime_CUDA\n");
|
||||
p = new InferenceHelperOnnxRuntime();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_LIBTORCH
|
||||
case kLibtorch:
|
||||
PRINT("Use LibTorch\n");
|
||||
p = new InferenceHelperLibtorch();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_LIBTORCH_CUDA
|
||||
case kLibtorchCuda:
|
||||
PRINT("Use LibTorch CUDA\n");
|
||||
p = new InferenceHelperLibtorch();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_TENSORFLOW
|
||||
case kTensorflow:
|
||||
PRINT("Use TensorFlow\n");
|
||||
p = new InferenceHelperTensorflow();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_TENSORFLOW_GPU
|
||||
case kTensorflowGpu:
|
||||
PRINT("Use TensorFlow GPU\n");
|
||||
p = new InferenceHelperTensorflow();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_SAMPLE
|
||||
case kSample:
|
||||
PRINT("Do not use this. this is just a reference code\n");
|
||||
p = new InferenceHelperSample();
|
||||
break;
|
||||
#endif
|
||||
#ifdef INFERENCE_HELPER_ENABLE_RKNN
|
||||
case kRknn:
|
||||
PRINT("Use Rknn\n")
|
||||
p = new InferenceHelperRKNN();
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
PRINT_E("Unsupported inference helper type (%d)\n", helper_type);
|
||||
break;
|
||||
}
|
||||
if (p == nullptr) {
|
||||
PRINT_E("Failed to create inference helper\n");
|
||||
} else {
|
||||
p->helper_type_ = helper_type;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifdef INFERENCE_HELPER_ENABLE_PRE_PROCESS_BY_OPENCV
|
||||
#include <opencv2/opencv.hpp>
|
||||
void InferenceHelper::PreProcessByOpenCV(const InputTensorInfo& input_tensor_info, bool is_nchw, cv::Mat& img_blob)
|
||||
{
|
||||
/* Generate mat from original data */
|
||||
cv::Mat img_src = cv::Mat(cv::Size(input_tensor_info.image_info.width, input_tensor_info.image_info.height), (input_tensor_info.image_info.channel == 3) ? CV_8UC3 : CV_8UC1, input_tensor_info.data);
|
||||
|
||||
/* Crop image */
|
||||
if (input_tensor_info.image_info.width == input_tensor_info.image_info.crop_width && input_tensor_info.image_info.height == input_tensor_info.image_info.crop_height) {
|
||||
/* do nothing */
|
||||
} else {
|
||||
img_src = img_src(cv::Rect(input_tensor_info.image_info.crop_x, input_tensor_info.image_info.crop_y, input_tensor_info.image_info.crop_width, input_tensor_info.image_info.crop_height));
|
||||
}
|
||||
|
||||
/* Resize image */
|
||||
if (input_tensor_info.image_info.crop_width == input_tensor_info.GetWidth() && input_tensor_info.image_info.crop_height == input_tensor_info.GetHeight()) {
|
||||
/* do nothing */
|
||||
} else {
|
||||
cv::resize(img_src, img_src, cv::Size(input_tensor_info.GetWidth(), input_tensor_info.GetHeight()));
|
||||
}
|
||||
|
||||
/* Convert color type */
|
||||
if (input_tensor_info.image_info.channel == input_tensor_info.GetChannel()) {
|
||||
if (input_tensor_info.image_info.channel == 3 && input_tensor_info.image_info.swap_color) {
|
||||
cv::cvtColor(img_src, img_src, cv::COLOR_BGR2RGB);
|
||||
}
|
||||
} else if (input_tensor_info.image_info.channel == 3 && input_tensor_info.GetChannel() == 1) {
|
||||
cv::cvtColor(img_src, img_src, (input_tensor_info.image_info.is_bgr) ? cv::COLOR_BGR2GRAY : cv::COLOR_RGB2GRAY);
|
||||
} else if (input_tensor_info.image_info.channel == 1 && input_tensor_info.GetChannel() == 3) {
|
||||
cv::cvtColor(img_src, img_src, cv::COLOR_GRAY2BGR);
|
||||
}
|
||||
|
||||
if (input_tensor_info.tensor_type == TensorInfo::kTensorTypeFp32) {
|
||||
/* Normalize image */
|
||||
if (input_tensor_info.GetChannel() == 3) {
|
||||
#if 1
|
||||
img_src.convertTo(img_src, CV_32FC3);
|
||||
cv::subtract(img_src, cv::Scalar(cv::Vec<float, 3>(input_tensor_info.normalize.mean)), img_src);
|
||||
cv::multiply(img_src, cv::Scalar(cv::Vec<float, 3>(input_tensor_info.normalize.norm)), img_src);
|
||||
#else
|
||||
img_src.convertTo(img_src, CV_32FC3, 1.0 / 255);
|
||||
cv::subtract(img_src, cv::Scalar(cv::Vec<float, 3>(input_tensor_info.normalize.mean)), img_src);
|
||||
cv::divide(img_src, cv::Scalar(cv::Vec<float, 3>(input_tensor_info.normalize.norm)), img_src);
|
||||
#endif
|
||||
} else {
|
||||
#if 1
|
||||
img_src.convertTo(img_src, CV_32FC1);
|
||||
cv::subtract(img_src, cv::Scalar(cv::Vec<float, 1>(input_tensor_info.normalize.mean)), img_src);
|
||||
cv::multiply(img_src, cv::Scalar(cv::Vec<float, 1>(input_tensor_info.normalize.norm)), img_src);
|
||||
#else
|
||||
img_src.convertTo(img_src, CV_32FC1, 1.0 / 255);
|
||||
cv::subtract(img_src, cv::Scalar(cv::Vec<float, 1>(input_tensor_info.normalize.mean)), img_src);
|
||||
cv::divide(img_src, cv::Scalar(cv::Vec<float, 1>(input_tensor_info.normalize.norm)), img_src);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
if (is_nchw) {
|
||||
/* Convert to 4-dimensional Mat in NCHW */
|
||||
img_src = cv::dnn::blobFromImage(img_src);
|
||||
}
|
||||
|
||||
img_blob = img_src;
|
||||
//memcpy(blobData, img_src.data, img_src.cols * img_src.rows * img_src.channels());
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
/* For the environment where OpenCV is not supported */
|
||||
void InferenceHelper::PreProcessByOpenCV(const InputTensorInfo& input_tensor_info, bool is_nchw, cv::Mat& img_blob)
|
||||
{
|
||||
PRINT_E("[PreProcessByOpenCV] Unsupported function called\n");
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void InferenceHelper::ConvertNormalizeParameters(InputTensorInfo& tensor_info)
|
||||
{
|
||||
if (tensor_info.data_type != InputTensorInfo::kDataTypeImage) return;
|
||||
|
||||
#if 0
|
||||
/* Convert to speeden up normalization: ((src / 255) - mean) / norm = src * 1 / (255 * norm) - (mean / norm) */
|
||||
for (int32_t i = 0; i < 3; i++) {
|
||||
tensor_info.normalize.mean[i] /= tensor_info.normalize.norm[i];
|
||||
tensor_info.normalize.norm[i] *= 255.0f;
|
||||
tensor_info.normalize.norm[i] = 1.0f / tensor_info.normalize.norm[i];
|
||||
}
|
||||
#endif
|
||||
#if 1
|
||||
/* Convert to speeden up normalization: ((src / 255) - mean) / norm = (src - (mean * 255)) * (1 / (255 * norm)) */
|
||||
for (int32_t i = 0; i < 3; i++) {
|
||||
tensor_info.normalize.mean[i] *= 255.0f;
|
||||
tensor_info.normalize.norm[i] *= 255.0f;
|
||||
tensor_info.normalize.norm[i] = 1.0f / tensor_info.normalize.norm[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void InferenceHelper::PreProcessImage(int32_t num_thread, const InputTensorInfo& input_tensor_info, float* dst)
|
||||
{
|
||||
const int32_t img_width = input_tensor_info.GetWidth();
|
||||
const int32_t img_height = input_tensor_info.GetHeight();
|
||||
const int32_t img_channel = input_tensor_info.GetChannel();
|
||||
uint8_t* src = (uint8_t*)(input_tensor_info.data);
|
||||
if (input_tensor_info.is_nchw == true) {
|
||||
/* convert NHWC to NCHW */
|
||||
#pragma omp parallel for num_threads(num_thread)
|
||||
for (int32_t c = 0; c < img_channel; c++) {
|
||||
for (int32_t i = 0; i < img_width * img_height; i++) {
|
||||
dst[c * img_width * img_height + i] = (src[i * img_channel + c] - input_tensor_info.normalize.mean[c]) * input_tensor_info.normalize.norm[c];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* convert NHWC to NHWC */
|
||||
#pragma omp parallel for num_threads(num_thread)
|
||||
for (int32_t i = 0; i < img_width * img_height; i++) {
|
||||
for (int32_t c = 0; c < img_channel; c++) {
|
||||
#if 1
|
||||
dst[i * img_channel + c] = (src[i * img_channel + c] - input_tensor_info.normalize.mean[c]) * input_tensor_info.normalize.norm[c];
|
||||
#else
|
||||
dst[i * img_channel + c] = (src[i * img_channel + c] / 255.0f - input_tensor_info.normalize.mean[c]) / input_tensor_info.normalize.norm[c];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InferenceHelper::PreProcessImage(int32_t num_thread, const InputTensorInfo& input_tensor_info, uint8_t* dst)
|
||||
{
|
||||
const int32_t img_width = input_tensor_info.GetWidth();
|
||||
const int32_t img_height = input_tensor_info.GetHeight();
|
||||
const int32_t img_channel = input_tensor_info.GetChannel();
|
||||
uint8_t* src = (uint8_t*)(input_tensor_info.data);
|
||||
if (input_tensor_info.is_nchw == true) {
|
||||
/* convert NHWC to NCHW */
|
||||
#pragma omp parallel for num_threads(num_thread)
|
||||
for (int32_t c = 0; c < img_channel; c++) {
|
||||
for (int32_t i = 0; i < img_width * img_height; i++) {
|
||||
dst[c * img_width * img_height + i] = src[i * img_channel + c];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* convert NHWC to NHWC */
|
||||
std::copy(src, src + input_tensor_info.GetElementNum(), dst);
|
||||
}
|
||||
}
|
||||
|
||||
void InferenceHelper::PreProcessImage(int32_t num_thread, const InputTensorInfo& input_tensor_info, int8_t* dst)
|
||||
{
|
||||
const int32_t img_width = input_tensor_info.GetWidth();
|
||||
const int32_t img_height = input_tensor_info.GetHeight();
|
||||
const int32_t img_channel = input_tensor_info.GetChannel();
|
||||
uint8_t* src = (uint8_t*)(input_tensor_info.data);
|
||||
if (input_tensor_info.is_nchw == true) {
|
||||
/* convert NHWC to NCHW */
|
||||
#pragma omp parallel for num_threads(num_thread)
|
||||
for (int32_t c = 0; c < img_channel; c++) {
|
||||
for (int32_t i = 0; i < img_width * img_height; i++) {
|
||||
dst[c * img_width * img_height + i] = src[i * img_channel + c] - 128;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#pragma omp parallel for num_threads(num_thread)
|
||||
for (int32_t i = 0; i < img_width * img_height; i++) {
|
||||
for (int32_t c = 0; c < img_channel; c++) {
|
||||
dst[i * img_channel + c] = src[i * img_channel + c] - 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void InferenceHelper::PreProcessBlob(int32_t num_thread, const InputTensorInfo& input_tensor_info, T* dst)
|
||||
{
|
||||
const int32_t img_width = input_tensor_info.GetWidth();
|
||||
const int32_t img_height = input_tensor_info.GetHeight();
|
||||
const int32_t img_channel = input_tensor_info.GetChannel();
|
||||
T* src = static_cast<T*>(input_tensor_info.data);
|
||||
if ((input_tensor_info.data_type == InputTensorInfo::kDataTypeBlobNchw && input_tensor_info.is_nchw) || (input_tensor_info.data_type == InputTensorInfo::kDataTypeBlobNhwc && !input_tensor_info.is_nchw)) {
|
||||
std::copy(src, src + input_tensor_info.GetElementNum(), dst);
|
||||
} else if (input_tensor_info.data_type == InputTensorInfo::kDataTypeBlobNchw) {
|
||||
/* NCHW -> NHWC */
|
||||
#pragma omp parallel for num_threads(num_thread)
|
||||
for (int32_t i = 0; i < img_width * img_height; i++) {
|
||||
for (int32_t c = 0; c < img_channel; c++) {
|
||||
dst[i * img_channel + c] = src[c * (img_width * img_height) + i];
|
||||
}
|
||||
}
|
||||
} else if (input_tensor_info.data_type == InputTensorInfo::kDataTypeBlobNhwc) {
|
||||
/* NHWC -> NCHW */
|
||||
#pragma omp parallel for num_threads(num_thread)
|
||||
for (int32_t i = 0; i < img_width * img_height; i++) {
|
||||
for (int32_t c = 0; c < img_channel; c++) {
|
||||
dst[c * (img_width * img_height) + i] = src[i * img_channel + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template void InferenceHelper::PreProcessBlob<float>(int32_t num_thread, const InputTensorInfo& input_tensor_info, float* dst);
|
||||
template void InferenceHelper::PreProcessBlob<int32_t>(int32_t num_thread, const InputTensorInfo& input_tensor_info, int32_t* dst);
|
||||
template void InferenceHelper::PreProcessBlob<int64_t>(int32_t num_thread, const InputTensorInfo& input_tensor_info, int64_t* dst);
|
||||
template void InferenceHelper::PreProcessBlob<uint8_t>(int32_t num_thread, const InputTensorInfo& input_tensor_info, uint8_t* dst);
|
||||
template void InferenceHelper::PreProcessBlob<int8_t>(int32_t num_thread, const InputTensorInfo& input_tensor_info, int8_t* dst);
|
||||
@@ -0,0 +1,280 @@
|
||||
/* Copyright 2021 iwatake2222
|
||||
|
||||
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.
|
||||
==============================================================================*/
|
||||
#ifndef INFERENCE_HELPER_
|
||||
#define INFERENCE_HELPER_
|
||||
|
||||
/* for general */
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
class TensorInfo {
|
||||
public:
|
||||
enum {
|
||||
kTensorTypeNone,
|
||||
kTensorTypeUint8,
|
||||
kTensorTypeInt8,
|
||||
kTensorTypeFp32,
|
||||
kTensorTypeInt32,
|
||||
kTensorTypeInt64,
|
||||
};
|
||||
|
||||
public:
|
||||
TensorInfo()
|
||||
: name("")
|
||||
, id(-1)
|
||||
, tensor_type(kTensorTypeNone)
|
||||
, is_nchw(true)
|
||||
{}
|
||||
~TensorInfo() {}
|
||||
|
||||
int32_t GetElementNum() const
|
||||
{
|
||||
int32_t element_num = 1;
|
||||
for (const auto& dim : tensor_dims) {
|
||||
element_num *= dim;
|
||||
}
|
||||
return element_num;
|
||||
}
|
||||
|
||||
int32_t GetBatch() const
|
||||
{
|
||||
if (tensor_dims.size() <= 0) return -1;
|
||||
return tensor_dims[0];
|
||||
}
|
||||
|
||||
int32_t GetChannel() const
|
||||
{
|
||||
if (is_nchw) {
|
||||
if (tensor_dims.size() <= 1) return -1;
|
||||
return tensor_dims[1];
|
||||
} else {
|
||||
if (tensor_dims.size() <= 3) return -1;
|
||||
return tensor_dims[3];
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GetHeight() const
|
||||
{
|
||||
if (is_nchw) {
|
||||
if (tensor_dims.size() <= 2) return -1;
|
||||
return tensor_dims[2];
|
||||
} else {
|
||||
if (tensor_dims.size() <= 1) return -1;
|
||||
return tensor_dims[1];
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GetWidth() const
|
||||
{
|
||||
if (is_nchw) {
|
||||
if (tensor_dims.size() <= 3) return -1;
|
||||
return tensor_dims[3];
|
||||
} else {
|
||||
if (tensor_dims.size() <= 2) return -1;
|
||||
return tensor_dims[2];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
std::string name; // [In] Set the name_ of tensor
|
||||
int32_t id; // [Out] Do not modify (Used in InferenceHelper)
|
||||
int32_t tensor_type; // [In] The type of tensor (e.g. kTensorTypeFp32)
|
||||
std::vector<int32_t> tensor_dims; // InputTensorInfo: [In] The dimentions of tensor. (If empty at initialize, the size is updated from model info.)
|
||||
// OutputTensorInfo: [Out] The dimentions of tensor is set from model information
|
||||
bool is_nchw; // [IN] NCHW or NHWC
|
||||
};
|
||||
|
||||
class InputTensorInfo : public TensorInfo {
|
||||
public:
|
||||
enum {
|
||||
kDataTypeImage,
|
||||
kDataTypeBlobNhwc, // data_ which already finished preprocess(color conversion, resize, normalize_, etc.)
|
||||
kDataTypeBlobNchw,
|
||||
};
|
||||
|
||||
public:
|
||||
InputTensorInfo()
|
||||
: data(nullptr)
|
||||
, data_type(kDataTypeImage)
|
||||
, image_info({ -1, -1, -1, -1, -1, -1, -1, true, false })
|
||||
, normalize({ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f })
|
||||
{}
|
||||
|
||||
InputTensorInfo(std::string name_, int32_t tensor_type_, bool is_nchw_ = true)
|
||||
: InputTensorInfo()
|
||||
{
|
||||
name = name_;
|
||||
tensor_type = tensor_type_;
|
||||
is_nchw = is_nchw_;
|
||||
}
|
||||
|
||||
~InputTensorInfo() {}
|
||||
|
||||
public:
|
||||
void* data; // [In] Set the pointer to image/blob
|
||||
int32_t data_type; // [In] Set the type of data_ (e.g. kDataTypeImage)
|
||||
|
||||
struct {
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t channel;
|
||||
int32_t crop_x;
|
||||
int32_t crop_y;
|
||||
int32_t crop_width;
|
||||
int32_t crop_height;
|
||||
bool is_bgr; // used when channel == 3 (true: BGR, false: RGB)
|
||||
bool swap_color;
|
||||
} image_info; // [In] used when data_type_ == kDataTypeImage
|
||||
|
||||
struct {
|
||||
float mean[3];
|
||||
float norm[3];
|
||||
} normalize; // [In] used when data_type_ == kDataTypeImage
|
||||
};
|
||||
|
||||
|
||||
class OutputTensorInfo : public TensorInfo {
|
||||
public:
|
||||
OutputTensorInfo()
|
||||
: data(nullptr)
|
||||
, quant({ 1.0f, 0 })
|
||||
, data_fp32_(nullptr)
|
||||
{}
|
||||
|
||||
OutputTensorInfo(std::string name_, int32_t tensor_type_, bool is_nchw_ = true)
|
||||
: OutputTensorInfo()
|
||||
{
|
||||
name = name_;
|
||||
tensor_type = tensor_type_;
|
||||
is_nchw = is_nchw_;
|
||||
}
|
||||
|
||||
~OutputTensorInfo() {
|
||||
if (data_fp32_ != nullptr) {
|
||||
delete[] data_fp32_;
|
||||
}
|
||||
}
|
||||
|
||||
float* GetDataAsFloat() { /* Returned pointer should be with const, but returning pointer without const is convenient to create cv::Mat */
|
||||
if (tensor_type == kTensorTypeUint8 || tensor_type == kTensorTypeInt8) {
|
||||
if (data_fp32_ == nullptr) {
|
||||
data_fp32_ = new float[GetElementNum()];
|
||||
}
|
||||
if (tensor_type == kTensorTypeUint8) {
|
||||
#pragma omp parallel
|
||||
for (int32_t i = 0; i < GetElementNum(); i++) {
|
||||
const uint8_t* val_uint8 = static_cast<const uint8_t*>(data);
|
||||
float val_float = (val_uint8[i] - quant.zero_point) * quant.scale;
|
||||
data_fp32_[i] = val_float;
|
||||
}
|
||||
} else {
|
||||
#pragma omp parallel
|
||||
for (int32_t i = 0; i < GetElementNum(); i++) {
|
||||
const int8_t* val_int8 = static_cast<const int8_t*>(data);
|
||||
float val_float = (val_int8[i] - quant.zero_point) * quant.scale;
|
||||
data_fp32_[i] = val_float;
|
||||
}
|
||||
}
|
||||
return data_fp32_;
|
||||
} else if (tensor_type == kTensorTypeFp32) {
|
||||
return static_cast<float*>(data);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void* data; // [Out] Pointer to the output data_
|
||||
struct {
|
||||
float scale;
|
||||
int32_t zero_point;
|
||||
} quant; // [Out] Parameters for dequantization (convert uint8 to float)
|
||||
|
||||
private:
|
||||
float* data_fp32_;
|
||||
};
|
||||
|
||||
|
||||
namespace cv {
|
||||
class Mat;
|
||||
};
|
||||
|
||||
class InferenceHelper {
|
||||
public:
|
||||
enum {
|
||||
kRetOk = 0,
|
||||
kRetErr = -1,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
kOpencv,
|
||||
kOpencvGpu,
|
||||
kTensorflowLite,
|
||||
kTensorflowLiteXnnpack,
|
||||
kTensorflowLiteGpu,
|
||||
kTensorflowLiteEdgetpu,
|
||||
kTensorflowLiteNnapi,
|
||||
kTensorrt,
|
||||
kNcnn,
|
||||
kNcnnVulkan,
|
||||
kMnn,
|
||||
kSnpe,
|
||||
kArmnn,
|
||||
kNnabla,
|
||||
kNnablaCuda,
|
||||
kOnnxRuntime,
|
||||
kOnnxRuntimeCuda,
|
||||
kLibtorch,
|
||||
kLibtorchCuda,
|
||||
kTensorflow,
|
||||
kTensorflowGpu,
|
||||
kSample,
|
||||
kRknn,
|
||||
} HelperType;
|
||||
|
||||
public:
|
||||
static InferenceHelper* Create(const HelperType helper_type);
|
||||
static void PreProcessByOpenCV(const InputTensorInfo& input_tensor_info, bool is_nchw, cv::Mat& img_blob); // use this if the selected inference engine doesn't support pre-process
|
||||
|
||||
public:
|
||||
virtual ~InferenceHelper() {}
|
||||
virtual int32_t SetNumThreads(const int32_t num_threads) = 0;
|
||||
virtual int32_t SetCustomOps(const std::vector<std::pair<const char*, const void*>>& custom_ops) = 0;
|
||||
virtual int32_t Initialize(const std::string& model_filename, std::vector<InputTensorInfo>& input_tensor_info_list, std::vector<OutputTensorInfo>& output_tensor_info_list) = 0;
|
||||
virtual int32_t Initialize(char* model_buffer, int model_size, std::vector<InputTensorInfo>& input_tensor_info_list, std::vector<OutputTensorInfo>& output_tensor_info_list) = 0;
|
||||
virtual int32_t Finalize(void) = 0;
|
||||
virtual int32_t PreProcess(const std::vector<InputTensorInfo>& input_tensor_info_list) = 0;
|
||||
virtual int32_t Process(std::vector<OutputTensorInfo>& output_tensor_info_list) = 0;
|
||||
virtual int32_t ParameterInitialization(std::vector<InputTensorInfo>& input_tensor_info_list, std::vector<OutputTensorInfo>& output_tensor_info_list) = 0;
|
||||
|
||||
protected:
|
||||
void ConvertNormalizeParameters(InputTensorInfo& tensor_info);
|
||||
|
||||
void PreProcessImage(int32_t num_thread, const InputTensorInfo& input_tensor_info, float* dst);
|
||||
void PreProcessImage(int32_t num_thread, const InputTensorInfo& input_tensor_info, uint8_t* dst);
|
||||
void PreProcessImage(int32_t num_thread, const InputTensorInfo& input_tensor_info, int8_t* dst);
|
||||
|
||||
template<typename T>
|
||||
void PreProcessBlob(int32_t num_thread, const InputTensorInfo& input_tensor_info, T *dst);
|
||||
|
||||
protected:
|
||||
HelperType helper_type_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Copyright 2021 iwatake2222
|
||||
|
||||
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.
|
||||
==============================================================================*/
|
||||
#ifndef INFERENCE_HELPER_LOG_
|
||||
#define INFERENCE_HELPER_LOG_
|
||||
|
||||
/* for general */
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
|
||||
#if defined(ANDROID) || defined(__ANDROID__)
|
||||
#define CV_COLOR_IS_RGB
|
||||
#include <android/log.h>
|
||||
#define INFERENCE_HELPER_LOG_NDK_TAG "HyperLPR3-Native-Inference"
|
||||
#define INFERENCE_HELPER_LOG_PRINT_(...) __android_log_print(ANDROID_LOG_INFO, INFERENCE_HELPER_LOG_NDK_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define INFERENCE_HELPER_LOG_PRINT_(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define INFERENCE_HELPER_LOG_PRINT(INFERENCE_HELPER_LOG_PRINT_TAG, ...) do { \
|
||||
INFERENCE_HELPER_LOG_PRINT_("[" INFERENCE_HELPER_LOG_PRINT_TAG "][%d] ", __LINE__); \
|
||||
INFERENCE_HELPER_LOG_PRINT_(__VA_ARGS__); \
|
||||
} while(0);
|
||||
|
||||
#define INFERENCE_HELPER_LOG_PRINT_E(INFERENCE_HELPER_LOG_PRINT_TAG, ...) do { \
|
||||
INFERENCE_HELPER_LOG_PRINT_("[ERR: " INFERENCE_HELPER_LOG_PRINT_TAG "][%d] ", __LINE__); \
|
||||
INFERENCE_HELPER_LOG_PRINT_(__VA_ARGS__); \
|
||||
} while(0);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,317 @@
|
||||
/* Copyright 2021 iwatake2222
|
||||
|
||||
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 ***/
|
||||
/* for general */
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
||||
/* for MNN */
|
||||
#include <MNN/ImageProcess.hpp>
|
||||
#include <MNN/Interpreter.hpp>
|
||||
#include <MNN/AutoTime.hpp>
|
||||
|
||||
/* for My modules */
|
||||
#include "inference_helper_log.h"
|
||||
#include "inference_helper_mnn.h"
|
||||
|
||||
/*** Macro ***/
|
||||
#define TAG "InferenceHelperMnn"
|
||||
#define PRINT(...) INFERENCE_HELPER_LOG_PRINT(TAG, __VA_ARGS__)
|
||||
#define PRINT_E(...) INFERENCE_HELPER_LOG_PRINT_E(TAG, __VA_ARGS__)
|
||||
|
||||
/*** Function ***/
|
||||
InferenceHelperMnn::InferenceHelperMnn()
|
||||
{
|
||||
num_threads_ = 1;
|
||||
}
|
||||
|
||||
InferenceHelperMnn::~InferenceHelperMnn()
|
||||
{
|
||||
}
|
||||
|
||||
int32_t InferenceHelperMnn::SetNumThreads(const int32_t num_threads)
|
||||
{
|
||||
num_threads_ = num_threads;
|
||||
return kRetOk;
|
||||
}
|
||||
|
||||
int32_t InferenceHelperMnn::SetCustomOps(const std::vector<std::pair<const char*, const void*>>& custom_ops)
|
||||
{
|
||||
PRINT("[WARNING] This method is not supported\n");
|
||||
return kRetOk;
|
||||
}
|
||||
|
||||
int32_t InferenceHelperMnn::ParameterInitialization(std::vector<InputTensorInfo>& input_tensor_info_list, std::vector<OutputTensorInfo>& output_tensor_info_list) {
|
||||
/* Check tensor info fits the info from model */
|
||||
for (auto& input_tensor_info : input_tensor_info_list) {
|
||||
auto input_tensor = net_->getSessionInput(session_, input_tensor_info.name.c_str());
|
||||
if (input_tensor == nullptr) {
|
||||
PRINT_E("Invalid input name (%s)\n", input_tensor_info.name.c_str());
|
||||
return kRetErr;
|
||||
}
|
||||
if ((input_tensor->getType().code == halide_type_float) && (input_tensor_info.tensor_type == TensorInfo::kTensorTypeFp32)) {
|
||||
/* OK */
|
||||
} else if ((input_tensor->getType().code == halide_type_uint) && (input_tensor_info.tensor_type == TensorInfo::kTensorTypeUint8)) {
|
||||
/* OK */
|
||||
} else {
|
||||
PRINT_E("Incorrect input tensor type (%d, %d)\n", input_tensor->getType().code, input_tensor_info.tensor_type);
|
||||
return kRetErr;
|
||||
}
|
||||
if ((input_tensor->channel() != -1) && (input_tensor->height() != -1) && (input_tensor->width() != -1)) {
|
||||
if (input_tensor_info.GetChannel() != -1) {
|
||||
if ((input_tensor->channel() == input_tensor_info.GetChannel()) && (input_tensor->height() == input_tensor_info.GetHeight()) && (input_tensor->width() == input_tensor_info.GetWidth())) {
|
||||
/* OK */
|
||||
} else {
|
||||
PRINT_E("W: %d != %d\n", input_tensor->width() , input_tensor_info.GetWidth());
|
||||
PRINT_E("H: %d != %d\n", input_tensor->height() , input_tensor_info.GetHeight());
|
||||
PRINT_E("C: %d != %d\n", input_tensor->channel() , input_tensor_info.GetChannel());
|
||||
PRINT_E("Incorrect input tensor size\n");
|
||||
return kRetErr;
|
||||
}
|
||||
} else {
|
||||
PRINT("Input tensor size is set from the model\n");
|
||||
input_tensor_info.tensor_dims.clear();
|
||||
for (int32_t dim = 0; dim < input_tensor->dimensions(); dim++) {
|
||||
input_tensor_info.tensor_dims.push_back(input_tensor->length(dim));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (input_tensor_info.GetChannel() != -1) {
|
||||
PRINT("Input tensor size is resized\n");
|
||||
/* In case the input size is not fixed */
|
||||
net_->resizeTensor(input_tensor, { 1, input_tensor_info.GetChannel(), input_tensor_info.GetHeight(), input_tensor_info.GetWidth() });
|
||||
net_->resizeSession(session_);
|
||||
} else {
|
||||
PRINT_E("Model input size is not set\n");
|
||||
return kRetErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto& output_tensor_info : output_tensor_info_list) {
|
||||
auto output_tensor = net_->getSessionOutput(session_, output_tensor_info.name.c_str());
|
||||
if (output_tensor == nullptr) {
|
||||
PRINT_E("Invalid output name (%s)\n", output_tensor_info.name.c_str());
|
||||
return kRetErr;
|
||||
}
|
||||
/* Output size is set when run inference later */
|
||||
}
|
||||
|
||||
/* Convert normalize parameter to speed up */
|
||||
for (auto& input_tensor_info : input_tensor_info_list) {
|
||||
ConvertNormalizeParameters(input_tensor_info);
|
||||
}
|
||||
|
||||
|
||||
/* Check if tensor info is set */
|
||||
for (const auto& input_tensor_info : input_tensor_info_list) {
|
||||
for (const auto& dim : input_tensor_info.tensor_dims) {
|
||||
if (dim <= 0) {
|
||||
PRINT_E("Invalid tensor size\n");
|
||||
return kRetErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
//for (const auto& output_tensor_info : output_tensor_info_list) {
|
||||
// for (const auto& dim : output_tensor_info.tensor_dims) {
|
||||
// if (dim <= 0) {
|
||||
// PRINT_E("Invalid tensor size\n");
|
||||
// return kRetErr;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
return kRetOk;
|
||||
}
|
||||
|
||||
int32_t InferenceHelperMnn::Initialize(char* model_buffer, int model_size, std::vector<InputTensorInfo>& input_tensor_info_list, std::vector<OutputTensorInfo>& output_tensor_info_list) {
|
||||
/*** Create network ***/
|
||||
net_.reset(MNN::Interpreter::createFromBuffer(model_buffer, model_size));
|
||||
if (!net_) {
|
||||
PRINT_E("Failed to load model model buffer\n");
|
||||
return kRetErr;
|
||||
}
|
||||
|
||||
MNN::ScheduleConfig scheduleConfig;
|
||||
scheduleConfig.type = MNN_FORWARD_CPU;
|
||||
scheduleConfig.numThread = num_threads_; // it seems, setting 1 has better performance on Android
|
||||
// MNN::BackendConfig bnconfig;
|
||||
// bnconfig.power = MNN::BackendConfig::Power_High;
|
||||
// bnconfig.precision = MNN::BackendConfig::Precision_Low;
|
||||
// scheduleConfig.backendConfig = &bnconfig;
|
||||
session_ = net_->createSession(scheduleConfig);
|
||||
if (!session_) {
|
||||
PRINT_E("Failed to create session\n");
|
||||
return kRetErr;
|
||||
}
|
||||
|
||||
return ParameterInitialization(input_tensor_info_list, output_tensor_info_list);
|
||||
}
|
||||
|
||||
int32_t InferenceHelperMnn::Initialize(const std::string& model_filename, std::vector<InputTensorInfo>& input_tensor_info_list, std::vector<OutputTensorInfo>& output_tensor_info_list)
|
||||
{
|
||||
/*** Create network ***/
|
||||
net_.reset(MNN::Interpreter::createFromFile(model_filename.c_str()));
|
||||
if (!net_) {
|
||||
PRINT_E("Failed to load model file (%s)\n", model_filename.c_str());
|
||||
return kRetErr;
|
||||
}
|
||||
|
||||
MNN::ScheduleConfig scheduleConfig;
|
||||
scheduleConfig.type = MNN_FORWARD_AUTO;
|
||||
scheduleConfig.numThread = num_threads_; // it seems, setting 1 has better performance on Android
|
||||
// MNN::BackendConfig bnconfig;
|
||||
// bnconfig.power = MNN::BackendConfig::Power_High;
|
||||
// bnconfig.precision = MNN::BackendConfig::Precision_Low;
|
||||
// scheduleConfig.backendConfig = &bnconfig;
|
||||
session_ = net_->createSession(scheduleConfig);
|
||||
if (!session_) {
|
||||
PRINT_E("Failed to create session\n");
|
||||
return kRetErr;
|
||||
}
|
||||
|
||||
return ParameterInitialization(input_tensor_info_list, output_tensor_info_list);
|
||||
|
||||
};
|
||||
|
||||
|
||||
int32_t InferenceHelperMnn::Finalize(void)
|
||||
{
|
||||
net_->releaseSession(session_);
|
||||
net_->releaseModel();
|
||||
net_.reset();
|
||||
out_mat_list_.clear();
|
||||
return kRetOk;
|
||||
}
|
||||
|
||||
int32_t InferenceHelperMnn::PreProcess(const std::vector<InputTensorInfo>& input_tensor_info_list)
|
||||
{
|
||||
for (const auto& input_tensor_info : input_tensor_info_list) {
|
||||
auto input_tensor = net_->getSessionInput(session_, input_tensor_info.name.c_str());
|
||||
if (input_tensor == nullptr) {
|
||||
PRINT_E("Invalid input name (%s)\n", input_tensor_info.name.c_str());
|
||||
return kRetErr;
|
||||
}
|
||||
if (input_tensor_info.data_type == InputTensorInfo::kDataTypeImage) {
|
||||
/* Crop */
|
||||
if ((input_tensor_info.image_info.width != input_tensor_info.image_info.crop_width) || (input_tensor_info.image_info.height != input_tensor_info.image_info.crop_height)) {
|
||||
PRINT_E("Crop is not supported\n");
|
||||
return kRetErr;
|
||||
}
|
||||
|
||||
MNN::CV::ImageProcess::Config image_processconfig;
|
||||
/* Convert color type */
|
||||
if ((input_tensor_info.image_info.channel == 3) && (input_tensor_info.GetChannel() == 3)) {
|
||||
image_processconfig.sourceFormat = (input_tensor_info.image_info.is_bgr) ? MNN::CV::BGR : MNN::CV::RGB;
|
||||
if (input_tensor_info.image_info.swap_color) {
|
||||
image_processconfig.destFormat = (input_tensor_info.image_info.is_bgr) ? MNN::CV::RGB : MNN::CV::BGR;
|
||||
} else {
|
||||
image_processconfig.destFormat = (input_tensor_info.image_info.is_bgr) ? MNN::CV::BGR : MNN::CV::RGB;
|
||||
}
|
||||
} else if ((input_tensor_info.image_info.channel == 1) && (input_tensor_info.GetChannel() == 1)) {
|
||||
image_processconfig.sourceFormat = MNN::CV::GRAY;
|
||||
image_processconfig.destFormat = MNN::CV::GRAY;
|
||||
} else if ((input_tensor_info.image_info.channel == 3) && (input_tensor_info.GetChannel() == 1)) {
|
||||
image_processconfig.sourceFormat = (input_tensor_info.image_info.is_bgr) ? MNN::CV::BGR : MNN::CV::RGB;
|
||||
image_processconfig.destFormat = MNN::CV::GRAY;
|
||||
} else if ((input_tensor_info.image_info.channel == 1) && (input_tensor_info.GetChannel() == 3)) {
|
||||
image_processconfig.sourceFormat = MNN::CV::GRAY;
|
||||
image_processconfig.destFormat = MNN::CV::BGR;
|
||||
} else {
|
||||
PRINT_E("Unsupported color conversion (%d, %d)\n", input_tensor_info.image_info.channel, input_tensor_info.GetChannel());
|
||||
return kRetErr;
|
||||
}
|
||||
|
||||
/* Normalize image */
|
||||
std::memcpy(image_processconfig.mean, input_tensor_info.normalize.mean, sizeof(image_processconfig.mean));
|
||||
std::memcpy(image_processconfig.normal, input_tensor_info.normalize.norm, sizeof(image_processconfig.normal));
|
||||
|
||||
/* Resize image */
|
||||
image_processconfig.filterType = MNN::CV::BILINEAR;
|
||||
MNN::CV::Matrix trans;
|
||||
trans.setScale(static_cast<float>(input_tensor_info.image_info.crop_width) / input_tensor_info.GetWidth(), static_cast<float>(input_tensor_info.image_info.crop_height) / input_tensor_info.GetHeight());
|
||||
|
||||
/* Do pre-process */
|
||||
std::shared_ptr<MNN::CV::ImageProcess> pretreat(MNN::CV::ImageProcess::create(image_processconfig));
|
||||
pretreat->setMatrix(trans);
|
||||
pretreat->convert(static_cast<uint8_t*>(input_tensor_info.data), input_tensor_info.image_info.crop_width, input_tensor_info.image_info.crop_height, 0, input_tensor);
|
||||
} else if ( (input_tensor_info.data_type == InputTensorInfo::kDataTypeBlobNhwc) || (input_tensor_info.data_type == InputTensorInfo::kDataTypeBlobNchw) ) {
|
||||
std::unique_ptr<MNN::Tensor> tensor;
|
||||
if (input_tensor_info.data_type == InputTensorInfo::kDataTypeBlobNhwc) {
|
||||
tensor.reset(new MNN::Tensor(input_tensor, MNN::Tensor::TENSORFLOW));
|
||||
} else {
|
||||
tensor.reset(new MNN::Tensor(input_tensor, MNN::Tensor::CAFFE));
|
||||
}
|
||||
if (tensor->getType().code == halide_type_float) {
|
||||
for (int32_t i = 0; i < input_tensor_info.GetWidth() * input_tensor_info.GetHeight() * input_tensor_info.GetChannel(); i++) {
|
||||
tensor->host<float>()[i] = static_cast<float*>(input_tensor_info.data)[i];
|
||||
}
|
||||
} else {
|
||||
for (int32_t i = 0; i < input_tensor_info.GetWidth() * input_tensor_info.GetHeight() * input_tensor_info.GetChannel(); i++) {
|
||||
tensor->host<uint8_t>()[i] = static_cast<uint8_t*>(input_tensor_info.data)[i];
|
||||
}
|
||||
}
|
||||
input_tensor->copyFromHostTensor(tensor.get());
|
||||
} else {
|
||||
PRINT_E("Unsupported data type (%d)\n", input_tensor_info.data_type);
|
||||
return kRetErr;
|
||||
}
|
||||
}
|
||||
return kRetOk;
|
||||
}
|
||||
|
||||
int32_t InferenceHelperMnn::Process(std::vector<OutputTensorInfo>& output_tensor_info_list)
|
||||
{
|
||||
net_->runSession(session_);
|
||||
|
||||
out_mat_list_.clear();
|
||||
for (auto& output_tensor_info : output_tensor_info_list) {
|
||||
auto output_tensor = net_->getSessionOutput(session_, output_tensor_info.name.c_str());
|
||||
if (output_tensor == nullptr) {
|
||||
PRINT_E("Invalid output name (%s)\n", output_tensor_info.name.c_str());
|
||||
return kRetErr;
|
||||
}
|
||||
|
||||
auto dimType = output_tensor->getDimensionType();
|
||||
std::unique_ptr<MNN::Tensor> outputUser(new MNN::Tensor(output_tensor, dimType));
|
||||
output_tensor->copyToHostTensor(outputUser.get());
|
||||
auto type = outputUser->getType();
|
||||
if (type.code == halide_type_float) {
|
||||
output_tensor_info.tensor_type = TensorInfo::kTensorTypeFp32;
|
||||
output_tensor_info.data = outputUser->host<float>();
|
||||
} else if (type.code == halide_type_uint && type.bytes() == 1) {
|
||||
output_tensor_info.tensor_type = TensorInfo::kTensorTypeUint8;
|
||||
output_tensor_info.data = outputUser->host<uint8_t>();
|
||||
} else {
|
||||
PRINT_E("Unexpected data type\n");
|
||||
return kRetErr;
|
||||
}
|
||||
|
||||
output_tensor_info.tensor_dims.clear();
|
||||
for (int32_t dim = 0; dim < outputUser->dimensions(); dim++) {
|
||||
output_tensor_info.tensor_dims.push_back(outputUser->length(dim));
|
||||
}
|
||||
|
||||
out_mat_list_.push_back(std::move(outputUser)); // store data in member variable so that data keep exist
|
||||
}
|
||||
|
||||
return kRetOk;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Copyright 2021 iwatake2222
|
||||
|
||||
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.
|
||||
==============================================================================*/
|
||||
#ifndef INFERENCE_HELPER_MNN_
|
||||
#define INFERENCE_HELPER_MNN_
|
||||
|
||||
/* for general */
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
/* for MNN */
|
||||
#include <MNN/ImageProcess.hpp>
|
||||
#include <MNN/Interpreter.hpp>
|
||||
#include <MNN/AutoTime.hpp>
|
||||
|
||||
/* for My modules */
|
||||
#include "inference_helper.h"
|
||||
|
||||
class InferenceHelperMnn : public InferenceHelper {
|
||||
public:
|
||||
InferenceHelperMnn();
|
||||
~InferenceHelperMnn() override;
|
||||
int32_t SetNumThreads(const int32_t num_threads) override;
|
||||
int32_t SetCustomOps(const std::vector<std::pair<const char*, const void*>>& custom_ops) override;
|
||||
int32_t Initialize(const std::string& model_filename, std::vector<InputTensorInfo>& input_tensor_info_list, std::vector<OutputTensorInfo>& output_tensor_info_list) override;
|
||||
int32_t Initialize(char* model_buffer, int model_size, std::vector<InputTensorInfo>& input_tensor_info_list, std::vector<OutputTensorInfo>& output_tensor_info_list) override;
|
||||
int32_t Finalize(void) override;
|
||||
int32_t PreProcess(const std::vector<InputTensorInfo>& input_tensor_info_list) override;
|
||||
int32_t Process(std::vector<OutputTensorInfo>& output_tensor_info_list) override;
|
||||
int32_t ParameterInitialization(std::vector<InputTensorInfo>& input_tensor_info_list, std::vector<OutputTensorInfo>& output_tensor_info_list) override;
|
||||
private:
|
||||
std::unique_ptr<MNN::Interpreter> net_;
|
||||
MNN::Session* session_;
|
||||
std::vector<std::unique_ptr<MNN::Tensor>> out_mat_list_;
|
||||
int32_t num_threads_;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user