add quick start demo

This commit is contained in:
yeyunpeng 2021-02-22 10:36:14 +08:00
parent 1252250d7e
commit 4ed332f28f
7 changed files with 1094 additions and 0 deletions

View File

@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.14)
project(QuickStartCpp)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3.0)
message(FATAL_ERROR "GCC version ${CMAKE_CXX_COMPILER_VERSION} must not be less than 7.3.0")
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
file(GLOB_RECURSE QUICK_START_CXX ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
add_library(mindspore-lite STATIC IMPORTED)
set_target_properties(mindspore-lite PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_SOURCE_DIR}/lib/libmindspore-lite.a)
add_executable(mindspore_quick_start_cpp ${QUICK_START_CXX})
target_link_libraries(
mindspore_quick_start_cpp
-Wl,--whole-archive mindspore-lite -Wl,--no-whole-archive
pthread
)

View File

@ -0,0 +1,43 @@
#!/bin/bash
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================
BASEPATH=$(cd "$(dirname $0)"; pwd)
get_version() {
VERSION_MAJOR=$(grep "const int ms_version_major =" ${BASEPATH}/../../include/version.h | tr -dc "[0-9]")
VERSION_MINOR=$(grep "const int ms_version_minor =" ${BASEPATH}/../../include/version.h | tr -dc "[0-9]")
VERSION_REVISION=$(grep "const int ms_version_revision =" ${BASEPATH}/../../include/version.h | tr -dc "[0-9]")
VERSION_STR=${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}
}
get_version
MODEL_DOWNLOAD_URL="https://download.mindspore.cn/model_zoo/official/lite/mobilenetv2_openimage_lite/1.1/mobilenetv2.ms"
MINDSPORE_LITE_DOWNLOAD_URL="https://ms-release.obs.cn-north-4.myhuaweicloud.com/${VERSION_STR}/MindSpore/lite/release/linux/mindspore-lite-${VERSION_STR}-inference-linux-x64.tar.gz"
mkdir -p build
mkdir -p lib
mkdir -p model
if [ ! -e ${BASEPATH}/model/mobilenetv2.ms ]; then
wget -c -O ${BASEPATH}/model/mobilenetv2.ms --no-check-certificate ${MODEL_DOWNLOAD_URL}
fi
if [ ! -e ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-linux-x64.tar.gz ]; then
wget -c -O ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-linux-x64.tar.gz --no-check-certificate ${MINDSPORE_LITE_DOWNLOAD_URL}
fi
tar xzvf ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-linux-x64.tar.gz -C ${BASEPATH}/build/
cp -r ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-linux-x64-avx/lib/libmindspore-lite.a ${BASEPATH}/lib
cp -r ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-linux-x64-avx/include ${BASEPATH}/
cd ${BASEPATH}/build
cmake ${BASEPATH}
make

View File

@ -0,0 +1,179 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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 <algorithm>
#include <random>
#include <iostream>
#include <fstream>
#include <cstring>
#include "include/errorcode.h"
#include "include/model.h"
#include "include/context.h"
#include "include/lite_session.h"
char *ReadFile(const char *file, size_t *size) {
if (file == nullptr) {
std::cerr << "file is nullptr." << std::endl;
return nullptr;
}
std::ifstream ifs(file);
if (!ifs.good()) {
std::cerr << "file: " << file << " is not exist." << std::endl;
return nullptr;
}
if (!ifs.is_open()) {
std::cerr << "file: " << file << " open failed." << std::endl;
return nullptr;
}
ifs.seekg(0, std::ios::end);
*size = ifs.tellg();
std::unique_ptr<char[]> buf(new (std::nothrow) char[*size]);
if (buf == nullptr) {
std::cerr << "malloc buf failed, file: " << file << std::endl;
ifs.close();
return nullptr;
}
ifs.seekg(0, std::ios::beg);
ifs.read(buf.get(), *size);
ifs.close();
return buf.release();
}
template <typename T, typename Distribution>
void GenerateRandomData(int size, void *data, Distribution distribution) {
std::mt19937 random_engine;
int elements_num = size / sizeof(T);
(void)std::generate_n(static_cast<T *>(data), elements_num,
[&]() { return static_cast<T>(distribution(random_engine)); });
}
int GenerateInputDataWithRandom(std::vector<mindspore::tensor::MSTensor *> inputs) {
for (auto tensor : inputs) {
auto input_data = tensor->MutableData();
void *random_data = malloc(tensor->Size());
if (input_data == nullptr) {
std::cerr << "MallocData for inTensor failed." << std::endl;
return -1;
}
GenerateRandomData<float>(tensor->Size(), random_data, std::uniform_real_distribution<float>(0.1f, 1.0f));
// Copy data to input tensor.
memcpy(input_data, random_data, tensor->Size());
}
return mindspore::lite::RET_OK;
}
int Run(mindspore::session::LiteSession *session) {
auto inputs = session->GetInputs();
auto ret = GenerateInputDataWithRandom(inputs);
if (ret != mindspore::lite::RET_OK) {
std::cerr << "Generate Random Input Data failed." << std::endl;
return ret;
}
ret = session->RunGraph();
if (ret != mindspore::lite::RET_OK) {
std::cerr << "Inference error " << ret << std::endl;
return ret;
}
auto out_tensors = session->GetOutputs();
for (auto tensor : out_tensors) {
std::cout << "tensor name is:" << tensor.first << " tensor size is:" << tensor.second->Size()
<< " tensor elements num is:" << tensor.second->ElementsNum() << std::endl;
auto out_data = reinterpret_cast<float *>(tensor.second->MutableData());
std::cout << "output data is:";
for (int i = 0; i < tensor.second->ElementsNum() && i <= 50; i++) {
std::cout << out_data[i] << " ";
}
std::cout << std::endl;
}
return mindspore::lite::RET_OK;
}
mindspore::session::LiteSession *Compile(mindspore::lite::Model *model) {
// Create and init context.
auto context = std::make_shared<mindspore::lite::Context>();
if (context == nullptr) {
std::cerr << "New context failed while." << std::endl;
return nullptr;
}
// Create the session.
mindspore::session::LiteSession *session = mindspore::session::LiteSession::CreateSession(context.get());
if (session == nullptr) {
std::cerr << "CreateSession failed while running." << std::endl;
return nullptr;
}
// Compile graph.
auto ret = session->CompileGraph(model);
if (ret != mindspore::lite::RET_OK) {
std::cerr << "Compile failed while running." << std::endl;
return nullptr;
}
// Note: when use model->Free(), the model can not be compiled again.
if (model != nullptr) {
model->Free();
}
return session;
}
int CompileAndRun(int argc, const char **argv) {
if (argc < 2) {
std::cerr << "Usage: ./mindspore_quick_start_cpp ../model/mobilenetv2.ms\n";
return -1;
}
// Read model file.
auto model_path = argv[1];
size_t size = 0;
char *model_buf = ReadFile(model_path, &size);
if (model_buf == nullptr) {
std::cerr << "Read model file failed." << std::endl;
return -1;
}
// Load the .ms model.
auto model = mindspore::lite::Model::Import(model_buf, size);
delete[](model_buf);
if (model == nullptr) {
std::cerr << "Import model file failed." << std::endl;
return -1;
}
// Compile MindSpore Lite model.
auto session = Compile(model);
if (session == nullptr) {
std::cerr << "Create session failed." << std::endl;
return -1;
}
// Run inference.
auto ret = Run(session);
if (ret != mindspore::lite::RET_OK) {
std::cerr << "MindSpore Lite run failed." << std::endl;
return -1;
}
// Delete model buffer.
delete model;
// Delete session buffer.
delete session;
return mindspore::lite::RET_OK;
}
int main(int argc, const char **argv) { return CompileAndRun(argc, argv); }

View File

@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 3.14)
project(RuntimeCpp)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3.0)
message(FATAL_ERROR "GCC version ${CMAKE_CXX_COMPILER_VERSION} must not be less than 7.3.0")
endif()
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
file(GLOB_RECURSE RUNTIME_CPP ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
add_executable(runtime_cpp ${RUNTIME_CPP})
find_library(log-lib log)
target_link_libraries(
runtime_cpp
-Wl,--whole-archive mindspore-lite -Wl,--no-whole-archive
hiai
hiai_ir
hiai_ir_build
${log-lib}
)
SET(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/build/tmp)
INSTALL(TARGETS runtime_cpp
DESTINATION exe)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib/libhiai.so
DESTINATION lib)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib/libhiai_ir.so
DESTINATION lib)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib/libhiai_ir_build.so
DESTINATION lib)
INSTALL(FILES
${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so
DESTINATION lib)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/model/mobilenetv2.ms
DESTINATION model)
set(CPACK_GENERATOR "TGZ")
set(CPACK_PACKAGE_FILE_NAME "runtime_cpp_demo")
set(CPACK_PACKAGE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/output)
include(CPack)

View File

@ -0,0 +1,55 @@
## 构建与运行
- 环境要求
- 系统环境Linux x86_64推荐使用Ubuntu 18.04.02LTS
- 编译依赖:
- [CMake](https://cmake.org/download/) >= 3.18.3
- [GCC](https://gcc.gnu.org/releases.html) >= 7.3.0
- [Android_NDK](https://dl.google.com/android/repository/android-ndk-r20b-linux-x86_64.zip) >= r20
- [Git](https://git-scm.com/downloads) >= 2.28.0
- 编译构建
在`mindspore/lite/examples/runtime_cpp`目录下执行build脚本将能够自动下载相关文件并编译Demo。
```bash
bash build.sh
```
> 若MindSpore Lite推理框架下载失败请手动下载硬件平台为CPU操作系统为Ubuntu-x64的[MindSpore Lite 模型推理框架](https://www.mindspore.cn/tutorial/lite/zh-CN/r1.1/use/downloads.html),解压后将其拷贝对应到`mindspore/lite/examples/runtime_cpp/lib`目录。
>
> 若mobilenetv2模型下载失败请手动下载相关模型文件[mobilenetv2](https://download.mindspore.cn/model_zoo/official/lite/mobilenetv2_openimage_lite/mobilenetv2.ms),并将其拷贝到`mindspore/lite/examples/runtime_cpp/model`目录。
- 文件传输
使用`adb`将`mindspore/lite/examples/runtime_cpp\output`目录下的`runtime_cpp_demo.tar.gz`压缩包发送到Android手机
```shell
adb push runtime_cpp_demo.tar.gz /data/local/tmp
```
- 执行推理
使用`adb`进入Android Shell命令模式
```shell
adb shell
```
进入压缩包所在的相关目录,并进行解压
```shell
cd /data/local/tmp && tar xzvf runtime_cpp_demo.tar.gz
```
配置`LD_LIBRARY_PATH`环境变量
```shell
export LD_LIBRARY_PATH = /data/local/tmp/runtime_cpp_demo/lib:{LD_LIBRARY_PATH}
```
编译构建后,进入`mindspore/lite/examples/runtime_cpp/build`目录并执行以下命令体验MindSpore Lite推理mobilenetv2模型。
```bash
./runtime_cpp ../model/mobilenetv2.ms 0
```

View File

@ -0,0 +1,49 @@
#!/bin/bash
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================
BASEPATH=$(
cd "$(dirname $0)"
pwd
)
get_version() {
VERSION_MAJOR=$(grep "const int ms_version_major =" ${BASEPATH}/../../include/version.h | tr -dc "[0-9]")
VERSION_MINOR=$(grep "const int ms_version_minor =" ${BASEPATH}/../../include/version.h | tr -dc "[0-9]")
VERSION_REVISION=$(grep "const int ms_version_revision =" ${BASEPATH}/../../include/version.h | tr -dc "[0-9]")
VERSION_STR=${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}
}
get_version
MODEL_DOWNLOAD_URL="https://download.mindspore.cn/model_zoo/official/lite/mobilenetv2_openimage_lite/1.1/mobilenetv2.ms"
MINDSPORE_LITE_DOWNLOAD_URL="https://ms-release.obs.cn-north-4.myhuaweicloud.com/${VERSION_STR}/MindSpore/lite/release/android/mindspore-lite-${VERSION_STR}-inference-android.tar.gz"
mkdir -p build
mkdir -p lib
mkdir -p model
if [ ! -e ${BASEPATH}/model/mobilenetv2.ms ]; then
wget -c -O ${BASEPATH}/model/mobilenetv2.ms --no-check-certificate ${MODEL_DOWNLOAD_URL}
fi
if [ ! -e ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-android.tar.gz ]; then
wget -c -O ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-android.tar.gz --no-check-certificate ${MINDSPORE_LITE_DOWNLOAD_URL}
fi
tar xzvf ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-android.tar.gz -C ${BASEPATH}/build/
cp -r ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-android/lib/aarch64/libmindspore-lite.a ${BASEPATH}/lib
cp -r ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-android/third_party/hiai_ddk/lib/aarch64/*.so ${BASEPATH}/lib
cp -r ${BASEPATH}/build/mindspore-lite-${VERSION_STR}-inference-android/include ${BASEPATH}/
cd ${BASEPATH}/build
cmake -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK}/build/cmake/android.toolchain.cmake" -DANDROID_NATIVE_API_LEVEL="19" \
-DANDROID_NDK="${ANDROID_NDK}" -DANDROID_ABI="arm64-v8a" -DANDROID_STL="c++_shared" ${BASEPATH}
make && make install && make package

View File

@ -0,0 +1,699 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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 <iostream>
#include <cstring>
#include <random>
#include <fstream>
#include <thread>
#include <algorithm>
#include "include/errorcode.h"
#include "include/model.h"
#include "include/context.h"
#include "include/lite_session.h"
#include "include/version.h"
char *ReadFile(const char *file, size_t *size) {
if (file == nullptr) {
std::cerr << "file is nullptr." << std::endl;
return nullptr;
}
std::ifstream ifs(file);
if (!ifs.good()) {
std::cerr << "file: " << file << " is not exist." << std::endl;
return nullptr;
}
if (!ifs.is_open()) {
std::cerr << "file: " << file << " open failed." << std::endl;
return nullptr;
}
ifs.seekg(0, std::ios::end);
*size = ifs.tellg();
std::unique_ptr<char[]> buf(new (std::nothrow) char[*size]);
if (buf == nullptr) {
std::cerr << "malloc buf failed, file: " << file << std::endl;
ifs.close();
return nullptr;
}
ifs.seekg(0, std::ios::beg);
ifs.read(buf.get(), *size);
ifs.close();
return buf.release();
}
template <typename T, typename Distribution>
void GenerateRandomData(int size, void *data, Distribution distribution) {
if (data == nullptr) {
std::cerr << "data is nullptr." << std::endl;
return;
}
std::mt19937 random_engine;
int elements_num = size / sizeof(T);
(void)std::generate_n(static_cast<T *>(data), elements_num,
[&]() { return static_cast<T>(distribution(random_engine)); });
}
std::shared_ptr<mindspore::lite::Context> CreateCPUContext() {
auto context = std::make_shared<mindspore::lite::Context>();
if (context == nullptr) {
std::cerr << "New context failed while running." << std::endl;
return nullptr;
}
// CPU device context has default values.
auto &cpu_device_info = context->device_list_[0].device_info_.cpu_device_info_;
// The large core takes priority in thread and core binding methods. This parameter will work in the BindThread
// interface. For specific binding effect, see the "Run Graph" section.
cpu_device_info.cpu_bind_mode_ = mindspore::lite::HIGHER_CPU;
// Use float16 operator as priority.
cpu_device_info.enable_float16_ = true;
return context;
}
std::shared_ptr<mindspore::lite::Context> CreateGPUContext() {
auto context = std::make_shared<mindspore::lite::Context>();
if (context == nullptr) {
std::cerr << "New context failed while running. " << std::endl;
return nullptr;
}
// If GPU device context is set. The preferred backend is GPU, which means, if there is a GPU operator, it will run on
// the GPU first, otherwise it will run on the CPU.
mindspore::lite::DeviceContext gpu_device_ctx{mindspore::lite::DT_GPU, {false}};
// GPU use float16 operator as priority.
gpu_device_ctx.device_info_.gpu_device_info_.enable_float16_ = true;
// The GPU device context needs to be push_back into device_list to work.
context->device_list_.push_back(gpu_device_ctx);
return context;
}
std::shared_ptr<mindspore::lite::Context> CreateNPUContext() {
auto context = std::make_shared<mindspore::lite::Context>();
if (context == nullptr) {
std::cerr << "New context failed while running. " << std::endl;
return nullptr;
}
mindspore::lite::DeviceContext npu_device_ctx{mindspore::lite::DT_NPU};
npu_device_ctx.device_info_.npu_device_info_.frequency_ = 3;
// The NPU device context needs to be push_back into device_list to work.
context->device_list_.push_back(npu_device_ctx);
return context;
}
int GetInputsAndSetData(mindspore::session::LiteSession *session) {
auto inputs = session->GetInputs();
// The model has only one input tensor.
auto in_tensor = inputs.front();
if (in_tensor == nullptr) {
std::cerr << "Input tensor is nullptr" << std::endl;
return -1;
}
auto input_data = in_tensor->MutableData();
if (input_data == nullptr) {
std::cerr << "MallocData for inTensor failed." << std::endl;
return -1;
}
GenerateRandomData<float>(in_tensor->Size(), input_data, std::uniform_real_distribution<float>(0.1f, 1.0f));
return 0;
}
int GetInputsByTensorNameAndSetData(mindspore::session::LiteSession *session) {
auto in_tensor = session->GetInputsByTensorName("2029_2028_1_construct_wrapper:x");
if (in_tensor == nullptr) {
std::cerr << "Input tensor is nullptr" << std::endl;
return -1;
}
auto input_data = in_tensor->MutableData();
if (input_data == nullptr) {
std::cerr << "MallocData for inTensor failed." << std::endl;
return -1;
}
GenerateRandomData<float>(in_tensor->Size(), input_data, std::uniform_real_distribution<float>(0.1f, 1.0f));
return 0;
}
void GetOutputsByNodeName(mindspore::session::LiteSession *session) {
// model has a output node named output_node_name_0.
auto output_vec = session->GetOutputsByNodeName("Default/Sigmoid-op204");
// output node named output_node_name_0 has only one output tensor.
auto out_tensor = output_vec.front();
if (out_tensor == nullptr) {
std::cerr << "Output tensor is nullptr" << std::endl;
return;
}
std::cout << "tensor size is:" << out_tensor->Size() << " tensor elements num is:" << out_tensor->ElementsNum()
<< std::endl;
// The model output data is float 32.
if (out_tensor->data_type() != mindspore::TypeId::kNumberTypeFloat32) {
std::cerr << "Output should in float32" << std::endl;
return;
}
auto out_data = reinterpret_cast<float *>(out_tensor->MutableData());
if (out_data == nullptr) {
std::cerr << "Data of out_tensor is nullptr" << std::endl;
return;
}
std::cout << "output data is:";
for (int i = 0; i < out_tensor->ElementsNum() && i < 10; i++) {
std::cout << out_data[i] << " ";
}
std::cout << std::endl;
}
void GetOutputByTensorName(mindspore::session::LiteSession *session) {
// We can use GetOutputTensorNames method to get all name of output tensor of model which is in order.
auto tensor_names = session->GetOutputTensorNames();
// Use output tensor name returned by GetOutputTensorNames as key
for (const auto &tensor_name : tensor_names) {
auto out_tensor = session->GetOutputByTensorName(tensor_name);
if (out_tensor == nullptr) {
std::cerr << "Output tensor is nullptr" << std::endl;
return;
}
std::cout << "tensor size is:" << out_tensor->Size() << " tensor elements num is:" << out_tensor->ElementsNum()
<< std::endl;
// The model output data is float 32.
if (out_tensor->data_type() != mindspore::TypeId::kNumberTypeFloat32) {
std::cerr << "Output should in float32" << std::endl;
return;
}
auto out_data = reinterpret_cast<float *>(out_tensor->MutableData());
if (out_data == nullptr) {
std::cerr << "Data of out_tensor is nullptr" << std::endl;
return;
}
std::cout << "output data is:";
for (int i = 0; i < out_tensor->ElementsNum() && i < 10; i++) {
std::cout << out_data[i] << " ";
}
std::cout << std::endl;
}
}
void GetOutputs(mindspore::session::LiteSession *session) {
auto out_tensors = session->GetOutputs();
for (auto out_tensor : out_tensors) {
std::cout << "tensor name is:" << out_tensor.first << " tensor size is:" << out_tensor.second->Size()
<< " tensor elements num is:" << out_tensor.second->ElementsNum() << std::endl;
// The model output data is float 32.
if (out_tensor.second->data_type() != mindspore::TypeId::kNumberTypeFloat32) {
std::cerr << "Output should in float32" << std::endl;
return;
}
auto out_data = reinterpret_cast<float *>(out_tensor.second->MutableData());
if (out_data == nullptr) {
std::cerr << "Data of out_tensor is nullptr" << std::endl;
return;
}
std::cout << "output data is:";
for (int i = 0; i < out_tensor.second->ElementsNum() && i < 10; i++) {
std::cout << out_data[i] << " ";
}
std::cout << std::endl;
}
}
mindspore::session::LiteSession *CreateSessionAndCompileByModel(mindspore::lite::Model *model) {
// Create and init CPU context.
// If you need to use GPU or NPU, you can refer to CreateGPUContext() or CreateNPUContext().
auto context = CreateCPUContext();
if (context == nullptr) {
std::cerr << "New context failed while." << std::endl;
return nullptr;
}
// Create the session.
mindspore::session::LiteSession *session = mindspore::session::LiteSession::CreateSession(context.get());
if (session == nullptr) {
std::cerr << "CreateSession failed while running." << std::endl;
return nullptr;
}
// Compile graph.
auto ret = session->CompileGraph(model);
if (ret != mindspore::lite::RET_OK) {
delete session;
std::cerr << "Compile failed while running." << std::endl;
return nullptr;
}
return session;
}
mindspore::session::LiteSession *CreateSessionAndCompileByModelBuffer(char *model_buf, size_t size) {
auto context = std::make_shared<mindspore::lite::Context>();
if (context == nullptr) {
std::cerr << "New context failed while running" << std::endl;
return nullptr;
}
// Use model buffer and context to create Session.
auto session = mindspore::session::LiteSession::CreateSession(model_buf, size, context.get());
if (session == nullptr) {
std::cerr << "CreateSession failed while running" << std::endl;
return nullptr;
}
return session;
}
int ResizeInputsTensorShape(mindspore::session::LiteSession *session) {
auto inputs = session->GetInputs();
std::vector<int> resize_shape = {1, 128, 128, 3};
// Assume the model has only one input,resize input shape to [1, 128, 128, 3]
std::vector<std::vector<int>> new_shapes;
new_shapes.push_back(resize_shape);
return session->Resize(inputs, new_shapes);
}
int Run(const char *model_path) {
// Read model file.
size_t size = 0;
char *model_buf = ReadFile(model_path, &size);
if (model_buf == nullptr) {
std::cerr << "Read model file failed." << std::endl;
return -1;
}
// Load the .ms model.
auto model = mindspore::lite::Model::Import(model_buf, size);
delete[](model_buf);
if (model == nullptr) {
std::cerr << "Import model file failed." << std::endl;
return -1;
}
// Compile MindSpore Lite model.
auto session = CreateSessionAndCompileByModel(model);
if (session == nullptr) {
delete model;
std::cerr << "Create session failed." << std::endl;
return -1;
}
// Note: when use model->Free(), the model can not be compiled again.
model->Free();
// Set inputs data.
// You can also get input through other methods, and you can refer to GetInputsAndSetData()
GetInputsByTensorNameAndSetData(session);
session->BindThread(true);
auto ret = session->RunGraph();
if (ret != mindspore::lite::RET_OK) {
delete model;
std::cerr << "Inference error " << ret << std::endl;
return ret;
}
session->BindThread(false);
// Get outputs data.
// You can also get output through other methods,
// and you can refer to GetOutputByTensorName() or GetOutputs().
GetOutputsByNodeName(session);
// Delete model buffer.
delete model;
// Delete session buffer.
delete session;
return 0;
}
int RunResize(const char *model_path) {
size_t size = 0;
char *model_buf = ReadFile(model_path, &size);
if (model_buf == nullptr) {
std::cerr << "Read model file failed." << std::endl;
return -1;
}
// Load the .ms model.
auto model = mindspore::lite::Model::Import(model_buf, size);
delete[](model_buf);
if (model == nullptr) {
std::cerr << "Import model file failed." << std::endl;
return -1;
}
// Compile MindSpore Lite model.
auto session = CreateSessionAndCompileByModel(model);
if (session == nullptr) {
delete model;
std::cerr << "Create session failed." << std::endl;
return -1;
}
// Resize inputs tensor shape.
auto ret = ResizeInputsTensorShape(session);
if (ret != mindspore::lite::RET_OK) {
delete model;
std::cerr << "Resize input tensor shape error." << ret << std::endl;
return ret;
}
// Set inputs data.
// You can also get input through other methods, and you can refer to GetInputsAndSetData()
GetInputsByTensorNameAndSetData(session);
session->BindThread(true);
ret = session->RunGraph();
if (ret != mindspore::lite::RET_OK) {
delete model;
std::cerr << "Inference error " << ret << std::endl;
return ret;
}
session->BindThread(false);
// Get outputs data.
// You can also get output through other methods,
// and you can refer to GetOutputByTensorName() or GetOutputs().
GetOutputsByNodeName(session);
// Delete model buffer.
delete model;
// Delete session buffer.
delete session;
return 0;
}
int RunCreateSessionSimplified(const char *model_path) {
size_t size = 0;
char *model_buf = ReadFile(model_path, &size);
if (model_buf == nullptr) {
std::cerr << "Read model file failed." << std::endl;
return -1;
}
// Compile MindSpore Lite model.
auto session = CreateSessionAndCompileByModelBuffer(model_buf, size);
if (session == nullptr) {
std::cerr << "Create session failed." << std::endl;
return -1;
}
// Set inputs data.
// You can also get input through other methods, and you can refer to GetInputsAndSetData()
GetInputsByTensorNameAndSetData(session);
session->BindThread(true);
auto ret = session->RunGraph();
if (ret != mindspore::lite::RET_OK) {
std::cerr << "Inference error " << ret << std::endl;
return ret;
}
session->BindThread(false);
// Get outputs data.
// You can also get output through other methods,
// and you can refer to GetOutputByTensorName() or GetOutputs().
GetOutputsByNodeName(session);
// Delete session buffer.
delete session;
return 0;
}
int RunSessionParallel(const char *model_path) {
size_t size = 0;
char *model_buf = ReadFile(model_path, &size);
if (model_buf == nullptr) {
std::cerr << "Read model file failed." << std::endl;
return -1;
}
// Load the .ms model.
auto model = mindspore::lite::Model::Import(model_buf, size);
delete[](model_buf);
if (model == nullptr) {
std::cerr << "Import model file failed." << std::endl;
return -1;
}
// Compile MindSpore Lite model.
auto session1 = CreateSessionAndCompileByModel(model);
if (session1 == nullptr) {
delete model;
std::cerr << "Create session failed." << std::endl;
return -1;
}
// Compile MindSpore Lite model.
auto session2 = CreateSessionAndCompileByModel(model);
if (session2 == nullptr) {
delete model;
std::cerr << "Create session failed." << std::endl;
return -1;
}
// Note: when use model->Free(), the model can not be compiled again.
model->Free();
std::thread thread1([&]() {
GetInputsByTensorNameAndSetData(session1);
auto status = session1->RunGraph();
if (status != 0) {
if (model != nullptr) {
delete model;
model = nullptr;
}
std::cerr << "Inference error " << status << std::endl;
return;
}
std::cout << "Session1 inference success" << std::endl;
});
std::thread thread2([&]() {
GetInputsByTensorNameAndSetData(session2);
auto status = session2->RunGraph();
if (status != 0) {
if (model != nullptr) {
delete model;
model = nullptr;
}
std::cerr << "Inference error " << status << std::endl;
return;
}
std::cout << "Session2 inference success" << std::endl;
});
thread1.join();
thread2.join();
// Get outputs data.
// You can also get output through other methods,
// and you can refer to GetOutputByTensorName() or GetOutputs().
GetOutputsByNodeName(session1);
GetOutputsByNodeName(session2);
// Delete model buffer.
if (model != nullptr) {
delete model;
model = nullptr;
}
// Delete session buffer.
delete session1;
delete session2;
return 0;
}
int RunWithSharedMemoryPool(const char *model_path) {
size_t size = 0;
char *model_buf = ReadFile(model_path, &size);
if (model_buf == nullptr) {
std::cerr << "Read model file failed." << std::endl;
return -1;
}
auto model = mindspore::lite::Model::Import(model_buf, size);
delete[](model_buf);
if (model == nullptr) {
std::cerr << "Import model file failed." << std::endl;
return -1;
}
auto context1 = std::make_shared<mindspore::lite::Context>();
if (context1 == nullptr) {
delete model;
std::cerr << "New context failed while running." << std::endl;
return -1;
}
auto session1 = mindspore::session::LiteSession::CreateSession(context1.get());
if (session1 == nullptr) {
delete model;
std::cerr << "CreateSession failed while running." << std::endl;
return -1;
}
auto ret = session1->CompileGraph(model);
if (ret != mindspore::lite::RET_OK) {
delete model;
std::cerr << "Compile failed while running." << std::endl;
return -1;
}
auto context2 = std::make_shared<mindspore::lite::Context>();
if (context2 == nullptr) {
delete model;
std::cerr << "New context failed while running." << std::endl;
return -1;
}
// Use the same allocator to share the memory pool.
context2->allocator = context1->allocator;
auto session2 = mindspore::session::LiteSession::CreateSession(context2.get());
if (session2 == nullptr) {
delete model;
std::cerr << "CreateSession failed while running " << std::endl;
return -1;
}
ret = session2->CompileGraph(model);
if (ret != mindspore::lite::RET_OK) {
delete model;
std::cerr << "Compile failed while running " << std::endl;
return -1;
}
// Note: when use model->Free(), the model can not be compiled again.
model->Free();
// Set inputs data.
// You can also get input through other methods, and you can refer to GetInputsAndSetData()
GetInputsByTensorNameAndSetData(session1);
GetInputsByTensorNameAndSetData(session2);
ret = session1->RunGraph();
if (ret != mindspore::lite::RET_OK) {
std::cerr << "Inference error " << ret << std::endl;
return ret;
}
ret = session2->RunGraph();
if (ret != mindspore::lite::RET_OK) {
delete model;
std::cerr << "Inference error " << ret << std::endl;
return ret;
}
// Get outputs data.
// You can also get output through other methods,
// and you can refer to GetOutputByTensorName() or GetOutputs().
GetOutputsByNodeName(session1);
GetOutputsByNodeName(session2);
// Delete model buffer.
delete model;
// Delete session buffer.
delete session1;
delete session2;
return 0;
}
int RunCallback(const char *model_path) {
size_t size = 0;
char *model_buf = ReadFile(model_path, &size);
if (model_buf == nullptr) {
std::cerr << "Read model file failed." << std::endl;
return -1;
}
// Load the .ms model.
auto model = mindspore::lite::Model::Import(model_buf, size);
delete[](model_buf);
if (model == nullptr) {
std::cerr << "Import model file failed." << std::endl;
return -1;
}
// Compile MindSpore Lite model.
auto session = CreateSessionAndCompileByModel(model);
if (session == nullptr) {
delete model;
std::cerr << "Create session failed." << std::endl;
return -1;
}
// Note: when use model->Free(), the model can not be compiled again.
model->Free();
// Set inputs data.
// You can also get input through other methods, and you can refer to GetInputsAndSetData()
GetInputsByTensorNameAndSetData(session);
// Definition of callback function before forwarding operator.
auto before_call_back = [&](const std::vector<mindspore::tensor::MSTensor *> &before_inputs,
const std::vector<mindspore::tensor::MSTensor *> &before_outputs,
const mindspore::CallBackParam &call_param) {
std::cout << "Before forwarding " << call_param.node_name << " " << call_param.node_type << std::endl;
return true;
};
// Definition of callback function after forwarding operator.
auto after_call_back = [&](const std::vector<mindspore::tensor::MSTensor *> &after_inputs,
const std::vector<mindspore::tensor::MSTensor *> &after_outputs,
const mindspore::CallBackParam &call_param) {
std::cout << "After forwarding " << call_param.node_name << " " << call_param.node_type << std::endl;
return true;
};
session->BindThread(true);
auto ret = session->RunGraph(before_call_back, after_call_back);
if (ret != mindspore::lite::RET_OK) {
delete model;
std::cerr << "Inference error " << ret << std::endl;
return ret;
}
session->BindThread(false);
// Get outputs data.
// You can also get output through other methods,
// and you can refer to GetOutputByTensorName() or GetOutputs().
GetOutputsByNodeName(session);
// Delete model buffer.
delete model;
// Delete session buffer.
delete session;
return 0;
}
int main(int argc, const char **argv) {
if (argc < 3) {
std::cerr << "Usage: ./runtime_cpp model_path flag" << std::endl;
std::cerr << "Example: ./runtime_cpp ../model/mobilenetv2.ms 0" << std::endl;
std::cerr << "When your Flag is 0, you will run MindSpore Lite inference." << std::endl;
std::cerr << "When your Flag is 1, you will run MindSpore Lite inference with resize." << std::endl;
std::cerr << "When your Flag is 2, you will run MindSpore Lite inference with CreateSession simplified API."
<< std::endl;
std::cerr << "When your Flag is 3, you will run MindSpore Lite inference with session parallel." << std::endl;
std::cerr << "When your Flag is 4, you will run MindSpore Lite inference with shared memory pool." << std::endl;
std::cerr << "When your Flag is 5, you will run MindSpore Lite inference with callback." << std::endl;
return -1;
}
std::string version = mindspore::lite::Version();
std::cout << "MindSpore Lite Version is " << version << std::endl;
auto model_path = argv[1];
auto flag = argv[2];
if (strcmp(flag, "0") == 0) {
return Run(model_path);
} else if (strcmp(flag, "1") == 0) {
return RunResize(model_path);
} else if (strcmp(flag, "2") == 0) {
return RunCreateSessionSimplified(model_path);
} else if (strcmp(flag, "3") == 0) {
return RunSessionParallel(model_path);
} else if (strcmp(flag, "4") == 0) {
return RunWithSharedMemoryPool(model_path);
} else if (strcmp(flag, "5") == 0) {
return RunCallback(model_path);
} else {
std::cerr << "Unsupported Flag " << flag << std::endl;
return -1;
}
}