You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
graphengine/ge/hybrid/model/hybrid_model.cc

321 lines
12 KiB

/**
* Copyright 2019-2020 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 "hybrid_model.h"
#include <vector>
#include "graph/debug/ge_attr_define.h"
#include "graph/load/new_model_manager/model_utils.h"
#include "graph/utils/graph_utils.h"
#include "graph/utils/node_utils.h"
#include "graph/utils/tensor_utils.h"
#include "graph/utils/type_utils.h"
#include "hybrid/common/npu_memory_allocator.h"
#include "hybrid/model/hybrid_model_builder.h"
#include "hybrid/node_executor/node_executor.h"
#include "common/op/ge_op_utils.h"
namespace ge {
namespace hybrid {
namespace {
const int64_t kMemSizeUnknownShape = -1; // Unknown shape mem size
}
HybridModel::HybridModel(GeRootModelPtr ge_model) : ge_root_model_(std::move(ge_model)) {
}
HybridModel::~HybridModel() {
GELOGD("[%s] HybridModel destroyed.", model_name_.c_str());
}
Status HybridModel::Init() {
GELOGD("Start to init hybrid model.");
GE_CHK_STATUS_RET(HybridModelBuilder(*this).Build(), "Failed to build hybrid model.");
GELOGD("HybridModel initialized successfully.");
return SUCCESS;
}
TensorValue* HybridModel::GetVariable(const string &name) const {
auto it = variable_tensors_.find(name);
if (it == variable_tensors_.end()) {
GELOGD("Failed to get variable tensor. var name = [%s]", name.c_str());
return nullptr;
}
GELOGD("Got variable tensor. var name = [%s], tensor = %s", name.c_str(), it->second->DebugString().c_str());
return it->second.get();
}
NodePtr HybridModel::GetVariableNode(const string &name) const {
auto it = device_variable_nodes_.find(name);
if (it != device_variable_nodes_.end()) {
return it->second;
}
auto host_find = host_variable_nodes_.find(name);
if (host_find != host_variable_nodes_.end()) {
return host_find->second;
}
GELOGD("Failed to get variable node by name = [%s]", name.c_str());
return nullptr;
}
const std::vector<domi::TaskDef> *HybridModel::GetTaskDefs(const NodePtr &node) const {
auto it = task_defs_.find(node);
if (it == task_defs_.end()) {
return nullptr;
}
return &it->second;
}
NodeItem *HybridModel::MutableNodeItem(const NodePtr &node) {
auto it = node_items_.find(node);
if (it == node_items_.end()) {
return nullptr;
}
return it->second.get();
}
const NodeItem *HybridModel::GetNodeItem(const NodePtr &node) const {
auto it = node_items_.find(node);
if (it == node_items_.end()) {
return nullptr;
}
return it->second.get();
}
GeModelPtr HybridModel::GetGeModel(const NodePtr &node) const {
auto it = known_shape_sub_models_.find(node);
if (it == known_shape_sub_models_.end()) {
GELOGE(INTERNAL_ERROR, "[%s] Failed to get GeModel for subgraph node.", node->GetName().c_str());
return nullptr;
}
return it->second;
}
const GraphItem* HybridModel::GetRootGraphItem() const {
return root_graph_item_.get();
}
const GraphItem *HybridModel::GetSubgraphItem(const std::string &graph_name) const {
GELOGD("To find subgraph item by name = %s", graph_name.c_str());
auto it = subgraph_items_.find(graph_name);
if (it == subgraph_items_.end()) {
GELOGD("Subgraph item not found by node = %s", graph_name.c_str());
return nullptr;
}
return it->second.get();
}
const GraphItem *HybridModel::GetSubgraphItem(const ComputeGraphPtr &subgraph) const {
if (subgraph == nullptr) {
GELOGE(PARAM_INVALID, "subgraph is nullptr");
return nullptr;
}
auto subgraph_name = subgraph->GetName();
return GetSubgraphItem(subgraph_name);
}
const string &HybridModel::GetModelName() const {
return model_name_;
}
Status HybridModel::GetDynamicBatchInfo(std::vector<std::vector<int64_t>> &batch_info, int32_t &dynamic_type) {
// dynamic shape do not need dynamic batch
batch_info = {};
dynamic_type = -1;
return SUCCESS;
}
void HybridModel::GetUserDesignateShapeOrder(std::vector<std::string> &user_input_shape_order) {
// dynamic shape do not need dynamic batch
user_input_shape_order = {};
}
void HybridModel::GetModelAttr(std::vector<std::string> &dynamic_output_shape_info) {
dynamic_output_shape_info = {};
}
Status HybridModel::GetInputOutputDescInfo(vector<InputOutputDescInfo> &input_desc,
vector<InputOutputDescInfo> &output_desc,
std::vector<uint32_t> &input_formats,
std::vector<uint32_t> &output_formats) {
auto node_item_list = root_graph_item_->GetInputNodes();
if (node_item_list.empty()) {
GELOGE(FAILED, "node item list is empty!");
return FAILED;
}
GE_CHECK_NOTNULL(node_item_list[0]->node);
GE_CHECK_NOTNULL(node_item_list[0]->node->GetOpDesc());
if (node_item_list[0]->node->GetOpDesc()->GetInputsSize() != 1) {
GELOGE(FAILED, "input size of op is not 1!");
return FAILED;
}
GE_CHK_STATUS_RET(GetInputDescInfo(input_desc, input_formats), "get input desc info failed");
GE_CHK_STATUS_RET(GetOutputDescInfo(output_desc, output_formats), "get ouput desc info failed");
return SUCCESS;
}
void HybridModel::SetInputDimsAndShapeRangesInfo(const vector<int64_t> &model_input_dims, std::vector<std::pair<int64_t,int64_t>> &shape_ranges,
InputOutputDescInfo &input) {
for (auto model_input_dim : model_input_dims) {
input.shape_info.dims.push_back(model_input_dim);
}
input.shape_info.shape_ranges = shape_ranges;
return;
}
void HybridModel::CreateInputDimsInfo(const OpDescPtr &op_desc, InputOutputDescInfo &input) {
std::vector<std::pair<int64_t,int64_t>> shape_ranges;
if (is_new_model_desc_ && op_desc->HasAttr(ATTR_NAME_INPUT_DIMS)) {
// When static aipp is set, need to get the model input dims which processed by aipp
vector<int64_t> model_input_dims;
(void)AttrUtils::GetListInt(op_desc, ATTR_NAME_INPUT_DIMS, model_input_dims);
SetInputDimsAndShapeRangesInfo(model_input_dims, shape_ranges, input);
return;
}
// judge if this data is linked dynamic aipp first, multiply batch has been considered
if (op_desc->HasAttr("_dynamic_aipp_input_dims")) {
vector<int64_t> dynamic_aipp_input_dims;
(void)AttrUtils::GetListInt(op_desc, "_dynamic_aipp_input_dims", dynamic_aipp_input_dims);
SetInputDimsAndShapeRangesInfo(dynamic_aipp_input_dims, shape_ranges, input);
return;
} else {
vector<int64_t> input_dims = op_desc->GetInputDescPtr(0)->GetShape().GetDims();
op_desc->GetInputDescPtr(0)->GetShapeRange(shape_ranges);
SetInputDimsAndShapeRangesInfo(input_dims, shape_ranges, input);
return;
}
}
Status HybridModel::GetInputDescInfo(vector<InputOutputDescInfo> &input_desc, std::vector<uint32_t> &formats) {
auto node_item_list = root_graph_item_->GetInputNodes();
for (auto &node_item : node_item_list) {
InputOutputDescInfo input;
GE_CHECK_NOTNULL(node_item->node);
auto op_desc = node_item->node->GetOpDesc();
GE_CHECK_NOTNULL(op_desc);
GE_CHECK_NOTNULL(op_desc->GetInputDescPtr(0));
Format format = op_desc->GetInputDescPtr(0)->GetFormat();
input.data_type = op_desc->GetInputDescPtr(0)->GetDataType();
input.name = op_desc->GetName();
int64_t input_size = 0;
GE_CHK_STATUS_RET(TensorUtils::GetSize(*op_desc->GetInputDescPtr(0), input_size), "get input size failed.");
// support dynamic shape
if (input_size < 0) {
GELOGD("dynamic shape scene, input size is unknown. "
"format=%d, data_type=%d, input_size=%ld",
format, input.data_type, input_size);
input_size = kMemSizeUnknownShape; // -1
}
// not support dynamic shape input for now, so input_size here will be not less than zero.
input.size = input_size;
CreateInputDimsInfo(op_desc, input);
formats.push_back(format);
input_desc.push_back(input);
}
is_new_model_desc_ = false;
return SUCCESS;
}
void HybridModel::CreateOutput(ConstGeTensorDescPtr &output_desc, InputOutputDescInfo &output_desc_info, uint32_t &format_result) {
GE_IF_BOOL_EXEC(output_desc == nullptr, GELOGE(FAILED, "output desc ptr is nullptr"); return );
Format format = output_desc->GetFormat();
GeShape shape = output_desc->GetShape();
std::vector<std::pair<int64_t,int64_t>> shape_ranges;
output_desc->GetShapeRange(shape_ranges);
DataType data_type = output_desc->GetDataType();
format_result = format;
if (format == FORMAT_FRACTAL_Z) { // FraczToHWCK
int64_t k = shape.GetDim(0); // 0: first dim
int64_t c = shape.GetDim(1); // 1: second dim
int64_t h = shape.GetDim(2); // 2: third dim
int64_t w = shape.GetDim(3); // 3: forth dim
output_desc_info.shape_info.dims.push_back(h);
output_desc_info.shape_info.dims.push_back(w);
output_desc_info.shape_info.dims.push_back(c);
output_desc_info.shape_info.dims.push_back(k);
if (shape_ranges.size() == 4) { // 4 dims
output_desc_info.shape_info.shape_ranges.push_back(shape_ranges[2]); // h:2
output_desc_info.shape_info.shape_ranges.push_back(shape_ranges[3]); // w:3
output_desc_info.shape_info.shape_ranges.push_back(shape_ranges[1]); // c:1
output_desc_info.shape_info.shape_ranges.push_back(shape_ranges[0]); // k:0
}
format_result = FORMAT_HWCN;
} else {
for (size_t j = 0; j < shape.GetDimNum(); j++) {
output_desc_info.shape_info.dims.push_back(shape.GetDim(j));
}
output_desc_info.shape_info.shape_ranges = shape_ranges;
}
int64_t tensor_size = 0;
(void)TensorUtils::CalcTensorMemSize(shape, format, data_type, tensor_size);
output_desc_info.size = static_cast<uint64_t>(tensor_size);
output_desc_info.data_type = output_desc->GetDataType();
}
Status HybridModel::GetOutputDescInfo(vector<InputOutputDescInfo> &output_desc, std::vector<uint32_t> &formats) {
std::vector<ConstGeTensorDescPtr> output_desc_list;
GE_CHK_STATUS_RET(root_graph_item_->GetOutputDescList(output_desc_list), "get output desc info failed"); // output_desc_list contains vaild input desc
vector<std::string> out_node_names;
(void)ge::AttrUtils::GetListStr(ge_root_model_->GetRootGraph(), ATTR_MODEL_OUT_NODES_NAME, out_node_names);
GE_CHECK_NOTNULL(root_graph_item_->GetOutputNode());
auto op_desc = root_graph_item_->GetOutputNode()->op_desc;
GE_CHECK_NOTNULL(op_desc);
auto out_size = static_cast<uint32_t>(op_desc->GetInputsSize());
GE_CHK_BOOL_RET_STATUS(out_size == output_desc_list.size(), FAILED, "output size[%u] not match output_desc_list size[%zu]", out_size, output_desc_list.size());
for (uint32_t index = 0; index < out_size; ++index) {
string output_name;
std::vector<std::string> src_name = op_desc->GetSrcName();
std::vector<int64_t> src_index = op_desc->GetSrcIndex();
if (out_size == out_node_names.size()) {
bool contains_colon = out_node_names[index].find(":") != std::string::npos;
output_name = contains_colon ? out_node_names[index] : out_node_names[index] + ":" + std::to_string(src_index[index]);
} else {
output_name = std::string("output_") + std::to_string(index) + "_" + src_name[index] + "_" + std::to_string(src_index[index]);
}
InputOutputDescInfo output_desc_info;
output_desc_info.name = output_name;
uint32_t format_result;
CreateOutput(output_desc_list[index], output_desc_info, format_result);
output_desc.push_back(output_desc_info);
formats.push_back(format_result);
}
return SUCCESS;
}
} // namespace hybrid
} // namespace ge