dynamic_batch

Signed-off-by: zhupuxu <zhupuxu@huawei.com>
This commit is contained in:
zhupuxu 2021-03-08 10:28:44 +08:00
parent 68eb5125c6
commit 5ca25451ee
9 changed files with 317 additions and 75 deletions

View File

@ -19,6 +19,7 @@
#include <string>
#include <memory>
#include <vector>
#include <map>
#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> &context, const std::string &shape);
static inline std::string GetInputShape(const std::shared_ptr<Context> &context);
static void SetInputShapeMap(const std::shared_ptr<Context> &context, const std::map<int, std::vector<int>> &shape);
static std::map<int, std::vector<int>> GetInputShapeMap(const std::shared_ptr<Context> &context);
static void SetDynamicBatchSize(const std::shared_ptr<Context> &context,
const std::vector<size_t> &dynamic_batch_size);
static inline std::string GetDynamicBatchSize(const std::shared_ptr<Context> &context);
static void SetOutputType(const std::shared_ptr<Context> &context, enum DataType output_type);
static enum DataType GetOutputType(const std::shared_ptr<Context> &context);
@ -107,6 +115,7 @@ struct MS_API ModelContext : public Context {
static void SetGpuTrtInferMode(const std::shared_ptr<Context> &context, const std::vector<char> &gpu_trt_infer_mode);
static std::vector<char> GetGpuTrtInferModeChar(const std::shared_ptr<Context> &context);
static std::vector<char> GetDynamicBatchSizeChar(const std::shared_ptr<Context> &context);
};
void GlobalContext::SetGlobalDeviceTarget(const std::string &device_target) {
@ -162,6 +171,10 @@ std::string ModelContext::GetFusionSwitchConfigPath(const std::shared_ptr<Contex
return CharToString(GetFusionSwitchConfigPathChar(context));
}
std::string ModelContext::GetDynamicBatchSize(const std::shared_ptr<Context> &context) {
return CharToString(GetDynamicBatchSizeChar(context));
}
void ModelContext::SetGpuTrtInferMode(const std::shared_ptr<Context> &context, const std::string &gpu_trt_infer_mode) {
SetGpuTrtInferMode(context, StringToChar(gpu_trt_infer_mode));
}

View File

@ -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<char> ModelContext::GetInputShapeChar(const std::shared_ptr<Context>
return StringToChar(ref);
}
void ModelContext::SetInputShapeMap(const std::shared_ptr<Context> &context,
const std::map<int, std::vector<int>> &shape) {
MS_EXCEPTION_IF_NULL(context);
context->data->params[kModelOptionInputShapeMap] = shape;
}
std::map<int, std::vector<int>> ModelContext::GetInputShapeMap(const std::shared_ptr<Context> &context) {
MS_EXCEPTION_IF_NULL(context);
return GetValue<std::map<int, std::vector<int>>>(context, kModelOptionInputShapeMap);
}
void ModelContext::SetOutputType(const std::shared_ptr<Context> &context, enum DataType output_type) {
MS_EXCEPTION_IF_NULL(context);
if (context->data == nullptr) {
@ -235,4 +249,23 @@ std::vector<char> ModelContext::GetGpuTrtInferModeChar(const std::shared_ptr<Con
const std::string &ref = GetValue<std::string>(context, kModelOptionGpuTrtInferMode);
return StringToChar(ref);
}
void ModelContext::SetDynamicBatchSize(const std::shared_ptr<Context> &context, const std::vector<size_t> &batch_size) {
MS_EXCEPTION_IF_NULL(context);
if (context->data == nullptr) {
context->data = std::make_shared<Data>();
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<char> ModelContext::GetDynamicBatchSizeChar(const std::shared_ptr<Context> &context) {
MS_EXCEPTION_IF_NULL(context);
const std::string &ref = GetValue<std::string>(context, kModelOptionDynamicBatchSize);
return StringToChar(ref);
}
} // namespace mindspore

View File

@ -53,18 +53,15 @@ inline static void PushbackIfNotNull(U *vec, T &&item) {
}
static void ConstructTensorDesc(const std::vector<AclTensorInfo> &acl_tensor_list, std::vector<std::string> *names,
std::vector<std::vector<int64_t>> *shapes, std::vector<enum DataType> *data_types,
std::vector<size_t> *mem_sizes) {
std::vector<std::vector<int64_t>> *shapes, std::vector<enum DataType> *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<int64_t> &shape) {
}
Status ModelProcess::ConstructTensors(const std::vector<AclTensorInfo> &acl_tensor_list,
std::vector<MSTensor> *tensor_list) {
std::vector<MSTensor> *tensor_list, const std::vector<size_t> &mem_sizes) {
MS_EXCEPTION_IF_NULL(tensor_list);
std::vector<std::string> names;
std::vector<std::vector<int64_t>> shapes;
std::vector<enum DataType> data_types;
std::vector<size_t> 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<AclTensorInfo> &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<AclTensorInfo> &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<MSTensor> &inputs) {
size_t index;
aclError ret;
input_size_.clear();
for (auto input : inputs) {
input_size_.push_back(input.DataSize());
}
auto *p = reinterpret_cast<const float *>(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<MSTensor> &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<MSTensor> &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<MSTensor> *outputs) {
}
std::vector<MSTensor> 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<MSTensor> ModelProcess::GetInputs() {
}
std::vector<MSTensor> 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();

View File

@ -61,10 +61,13 @@ class ModelProcess {
private:
Status CreateDataBuffer(void **data_mem_buffer, size_t buffer_size, aclmdlDataset *dataset);
Status CheckAndInitInput(const std::vector<MSTensor> &inputs);
Status ConstructTensors(const std::vector<AclTensorInfo> &acl_tensor_list, std::vector<MSTensor> *tensor_list);
Status ConstructTensors(const std::vector<AclTensorInfo> &acl_tensor_list, std::vector<MSTensor> *tensor_list,
const std::vector<size_t> &mem_sizes);
Status BuildOutputs(std::vector<MSTensor> *outputs);
Status SetBatchSize(const std::vector<MSTensor> &inputs);
Status InitInputsBuffer();
Status InitOutputsBuffer();
Status ResetOutputSize();
void DestroyInputsDataset();
void DestroyInputsDataMem();
@ -81,6 +84,9 @@ class ModelProcess {
std::vector<AclTensorInfo> output_infos_;
std::vector<MSTensor> input_tensors_;
std::vector<MSTensor> output_tensors_;
std::vector<size_t> output_size_;
std::vector<size_t> input_size_;
size_t GetDynamicDims(const std::vector<AclTensorInfo> &);
};
} // namespace mindspore

View File

@ -47,6 +47,20 @@ Status AclModel::Build() {
graph = iter->second;
} else {
auto func_graph = ModelImpl::GetFuncGraph();
auto inputs = func_graph->parameters();
std::vector<std::string> input_names;
for (auto node : inputs) {
auto para = node->cast<ParameterPtr>();
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);

View File

@ -27,10 +27,9 @@ AclModelOptions::AclModelOptions(const std::shared_ptr<Context> &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> &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<std::string> &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<std::string, std::string>, std::map<std::string, std::string>> AclModelOptions::GenAclOptions()
const {
const std::map<std::string const *, std::string> 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<std::string const *, std::string> 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<std::string, std::string> init_options;
std::map<std::string, std::string> build_options;

View File

@ -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> &context);
~AclModelOptions() = default;
std::string GenAclOptionsKey() const;
void RenameInput(const std::vector<std::string> &);
// return tuple<init_options, build_options>
std::tuple<std::map<std::string, std::string>, std::map<std::string, std::string>> 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<int, std::vector<int>> input_shape_map_;
std::vector<std::string> dynamic_image_size_nums_;
};
} // namespace mindspore

View File

@ -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<ParameterPtr>();
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;

View File

@ -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 <string>
#include <vector>
#include <map>
#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<int,std::vector<int>> input_shape;
input_shape.insert(std::make_pair(0,std::vector<int>{-1,2}));
input_shape.insert(std::make_pair(1,std::vector<int>{-1,2}));
auto model_context = std::make_shared<ModelContext>();
std::vector<size_t> 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<MSTensor> origin_inputs = tensor_add.GetInputs();
ASSERT_EQ(origin_inputs.size()-1, 2);
// prepare input
std::vector<MSTensor> outputs;
std::vector<MSTensor> 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<const float *>(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<row;i++)
for(size_t j=0;j<col;j++){
input_data1[k++]=input_data_1[i][j];
input_data2[t++]=input_data_2[i][j];
}
for (size_t i = 0; i < inputs[0].DataSize() / sizeof(float); ++i) {
ASSERT_LE(std::abs(p[i] - input_data1[i]), 1e-4);
}
p = reinterpret_cast<const float *>(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<const float *>(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);
}
}
}