diff --git a/ge/CMakeLists.txt b/ge/CMakeLists.txt index 26a7ee99..3a0f7638 100755 --- a/ge/CMakeLists.txt +++ b/ge/CMakeLists.txt @@ -144,6 +144,7 @@ set(TRAIN_SRC_LIST "graph/passes/atomic_addr_clean_pass.cc" "graph/passes/mark_same_addr_pass.cc" "graph/passes/mark_graph_unknown_status_pass.cc" + "graph/passes/dynamic_single_op_reset_shape_pass.cc" "graph/passes/mark_agnostic_pass.cc" "graph/partition/dynamic_shape_partition.cc" "graph/partition/stage_partition.cc" @@ -434,6 +435,7 @@ set(INFER_SRC_LIST "graph/passes/atomic_addr_clean_pass.cc" "graph/passes/mark_same_addr_pass.cc" "graph/passes/mark_graph_unknown_status_pass.cc" + "graph/passes/dynamic_single_op_reset_shape_pass.cc" "graph/passes/mark_agnostic_pass.cc" "graph/common/omg_util.cc" "graph/common/bcast.cc" diff --git a/ge/ge_inference.mk b/ge/ge_inference.mk index 80887e8b..bfb612ea 100755 --- a/ge/ge_inference.mk +++ b/ge/ge_inference.mk @@ -109,6 +109,7 @@ OMG_HOST_SRC_FILES := \ graph/passes/atomic_addr_clean_pass.cc \ graph/passes/mark_same_addr_pass.cc \ graph/passes/mark_graph_unknown_status_pass.cc \ + graph/passes/dynamic_single_op_reset_shape_pass.cc \ graph/passes/mark_agnostic_pass.cc \ graph/common/omg_util.cc \ graph/common/bcast.cc \ diff --git a/ge/ge_runner.mk b/ge/ge_runner.mk index c0f59320..25718e9b 100644 --- a/ge/ge_runner.mk +++ b/ge/ge_runner.mk @@ -113,6 +113,7 @@ LIBGE_LOCAL_SRC_FILES := \ graph/passes/atomic_addr_clean_pass.cc \ graph/passes/mark_same_addr_pass.cc \ graph/passes/mark_graph_unknown_status_pass.cc \ + graph/passes/dynamic_single_op_reset_shape_pass.cc \ graph/passes/mark_agnostic_pass.cc \ graph/partition/dynamic_shape_partition.cc \ graph/partition/stage_partition.cc \ diff --git a/ge/generator/ge_generator.cc b/ge/generator/ge_generator.cc index aecd87af..acb029e9 100644 --- a/ge/generator/ge_generator.cc +++ b/ge/generator/ge_generator.cc @@ -47,6 +47,8 @@ const char *const kEngineNameDefault = "default"; const char *const kVectorEngine = "VectorEngine"; const char *const kAIcoreEngine = "AIcoreEngine"; const char *const kFileNameSuffix = "online"; +const size_t kDynamicDimSize = 1; +const int64_t kDynamicDimValue = -2; std::map engine_type_map{ {ge::ENGINE_SYS, kEngineNameDefault}, {ge::ENGINE_AICORE, kAIcoreEngine}, {ge::ENGINE_VECTOR, kVectorEngine}}; @@ -248,6 +250,43 @@ static void GetOpsProtoPath(string &opsproto_path) { opsproto_path = (path_base + "ops/op_proto/custom/" + ":") + (path_base + "ops/op_proto/built-in/"); } +static Status CheckShapeReset(const OpDescPtr &op_desc, bool &change_shape_flag) { + GE_CHECK_NOTNULL_EXEC(op_desc, return PARAM_INVALID); + change_shape_flag = false; + for (size_t i = 0; i < op_desc->GetAllInputsDesc().size(); i++) { + auto input_desc = op_desc->MutableInputDesc(static_cast(i)); + GE_CHECK_NOTNULL(input_desc); + // pass scalar input desc + auto dims = input_desc->GetShape().GetDims(); + if (dims.size() == kDynamicDimSize && dims[0] == kDynamicDimValue) { + change_shape_flag = true; + } + } + return SUCCESS; +} + +static void ResetTensorVecShape(const vector &inputs, vector &inputs_dynamic) { + for (auto input : inputs) { + auto input_desc = input.GetTensorDesc(); + GeShape shape_ori = input_desc.GetShape(); + + std::vector dynamic_shape_dims = {kDynamicDimValue}; + GeShape dynamic_shape(dynamic_shape_dims); + + ge::GeTensor inputTensor; + ge::GeTensorDesc desc(input_desc); + + bool is_const = false; + (void)AttrUtils::GetBool(input_desc, CONST_ATTR_NAME_INPUT, is_const); + if (!is_const && shape_ori.GetDims().size() > 0) { + desc.SetShape(dynamic_shape); + } + + inputTensor.SetTensorDesc(desc); + inputs_dynamic.push_back(inputTensor); + } +} + class GeGenerator::Impl { public: Impl(OmgContext &omg_context) : omg_context_(omg_context) {} @@ -638,7 +677,18 @@ Status GeGenerator::BuildSingleOp(OpDescPtr &op_desc, const vector &in } GeModelPtr &ge_model = name_to_ge_model.begin()->second; GELOGD("The opType in op_desc_tmp is [%s]", op_desc_tmp->GetType().c_str()); - GE_CHK_STATUS_RET_NOLOG(impl_->SaveParams(ge_model, op_desc_tmp->GetType(), op_attrs, inputs, outputs)); + + bool dynamic_flag = false; + if (CheckShapeReset(op_desc, dynamic_flag) == SUCCESS && dynamic_flag) { + vector inputs_dynamic; + vector outputs_dynamic; + ResetTensorVecShape(inputs, inputs_dynamic); + ResetTensorVecShape(outputs, outputs_dynamic); + GE_CHK_STATUS_RET_NOLOG( + impl_->SaveParams(ge_model, op_desc_tmp->GetType(), op_attrs, inputs_dynamic, outputs_dynamic)); + } else { + GE_CHK_STATUS_RET_NOLOG(impl_->SaveParams(ge_model, op_desc_tmp->GetType(), op_attrs, inputs, outputs)); + } GE_CHK_STATUS_RET_NOLOG(impl_->SaveModel(model_file_name, ge_model, model_buff)); return SUCCESS; } diff --git a/ge/graph/manager/graph_manager.cc b/ge/graph/manager/graph_manager.cc index 4f5c190d..46a0ec2e 100755 --- a/ge/graph/manager/graph_manager.cc +++ b/ge/graph/manager/graph_manager.cc @@ -56,6 +56,7 @@ #include "graph/passes/iterator_op_pass.h" #include "graph/passes/link_gen_mask_nodes_pass.h" #include "graph/passes/mark_graph_unknown_status_pass.h" +#include "graph/passes/dynamic_single_op_reset_shape_pass.h" #include "graph/passes/merge_pass.h" #include "graph/passes/merge_input_memcpy_pass.h" #include "graph/passes/merge_to_stream_merge_pass.h" @@ -631,11 +632,22 @@ Status GraphManager::ReplaceSubgraphWithOriGraph(const ComputeGraphPtr &compute_ Status GraphManager::SetSubgraph(uint64_t session_id, ComputeGraphPtr compute_graph, GraphPartitioner &partitioner) { GE_CHECK_NOTNULL(compute_graph); + PassManager pass_for_dynamic_shape_reset_optimize; + GE_CHK_STATUS_RET(pass_for_dynamic_shape_reset_optimize.AddPass( + "SetSubgraph::AfterSetSubgraph::DynamicSingleOpResetShapePass", new (std::nothrow) DynamicSingleOpResetShapePass)) + GE_TIMESTAMP_START(pass_for_dynamic_shape_reset_optimize); + Status ret = pass_for_dynamic_shape_reset_optimize.Run(compute_graph); + GE_TIMESTAMP_END(pass_for_dynamic_shape_reset_optimize, "SetSubgraph::AfterSetSubgraph"); + if (ret != SUCCESS && ret != NOT_CHANGED) { + GELOGE(ret, "Run passes when optimize subgraph failed"); + return ret; + } + auto sub_graph_map = partitioner.GetSubGraphMap(); GELOGD("Directly optimize subgraph with build mode:%s, and step:%s.", options_.build_mode.c_str(), options_.build_step.c_str()); - Status ret = OptimizeSubGraphWithMultiThreads(compute_graph, sub_graph_map, session_id); + ret = OptimizeSubGraphWithMultiThreads(compute_graph, sub_graph_map, session_id); if (ret != SUCCESS) { GELOGE(ret, "Multiply optimize subgraph failed"); return ret; diff --git a/ge/graph/passes/dynamic_single_op_reset_shape_pass.cc b/ge/graph/passes/dynamic_single_op_reset_shape_pass.cc new file mode 100644 index 00000000..d50b6df9 --- /dev/null +++ b/ge/graph/passes/dynamic_single_op_reset_shape_pass.cc @@ -0,0 +1,159 @@ +/** + * Copyright 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 "graph/passes/dynamic_single_op_reset_shape_pass.h" +#include "common/ge_inner_error_codes.h" +#include "graph/utils/node_utils.h" +#include "graph/utils/graph_utils.h" +#include "graph/utils/tensor_utils.h" +#include "graph/utils/op_desc_utils.h" +#include "graph/utils/type_utils.h" +#include "graph/debug/ge_attr_define.h" + +namespace ge { +namespace { +const int64_t kDynamicShapeDim = -2; +const char *const kEngineNameAiCpu = "DNN_VM_AICPU_ASCEND"; +const char *const kEngineNameAiCpuTf = "DNN_VM_AICPU"; +} // namespace +Status DynamicSingleOpResetShapePass::Run(ComputeGraphPtr graph) { + GE_CHECK_NOTNULL(graph); + + std::shared_ptr instance = ge::GELib::GetInstance(); + if (instance == nullptr || !instance->InitFlag()) { + GELOGE(ge::GE_CLI_GE_NOT_INITIALIZED, "Run CompileNodesPass failed."); + return ge::GE_CLI_GE_NOT_INITIALIZED; + } + + // pass if graph has not aicpu node. + bool is_not_aicpu = false; + if (CheckAllAicpuNodes(graph, is_not_aicpu) != SUCCESS) { + GELOGE(ge::GE_CLI_GE_NOT_INITIALIZED, "Check if graph has not aicpu node failed."); + return ge::GE_CLI_GE_NOT_INITIALIZED; + } + if (is_not_aicpu) { + GELOGI("The graph [%s] has not aicpu node, whose aicpu nodes would not be reset dynamic shape", + graph->GetName().c_str()); + return SUCCESS; + } + + for (const auto &node : graph->GetDirectNode()) { + GE_CHECK_NOTNULL(node->GetOpDesc()); + // pass input and output node + if (node->GetType() == DATA || node->GetType() == CONSTANT || node->GetType() == CONSTANTOP || + node->GetType() == NETOUTPUT) { + continue; + } + + // pass node without attr: ATTR_DYNAMIC_SHAPE_SINGLE_AICPU + bool single_aicpu_unknown = false; + if (!AttrUtils::GetBool(node->GetOpDesc(), ATTR_DYNAMIC_SHAPE_SINGLE_AICPU, single_aicpu_unknown) || + !single_aicpu_unknown) { + continue; + } + + // reset aicpu shape to unknown shape + auto op_desc = node->GetOpDesc(); + if (ResetOpShape(op_desc) != SUCCESS) { + GELOGE(ge::GE_CLI_GE_NOT_INITIALIZED, "Reset node[%s] dynamic shapr failed.", node->GetName().c_str()); + return ge::GE_CLI_GE_NOT_INITIALIZED; + } + GELOGD("Reset dynamic aicpu node [%s] shape success!", node->GetName().c_str()); + } + + GELOGD("Reset dynamic aicpu nodes shape of graph [%s] success!", graph->GetName().c_str()); + return SUCCESS; +} + +Status DynamicSingleOpResetShapePass::CheckAllAicpuNodes(const ComputeGraphPtr &graph, bool &is_not_aicpu) { + is_not_aicpu = false; + for (const auto &node : graph->GetDirectNode()) { + GE_CHECK_NOTNULL(node->GetOpDesc()); + // pass input and output node + if (node->GetType() == DATA || node->GetType() == CONSTANT || node->GetType() == CONSTANTOP || + node->GetType() == NETOUTPUT) { + continue; + } + + // find if there are aicpu nodes. + auto op_desc = node->GetOpDesc(); + string engine_name = op_desc->GetOpEngineName(); + if (engine_name.empty()) { + GELOGE(GRAPH_FAILED, "Get engine failed of node[%s].", node->GetName().c_str()); + return GRAPH_FAILED; + } + if (engine_name != kEngineNameAiCpu && engine_name != kEngineNameAiCpuTf) { + is_not_aicpu = true; + return SUCCESS; + } + } + return SUCCESS; +} + +bool DynamicSingleOpResetShapePass::CheckIfConstInput(const GeTensorDescPtr &input_tensor_desc) { + bool is_const = false; + (void)AttrUtils::GetBool(input_tensor_desc, CONST_ATTR_NAME_INPUT, is_const); + return is_const; +} + +Status DynamicSingleOpResetShapePass::ResetOpShape(OpDescPtr &op_desc) { + GE_CHECK_NOTNULL(op_desc); + std::vector dynamic_shape_dims = {kDynamicShapeDim}; + GeShape dynamic_shape(dynamic_shape_dims); + bool reset_shape_flag = false; + if (ResetInputTensorShape(op_desc, dynamic_shape, reset_shape_flag) == SUCCESS && reset_shape_flag) { + (void)ResetOutputTensorShape(op_desc, dynamic_shape); + } + return SUCCESS; +} + +Status DynamicSingleOpResetShapePass::ResetInputTensorShape(OpDescPtr &op_desc, const GeShape &dynamic_shape, + bool &reset_shape_flag) { + reset_shape_flag = false; + GE_CHECK_NOTNULL(op_desc); + for (size_t i = 0; i < op_desc->GetAllInputsDesc().size(); i++) { + auto input_desc = op_desc->MutableInputDesc(static_cast(i)); + GE_CHECK_NOTNULL(input_desc); + // pass scalar input desc + auto dims_ori = input_desc->GetShape().GetDims(); + if (dims_ori.size() == 0) { + continue; + } + // pass const input + if (CheckIfConstInput(input_desc)) { + continue; + } + reset_shape_flag = true; + input_desc->SetShape(dynamic_shape); + } + return SUCCESS; +} + +Status DynamicSingleOpResetShapePass::ResetOutputTensorShape(OpDescPtr &op_desc, const GeShape &dynamic_shape) { + GE_CHECK_NOTNULL(op_desc); + for (size_t i = 0; i < op_desc->GetAllOutputsDesc().size(); i++) { + auto output_desc = op_desc->MutableOutputDesc(static_cast(i)); + GE_CHECK_NOTNULL(output_desc); + // pass scalar input desc + auto output_dims_ori = output_desc->GetShape().GetDims(); + if (output_dims_ori.size() == 0) { + continue; + } + output_desc->SetShape(dynamic_shape); + } + return SUCCESS; +} +} // namespace ge \ No newline at end of file diff --git a/ge/graph/passes/dynamic_single_op_reset_shape_pass.h b/ge/graph/passes/dynamic_single_op_reset_shape_pass.h new file mode 100644 index 00000000..897fcac6 --- /dev/null +++ b/ge/graph/passes/dynamic_single_op_reset_shape_pass.h @@ -0,0 +1,36 @@ +/** + * Copyright 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. + */ + +#ifndef GE_GRAPH_PASSES_DYNAMIC_SINGLE_OP_RESET_SHAPE_PASS_H_ +#define GE_GRAPH_PASSES_DYNAMIC_SINGLE_OP_RESET_SHAPE_PASS_H_ +#include "graph/graph.h" +#include "inc/graph_pass.h" +#include "init/gelib.h" + +namespace ge { +class DynamicSingleOpResetShapePass : public GraphPass { + public: + Status Run(ComputeGraphPtr graph) override; + + private: + Status ResetOpShape(OpDescPtr &op_desc); + Status ResetInputTensorShape(OpDescPtr &op_desc, const GeShape &dynamic_shape, bool &reset_shape_flag); + Status ResetOutputTensorShape(OpDescPtr &op_desc, const GeShape &dynamic_shape); + Status CheckAllAicpuNodes(const ComputeGraphPtr &graph, bool &is_not_aicpu); + bool CheckIfConstInput(const GeTensorDescPtr &input_tensor_desc); +}; +} // namespace ge +#endif // GE_GRAPH_PASSES_DYNAMIC_SINGLE_OP_RESET_SHAPE_PASS_H_ diff --git a/tests/ut/ge/CMakeLists.txt b/tests/ut/ge/CMakeLists.txt index fb065529..6fad46bf 100755 --- a/tests/ut/ge/CMakeLists.txt +++ b/tests/ut/ge/CMakeLists.txt @@ -182,6 +182,7 @@ set(COMMON_SRC_FILES "${GE_CODE_DIR}/ge/graph/passes/atomic_addr_clean_pass.cc" "${GE_CODE_DIR}/ge/graph/passes/mark_same_addr_pass.cc" "${GE_CODE_DIR}/ge/graph/passes/mark_graph_unknown_status_pass.cc" + "${GE_CODE_DIR}/ge/graph/passes/dynamic_single_op_reset_shape_pass.cc" "${GE_CODE_DIR}/ge/graph/passes/mark_agnostic_pass.cc" "${GE_CODE_DIR}/ge/graph/passes/dimension_compute_pass.cc" "${GE_CODE_DIR}/ge/graph/passes/dimension_adjust_pass.cc"