diff --git a/include/api/context.h b/include/api/context.h index 9105f73915..3f52d7ae9d 100644 --- a/include/api/context.h +++ b/include/api/context.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "include/api/types.h" #include "include/api/dual_abi_helper.h" @@ -68,6 +69,13 @@ struct MS_API ModelContext : public Context { static inline void SetInputShape(const std::shared_ptr &context, const std::string &shape); static inline std::string GetInputShape(const std::shared_ptr &context); + static void SetInputShapeMap(const std::shared_ptr &context, const std::map> &shape); + static std::map> GetInputShapeMap(const std::shared_ptr &context); + + static void SetDynamicBatchSize(const std::shared_ptr &context, + const std::vector &dynamic_batch_size); + static inline std::string GetDynamicBatchSize(const std::shared_ptr &context); + static void SetOutputType(const std::shared_ptr &context, enum DataType output_type); static enum DataType GetOutputType(const std::shared_ptr &context); @@ -107,6 +115,7 @@ struct MS_API ModelContext : public Context { static void SetGpuTrtInferMode(const std::shared_ptr &context, const std::vector &gpu_trt_infer_mode); static std::vector GetGpuTrtInferModeChar(const std::shared_ptr &context); + static std::vector GetDynamicBatchSizeChar(const std::shared_ptr &context); }; void GlobalContext::SetGlobalDeviceTarget(const std::string &device_target) { @@ -162,6 +171,10 @@ std::string ModelContext::GetFusionSwitchConfigPath(const std::shared_ptr &context) { + return CharToString(GetDynamicBatchSizeChar(context)); +} + void ModelContext::SetGpuTrtInferMode(const std::shared_ptr &context, const std::string &gpu_trt_infer_mode) { SetGpuTrtInferMode(context, StringToChar(gpu_trt_infer_mode)); } diff --git a/mindspore/ccsrc/cxx_api/context.cc b/mindspore/ccsrc/cxx_api/context.cc index 3f5597098d..fb3ca74cb6 100644 --- a/mindspore/ccsrc/cxx_api/context.cc +++ b/mindspore/ccsrc/cxx_api/context.cc @@ -24,6 +24,7 @@ constexpr auto kGlobalContextDeviceID = "mindspore.ascend.globalcontext.device_i constexpr auto kGlobalContextDumpCfgPath = "mindspore.ascend.globalcontext.dump_config_file_path"; constexpr auto kModelOptionInsertOpCfgPath = "mindspore.option.insert_op_config_file_path"; // aipp config file constexpr auto kModelOptionInputFormat = "mindspore.option.input_format"; // nchw or nhwc +constexpr auto kModelOptionInputShapeMap = "mindspore.option.input_shape_map"; constexpr auto kModelOptionInputShape = "mindspore.option.input_shape"; // Mandatory while dynamic batch: e.g. "input_op_name1: n1,c2,h3,w4;input_op_name2: n4,c3,h2,w1" constexpr auto kModelOptionOutputType = "mindspore.option.output_type"; // "FP32", "UINT8" or "FP16", default as "FP32" @@ -33,6 +34,8 @@ constexpr auto kModelOptionOpSelectImplMode = "mindspore.option.op_select_impl_m constexpr auto KModelOptionFusionSwitchCfgPath = "mindspore.option.fusion_switch_config_file_path"; // "False": Inference with native backend, "True": Inference with Tensor-RT engine, default as "False" constexpr auto kModelOptionGpuTrtInferMode = "mindspore.option.gpu_trt_infer_mode"; +constexpr auto kModelOptionDynamicBatchSize = "mindspore.option.dynamic_batch_size"; +constexpr auto kModelOptionDynamicImageSize = "mindspore.option.dynamic_image_size"; namespace mindspore { struct Context::Data { @@ -159,6 +162,17 @@ std::vector ModelContext::GetInputShapeChar(const std::shared_ptr return StringToChar(ref); } +void ModelContext::SetInputShapeMap(const std::shared_ptr &context, + const std::map> &shape) { + MS_EXCEPTION_IF_NULL(context); + context->data->params[kModelOptionInputShapeMap] = shape; +} + +std::map> ModelContext::GetInputShapeMap(const std::shared_ptr &context) { + MS_EXCEPTION_IF_NULL(context); + return GetValue>>(context, kModelOptionInputShapeMap); +} + void ModelContext::SetOutputType(const std::shared_ptr &context, enum DataType output_type) { MS_EXCEPTION_IF_NULL(context); if (context->data == nullptr) { @@ -235,4 +249,23 @@ std::vector ModelContext::GetGpuTrtInferModeChar(const std::shared_ptr(context, kModelOptionGpuTrtInferMode); return StringToChar(ref); } + +void ModelContext::SetDynamicBatchSize(const std::shared_ptr &context, const std::vector &batch_size) { + MS_EXCEPTION_IF_NULL(context); + if (context->data == nullptr) { + context->data = std::make_shared(); + MS_EXCEPTION_IF_NULL(context->data); + } + std::string batchs = ""; + for (auto bs : batch_size) { + batchs += std::to_string(bs) + ","; + } + context->data->params[kModelOptionDynamicBatchSize] = batchs; +} + +std::vector ModelContext::GetDynamicBatchSizeChar(const std::shared_ptr &context) { + MS_EXCEPTION_IF_NULL(context); + const std::string &ref = GetValue(context, kModelOptionDynamicBatchSize); + return StringToChar(ref); +} } // namespace mindspore diff --git a/mindspore/ccsrc/cxx_api/graph/acl/model_process.cc b/mindspore/ccsrc/cxx_api/graph/acl/model_process.cc index c153ae7df2..509a78d15f 100644 --- a/mindspore/ccsrc/cxx_api/graph/acl/model_process.cc +++ b/mindspore/ccsrc/cxx_api/graph/acl/model_process.cc @@ -53,18 +53,15 @@ inline static void PushbackIfNotNull(U *vec, T &&item) { } static void ConstructTensorDesc(const std::vector &acl_tensor_list, std::vector *names, - std::vector> *shapes, std::vector *data_types, - std::vector *mem_sizes) { + std::vector> *shapes, std::vector *data_types) { ClearIfNotNull(names); ClearIfNotNull(shapes); ClearIfNotNull(data_types); - ClearIfNotNull(mem_sizes); for (size_t i = 0; i < acl_tensor_list.size(); ++i) { const auto &info = acl_tensor_list[i]; PushbackIfNotNull(names, info.name); PushbackIfNotNull(shapes, info.dims); PushbackIfNotNull(data_types, TransToApiType(info.data_type)); - PushbackIfNotNull(mem_sizes, info.buffer_size); } } @@ -81,20 +78,17 @@ static std::string ShapeToString(const std::vector &shape) { } Status ModelProcess::ConstructTensors(const std::vector &acl_tensor_list, - std::vector *tensor_list) { + std::vector *tensor_list, const std::vector &mem_sizes) { MS_EXCEPTION_IF_NULL(tensor_list); std::vector names; std::vector> shapes; std::vector data_types; - std::vector mem_sizes; - - ConstructTensorDesc(acl_tensor_list, &names, &shapes, &data_types, &mem_sizes); + ConstructTensorDesc(acl_tensor_list, &names, &shapes, &data_types); tensor_list->clear(); if (names.size() != acl_tensor_list.size() || shapes.size() != acl_tensor_list.size() || - data_types.size() != acl_tensor_list.size() || mem_sizes.size() != acl_tensor_list.size()) { + data_types.size() != acl_tensor_list.size()) { MS_LOG(ERROR) << "Inner error, size do not match: names size " << names.size() << " shapes size " << shapes.size() - << " data types size " << data_types.size() << " mem sizes size " << mem_sizes.size() - << " acl_tensor_list size " << acl_tensor_list.size(); + << " data types size " << data_types.size() << " acl_tensor_list size " << acl_tensor_list.size(); return kMCFailed; } @@ -102,7 +96,7 @@ Status ModelProcess::ConstructTensors(const std::vector &acl_tens for (size_t i = 0; i < acl_tensor_list.size(); ++i) { tensor_list->emplace_back(names[i], data_types[i], shapes[i], nullptr, mem_sizes[i]); auto ret = aclrtMemcpy((*tensor_list)[i].MutableData(), (*tensor_list)[i].DataSize(), - acl_tensor_list[i].device_data, acl_tensor_list[i].buffer_size, kind); + acl_tensor_list[i].device_data, mem_sizes[i], kind); if (ret != ACL_ERROR_NONE) { MS_LOG(ERROR) << "Memcpy input " << i << " from " << (is_run_on_device_ ? "host" : "device") << " to host failed, memory size " << acl_tensor_list[i].buffer_size; @@ -165,6 +159,7 @@ Status ModelProcess::InitInputsBuffer() { } MS_LOG(INFO) << "Name of input " << i << " is " << input_name; input_infos_.emplace_back(AclTensorInfo{data_mem_buffer, buffer_size, data_type, shape, input_name}); + input_size_.push_back(buffer_size); } MS_LOG(INFO) << "Create model inputs success"; return kSuccess; @@ -319,38 +314,72 @@ Status ModelProcess::UnLoad() { return kSuccess; } +size_t ModelProcess::GetDynamicDims(const std::vector &inputs) { + size_t max_num = 0; + for (auto input : inputs) { + size_t cur_num = std::count(input.dims.begin(), input.dims.end(), -1); + if (cur_num > max_num) { + max_num = cur_num; + } + } + return max_num; +} + +Status ModelProcess::SetBatchSize(const std::vector &inputs) { + size_t index; + aclError ret; + input_size_.clear(); + for (auto input : inputs) { + input_size_.push_back(input.DataSize()); + } + auto *p = reinterpret_cast(inputs[inputs.size() - 1].Data().get()); + MS_EXCEPTION_IF_NULL(p); + auto dynamicBatchSize = p[0]; + ret = aclmdlGetInputIndexByName(model_desc_, ACL_DYNAMIC_TENSOR_NAME, &index); + if (ret != ACL_ERROR_NONE) { + MS_LOG(ERROR) << "get index failed"; + return kMCDeviceError; + } + ret = aclmdlSetDynamicBatchSize(model_id_, inputs_, index, dynamicBatchSize); + if (ret != ACL_ERROR_NONE) { + MS_LOG(ERROR) << "dynamic batch set failed, modelId is " << model_id_; + return kMCDeviceError; + } + return kSuccess; +} + Status ModelProcess::CheckAndInitInput(const std::vector &inputs) { aclError ret; inputs_ = aclmdlCreateDataset(); + size_t dynamic_nums = GetDynamicDims(input_infos_); // check inputs - if (inputs.size() != input_infos_.size()) { - MS_LOG(ERROR) << "Inputs count not match, required count " << input_infos_.size() << ", given count " - << inputs.size(); - return kMCInvalidInput; - } - for (size_t i = 0; i < input_infos_.size(); ++i) { - if (inputs[i].Shape() != input_infos_[i].dims) { - MS_LOG(INFO) << "Note: input " << i << " shape not match, required " << ShapeToString(input_infos_[i].dims) - << ", given " << ShapeToString(inputs[i].Shape()); - } - - if (inputs[i].DataType() != TransToApiType(input_infos_[i].data_type)) { - MS_LOG(INFO) << "Note: input " << i << " data type not match, required " - << TransToApiType(input_infos_[i].data_type) << ", given " << inputs[i].DataType(); - } - - if (inputs[i].DataSize() != input_infos_[i].buffer_size) { - MS_LOG(ERROR) << "Input " << i << " data size not match, required size " << input_infos_[i].buffer_size - << ", given count " << inputs[i].DataSize(); + if (dynamic_nums == 0) { + if (inputs.size() != input_infos_.size()) { + MS_LOG(ERROR) << "Inputs count not match, required count " << input_infos_.size() << ", given count " + << inputs.size(); return kMCInvalidInput; } + for (size_t i = 0; i < input_infos_.size(); ++i) { + if (inputs[i].Shape() != input_infos_[i].dims) { + MS_LOG(INFO) << "Note: input " << i << " shape not match, required " << ShapeToString(input_infos_[i].dims) + << ", given " << ShapeToString(inputs[i].Shape()); + } + if (inputs[i].DataType() != TransToApiType(input_infos_[i].data_type)) { + MS_LOG(INFO) << "Note: input " << i << " data type not match, required " + << TransToApiType(input_infos_[i].data_type) << ", given " << inputs[i].DataType(); + } + if (inputs[i].DataSize() != input_infos_[i].buffer_size) { + MS_LOG(ERROR) << "Input " << i << " data size not match, required size " << input_infos_[i].buffer_size + << ", given count " << inputs[i].DataSize(); + return kMCInvalidInput; + } + } } // copy inputs for (size_t i = 0; i < input_infos_.size(); ++i) { const auto &info = input_infos_[i]; auto input = inputs[i]; const void *data = input.MutableData(); - void *input_buffer = nullptr; if (!is_run_on_device_) { ret = aclrtMemcpy(info.device_data, info.buffer_size, data, input.DataSize(), ACL_MEMCPY_HOST_TO_DEVICE); @@ -374,6 +403,40 @@ Status ModelProcess::CheckAndInitInput(const std::vector &inputs) { return kMCDeviceError; } } + if (dynamic_nums == 1) { + if (SetBatchSize(inputs) == kMCDeviceError) { + MS_LOG(ERROR) << "failed to convert dynamic batch size"; + return kMCDeviceError; + } + } else if (dynamic_nums == 2) { + MS_LOG(ERROR) << "only dynamic batch size is supported"; + return kMCInvalidInput; + } + if (ResetOutputSize() == kMCDeviceError) { + MS_LOG(ERROR) << "reset output size failed"; + return kMCDeviceError; + } + return kSuccess; +} + +Status ModelProcess::ResetOutputSize() { + aclDataType output_type; + aclError ret; + size_t output_size = aclmdlGetNumOutputs(model_desc_); + for (size_t index = 0; index < output_size; index++) { + size_t dims = 1; + struct aclmdlIODims output_dims; + ret = aclmdlGetCurOutputDims(model_desc_, index, &output_dims); + if (ret != ACL_ERROR_NONE) { + MS_LOG(ERROR) << "get output dim error."; + return kMCDeviceError; + } + for (size_t i = 0; i < output_dims.dimCount; i++) { + dims *= output_dims.dims[i]; + } + output_type = aclmdlGetOutputDataType(model_desc_, index); + output_size_.push_back(dims * aclDataTypeSize(output_type)); + } return kSuccess; } @@ -427,7 +490,7 @@ Status ModelProcess::BuildOutputs(std::vector *outputs) { } std::vector ModelProcess::GetInputs() { - Status ret = ConstructTensors(input_infos_, &input_tensors_); + Status ret = ConstructTensors(input_infos_, &input_tensors_, input_size_); if (ret != kSuccess) { MS_LOG(ERROR) << "ConstructTensors failed."; input_tensors_.clear(); @@ -437,7 +500,7 @@ std::vector ModelProcess::GetInputs() { } std::vector ModelProcess::GetOutputs() { - Status ret = ConstructTensors(output_infos_, &output_tensors_); + Status ret = ConstructTensors(output_infos_, &output_tensors_, output_size_); if (ret != kSuccess) { MS_LOG(ERROR) << "ConstructTensors failed."; output_tensors_.clear(); diff --git a/mindspore/ccsrc/cxx_api/graph/acl/model_process.h b/mindspore/ccsrc/cxx_api/graph/acl/model_process.h index 7906b17823..6980c0056c 100644 --- a/mindspore/ccsrc/cxx_api/graph/acl/model_process.h +++ b/mindspore/ccsrc/cxx_api/graph/acl/model_process.h @@ -61,10 +61,13 @@ class ModelProcess { private: Status CreateDataBuffer(void **data_mem_buffer, size_t buffer_size, aclmdlDataset *dataset); Status CheckAndInitInput(const std::vector &inputs); - Status ConstructTensors(const std::vector &acl_tensor_list, std::vector *tensor_list); + Status ConstructTensors(const std::vector &acl_tensor_list, std::vector *tensor_list, + const std::vector &mem_sizes); Status BuildOutputs(std::vector *outputs); + Status SetBatchSize(const std::vector &inputs); Status InitInputsBuffer(); Status InitOutputsBuffer(); + Status ResetOutputSize(); void DestroyInputsDataset(); void DestroyInputsDataMem(); @@ -81,6 +84,9 @@ class ModelProcess { std::vector output_infos_; std::vector input_tensors_; std::vector output_tensors_; + std::vector output_size_; + std::vector input_size_; + size_t GetDynamicDims(const std::vector &); }; } // namespace mindspore diff --git a/mindspore/ccsrc/cxx_api/model/acl/acl_model.cc b/mindspore/ccsrc/cxx_api/model/acl/acl_model.cc index 0b299c429f..e22e89c3ba 100644 --- a/mindspore/ccsrc/cxx_api/model/acl/acl_model.cc +++ b/mindspore/ccsrc/cxx_api/model/acl/acl_model.cc @@ -47,6 +47,20 @@ Status AclModel::Build() { graph = iter->second; } else { auto func_graph = ModelImpl::GetFuncGraph(); + auto inputs = func_graph->parameters(); + std::vector input_names; + for (auto node : inputs) { + auto para = node->cast(); + MS_EXCEPTION_IF_NULL(para); + std::string name = para->name(); + for (auto pos = name.find(':'); pos != std::string::npos; pos = name.find(':')) { + name = name.substr(0, pos) + "_" + name.substr(pos + 1); + MS_LOG(INFO) << name; + } + para->set_name(name); + input_names.push_back(name); + } + options->RenameInput(input_names); MS_EXCEPTION_IF_NULL(func_graph); model_converter_.set_options(options.get()); auto om_data = model_converter_.LoadMindIR(func_graph); diff --git a/mindspore/ccsrc/cxx_api/model/acl/acl_model_options.cc b/mindspore/ccsrc/cxx_api/model/acl/acl_model_options.cc index d98be0f589..841ebc19b8 100644 --- a/mindspore/ccsrc/cxx_api/model/acl/acl_model_options.cc +++ b/mindspore/ccsrc/cxx_api/model/acl/acl_model_options.cc @@ -27,10 +27,9 @@ AclModelOptions::AclModelOptions(const std::shared_ptr &context) { if (context == nullptr) { return; } - insert_op_cfg_path = ModelContext::GetInsertOpConfigPath(context); - input_format = ModelContext::GetInputFormat(context); - input_shape = ModelContext::GetInputShape(context); - + insert_op_cfg_path_ = ModelContext::GetInsertOpConfigPath(context); + input_format_ = ModelContext::GetInputFormat(context); + input_shape_map_ = ModelContext::GetInputShapeMap(context); auto out_type = ModelContext::GetOutputType(context); auto iter = kSupportedDtypeOptionMap.find(out_type); if (out_type == DataType::kTypeUnknown) { @@ -38,26 +37,46 @@ AclModelOptions::AclModelOptions(const std::shared_ptr &context) { } else if (iter == kSupportedDtypeOptionMap.end()) { MS_LOG(WARNING) << "Unsupported output type " << out_type << ", use FP32 as default."; } else { - output_type = iter->second; + output_type_ = iter->second; } + dynamic_batch_size_ = ModelContext::GetDynamicBatchSize(context); + precision_mode_ = ModelContext::GetPrecisionMode(context); + op_select_impl_mode_ = ModelContext::GetOpSelectImplMode(context); + fusion_switch_cfg_path_ = ModelContext::GetFusionSwitchConfigPath(context); +} - precision_mode = ModelContext::GetPrecisionMode(context); - op_select_impl_mode = ModelContext::GetOpSelectImplMode(context); - fusion_switch_cfg_path = ModelContext::GetFusionSwitchConfigPath(context); +void AclModelOptions::RenameInput(const std::vector &input_names) { + if (input_names.size() != input_shape_map_.size()) { + MS_LOG(INFO) << "Inputs count not match"; + return; + } + input_shape_ = ""; + for (size_t i = 0; i < input_shape_map_.size(); i++) { + std::string s; + for (size_t j = 0; j < input_shape_map_[i].size(); j++) { + s += std::to_string(input_shape_map_[i][j]) + ","; + } + input_shape_ += input_names[i] + ":" + s.substr(0, s.size() - 1) + ";"; + } + input_shape_ = input_shape_.substr(0, input_shape_.size() - 1); + MS_LOG(INFO) << "input name is " << input_shape_; } std::tuple, std::map> AclModelOptions::GenAclOptions() const { const std::map init_options_map = { - {&op_select_impl_mode, ge::ir_option::OP_SELECT_IMPL_MODE}, - {&soc_version, ge::ir_option::SOC_VERSION}, - {&fusion_switch_cfg_path, ge::ir_option::FUSION_SWITCH_FILE}}; + {&op_select_impl_mode_, ge::ir_option::OP_SELECT_IMPL_MODE}, + {&soc_version_, ge::ir_option::SOC_VERSION}, + {&fusion_switch_cfg_path_, ge::ir_option::FUSION_SWITCH_FILE}}; const std::map build_options_map = { - {&insert_op_cfg_path, ge::ir_option::INSERT_OP_FILE}, {&input_format, ge::ir_option::INPUT_FORMAT}, - {&input_shape, ge::ir_option::INPUT_SHAPE}, {&output_type, ge::ir_option::OUTPUT_TYPE}, - {&precision_mode, ge::ir_option::PRECISION_MODE}, - }; + {&insert_op_cfg_path_, ge::ir_option::INSERT_OP_FILE}, + {&input_format_, ge::ir_option::INPUT_FORMAT}, + {&input_shape_, ge::ir_option::INPUT_SHAPE}, + {&output_type_, ge::ir_option::OUTPUT_TYPE}, + {&precision_mode_, ge::ir_option::PRECISION_MODE}, + {&dynamic_batch_size_, ge::ir_option::DYNAMIC_BATCH_SIZE}, + {&dynamic_image_size_, ge::ir_option::DYNAMIC_IMAGE_SIZE}}; std::map init_options; std::map build_options; diff --git a/mindspore/ccsrc/cxx_api/model/acl/acl_model_options.h b/mindspore/ccsrc/cxx_api/model/acl/acl_model_options.h index 5bc32bf8de..06a9f6669a 100644 --- a/mindspore/ccsrc/cxx_api/model/acl/acl_model_options.h +++ b/mindspore/ccsrc/cxx_api/model/acl/acl_model_options.h @@ -26,23 +26,31 @@ #include "include/api/context.h" namespace mindspore { -struct AclModelOptions { - // build options - std::string insert_op_cfg_path; - std::string input_format; - std::string input_shape; - std::string output_type; - std::string precision_mode; - std::string op_select_impl_mode; - std::string fusion_switch_cfg_path; - std::string soc_version = "Ascend310"; - +class AclModelOptions { + public: explicit AclModelOptions(const std::shared_ptr &context); ~AclModelOptions() = default; + std::string GenAclOptionsKey() const; + void RenameInput(const std::vector &); // return tuple std::tuple, std::map> GenAclOptions() const; - std::string GenAclOptionsKey() const; + + private: + std::string output_node_; // todo: at convert.cc::BuildGraph(), no atc options + // build options + std::string insert_op_cfg_path_; + std::string input_format_; + std::string input_shape_; + std::string output_type_; + std::string precision_mode_; + std::string op_select_impl_mode_; + std::string fusion_switch_cfg_path_; + std::string soc_version_ = "Ascend310"; + std::string dynamic_batch_size_; + std::string dynamic_image_size_; + std::map> input_shape_map_; + std::vector dynamic_image_size_nums_; }; } // namespace mindspore diff --git a/mindspore/ccsrc/cxx_api/model/acl/model_converter.cc b/mindspore/ccsrc/cxx_api/model/acl/model_converter.cc index b1dc2e8858..cb165fb86a 100644 --- a/mindspore/ccsrc/cxx_api/model/acl/model_converter.cc +++ b/mindspore/ccsrc/cxx_api/model/acl/model_converter.cc @@ -72,19 +72,6 @@ bool CreateSessionAndGraphRunner() { } // namespace transform::DfGraphPtr ModelConverter::ConvertFuncGraphToAIR(const FuncGraphPtr &anf_graph) { - for (auto &anf_node : anf_graph->parameters()) { - MS_EXCEPTION_IF_NULL(anf_node); - auto para = anf_node->cast(); - MS_EXCEPTION_IF_NULL(para); - // normalize name - std::string name = para->name(); - for (auto pos = name.find(':'); pos != std::string::npos; pos = name.find(':')) { - name = name.substr(0, pos) + "_" + name.substr(pos + 1); - MS_LOG(INFO) << name; - } - para->set_name(name); - } - transform::DfGraphConvertor converter(anf_graph); std::string net_id = "0"; std::string init_graph = "init_subgraph." + net_id; diff --git a/tests/st/cpp/model/test_dynamic_batch_size.cc b/tests/st/cpp/model/test_dynamic_batch_size.cc new file mode 100644 index 0000000000..57462207cd --- /dev/null +++ b/tests/st/cpp/model/test_dynamic_batch_size.cc @@ -0,0 +1,99 @@ +/** + * 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 "common/common_test.h" +#include "include/api/model.h" +#include "include/api/serialization.h" +#include "include/api/context.h" + +using namespace mindspore; + +static const char tensor_add_file[] = "/home/workspace/mindspore_dataset/mindir/add/add.mindir"; +static const float input_data_1[2][2] = {{1,2},{3,4}}; +static const float input_data_2[2][2] = {{2,3},{4,5}}; +static const float input_data_3[1] ={2}; + +class TestDynamicBatchSize : public ST::Common { + public: + TestDynamicBatchSize() {} +}; + +TEST_F(TestDynamicBatchSize, InferMindIR) { + mindspore::GlobalContext::SetGlobalDeviceTarget(mindspore::kDeviceTypeAscend310); + mindspore::GlobalContext::SetGlobalDeviceID(2); + std::map> input_shape; + input_shape.insert(std::make_pair(0,std::vector{-1,2})); + input_shape.insert(std::make_pair(1,std::vector{-1,2})); + auto model_context = std::make_shared(); + std::vector dynamic_batch_size ={1,2,4,8}; + ModelContext::SetDynamicBatchSize(model_context,dynamic_batch_size); + ModelContext::SetInputShapeMap(model_context,input_shape); + auto graph = Serialization::LoadModel(tensor_add_file, ModelType::kMindIR); + Model tensor_add(GraphCell(graph),model_context); + ASSERT_TRUE(tensor_add.Build() == kSuccess); + + // get model inputs + std::vector origin_inputs = tensor_add.GetInputs(); + ASSERT_EQ(origin_inputs.size()-1, 2); + + // prepare input + std::vector outputs; + std::vector inputs; + size_t row = sizeof(input_data_1)/sizeof(input_data_1[0]); + size_t col = sizeof(input_data_1[0])/sizeof(input_data_1[0][0]);; + inputs.emplace_back(origin_inputs[0].Name(), origin_inputs[0].DataType(), origin_inputs[0].Shape(), + input_data_1, sizeof(float) * row*col); + inputs.emplace_back(origin_inputs[1].Name(), origin_inputs[1].DataType(), origin_inputs[1].Shape(), + input_data_2, sizeof(float) * row*col); + inputs.emplace_back(origin_inputs[2].Name(), origin_inputs[2].DataType(), origin_inputs[2].Shape(), + input_data_3, sizeof(float) * 1); + + // infer + ASSERT_TRUE(tensor_add.Predict(inputs, &outputs) == kSuccess); + + // assert input + inputs = tensor_add.GetInputs(); + ASSERT_EQ(inputs.size()-1, 2); + auto after_input_data_1 = inputs[0].Data(); + auto after_input_data_2 = inputs[1].Data(); + const float *p = reinterpret_cast(after_input_data_1.get()); + float input_data1[inputs[0].DataSize() / sizeof(float)] ={0}; + float input_data2[inputs[1].DataSize() / sizeof(float)] ={0}; + size_t k=0,t=0; + for(size_t i=0;i(after_input_data_2.get()); + for (size_t i = 0; i < inputs[1].DataSize() / sizeof(float); ++i) { + ASSERT_LE(std::abs(p[i] - input_data2[i]), 1e-4); + } + + // assert output + for (auto &buffer : outputs) { + auto buffer_data = buffer.Data(); + p = reinterpret_cast(buffer_data.get()); + for (size_t i = 0; i < buffer.DataSize() / sizeof(float); ++i) { + ASSERT_LE(std::abs(p[i] - (input_data1[i] + input_data2[i])), 1e-4); + } + } +}