CMakeList.txt内容
cmake_minimum_required(VERSION 3.10)
project(tnn_test_aarch)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# opencv
#set(opencv_dir "./3rdparty/opencv/opencv-linux-aarch64")
set(opencv_dir "./3rdparty/opencv/opencv-linux-x64")
include_directories(${opencv_dir}/include)
link_directories(${opencv_dir}/lib)
set(OpenCV_LIBS opencv_core opencv_features2d opencv_imgcodecs opencv_imgproc)
#find_package(OpenCV REQUIRED)
#tnn
#set(tnn_dir "./3rdparty/tnn/tnn_linux_aarch64")
set(tnn_dir "./3rdparty/tnn/tnn_linux")
include_directories(${tnn_dir}/include)
link_directories(${tnn_dir}/lib)
set(TNN_LIBS TNN)
add_executable(tnn_test_aarch main.cpp tnn_test.cpp mnn_test.cpp)
target_link_libraries(tnn_test_aarch ${OpenCV_LIBS} ${TNN_LIBS})
//////////////////////////////////////////////////////////////////////
//
// Created by DangXS on 2022/12/8.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cfloat>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <string>
#include <iostream>
#include "tnn/core/common.h"
#include "tnn/core/instance.h"
#include "tnn/core/macro.h"
#include "tnn/core/tnn.h"
#include "tnn/utils/blob_converter.h"
#include "tnn/utils/cpu_utils.h"
#include "tnn/utils/data_type_utils.h"
#include "tnn/utils/dims_vector_utils.h"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
#define LITETNN_DEBUG
#define DEVICE_X86 0x0010
#define DEVICE_ARM 0x0020
#define DEVICE_OPENCL 0x1000
//#define DEVICE DEVICE_X86
#define DEVICE DEVICE_ARM
//#define DEVICE DEVICE_OPENCL
// static methods.
// reference: https://github.com/Tencent/TNN/blob/master/examples/base/utils/utils.cc
std::string content_buffer_from(const char *proto_or_model_path) {
std::ifstream file(proto_or_model_path, std::ios::binary);
if (file.is_open()) {
file.seekg(0, std::ifstream::end);
int size = file.tellg();
char *content = new char[size];
file.seekg(0, std::ifstream::beg);
file.read(content, size);
std::string file_content;
file_content.assign(content, size);
delete[] content;
file.close();
return file_content;
} // empty buffer
else {
#ifdef LITETNN_DEBUG
std::cout << "Can not open " << proto_or_model_path << "\n";
#endif
return "";
}
}
// static methods.
tnn::DimsVector get_input_shape(
const std::shared_ptr<tnn::Instance> &_instance,
std::string name) {
tnn::DimsVector shape = {};
tnn::BlobMap blob_map = {};
if (_instance) {
_instance->GetAllInputBlobs(blob_map);
}
if (name == "" && blob_map.size() > 0)
if (blob_map.begin()->second)
shape = blob_map.begin()->second->GetBlobDesc().dims;
if (blob_map.find(name) != blob_map.end()
&& blob_map[name]) {
shape = blob_map[name]->GetBlobDesc().dims;
}
return shape;
}
// static methods.
tnn::DimsVector get_output_shape(
const std::shared_ptr<tnn::Instance> &_instance,
std::string name) {
tnn::DimsVector shape = {};
tnn::BlobMap blob_map = {};
if (_instance) {
_instance->GetAllOutputBlobs(blob_map);
}
if (name == "" && blob_map.size() > 0)
if (blob_map.begin()->second)
shape = blob_map.begin()->second->GetBlobDesc().dims;
if (blob_map.find(name) != blob_map.end()
&& blob_map[name]) {
shape = blob_map[name]->GetBlobDesc().dims;
}
return shape;
}
// static methods.
std::vector<std::string> get_input_names(
const std::shared_ptr<tnn::Instance> &_instance) {
std::vector<std::string> names;
if (_instance) {
tnn::BlobMap blob_map;
_instance->GetAllInputBlobs(blob_map);
for (const auto &item : blob_map) {
names.push_back(item.first);
}
}
return names;
}
// static method
std::vector<std::string> get_output_names(
const std::shared_ptr<tnn::Instance> &_instance) {
std::vector<std::string> names;
if (_instance) {
tnn::BlobMap blob_map;
_instance->GetAllOutputBlobs(blob_map);
for (const auto &item : blob_map) {
names.push_back(item.first);
}
}
return names;
}
// static method
tnn::MatType get_output_mat_type(
const std::shared_ptr<tnn::Instance> &_instance,
std::string name) {
if (_instance) {
tnn::BlobMap output_blobs;
_instance->GetAllOutputBlobs(output_blobs);
auto blob = (name == "") ? output_blobs.begin()->second : output_blobs[name];
if (blob->GetBlobDesc().data_type == tnn::DATA_TYPE_INT32) {
return tnn::NC_INT32;
}
}
return tnn::NCHW_FLOAT;
}
// static method
tnn::DataFormat get_output_data_format(
const std::shared_ptr<tnn::Instance> &_instance,
std::string name) {
if (_instance) {
tnn::BlobMap output_blobs;
_instance->GetAllOutputBlobs(output_blobs);
auto blob = (name == "") ? output_blobs.begin()->second : output_blobs[name];
return blob->GetBlobDesc().data_format;
}
return tnn::DATA_FORMAT_NCHW;
}
// static method
tnn::MatType get_input_mat_type(
const std::shared_ptr<tnn::Instance> &_instance,
std::string name) {
if (_instance) {
tnn::BlobMap input_blobs;
_instance->GetAllInputBlobs(input_blobs);
auto blob = (name == "") ? input_blobs.begin()->second : input_blobs[name];
if (blob->GetBlobDesc().data_type == tnn::DATA_TYPE_INT32) {
return tnn::NC_INT32;
}
}
return tnn::NCHW_FLOAT;
}
// static method
tnn::DataFormat get_input_data_format(
const std::shared_ptr<tnn::Instance> &_instance,
std::string name) {
if (_instance) {
tnn::BlobMap input_blobs;
_instance->GetAllInputBlobs(input_blobs);
auto blob = (name == "") ? input_blobs.begin()->second : input_blobs[name];
return blob->GetBlobDesc().data_format;
}
return tnn::DATA_FORMAT_NCHW;
}
int main(int argc, char *argv[]) {
const char *proto_path = "./1.tnnproto";
const char *model_path = "./1.tnnmodel";
// const char *proto_path = "./1.param";
// const char *model_path = "./1.bin";
// Note, tnn:: actually is TNN_NS::, I prefer the first one.
std::shared_ptr<tnn::TNN> net;
std::shared_ptr<tnn::Instance> instance;
std::shared_ptr<tnn::Mat> input_mat; // assume single input.
std::string proto_content_buffer, model_content_buffer;
proto_content_buffer = content_buffer_from(proto_path);
model_content_buffer = content_buffer_from(model_path);
tnn::ModelConfig model_config;
model_config.model_type = tnn::MODEL_TYPE_TNN;
// model_config.model_type = tnn::MODEL_TYPE_NCNN;
model_config.params = {proto_content_buffer, model_content_buffer};
// 1. init TNN net
tnn::Status status;
net = std::make_shared<tnn::TNN>();
status = net->Init(model_config);
model_config.params.clear();
if (status != tnn::TNN_OK || !net) {
#ifdef LITETNN_DEBUG
std::cout << "CreateInst failed!\t" << status.description().c_str() << "\n";
#endif
std::cout << "net->Init failed!\n";
return -100;
}
// 2. init device type, change this default setting
// for better performance. such as CUDA/OPENCL/...
auto _device = (tnn::DeviceType) DEVICE;
tnn::DeviceType network_device_type = _device; // CPU,GPU
tnn::DeviceType input_device_type = _device; // CPU only
tnn::DeviceType output_device_type = _device;
const unsigned int num_threads = 2;
int input_batch;
int input_channel;
int input_height;
int input_width;
unsigned int input_value_size;
tnn::DataFormat input_data_format; // e.g DATA_FORMAT_NHWC
tnn::MatType input_mat_type; // e.g NCHW_FLOAT
// Actually, i prefer to hardcode the input/output names
// into subclasses, but we just let the auto detection here
// to make sure the debug information can show more details.
std::string input_name; // assume single input only.
std::vector<std::string> output_names; // assume >= 1 outputs.
tnn::DimsVector input_shape; // vector<int>
std::map<std::string, tnn::DimsVector> output_shapes;
// 3. init instance
tnn::NetworkConfig network_config;
network_config.library_path = {""};
network_config.device_type = network_device_type;
instance = net->CreateInst(network_config, status);
if (status != tnn::TNN_OK || !instance) {
#ifdef LITETNN_DEBUG
std::cout << "CreateInst failed!" << status.description().c_str() << "\n";
#endif
return -200;
}
// 4. setting up num_threads
instance->SetCpuNumThreads((int) num_threads);
// 5. init input information.
input_name = get_input_names(instance).front();
printf("input_name: %s\n", input_name.c_str());
input_shape = get_input_shape(instance, input_name);
printf("input_shape: \n\t");
for (int i = 0; i < input_shape.size(); ++i) {
printf(" %d", input_shape[i]);
}
printf("\n");
if (input_shape.size() != 4) {
#ifdef LITETNN_DEBUG
throw std::runtime_error("Found input_shape.size()!=4, but "
"BasicTNNHandler only support 4 dims."
"Such as NCHW, NHWC ...");
#else
return -400;
#endif
}
input_mat_type = get_input_mat_type(instance, input_name);
input_data_format = get_input_data_format(instance, input_name);
printf("input_data_format: %d\n", input_data_format);
input_batch = input_shape.at(0);
input_channel = input_shape.at(1);
input_height = input_shape.at(2);
input_width = input_shape.at(3);
// 6. init input_mat
input_value_size = input_batch * input_channel * input_height * input_width;
// 7. init output information, debug only.
output_names = get_output_names(instance);
int num_outputs = output_names.size();
printf("output_names: \n\t");
for (auto &name: output_names) {
output_shapes[name] = get_output_shape(instance, name);
printf("%s, ", name.c_str());
}
printf("\n");
// forward
string img_path = "./1.jpg";
cv::Mat mat = cv::imread(img_path);
assert(!mat.empty());
// In TNN: x*scale + bias
std::vector<float> scale_vals = {
(1.0f / 0.229f) * (1.0 / 255.f),
(1.0f / 0.224f) * (1.0 / 255.f),
(1.0f / 0.225f) * (1.0 / 255.f)
};
std::vector<float> bias_vals = {
-0.485f * 255.f * (1.0f / 0.229f) * (1.0 / 255.f),
-0.456f * 255.f * (1.0f / 0.224f) * (1.0 / 255.f),
-0.406f * 255.f * (1.0f / 0.225f) * (1.0 / 255.f)
};
// 1. make input mat
cv::Mat mat_rs;
cv::resize(mat, mat_rs, cv::Size(input_width, input_height));
cv::cvtColor(mat_rs, mat_rs, cv::COLOR_BGR2RGB);
// // Format Types: (0: NCHW FLOAT), (1: 8UC3), (2: 8UC1)
// tnn::DataType data_type = tnn::DataType::DATA_TYPE_INT8;
// int bytes = tnn::DimsVectorUtils::Count(input_shape) * tnn::DataTypeUtils::GetBytesSize(data_type);
// void *mat_data = malloc(bytes);
// input_mat = std::make_shared<tnn::Mat>(input_device_type, tnn::N8UC3, input_shape, mat_data);
// push into input_mat (1,3,224,224)
input_mat = std::make_shared<tnn::Mat>(input_device_type, tnn::N8UC3, input_shape, (void *) mat_rs.data);
assert(input_mat->GetData()!= nullptr);
// 2. set input_mat
tnn::MatConvertParam input_cvt_param;
input_cvt_param.scale = scale_vals;
input_cvt_param.bias = bias_vals;
status = instance->SetInputMat(input_mat, input_cvt_param);
if (status != tnn::TNN_OK) {
#ifdef LITETNN_DEBUG
std::cout << status.description().c_str() << "\n";
#endif
return -500;
}
// 3. forward
double c1 = cv::getTickCount();
status = instance->Forward();
double c2 = cv::getTickCount();
auto spend_time = (c2 - c1) / cv::getTickFrequency();
printf("forward elapsed: %f ms\n", spend_time);
if (status != tnn::TNN_OK) {
#ifdef LITETNN_DEBUG
std::cout << status.description().c_str() << "\n";
#endif
return -600;
}
// 4. fetch.
tnn::MatConvertParam cvt_param;
std::vector<std::shared_ptr<tnn::Mat>> feat_mats;
for (int i = 0; i < output_names.size(); ++i) {
std::shared_ptr<tnn::Mat> feat_mat;
status = instance->GetOutputMat(feat_mat, cvt_param, output_names[i], output_device_type);
feat_mats.push_back(feat_mat);
}
printf("net output: \n");
for (int i = 0; i < output_names.size(); ++i) {
printf("name: %s\t\tfeat shape: %d %d %d %d\n", output_names[i].c_str(),
feat_mats[i]->GetBatch(), feat_mats[i]->GetChannel(), feat_mats[i]->GetHeight(),
feat_mats[i]->GetWidth());
float *data = reinterpret_cast<float *>(feat_mats[i]->GetData());
for (int j = 0; j < 10; ++j) {
std::cout << data[j] << ", ";
}
std::cout << std::endl;
}
printf("\n");
if (status != tnn::TNN_OK) {
#ifdef LITETNN_DEBUG
std::cout << status.description().c_str() << "\n";
#endif
return -700;
}
// release
// free(mat_data);
status = net->DeInit();
if (status != tnn::TNN_OK || !net) {
#ifdef LITETNN_DEBUG
std::cout << "DeInit failed!" << status.description().c_str() << "\n";
#endif
std::cout << "net->DeInit failed!\n";
return -1000;
}
return 0;
}