diff --git a/mindspore/lite/examples/quick_start_cpp/CMakeLists.txt b/mindspore/lite/examples/quick_start_cpp/CMakeLists.txt new file mode 100644 index 0000000000..612e9288c4 --- /dev/null +++ b/mindspore/lite/examples/quick_start_cpp/CMakeLists.txt @@ -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 +) \ No newline at end of file diff --git a/mindspore/lite/examples/quick_start_cpp/build.sh b/mindspore/lite/examples/quick_start_cpp/build.sh new file mode 100644 index 0000000000..339782a33f --- /dev/null +++ b/mindspore/lite/examples/quick_start_cpp/build.sh @@ -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 \ No newline at end of file diff --git a/mindspore/lite/examples/quick_start_cpp/main.cc b/mindspore/lite/examples/quick_start_cpp/main.cc new file mode 100644 index 0000000000..802dfc7740 --- /dev/null +++ b/mindspore/lite/examples/quick_start_cpp/main.cc @@ -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 +#include +#include +#include +#include +#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 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 +void GenerateRandomData(int size, void *data, Distribution distribution) { + std::mt19937 random_engine; + int elements_num = size / sizeof(T); + (void)std::generate_n(static_cast(data), elements_num, + [&]() { return static_cast(distribution(random_engine)); }); +} + +int GenerateInputDataWithRandom(std::vector 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(tensor->Size(), random_data, std::uniform_real_distribution(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(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(); + 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); } diff --git a/mindspore/lite/examples/runtime_cpp/CMakeLists.txt b/mindspore/lite/examples/runtime_cpp/CMakeLists.txt new file mode 100644 index 0000000000..b406b9f08d --- /dev/null +++ b/mindspore/lite/examples/runtime_cpp/CMakeLists.txt @@ -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) diff --git a/mindspore/lite/examples/runtime_cpp/README.md b/mindspore/lite/examples/runtime_cpp/README.md new file mode 100644 index 0000000000..5b244e68aa --- /dev/null +++ b/mindspore/lite/examples/runtime_cpp/README.md @@ -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 + ``` diff --git a/mindspore/lite/examples/runtime_cpp/build.sh b/mindspore/lite/examples/runtime_cpp/build.sh new file mode 100644 index 0000000000..0bafae0890 --- /dev/null +++ b/mindspore/lite/examples/runtime_cpp/build.sh @@ -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 diff --git a/mindspore/lite/examples/runtime_cpp/main.cc b/mindspore/lite/examples/runtime_cpp/main.cc new file mode 100644 index 0000000000..08c005e3da --- /dev/null +++ b/mindspore/lite/examples/runtime_cpp/main.cc @@ -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 +#include +#include +#include +#include +#include +#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 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 +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(data), elements_num, + [&]() { return static_cast(distribution(random_engine)); }); +} + +std::shared_ptr CreateCPUContext() { + auto context = std::make_shared(); + 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 CreateGPUContext() { + auto context = std::make_shared(); + 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 CreateNPUContext() { + auto context = std::make_shared(); + 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(in_tensor->Size(), input_data, std::uniform_real_distribution(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(in_tensor->Size(), input_data, std::uniform_real_distribution(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(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(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(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(); + 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 resize_shape = {1, 128, 128, 3}; + // Assume the model has only one input,resize input shape to [1, 128, 128, 3] + std::vector> 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(); + 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(); + 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 &before_inputs, + const std::vector &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 &after_inputs, + const std::vector &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; + } +}