已合并
[binary]【PR】: 新增option ge.inputHintValue 支持host tensor 符号化推导 #4251
chengyutao3创建于 8月4日
[binary]【PR】: 新增option ge.inputHintValue 支持host tensor 符号化推导 #4251
已合并
共 17 个文件变更+688-119
| @@ -20,6 +20,7 @@ namespace ge { | |||
| 20 | namespace { | 20 | namespace { |
| 21 | const std::unordered_set<std::string> kFirstEPOptions = {INPUT_SHAPE, | 21 | const std::unordered_set<std::string> kFirstEPOptions = {INPUT_SHAPE, |
| 22 | INPUT_HINT_SHAPE, | 22 | INPUT_HINT_SHAPE, |
| 23 | + INPUT_HINT_VALUE, | ||
| 23 | INPUT_SHAPE_RANGE, | 24 | INPUT_SHAPE_RANGE, |
| 24 | INPUT_FORMAT, | 25 | INPUT_FORMAT, |
| 25 | ge::OPTION_INPUT_REUSE_MEM_INDEXES, | 26 | ge::OPTION_INPUT_REUSE_MEM_INDEXES, |
| @@ -21,6 +21,8 @@ | |||
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | + | ||
| 25 | + | ||
| 24 | 26 | ||
| 25 | do { \ | 27 | do { \ |
| 26 | bool tmp_ret = (exp); \ | 28 | bool tmp_ret = (exp); \ |
| @@ -78,18 +80,60 @@ bool IsEnableBatchCpy(const std::vector<gert::Tensor> &inputs) { | |||
| 78 | 80 | ||
| 79 | // todo if host exec option, remember to handle | 81 | // todo if host exec option, remember to handle |
| 80 | Status CopyHostInputsToDevice(UserGraphExecution &execution_task, Allocator *const allocator, | 82 | Status CopyHostInputsToDevice(UserGraphExecution &execution_task, Allocator *const allocator, |
| 81 | - std::vector<gert::Tensor> &device_gert_tensors) { | 83 | + std::vector<gert::Tensor> &device_gert_tensors, |
| 84 | + const std::set<size_t> &keep_on_host_idxs = {}) { | ||
| 82 | const auto *external_rt_inputs = execution_task.external_rt_inputs; | 85 | const auto *external_rt_inputs = execution_task.external_rt_inputs; |
| 83 | auto &inputs_memblocks = execution_task.inputs_memblocks; | 86 | auto &inputs_memblocks = execution_task.inputs_memblocks; |
| 84 | bool enable_input_batch_cpy = IsEnableBatchCpy(*external_rt_inputs); | 87 | bool enable_input_batch_cpy = IsEnableBatchCpy(*external_rt_inputs); |
| 85 | - GE_ASSERT_SUCCESS(TensorTransUtils::TransHostGertTensorsToDevice(allocator, *external_rt_inputs, device_gert_tensors, | 88 | + if (keep_on_host_idxs.empty()) { |
| 86 | - inputs_memblocks, enable_input_batch_cpy)); | 89 | + GE_ASSERT_SUCCESS(TensorTransUtils::TransHostGertTensorsToDevice( |
| 90 | + allocator, *external_rt_inputs, device_gert_tensors, inputs_memblocks, enable_input_batch_cpy)); | ||
| 91 | + return SUCCESS; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + std::vector<gert::Tensor> to_device_src; | ||
| 95 | + std::vector<gert::Tensor> host_vec; | ||
| 96 | + for (size_t i = 0U; i < external_rt_inputs->size(); ++i) { | ||
| 97 | + gert::Tensor src((*external_rt_inputs)[i].GetShape(), (*external_rt_inputs)[i].GetFormat(), | ||
| 98 | + (*external_rt_inputs)[i].GetDataType()); | ||
| 99 | + src.MutableOriginShape() = (*external_rt_inputs)[i].GetOriginShape(); | ||
| 100 | + src.MutableStorageShape() = (*external_rt_inputs)[i].GetStorageShape(); | ||
| 101 | + src.MutableTensorData().ShareFrom((*external_rt_inputs)[i].GetTensorData()); | ||
| 102 | + if (keep_on_host_idxs.count(i) > 0U) { | ||
| 103 | + host_vec.emplace_back(std::move(src)); | ||
| 104 | + } else { | ||
| 105 | + to_device_src.emplace_back(std::move(src)); | ||
| 106 | + } | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + std::vector<gert::Tensor> to_device_dst; | ||
| 110 | + std::vector<MemBlock *> to_device_blocks(to_device_src.size(), nullptr); | ||
| 111 | + if (!to_device_src.empty()) { | ||
| 112 | + GE_ASSERT_SUCCESS(TensorTransUtils::TransHostGertTensorsToDevice(allocator, to_device_src, to_device_dst, | ||
| 113 | + to_device_blocks, enable_input_batch_cpy)); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + device_gert_tensors.resize(external_rt_inputs->size()); | ||
| 117 | + inputs_memblocks.resize(external_rt_inputs->size(), nullptr); | ||
| 118 | + size_t host_pos = 0U; | ||
| 119 | + size_t device_pos = 0U; | ||
| 120 | + for (size_t i = 0U; i < external_rt_inputs->size(); ++i) { | ||
| 121 | + if (keep_on_host_idxs.count(i) > 0U) { | ||
| 122 | + device_gert_tensors[i] = std::move(host_vec[host_pos++]); | ||
| 123 | + } else { | ||
| 124 | + device_gert_tensors[i] = std::move(to_device_dst[device_pos]); | ||
| 125 | + inputs_memblocks[i] = to_device_blocks[device_pos]; | ||
| 126 | + ++device_pos; | ||
| 127 | + } | ||
| 128 | + } | ||
| 87 | return SUCCESS; | 129 | return SUCCESS; |
| 88 | } | 130 | } |
| 89 | 131 | ||
| 90 | Status FreeInputsAllocByJit(std::vector<MemBlock *> &input_blocks) { | 132 | Status FreeInputsAllocByJit(std::vector<MemBlock *> &input_blocks) { |
| 91 | for (auto &mem_block : input_blocks) { | 133 | for (auto &mem_block : input_blocks) { |
| 92 | - GE_ASSERT_NOTNULL(mem_block); | 134 | + if (mem_block == nullptr) { |
| 135 | + continue; | ||
| 136 | + } | ||
| 93 | mem_block->Free(); | 137 | mem_block->Free(); |
| 94 | } | 138 | } |
| 95 | return SUCCESS; | 139 | return SUCCESS; |
| @@ -113,15 +157,34 @@ Status GetAllCondInputData(const ComputeGraphPtr &graph, std::set<size_t> &data_ | |||
| 113 | return SUCCESS; | 157 | return SUCCESS; |
| 114 | } | 158 | } |
| 115 | 159 | ||
| 160 | +Status GetAllValueDependentData(const ComputeGraphPtr &graph, std::set<size_t> &data_idx) { | ||
| 161 | + GE_ASSERT_NOTNULL(graph); | ||
| 162 | + for (const auto &node : graph->GetAllNodes()) { | ||
| 163 | + if (!OpTypeUtils::IsDataNode(node->GetType())) { | ||
| 164 | + continue; | ||
| 165 | + } | ||
| 166 | + int32_t data_index = -1; | ||
| 167 | + (void)AttrUtils::GetInt(node->GetOpDesc(), "index", data_index); | ||
| 168 | + if (data_index >= 0 && SymbolicInferUtil::IsValueDependentDataNode(node)) { | ||
| 169 | + data_idx.insert(static_cast<size_t>(data_index)); | ||
| 170 | + } | ||
| 171 | + } | ||
| 172 | + return SUCCESS; | ||
| 173 | +} | ||
| 174 | + | ||
| 116 | Status BuildCompileInputs(const std::vector<gert::Tensor> &ori_inputs, const ComputeGraphPtr &graph, | 175 | Status BuildCompileInputs(const std::vector<gert::Tensor> &ori_inputs, const ComputeGraphPtr &graph, |
| 117 | std::vector<gert::Tensor> &compile_inputs) { | 176 | std::vector<gert::Tensor> &compile_inputs) { |
| 118 | std::set<size_t> need_host_data_idx; | 177 | std::set<size_t> need_host_data_idx; |
| 119 | GE_ASSERT_SUCCESS(GetAllCondInputData(graph, need_host_data_idx)); | 178 | GE_ASSERT_SUCCESS(GetAllCondInputData(graph, need_host_data_idx)); |
| 179 | + GE_ASSERT_SUCCESS(GetAllValueDependentData(graph, need_host_data_idx)); | ||
| 120 | 180 | ||
| 121 | compile_inputs = TensorTransUtils::ShareFromGertTenosrs(ori_inputs); | 181 | compile_inputs = TensorTransUtils::ShareFromGertTenosrs(ori_inputs); |
| 122 | for (size_t data_idx : need_host_data_idx) { | 182 | for (size_t data_idx : need_host_data_idx) { |
| 123 | - GELOGD("input[%u] need copy data to host.", data_idx); | ||
| 124 | GE_ASSERT_TRUE(data_idx < compile_inputs.size()); | 183 | GE_ASSERT_TRUE(data_idx < compile_inputs.size()); |
| 184 | + if (compile_inputs[data_idx].GetPlacement() == gert::TensorPlacement::kOnHost) { | ||
| 185 | + continue; | ||
| 186 | + } | ||
| 187 | + GELOGD("input[%u] need copy data to host.", data_idx); | ||
| 125 | gert::Tensor host_tensor; | 188 | gert::Tensor host_tensor; |
| 126 | GE_ASSERT_SUCCESS(TensorTransUtils::TransGertTensorToHost(compile_inputs[data_idx], host_tensor)); | 189 | GE_ASSERT_SUCCESS(TensorTransUtils::TransGertTensorToHost(compile_inputs[data_idx], host_tensor)); |
| 127 | compile_inputs[data_idx] = std::move(host_tensor); | 190 | compile_inputs[data_idx] = std::move(host_tensor); |
| @@ -267,7 +330,11 @@ Status JitExecutor::RunWithCallback(UserGraphExecution &&task) { | |||
| 267 | 330 | ||
| 268 | std::vector<gert::Tensor> tensors0; | 331 | std::vector<gert::Tensor> tensors0; |
| 269 | GE_MAKE_GUARD(free_input_mem, [&task]() { (void)FreeInputsAllocByJit(task.inputs_memblocks); }); | 332 | GE_MAKE_GUARD(free_input_mem, [&task]() { (void)FreeInputsAllocByJit(task.inputs_memblocks); }); |
| 270 | - JIT_ASSERT_SUCCESS(CopyHostInputsToDevice(task, device_allocator_.get(), tensors0), task); | 333 | + std::set<size_t> keep_on_host_idxs; |
| 334 | + if (ep != nullptr && ep->GetSlicedGraph() != nullptr) { | ||
| 335 | + (void)GetAllValueDependentData(ep->GetSlicedGraph(), keep_on_host_idxs); | ||
| 336 | + } | ||
| 337 | + JIT_ASSERT_SUCCESS(CopyHostInputsToDevice(task, device_allocator_.get(), tensors0, keep_on_host_idxs), task); | ||
| 271 | 338 | ||
| 272 | std::vector<gert::Tensor> tensors1; | 339 | std::vector<gert::Tensor> tensors1; |
| 273 | auto inputs = &tensors0; | 340 | auto inputs = &tensors0; |
| @@ -224,8 +224,8 @@ const std::set<std::string> graph_options = { | |||
| 224 | OPTION_BUILD_GRAPH_MODE, OPTION_BUILD_CONFIG, OPTION_EXEC_FORMAT_MODEL, AICORE_NUM, OPTION_EXEC_INPUT_FUSION_SIZE, | 224 | OPTION_BUILD_GRAPH_MODE, OPTION_BUILD_CONFIG, OPTION_EXEC_FORMAT_MODEL, AICORE_NUM, OPTION_EXEC_INPUT_FUSION_SIZE, |
| 225 | OPTION_EXEC_DYNAMIC_GRAPH_PARALLEL_MODE, OO_LEVEL, OO_CONSTANT_FOLDING, OO_DEAD_CODE_ELIMINATION, | 225 | OPTION_EXEC_DYNAMIC_GRAPH_PARALLEL_MODE, OO_LEVEL, OO_CONSTANT_FOLDING, OO_DEAD_CODE_ELIMINATION, |
| 226 | OPTION_EXPORT_COMPILE_STAT, OPTION_ALL_TENSOR_NOT_EMPTY, OPTION_EXEC_HOST_INPUT_INDEXES, "ge.inputHintShape", | 226 | OPTION_EXPORT_COMPILE_STAT, OPTION_ALL_TENSOR_NOT_EMPTY, OPTION_EXEC_HOST_INPUT_INDEXES, "ge.inputHintShape", |
| 227 | - configure_option::INPUT_BATCH_CPY, OPTIMIZATION_SWITCH, OUTPUT_DATATYPE, OPTION_OUTPUT_REUSE_INPUT_MEM_INDEXES, | 227 | + "ge.inputHintValue", configure_option::INPUT_BATCH_CPY, OPTIMIZATION_SWITCH, OUTPUT_DATATYPE, |
| 228 | - TILING_SCHEDULE_OPTIMIZE}; | 228 | + OPTION_OUTPUT_REUSE_INPUT_MEM_INDEXES, TILING_SCHEDULE_OPTIMIZE}; |
| 229 | 229 | ||
| 230 | static Status CheckSupportedOptions(const std::map<std::string, std::string> &input_options, | 230 | static Status CheckSupportedOptions(const std::map<std::string, std::string> &input_options, |
| 231 | const std::set<std::string> &supported_options, const std::string &level) { | 231 | const std::set<std::string> &supported_options, const std::string &level) { |
| @@ -113,6 +113,7 @@ const char *const kInputShapeRangeSample5 = "\"16\""; | |||
| 113 | const char *const kInputShapeRangeSample6 = "\"input_name1:n1~n2,c1,h1,w1\""; | 113 | const char *const kInputShapeRangeSample6 = "\"input_name1:n1~n2,c1,h1,w1\""; |
| 114 | const char *const kInputShapeRangeSample7 = "\"n1~n2,c1,h1,w1;n3,c2,h2,w2\""; | 114 | const char *const kInputShapeRangeSample7 = "\"n1~n2,c1,h1,w1;n3,c2,h2,w2\""; |
| 115 | const char *const kHintInputShape = "ge.inputHintShape"; | 115 | const char *const kHintInputShape = "ge.inputHintShape"; |
| 116 | +const char *const kHintInputValue = "ge.inputHintValue"; | ||
| 116 | 117 | ||
| 117 | const std::unordered_set<std::string> kSupportedPrintMode = {"enable", "disable"}; | 118 | const std::unordered_set<std::string> kSupportedPrintMode = {"enable", "disable"}; |
| 118 | const std::unordered_set<std::string> kValidHostEnvOs = {"minios", "linux"}; | 119 | const std::unordered_set<std::string> kValidHostEnvOs = {"minios", "linux"}; |
| @@ -152,6 +153,65 @@ Status ConstructShapeFromStr(const std::string &shape_str, GeShape &shape) { | |||
| 152 | return GRAPH_SUCCESS; | 153 | return GRAPH_SUCCESS; |
| 153 | } | 154 | } |
| 154 | 155 | ||
| 156 | +Status ConstructValueListFromStr(const std::string &value_str, std::vector<int64_t> &values) { | ||
| 157 | + GE_ASSERT_TRUE(value_str.length() >= kLeastStrElementNum && value_str.front() == '[' && value_str.back() == ']'); | ||
| 158 | + auto value_content_str = value_str.substr(1, value_str.length() - kLeastStrElementNum); | ||
| 159 | + auto val_strs = ge::StringUtils::Split(value_content_str, ','); | ||
| 160 | + values.clear(); | ||
| 161 | + for (auto &str : val_strs) { | ||
| 162 | + if (str.empty()) { | ||
| 163 | + continue; | ||
| 164 | + } | ||
| 165 | + int64_t val = -1; | ||
| 166 | + GE_ASSERT_SUCCESS(ConvertToInt64(ge::StringUtils::Trim(str), val), "Value: %s is invalid in option", | ||
| 167 | + value_str.c_str()); | ||
| 168 | + GE_ASSERT_TRUE(val >= 0L, "Value in %s should not less than 0, but get: %lld.", kHintInputValue, val); | ||
| 169 | + values.push_back(val); | ||
| 170 | + } | ||
| 171 | + return GRAPH_SUCCESS; | ||
| 172 | +} | ||
| 173 | + | ||
| 174 | +template <typename ElemType, typename ElemParser> | ||
| 175 | +Status ParseIndexedListOption(const std::string &option_name, const std::string &option_value, | ||
| 176 | + std::vector<std::pair<int64_t, ElemType>> &result, ElemParser parse_elem) { | ||
| 177 | + std::vector<std::string> input_option_strs = ge::StringUtils::Split(option_value, ';'); | ||
| 178 | + result.reserve(input_option_strs.size()); | ||
| 179 | + std::set<int64_t> index_set; | ||
| 180 | + for (size_t i = 0U; i < input_option_strs.size(); i++) { | ||
| 181 | + auto &input_option_local = StringUtils::Trim(input_option_strs[i]); | ||
| 182 | + if (input_option_local.empty()) { | ||
| 183 | + GELOGW("Options[%s] is invalid, Input[%zu] is empty.", option_name.c_str(), i); | ||
| 184 | + continue; | ||
| 185 | + } | ||
| 186 | + std::vector<std::string> index_and_value_str = ge::StringUtils::Split(input_option_local, ':'); | ||
| 187 | + if (index_and_value_str.size() != kLeastStrElementNum) { | ||
| 188 | + REPORT_PREDEFINED_ERR_MSG("E10014", std::vector<const char *>({"parameter", "value"}), | ||
| 189 | + std::vector<const char *>({option_name.c_str(), option_value.c_str()})); | ||
| 190 | + GELOGE(PARAM_INVALID, "Options[%s] is invalid, input[%zu][%s] not match pattern: input_index:[v0,v1,...]", | ||
🟡 Medium Priority changed line 189-190 → GELOGE 格式串中使用 修改:将 建议:将 ![]() ![]() 不准确? | |||
| 191 | + option_name.c_str(), i, input_option_local.c_str()); | ||
| 192 | + return PARAM_INVALID; | ||
| 193 | + } | ||
| 194 | + int64_t index = -1; | ||
| 195 | + if (ConvertToInt64(index_and_value_str.front(), index) != SUCCESS || index < 0 || !index_set.insert(index).second) { | ||
| 196 | + REPORT_PREDEFINED_ERR_MSG("E10014", std::vector<const char *>({"parameter", "value"}), | ||
| 197 | + std::vector<const char *>({option_name.c_str(), option_value.c_str()})); | ||
| 198 | + GELOGE(PARAM_INVALID, "Option[%s] is invalid, input[%zu][%s] check index fail.", option_name.c_str(), i, | ||
🟡 Medium Priority changed line 197-198 → 修改:将 建议: ![]() ![]() 不准确? | |||
| 199 | + input_option_local.c_str()); | ||
| 200 | + return PARAM_INVALID; | ||
| 201 | + } | ||
| 202 | + ElemType elem; | ||
| 203 | + if (parse_elem(StringUtils::Trim(index_and_value_str.back()), elem) != GRAPH_SUCCESS) { | ||
| 204 | + REPORT_PREDEFINED_ERR_MSG("E10014", std::vector<const char *>({"parameter", "value"}), | ||
| 205 | + std::vector<const char *>({option_name.c_str(), option_value.c_str()})); | ||
| 206 | + GELOGE(PARAM_INVALID, "Option[%s] is invalid, Input[%zu] parse value[%s] failed.", option_name.c_str(), i, | ||
🟡 Medium Priority changed line 205-206 → 修改:将 建议: ![]() ![]() 不准确? | |||
| 207 | + input_option_local.c_str()); | ||
| 208 | + return PARAM_INVALID; | ||
| 209 | + } | ||
| 210 | + result.emplace_back(std::make_pair(index, elem)); | ||
| 211 | + } | ||
| 212 | + return GRAPH_SUCCESS; | ||
| 213 | +} | ||
| 214 | + | ||
| 155 | static bool StringToLongNoThrow(const std::string &str, long &val) { | 215 | static bool StringToLongNoThrow(const std::string &str, long &val) { |
| 156 | std::string val_str(str); | 216 | std::string val_str(str); |
| 157 | std::stringstream ss(StringUtils::Trim(val_str)); | 217 | std::stringstream ss(StringUtils::Trim(val_str)); |
| @@ -1067,51 +1127,15 @@ Status ParseHintInputShape(std::vector<GeShape> &option_shape) { | |||
| 1067 | return GRAPH_SUCCESS; | 1127 | return GRAPH_SUCCESS; |
| 1068 | } | 1128 | } |
| 1069 | GELOGI("Option %s is set, value: %s.", INPUT_HINT_SHAPE, input_option.c_str()); | 1129 | GELOGI("Option %s is set, value: %s.", INPUT_HINT_SHAPE, input_option.c_str()); |
| 1070 | - std::vector<std::string> input_option_strs = ge::StringUtils::Split(input_option, ';'); | 1130 | + std::vector<std::pair<int64_t, GeShape>> parse_shape; |
| 1131 | + GE_ASSERT_SUCCESS(ParseIndexedListOption<GeShape>( | ||
| 1132 | + "ge.inputHintShape", input_option, parse_shape, | ||
| 1133 | + [](const std::string &s, GeShape &shape) { return ConstructShapeFromStr(s, shape); })); | ||
| 1071 | 1134 | ||
| 1072 | - std::vector<pair<int64_t, GeShape>> parse_shape; | ||
| 1073 | - parse_shape.reserve(input_option_strs.size()); | ||
| 1074 | - std::set<int64_t> index_set; | ||
| 1075 | int64_t max_index = 0L; | 1135 | int64_t max_index = 0L; |
| 1076 | - for (size_t i = 0U; i < input_option_strs.size(); i++) { | 1136 | + for (const auto &item : parse_shape) { |
| 1077 | - auto &input_option_local = StringUtils::Trim(input_option_strs[i]); | 1137 | + max_index = item.first > max_index ? item.first : max_index; |
| 1078 | - // 如果配置的input是空跳过解析 | ||
| 1079 | - if (input_option_local.empty()) { | ||
| 1080 | - GELOGW("Options[%s] is invalid, Input[%u] is empty.", INPUT_HINT_SHAPE); | ||
| 1081 | - continue; | ||
| 1082 | - } | ||
| 1083 | - std::vector<std::string> index_and_shape_str = ge::StringUtils::Split(input_option_local, ':'); | ||
| 1084 | - // 的左右两边必须是有元素的,key和value元素 | ||
| 1085 | - if (index_and_shape_str.size() != kLeastStrElementNum) { | ||
| 1086 | - REPORT_PREDEFINED_ERR_MSG("E10014", std::vector<const char *>({"parameter", "value"}), | ||
| 1087 | - std::vector<const char *>({"input_hint_shape", input_option.c_str()})); | ||
| 1088 | - GELOGE(PARAM_INVALID, | ||
| 1089 | - "Options[--input_hint_shape] is invalid, input[%u][%s] not match pattern: input_index:[n,c,h,w]", i, | ||
| 1090 | - input_option_local.c_str()); | ||
| 1091 | - return PARAM_INVALID; | ||
| 1092 | - } | ||
| 1093 | - | ||
| 1094 | - int64_t index = -1; | ||
| 1095 | - if (ConvertToInt64(index_and_shape_str.front(), index) != SUCCESS || index < 0 || !index_set.insert(index).second) { | ||
| 1096 | - REPORT_PREDEFINED_ERR_MSG("E10014", std::vector<const char *>({"parameter", "value"}), | ||
| 1097 | - std::vector<const char *>({"input_hint_shape", input_option.c_str()})); | ||
| 1098 | - GELOGE(PARAM_INVALID, "Option[--input_hint_shape] is invalid, input[%u][%s] check index fail.", i, | ||
| 1099 | - input_option_local.c_str()); | ||
| 1100 | - return PARAM_INVALID; | ||
| 1101 | - } | ||
| 1102 | - max_index = index > max_index ? index : max_index; | ||
| 1103 | - | ||
| 1104 | - GeShape shape; | ||
| 1105 | - if (ConstructShapeFromStr(StringUtils::Trim(index_and_shape_str.back()), shape) != GRAPH_SUCCESS) { | ||
| 1106 | - REPORT_PREDEFINED_ERR_MSG("E10014", std::vector<const char *>({"parameter", "value"}), | ||
| 1107 | - std::vector<const char *>({"input_hint_shape", input_option.c_str()})); | ||
| 1108 | - GELOGE(PARAM_INVALID, "Option[--input_hint_shape] is invalid, Input[%u] parse shape[%s] failed.", i, | ||
| 1109 | - input_option_local.c_str()); | ||
| 1110 | - return PARAM_INVALID; | ||
| 1111 | - } | ||
| 1112 | - parse_shape.emplace_back(std::make_pair(index, shape)); | ||
| 1113 | } | 1138 | } |
| 1114 | - | ||
| 1115 | option_shape.resize(max_index + 1, GeShape(DUMMY_SHAPE)); | 1139 | option_shape.resize(max_index + 1, GeShape(DUMMY_SHAPE)); |
| 1116 | for (const auto &shape : parse_shape) { | 1140 | for (const auto &shape : parse_shape) { |
| 1117 | option_shape[shape.first] = shape.second; | 1141 | option_shape[shape.first] = shape.second; |
| @@ -1119,6 +1143,24 @@ Status ParseHintInputShape(std::vector<GeShape> &option_shape) { | |||
| 1119 | return GRAPH_SUCCESS; | 1143 | return GRAPH_SUCCESS; |
| 1120 | } | 1144 | } |
| 1121 | 1145 | ||
| 1146 | +Status ParseHintInputValue(std::map<int64_t, std::vector<int64_t>> &option_value) { | ||
| 1147 | + std::string input_option; | ||
| 1148 | + (void)ge::GetContext().GetOption(kHintInputValue, input_option); | ||
| 1149 | + if (input_option.empty()) { | ||
| 1150 | + GELOGI("Option %s is not set, skip parse hint value.", kHintInputValue); | ||
| 1151 | + return GRAPH_SUCCESS; | ||
| 1152 | + } | ||
| 1153 | + GELOGI("Option %s is set, value: %s.", kHintInputValue, input_option.c_str()); | ||
| 1154 | + std::vector<std::pair<int64_t, std::vector<int64_t>>> parse_values; | ||
| 1155 | + GE_ASSERT_SUCCESS(ParseIndexedListOption<std::vector<int64_t>>( | ||
| 1156 | + "ge.inputHintValue", input_option, parse_values, | ||
| 1157 | + [](const std::string &s, std::vector<int64_t> &values) { return ConstructValueListFromStr(s, values); })); | ||
| 1158 | + for (auto &item : parse_values) { | ||
| 1159 | + option_value[item.first] = std::move(item.second); | ||
| 1160 | + } | ||
| 1161 | + return GRAPH_SUCCESS; | ||
| 1162 | +} | ||
| 1163 | + | ||
| 1122 | std::string GetAutofuseFlagValue(const std::string &option) { | 1164 | std::string GetAutofuseFlagValue(const std::string &option) { |
| 1123 | // 自动融合新的环境变量 | 1165 | // 自动融合新的环境变量 |
| 1124 | const char_t *auto_fuse_options = nullptr; | 1166 | const char_t *auto_fuse_options = nullptr; |
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | + | ||
| 20 | 21 | ||
| 21 | 22 | ||
| 22 | 23 | ||
| @@ -80,6 +81,13 @@ Status CheckAndTransferInputShapeToRange(std::string &input_shape, std::string & | |||
| 80 | */ | 81 | */ |
| 81 | Status ParseHintInputShape(std::vector<GeShape> &option_shape); | 82 | Status ParseHintInputShape(std::vector<GeShape> &option_shape); |
| 82 | 83 | ||
| 84 | +/* | ||
| 85 | + * @brief 获取ge.inputHintValue中对应option的值, 并将其转化为map<int64_t, vector<int64_t>> | ||
| 86 | + * @out_param option_value 从option中解析的字符串转成成的value map | ||
| 87 | + * @return 成功返回GRAPH_SUCCESS, 失败返回FAILED | ||
| 88 | + */ | ||
| 89 | +Status ParseHintInputValue(std::map<int64_t, std::vector<int64_t>> &option_value); | ||
| 90 | + | ||
| 83 | Status ParserShapeRangeByName(std::string &input_shape, std::string &input_shape_range); | 91 | Status ParserShapeRangeByName(std::string &input_shape, std::string &input_shape_range); |
| 84 | 92 | ||
| 85 | Status CheckDynamicInputParamValid(std::string &dynamic_batch_size, std::string &dynamic_image_size, | 93 | Status CheckDynamicInputParamValid(std::string &dynamic_batch_size, std::string &dynamic_image_size, |
| @@ -393,14 +393,23 @@ std::vector<int64_t> GetDimsFromGertShape(const gert::Shape &gert_shape) { | |||
| 393 | return dims; | 393 | return dims; |
| 394 | } | 394 | } |
| 395 | 395 | ||
| 396 | -TensorDesc GetTensorDescFromGertTensor(const gert::Tensor &gert_tensor) { | 396 | +ge::Tensor GetTensorDescFromGertTensor(const gert::Tensor &gert_tensor) { |
| 397 | ge::Shape storage_shape{GetDimsFromGertShape(gert_tensor.GetStorageShape())}; | 397 | ge::Shape storage_shape{GetDimsFromGertShape(gert_tensor.GetStorageShape())}; |
| 398 | TensorDesc tensor_desc{std::move(storage_shape), gert_tensor.GetStorageFormat(), gert_tensor.GetDataType()}; | 398 | TensorDesc tensor_desc{std::move(storage_shape), gert_tensor.GetStorageFormat(), gert_tensor.GetDataType()}; |
| 399 | const ge::Shape origin_shape{GetDimsFromGertShape(gert_tensor.GetOriginShape())}; | 399 | const ge::Shape origin_shape{GetDimsFromGertShape(gert_tensor.GetOriginShape())}; |
| 400 | 400 | ||
| 401 | tensor_desc.SetOriginFormat(gert_tensor.GetOriginFormat()); | 401 | tensor_desc.SetOriginFormat(gert_tensor.GetOriginFormat()); |
| 402 | tensor_desc.SetOriginShape(origin_shape); | 402 | tensor_desc.SetOriginShape(origin_shape); |
| 403 | - return tensor_desc; | 403 | + tensor_desc.SetPlacement(gert::TensorPlacementUtils::IsOnHost(gert_tensor.GetPlacement()) |
| 404 | + ? ge::Placement::kPlacementHost | ||
| 405 | + : ge::Placement::kPlacementDevice); | ||
| 406 | + | ||
| 407 | + ge::Tensor ge_tensor(tensor_desc); | ||
| 408 | + if ((tensor_desc.GetPlacement() == ge::Placement::kPlacementHost) && (gert_tensor.GetAddr() != nullptr) && | ||
| 409 | + (gert_tensor.GetSize() > 0U)) { | ||
| 410 | + (void)ge_tensor.SetData(reinterpret_cast<const uint8_t *>(gert_tensor.GetAddr()), gert_tensor.GetSize()); | ||
| 411 | + } | ||
| 412 | + return ge_tensor; | ||
| 404 | } | 413 | } |
| 405 | 414 | ||
| 406 | Status SaveRootModel(const GeRootModelPtr &ge_root_model, ModelBufferData &model_buff) { | 415 | Status SaveRootModel(const GeRootModelPtr &ge_root_model, ModelBufferData &model_buff) { |
| @@ -3799,8 +3808,7 @@ Status GraphManager::CheckIncreBuildAndPreRun(const std::shared_ptr<RunArgs> &ar | |||
| 3799 | 3808 | ||
| 3800 | std::vector<ge::Tensor> inputs_desc; | 3809 | std::vector<ge::Tensor> inputs_desc; |
| 3801 | for (const auto &gert_tensor : args->input_tensor) { | 3810 | for (const auto &gert_tensor : args->input_tensor) { |
| 3802 | - const auto tensor_desc = GetTensorDescFromGertTensor(gert_tensor); | 3811 | + inputs_desc.emplace_back(GetTensorDescFromGertTensor(gert_tensor)); |
| 3803 | - inputs_desc.emplace_back(ge::Tensor(tensor_desc)); | ||
| 3804 | } | 3812 | } |
| 3805 | 3813 | ||
| 3806 | const auto ret = CompileGraph(graph_node->GetGraphId(), args->session_id, inputs_desc); | 3814 | const auto ret = CompileGraph(graph_node->GetGraphId(), args->session_id, inputs_desc); |
| @@ -10,7 +10,10 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | + | ||
| 13 | 14 | ||
| 15 | + | ||
| 16 | + | ||
| 14 | 17 | ||
| 15 | 18 | ||
| 16 | 19 | ||
| @@ -120,4 +123,45 @@ NodePtr SymbolicInferUtil::GetCondInput(const NodePtr &node) { | |||
| 120 | return parent_input == nullptr ? cond_input : parent_input; | 123 | return parent_input == nullptr ? cond_input : parent_input; |
| 121 | } | 124 | } |
| 122 | 125 | ||
| 126 | +bool SymbolicInferUtil::IsValueDependentDataNode(const NodePtr &data_node) { | ||
| 127 | + for (const auto &out_anchor : data_node->GetAllOutDataAnchors()) { | ||
| 128 | + for (const auto &peer_anchor : out_anchor->GetPeerInDataAnchors()) { | ||
| 129 | + if (peer_anchor->GetOwnerNode() == nullptr || peer_anchor->GetOwnerNode()->GetOpDesc() == nullptr) { | ||
| 130 | + continue; | ||
| 131 | + } | ||
| 132 | + auto consumer_op = peer_anchor->GetOwnerNode()->GetOpDesc(); | ||
| 133 | + const size_t input_idx = static_cast<size_t>(peer_anchor->GetIdx()); | ||
| 134 | + | ||
| 135 | + auto functions = gert::OpImplInferSymbolShapeRegistry::GetInstance().GetOpImpl(consumer_op->GetType().c_str()); | ||
| 136 | + if (functions != nullptr) { | ||
| 137 | + const gert::OpImplKernelRegistry::OpImplFunctionsV2 *function_new = nullptr; | ||
| 138 | + auto space_registry = gert::DefaultOpImplSpaceRegistryV2::GetInstance().GetSpaceRegistry(); | ||
| 139 | + if (space_registry != nullptr) { | ||
| 140 | + function_new = space_registry->GetOpImpl(consumer_op->GetType().c_str()); | ||
| 141 | + } | ||
| 142 | + if (function_new == nullptr) { | ||
| 143 | + function_new = const_cast<gert::OpImplKernelRegistry::OpImplFunctionsV2 *>(functions); | ||
| 144 | + } | ||
| 145 | + size_t ir_index = 0UL; | ||
| 146 | + if (ge::OpDescUtils::GetInputIrIndexByInstanceIndex(consumer_op, input_idx, ir_index) != GRAPH_SUCCESS) { | ||
| 147 | + ir_index = input_idx; | ||
| 148 | + } | ||
| 149 | + if (function_new->IsInputDataDependency(ir_index)) { | ||
| 150 | + return true; | ||
| 151 | + } | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + const auto &op_infer_depends = consumer_op->GetOpInferDepends(); | ||
| 155 | + if (op_infer_depends.empty()) { | ||
| 156 | + continue; | ||
| 157 | + } | ||
| 158 | + auto input_name = consumer_op->GetValidInputNameByIndex(static_cast<uint32_t>(input_idx)); | ||
| 159 | + if (std::find(op_infer_depends.cbegin(), op_infer_depends.cend(), input_name) != op_infer_depends.cend()) { | ||
| 160 | + return true; | ||
| 161 | + } | ||
| 162 | + } | ||
| 163 | + } | ||
| 164 | + return false; | ||
| 165 | +} | ||
| 166 | + | ||
| 123 | } // namespace ge | 167 | } // namespace ge |
| @@ -139,6 +139,7 @@ class SymbolicInferUtil { | |||
| 139 | static std::string DumpSymbolTensor(const gert::SymbolTensor &symbolic_tensor); | 139 | static std::string DumpSymbolTensor(const gert::SymbolTensor &symbolic_tensor); |
| 140 | static bool IsSupportCondNode(const NodePtr &node); | 140 | static bool IsSupportCondNode(const NodePtr &node); |
| 141 | static NodePtr GetCondInput(const NodePtr &node); | 141 | static NodePtr GetCondInput(const NodePtr &node); |
| 142 | + static bool IsValueDependentDataNode(const NodePtr &data_node); | ||
| 142 | }; | 143 | }; |
| 143 | } // namespace ge | 144 | } // namespace ge |
| 144 | 145 | ||
| @@ -9,6 +9,7 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | + | ||
| 12 | 13 | ||
| 13 | 14 | ||
| 14 | 15 | ||
| @@ -26,6 +27,8 @@ | |||
| 26 | 27 | ||
| 27 | 28 | ||
| 28 | 29 | ||
| 30 | + | ||
| 31 | + | ||
| 29 | 32 | ||
| 30 | namespace ge { | 33 | namespace ge { |
| 31 | namespace { | 34 | namespace { |
| @@ -172,6 +175,72 @@ bool SupportSymbolizeValueSum(const GeTensor &ge_tensor) { | |||
| 172 | return true; | 175 | return true; |
| 173 | } | 176 | } |
| 174 | 177 | ||
| 178 | +template <typename T> | ||
| 179 | +std::vector<Expression> CreateSymbolValueElement(const GeTensor &tensor, int32_t data_index, ge::DataType dtype, | ||
| 180 | + ShapeEnvAttr *shape_env_attr) { | ||
| 181 | + std::vector<Expression> result; | ||
| 182 | + const T *const data = reinterpret_cast<const T *>(tensor.GetData().GetData()); | ||
| 183 | + GE_ASSERT_NOTNULL(data); | ||
| 184 | + const size_t elem_num = tensor.GetData().size() / sizeof(T); | ||
| 185 | + for (size_t i = 0UL; i < elem_num; i++) { | ||
| 186 | + auto source = MakeShared<InputValueElementSource>(data_index, i, dtype); | ||
| 187 | + auto symbol = shape_env_attr->CreateSymbol<int64_t>(static_cast<int64_t>(data[i]), source); | ||
| 188 | + result.emplace_back(symbol); | ||
| 189 | + GELOGI("Symbolize value from data, data_index %d, elem_idx %zu, value %lld, symbol name %s, source str is %s", | ||
| 190 | + data_index, i, static_cast<int64_t>(data[i]), symbol.GetName().get(), source->GetSourceStr().c_str()); | ||
| 191 | + } | ||
| 192 | + return result; | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +Status SymbolizeInputValue(const GeTensor &tensor, int32_t data_index, const NodePtr &data_node, | ||
| 196 | + const std::map<int64_t, std::vector<int64_t>> &hint_value_map, ShapeEnvAttr *shape_env_attr, | ||
| 197 | + SymbolicDescAttr *symbolic_desc_attr) { | ||
| 198 | + if (symbolic_desc_attr->symbolic_tensor.GetSymbolicValue() != nullptr) { | ||
| 199 | + return SUCCESS; | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + std::vector<Expression> sym_value; | ||
| 203 | + if (tensor.GetTensorDesc().GetPlacement() == kPlacementHost && tensor.GetData().size() > 0U && | ||
| 204 | + SymbolicInferUtil::IsValueDependentDataNode(data_node)) { | ||
| 205 | + (void)ge::AttrUtils::SetBool(data_node->GetOpDesc(), ATTR_NAME_HOST_TENSOR_AS_MODEL_INPUT, true); | ||
| 206 | + GELOGI("Mark data node %s as host tensor for value-dependent infer", data_node->GetNamePtr()); | ||
| 207 | + const auto dtype = tensor.GetTensorDesc().GetDataType(); | ||
| 208 | + switch (dtype) { | ||
| 209 | + case DT_INT32: | ||
| 210 | + sym_value = CreateSymbolValueElement<int32_t>(tensor, data_index, dtype, shape_env_attr); | ||
| 211 | + break; | ||
| 212 | + case DT_INT64: | ||
| 213 | + sym_value = CreateSymbolValueElement<int64_t>(tensor, data_index, dtype, shape_env_attr); | ||
| 214 | + break; | ||
| 215 | + case DT_UINT32: | ||
| 216 | + sym_value = CreateSymbolValueElement<uint32_t>(tensor, data_index, dtype, shape_env_attr); | ||
| 217 | + break; | ||
| 218 | + case DT_UINT64: | ||
| 219 | + sym_value = CreateSymbolValueElement<uint64_t>(tensor, data_index, dtype, shape_env_attr); | ||
| 220 | + break; | ||
| 221 | + default: | ||
| 222 | + GELOGW("hint value unsupported data type %s, skip.", | ||
| 223 | + TypeUtils::DataTypeToSerialString(tensor.GetTensorDesc().GetDataType()).c_str()); | ||
| 224 | + break; | ||
| 225 | + } | ||
| 226 | + } else { | ||
| 227 | + auto it = hint_value_map.find(data_index); | ||
| 228 | + if (it != hint_value_map.end()) { | ||
| 229 | + for (size_t elem_idx = 0; elem_idx < it->second.size(); ++elem_idx) { | ||
| 230 | + auto source = MakeShared<InputValueElementSource>(data_index, elem_idx, tensor.GetTensorDesc().GetDataType()); | ||
| 231 | + auto symbol = shape_env_attr->CreateSymbol<int64_t>(it->second[elem_idx], source); | ||
| 232 | + sym_value.emplace_back(symbol); | ||
| 233 | + GELOGI("Symbolize value from option, data_index %d, elem_idx %zu, value %lld, symbol name %s, source str is %s", | ||
| 234 | + data_index, elem_idx, it->second[elem_idx], symbol.GetName().get(), source->GetSourceStr().c_str()); | ||
| 235 | + } | ||
| 236 | + } | ||
| 237 | + } | ||
| 238 | + if (!sym_value.empty()) { | ||
| 239 | + symbolic_desc_attr->symbolic_tensor.SetSymbolicValue(ge::MakeUnique<std::vector<Expression>>(std::move(sym_value))); | ||
| 240 | + } | ||
| 241 | + return SUCCESS; | ||
| 242 | +} | ||
| 243 | + | ||
| 175 | bool IsAippInput(const NodePtr &data_node) { | 244 | bool IsAippInput(const NodePtr &data_node) { |
| 176 | auto output_nodes = NodeUtils::GetOutDataNodes(*data_node, nullptr); | 245 | auto output_nodes = NodeUtils::GetOutDataNodes(*data_node, nullptr); |
| 177 | return output_nodes.size() == 1 && output_nodes[0]->GetType() == AIPP; | 246 | return output_nodes.size() == 1 && output_nodes[0]->GetType() == AIPP; |
| @@ -318,6 +387,8 @@ Status SymbolizeRootGraph(const ComputeGraphPtr &graph, const std::vector<GeTens | |||
| 318 | GE_ASSERT_SUCCESS(GetSupportSymbolizeInputDataNodes(graph, data_nodes, graph_inputs.size())); | 387 | GE_ASSERT_SUCCESS(GetSupportSymbolizeInputDataNodes(graph, data_nodes, graph_inputs.size())); |
| 319 | auto shape_env_attr = graph->GetAttrsGroup<ShapeEnvAttr>(); | 388 | auto shape_env_attr = graph->GetAttrsGroup<ShapeEnvAttr>(); |
| 320 | GE_ASSERT_NOTNULL(shape_env_attr); | 389 | GE_ASSERT_NOTNULL(shape_env_attr); |
| 390 | + std::map<int64_t, std::vector<int64_t>> hint_value_map; | ||
| 391 | + GE_ASSERT_SUCCESS(ParseHintInputValue(hint_value_map)); | ||
| 321 | for (auto &data_node : data_nodes) { | 392 | for (auto &data_node : data_nodes) { |
| 322 | auto op_desc = data_node->GetOpDescBarePtr(); | 393 | auto op_desc = data_node->GetOpDescBarePtr(); |
| 323 | DataSymbolizeInfo info; | 394 | DataSymbolizeInfo info; |
| @@ -339,10 +410,14 @@ Status SymbolizeRootGraph(const ComputeGraphPtr &graph, const std::vector<GeTens | |||
| 339 | const auto symbolic_desc_attr = op_desc->MutableOutputDesc(0)->GetOrCreateAttrsGroup<SymbolicDescAttr>(); | 410 | const auto symbolic_desc_attr = op_desc->MutableOutputDesc(0)->GetOrCreateAttrsGroup<SymbolicDescAttr>(); |
| 340 | GE_ASSERT_SUCCESS(SymbolizeShape(info, op_desc, shape_env_attr, symbolic_desc_attr, ge_shape)); | 411 | GE_ASSERT_SUCCESS(SymbolizeShape(info, op_desc, shape_env_attr, symbolic_desc_attr, ge_shape)); |
| 341 | 412 | ||
| 342 | - int64_t symbolize_value_type = SYMBOLIZE_VALUE_TYPE_NONE; | ||
| 343 | const auto &tensor = graph_inputs.at(data_index); | 413 | const auto &tensor = graph_inputs.at(data_index); |
| 414 | + GE_ASSERT_SUCCESS( | ||
| 415 | + SymbolizeInputValue(tensor, data_index, data_node, hint_value_map, shape_env_attr, symbolic_desc_attr)); | ||
| 416 | + | ||
| 417 | + int64_t symbolize_value_type = SYMBOLIZE_VALUE_TYPE_NONE; | ||
| 344 | if (AttrUtils::GetInt(op_desc, kSymbolizeValueType, symbolize_value_type) && | 418 | if (AttrUtils::GetInt(op_desc, kSymbolizeValueType, symbolize_value_type) && |
| 345 | - symbolize_value_type == static_cast<ino64_t>(SYMBOLIZE_VALUE_TYPE_SUM) && SupportSymbolizeValueSum(tensor)) { | 419 | + symbolize_value_type == static_cast<int64_t>(SYMBOLIZE_VALUE_TYPE_SUM) && SupportSymbolizeValueSum(tensor) && |
| 420 | + symbolic_desc_attr->symbolic_tensor.GetSymbolicValue() == nullptr) { | ||
| 346 | GELOGI("Symbolize value sum for node %s[%s]", op_desc->GetNamePtr(), op_desc->GetTypePtr()); | 421 | GELOGI("Symbolize value sum for node %s[%s]", op_desc->GetNamePtr(), op_desc->GetTypePtr()); |
| 347 | GE_ASSERT_SUCCESS(SymbolizeInputValueForRepeat(tensor, symbolic_desc_attr, shape_env_attr, data_index)); | 422 | GE_ASSERT_SUCCESS(SymbolizeInputValueForRepeat(tensor, symbolic_desc_attr, shape_env_attr, data_index)); |
| 348 | } | 423 | } |
| @@ -381,6 +456,23 @@ std::string InputValueSumSource::GetSourceStr() const { | |||
| 381 | )"; | 456 | )"; |
| 382 | } | 457 | } |
| 383 | 458 | ||
| 459 | +std::string InputValueElementSource::GetSourceStr() const { | ||
| 460 | + return R"([&]() -> int64_t { | ||
| 461 | + const auto* tensor = context->GetGraphInputTensor()" + | ||
| 462 | + std::to_string(input_data_idx_) + R"(); | ||
| 463 | + if (tensor == nullptr) { | ||
| 464 | + return -1; | ||
| 465 | + } | ||
| 466 | + const auto* data = tensor->GetData<)" + | ||
| 467 | + kGeDType2CppDtype[dtype_] + R"(>(); | ||
| 468 | + if (data == nullptr) { | ||
| 469 | + return -1; | ||
| 470 | + } | ||
| 471 | + return static_cast<int64_t>(data[)" + | ||
| 472 | + std::to_string(elem_idx_) + R"(]); | ||
| 473 | + }())"; | ||
| 474 | +} | ||
| 475 | + | ||
| 384 | std::string InputRankSource::GetSourceStr() const { | 476 | std::string InputRankSource::GetSourceStr() const { |
| 385 | return R"([&]() -> size_t { | 477 | return R"([&]() -> size_t { |
| 386 | const auto *tensor = context->GetGraphInputTensor()" + | 478 | const auto *tensor = context->GetGraphInputTensor()" + |
| @@ -46,6 +46,19 @@ class InputValueSumSource : public ge::Source { | |||
| 46 | ge::DataType dtype_; // 描述value的数据类型,用于后续执行时取值 | 46 | ge::DataType dtype_; // 描述value的数据类型,用于后续执行时取值 |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | +class InputValueElementSource : public ge::Source { | ||
| 50 | + public: | ||
| 51 | + InputValueElementSource(int32_t input_data_idx, size_t elem_idx, ge::DataType dtype) | ||
| 52 | + : input_data_idx_(input_data_idx), elem_idx_(elem_idx), dtype_(dtype) {} | ||
| 53 | + | ||
| 54 | + [[nodiscard]] std::string GetSourceStr() const override; | ||
| 55 | + | ||
| 56 | + private: | ||
| 57 | + int32_t input_data_idx_; // Data的index,描述symbol来自于graph输入中第几个输入data | ||
| 58 | + size_t elem_idx_; // 描述symbol来自于tensor data中第几个元素 | ||
| 59 | + ge::DataType dtype_; // 描述value的数据类型,用于后续执行时取值 | ||
| 60 | +}; | ||
| 61 | + | ||
| 49 | class InputRankSource final : public ge::Source { | 62 | class InputRankSource final : public ge::Source { |
| 50 | public: | 63 | public: |
| 51 | explicit InputRankSource(const int32_t input_data_idx) : input_data_idx_(input_data_idx) {} | 64 | explicit InputRankSource(const int32_t input_data_idx) : input_data_idx_(input_data_idx) {} |
| @@ -370,6 +370,9 @@ const std::string INPUT_SHAPE = "ge.inputShape"; | |||
| 370 | // Configure shape hint of dynamic shape | 370 | // Configure shape hint of dynamic shape |
| 371 | const char_t *const INPUT_HINT_SHAPE = "ge.inputHintShape"; | 371 | const char_t *const INPUT_HINT_SHAPE = "ge.inputHintShape"; |
| 372 | 372 | ||
| 373 | +// Configure value hint of dynamic shape | ||
| 374 | +const char_t *const INPUT_HINT_VALUE = "ge.inputHintValue"; | ||
| 375 | + | ||
| 373 | const std::string OUTPUT_MAX_SIZE = "ge.outputMaxSize"; | 376 | const std::string OUTPUT_MAX_SIZE = "ge.outputMaxSize"; |
| 374 | 377 | ||
| 375 | const std::string DYNAMIC_NODE_TYPE = "ge.dynamicNodeType"; | 378 | const std::string DYNAMIC_NODE_TYPE = "ge.dynamicNodeType"; |
| @@ -686,6 +689,7 @@ static const char_t *const OO_DEAD_CODE_ELIMINATION = ge::OO_DEAD_CODE_ELIMINATI | |||
| 686 | static const char_t *const OPTION_EXPORT_COMPILE_STAT = ge::OPTION_EXPORT_COMPILE_STAT; | 689 | static const char_t *const OPTION_EXPORT_COMPILE_STAT = ge::OPTION_EXPORT_COMPILE_STAT; |
| 687 | static const char_t *const OPTIMIZATION_SWITCH = ge::OPTIMIZATION_SWITCH; | 690 | static const char_t *const OPTIMIZATION_SWITCH = ge::OPTIMIZATION_SWITCH; |
| 688 | static const char_t *const INPUT_HINT_SHAPE = ge::INPUT_HINT_SHAPE; | 691 | static const char_t *const INPUT_HINT_SHAPE = ge::INPUT_HINT_SHAPE; |
| 692 | +static const char_t *const INPUT_HINT_VALUE = ge::INPUT_HINT_VALUE; | ||
| 689 | static const char_t *const OPTION_OUTPUT_REUSE_INPUT_MEM_INDEXES = ge::OPTION_OUTPUT_REUSE_INPUT_MEM_INDEXES; | 693 | static const char_t *const OPTION_OUTPUT_REUSE_INPUT_MEM_INDEXES = ge::OPTION_OUTPUT_REUSE_INPUT_MEM_INDEXES; |
| 690 | static const char_t *const OPTION_H2D_OVERLAPPED_WITH_COMPUTE = ge::OPTION_H2D_OVERLAPPED_WITH_COMPUTE; | 694 | static const char_t *const OPTION_H2D_OVERLAPPED_WITH_COMPUTE = ge::OPTION_H2D_OVERLAPPED_WITH_COMPUTE; |
| 691 | static const char_t *const OFFLINE_MODE = "ge.offlineMode"; | 695 | static const char_t *const OFFLINE_MODE = "ge.offlineMode"; |
| @@ -742,6 +746,7 @@ const std::set<std::string> ir_builder_suppported_options = {INPUT_FORMAT, | |||
| 742 | OPTION_EXPORT_COMPILE_STAT, | 746 | OPTION_EXPORT_COMPILE_STAT, |
| 743 | OPTIMIZATION_SWITCH, | 747 | OPTIMIZATION_SWITCH, |
| 744 | INPUT_HINT_SHAPE, | 748 | INPUT_HINT_SHAPE, |
| 749 | + INPUT_HINT_VALUE, | ||
| 745 | OPTION_OUTPUT_REUSE_INPUT_MEM_INDEXES, | 750 | OPTION_OUTPUT_REUSE_INPUT_MEM_INDEXES, |
| 746 | OPTION_H2D_OVERLAPPED_WITH_COMPUTE, | 751 | OPTION_H2D_OVERLAPPED_WITH_COMPUTE, |
| 747 | OFFLINE_MODE, | 752 | OFFLINE_MODE, |
| @@ -301,4 +301,101 @@ TEST_F(SymbolizeValueST, test_symbolize_value_and_repeat_infer) { | |||
| 301 | EXPECT_EQ(symbol_expr3.GetHint(hint), true); | 301 | EXPECT_EQ(symbol_expr3.GetHint(hint), true); |
| 302 | EXPECT_EQ(hint, 16 * 2); | 302 | EXPECT_EQ(hint, 16 * 2); |
| 303 | } | 303 | } |
| 304 | + | ||
| 305 | +// ============ Reshape + hint value helpers ============ | ||
| 306 | +ComputeGraphPtr BuildReshapeGraphForTest() { | ||
| 307 | + auto data0 = OP_CFG("Data") | ||
| 308 | + .InCnt(1) | ||
| 309 | + .Attr(ATTR_NAME_INDEX, 0) | ||
| 310 | + .TensorDesc(FORMAT_ND, DT_FLOAT16, {-1, -1, -1, -1}) | ||
| 311 | + .OutCnt(1) | ||
| 312 | + .OutNames({"y"}) | ||
| 313 | + .Build("data0"); | ||
| 314 | + auto data1 = OP_CFG("Data") | ||
| 315 | + .InCnt(1) | ||
| 316 | + .Attr(ATTR_NAME_INDEX, 1) | ||
| 317 | + .TensorDesc(FORMAT_ND, DT_INT64, {2}) | ||
| 318 | + .OutCnt(1) | ||
| 319 | + .OutNames({"y"}) | ||
| 320 | + .Build("data1"); | ||
| 321 | + auto reshape = | ||
| 322 | + OP_CFG("Reshape").TensorDesc(FORMAT_ND, DT_FLOAT16, {-1, -1}).InCnt(2).OutCnt(1).OutNames({"y"}).Build("reshape"); | ||
| 323 | + DEF_GRAPH(g1) { | ||
| 324 | + CHAIN(NODE(data0)->EDGE(0, 0)->NODE(reshape)->NODE("NetOutput", "NetOutput")); | ||
| 325 | + CHAIN(NODE(data1)->EDGE(0, 1)->NODE(reshape)); | ||
| 326 | + }; | ||
| 327 | + auto graph = ToComputeGraph(g1); | ||
| 328 | + graph->TopologicalSorting(); | ||
| 329 | + for (auto &node : graph->GetAllNodes()) { | ||
| 330 | + if (node->GetType() == DATA) { | ||
| 331 | + node->GetOpDesc()->MutableOutputDesc(0)->SetPlacement(kPlacementHost); | ||
| 332 | + } | ||
| 333 | + } | ||
| 334 | + // 设置 Reshape 的 shape 输入为 DT_INT64,与 data1 一致,避免 autofuse 插入 Cast | ||
| 335 | + auto reshape_node = graph->FindNode("reshape"); | ||
| 336 | + if (reshape_node != nullptr) { | ||
| 337 | + reshape_node->GetOpDesc()->MutableInputDesc(1)->SetDataType(DT_INT64); | ||
| 338 | + reshape_node->GetOpDesc()->MutableInputDesc(1)->SetOriginDataType(DT_INT64); | ||
| 339 | + reshape_node->GetOpDesc()->AppendIrInput("x", ge::kIrInputRequired); | ||
| 340 | + reshape_node->GetOpDesc()->AppendIrInput("shape", ge::kIrInputRequired); | ||
| 341 | + } | ||
| 342 | + return graph; | ||
| 343 | +} | ||
| 344 | + | ||
| 345 | +// 空 graph_inputs data + option → Reshape 符号化推导成功 | ||
| 346 | +TEST_F(SymbolizeValueST, reshape_symbolize_infer_with_input_hint_value) { | ||
| 347 | + dlog_setlevel(0, 0, 0); | ||
| 348 | + auto graph = BuildReshapeGraphForTest(); | ||
| 349 | + ASSERT_NE(graph, nullptr); | ||
| 350 | + GeTensor tensor0(GeTensorDesc(GeShape({5, 1, 20, 20}), FORMAT_ND, DT_FLOAT16)); | ||
| 351 | + GeTensor tensor1(GeTensorDesc(GeShape({2}), FORMAT_ND, DT_INT64)); | ||
| 352 | + GetThreadLocalContext().SetGraphOption({ | ||
| 353 | + {INPUT_HINT_SHAPE, "0:[5, 1, 20, 20]"}, | ||
| 354 | + {INPUT_HINT_VALUE, "1:[5, 400]"}, | ||
| 355 | + }); | ||
| 356 | + AutofuseOptimize autofuser; | ||
| 357 | + ASSERT_EQ(autofuser.Run(graph, {tensor0, tensor1}), ge::GRAPH_SUCCESS); | ||
| 358 | + | ||
| 359 | + auto shape_env = graph->GetAttrsGroup<ShapeEnvAttr>(); | ||
| 360 | + ASSERT_NE(shape_env, nullptr); | ||
| 361 | + ShapeEnvGuarder guarder(shape_env); | ||
| 362 | + auto reshape_sym = graph->FindNode("reshape")->GetOpDesc()->MutableOutputDesc(0)->GetAttrsGroup<SymbolicDescAttr>(); | ||
| 363 | + ASSERT_NE(reshape_sym, nullptr); | ||
| 364 | + auto out_shape = reshape_sym->symbolic_tensor.GetOriginSymbolShape(); | ||
| 365 | + ASSERT_EQ(out_shape.GetDimNum(), 2U); | ||
| 366 | + int64_t hint = -1; | ||
| 367 | + EXPECT_EQ(out_shape.GetDim(0).GetHint(hint), true); | ||
| 368 | + EXPECT_EQ(hint, 5); | ||
| 369 | + hint = -1; | ||
| 370 | + EXPECT_EQ(out_shape.GetDim(1).GetHint(hint), true); | ||
| 371 | + EXPECT_EQ(hint, 400); | ||
| 372 | +} | ||
| 373 | + | ||
| 374 | +// graph_inputs 有真实 data → 以真实 data 为准 | ||
| 375 | +TEST_F(SymbolizeValueST, reshape_symbolize_infer_with_real_data) { | ||
| 376 | + dlog_setlevel(0, 0, 0); | ||
| 377 | + auto graph = BuildReshapeGraphForTest(); | ||
| 378 | + ASSERT_NE(graph, nullptr); | ||
| 379 | + GeTensor tensor0(GeTensorDesc(GeShape({5, 1, 20, 20}), FORMAT_ND, DT_FLOAT16)); | ||
| 380 | + GeTensor tensor1(GeTensorDesc(GeShape({2}), FORMAT_ND, DT_INT64)); | ||
| 381 | + vector<int64_t> shape_val = {100, 20}; | ||
| 382 | + tensor1.SetData(reinterpret_cast<uint8_t *>(shape_val.data()), shape_val.size() * sizeof(int64_t)); | ||
| 383 | + AutofuseOptimize autofuser; | ||
| 384 | + ASSERT_EQ(autofuser.Run(graph, {tensor0, tensor1}), ge::GRAPH_SUCCESS); | ||
| 385 | + | ||
| 386 | + auto shape_env = graph->GetAttrsGroup<ShapeEnvAttr>(); | ||
| 387 | + ASSERT_NE(shape_env, nullptr); | ||
| 388 | + ShapeEnvGuarder guarder(shape_env); | ||
| 389 | + auto reshape_sym = graph->FindNode("reshape")->GetOpDesc()->MutableOutputDesc(0)->GetAttrsGroup<SymbolicDescAttr>(); | ||
| 390 | + ASSERT_NE(reshape_sym, nullptr); | ||
| 391 | + auto out_shape = reshape_sym->symbolic_tensor.GetOriginSymbolShape(); | ||
| 392 | + ASSERT_EQ(out_shape.GetDimNum(), 2U); | ||
| 393 | + int64_t hint = -1; | ||
| 394 | + EXPECT_EQ(out_shape.GetDim(0).GetHint(hint), true); | ||
| 395 | + EXPECT_EQ(hint, 100); | ||
| 396 | + hint = -1; | ||
| 397 | + EXPECT_EQ(out_shape.GetDim(1).GetHint(hint), true); | ||
| 398 | + EXPECT_EQ(hint, 20); | ||
| 399 | +} | ||
| 400 | + | ||
| 304 | } // namespace ge | 401 | } // namespace ge |
| @@ -5930,4 +5930,42 @@ TEST_F(UtestGraphManagerTest, GraphManager_UpdateDynamicParams_WithDynamicDims) | |||
| 5930 | graph_manager.UpdateDynamicParams(input_shape, dynamic_dims, dynamic_node_type, graph_options); | 5930 | graph_manager.UpdateDynamicParams(input_shape, dynamic_dims, dynamic_node_type, graph_options); |
| 5931 | EXPECT_EQ(dynamic_node_type, 2); | 5931 | EXPECT_EQ(dynamic_node_type, 2); |
| 5932 | } | 5932 | } |
| 5933 | + | ||
| 5934 | +TEST_F(UtestGraphManagerTest, CheckIncreBuild_PreRun_DeviceTensor_NoCrash) { | ||
| 5935 | + GraphId graph_id = 1; | ||
| 5936 | + GraphManager graph_manager; | ||
| 5937 | + graph_manager.graph_rebuild_state_ctrl_ = MakeShared<GraphRebuildStateCtrl>(); | ||
| 5938 | + std::shared_ptr<RunArgs> arg = std::make_shared<RunArgs>(); | ||
| 5939 | + ASSERT_TRUE(arg != nullptr); | ||
| 5940 | + arg->callback = [](Status, std::vector<gert::Tensor> &) {}; | ||
| 5941 | + std::vector<gert::Tensor> inputs; | ||
| 5942 | + inputs.emplace_back(gert::StorageShape({2, 3}, {2, 3}), | ||
| 5943 | + gert::StorageFormat(FORMAT_ND, FORMAT_ND, gert::ExpandDimsType()), DT_FLOAT16); | ||
| 5944 | + inputs[0].SetPlacement(gert::TensorPlacement::kOnDeviceHbm); | ||
| 5945 | + arg->input_tensor = std::move(inputs); | ||
| 5946 | + GraphNodePtr graph_node = MakeShared<ge::GraphNode>(graph_id); | ||
| 5947 | + graph_node->SetBuildFlag(false); | ||
| 5948 | + graph_node->Lock(); | ||
| 5949 | + Status status = graph_manager.CheckIncreBuildAndPreRun(arg, graph_node); | ||
| 5950 | + EXPECT_NE(status, ge::SUCCESS); | ||
| 5951 | +} | ||
| 5952 | + | ||
| 5953 | +TEST_F(UtestGraphManagerTest, CheckIncreBuild_PreRun_HostTensor_NoCrash) { | ||
| 5954 | + GraphId graph_id = 2; | ||
| 5955 | + GraphManager graph_manager; | ||
| 5956 | + graph_manager.graph_rebuild_state_ctrl_ = MakeShared<GraphRebuildStateCtrl>(); | ||
| 5957 | + std::shared_ptr<RunArgs> arg = std::make_shared<RunArgs>(); | ||
| 5958 | + ASSERT_TRUE(arg != nullptr); | ||
| 5959 | + arg->callback = [](Status, std::vector<gert::Tensor> &) {}; | ||
| 5960 | + const std::vector<int64_t> data = {100, 20}; | ||
| 5961 | + std::vector<gert::Tensor> inputs; | ||
| 5962 | + inputs.emplace_back(gert::StorageShape({2}, {2}), gert::StorageFormat(FORMAT_ND, FORMAT_ND, gert::ExpandDimsType()), | ||
| 5963 | + gert::TensorPlacement::kOnHost, DT_INT64, const_cast<int64_t *>(data.data())); | ||
| 5964 | + arg->input_tensor = std::move(inputs); | ||
| 5965 | + GraphNodePtr graph_node = MakeShared<ge::GraphNode>(graph_id); | ||
| 5966 | + graph_node->SetBuildFlag(false); | ||
| 5967 | + graph_node->Lock(); | ||
| 5968 | + Status status = graph_manager.CheckIncreBuildAndPreRun(arg, graph_node); | ||
| 5969 | + EXPECT_NE(status, ge::SUCCESS); | ||
| 5970 | +} | ||
| 5933 | } // namespace ge | 5971 | } // namespace ge |
| @@ -0,0 +1,163 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +namespace ge { | ||
| 34 | + | ||
| 35 | +class SymbolicValueInferenceUT : public testing::Test { | ||
| 36 | + public: | ||
| 37 | + protected: | ||
| 38 | + void SetUp() override { | ||
| 39 | + EnableSliceScheduleEnv(); | ||
| 40 | + dlog_setlevel(0, 0, 0); | ||
| 41 | + global_options_ = GetThreadLocalContext().GetAllGlobalOptions(); | ||
| 42 | + graph_options_ = GetThreadLocalContext().GetAllGraphOptions(); | ||
| 43 | + session_options_ = GetThreadLocalContext().GetAllSessionOptions(); | ||
| 44 | + GetThreadLocalContext().SetGlobalOption({}); | ||
| 45 | + GetThreadLocalContext().SetGraphOption({}); | ||
| 46 | + GetThreadLocalContext().SetSessionOption({}); | ||
| 47 | + std::map<std::string, std::string> options; | ||
| 48 | + GetThreadLocalContext().GetOo().Initialize(options, OptionRegistry::GetInstance().GetRegisteredOptTable()); | ||
| 49 | + } | ||
| 50 | + void TearDown() override { | ||
| 51 | + GetThreadLocalContext().SetGlobalOption(global_options_); | ||
| 52 | + GetThreadLocalContext().SetGraphOption(graph_options_); | ||
| 53 | + GetThreadLocalContext().SetSessionOption(session_options_); | ||
| 54 | + DisableSliceScheduleEnv(); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + ComputeGraphPtr CreateReshapeGraph() { | ||
| 58 | + auto data0 = OP_CFG("Data") | ||
| 59 | + .InCnt(1) | ||
| 60 | + .Attr(ATTR_NAME_INDEX, 0) | ||
| 61 | + .TensorDesc(FORMAT_ND, DT_FLOAT16, {-1, -1, -1, -1}) | ||
| 62 | + .OutCnt(1) | ||
| 63 | + .OutNames({"y"}) | ||
| 64 | + .Build("data0"); | ||
| 65 | + auto data1 = OP_CFG("Data") | ||
| 66 | + .InCnt(1) | ||
| 67 | + .Attr(ATTR_NAME_INDEX, 1) | ||
| 68 | + .TensorDesc(FORMAT_ND, DT_INT64, {2}) | ||
| 69 | + .OutCnt(1) | ||
| 70 | + .OutNames({"y"}) | ||
| 71 | + .Build("data1"); | ||
| 72 | + auto reshape = OP_CFG("Reshape") | ||
| 73 | + .TensorDesc(FORMAT_ND, DT_FLOAT16, {-1, -1}) | ||
| 74 | + .InCnt(2) | ||
| 75 | + .OutCnt(1) | ||
| 76 | + .OutNames({"y"}) | ||
| 77 | + .Build("reshape"); | ||
| 78 | + DEF_GRAPH(g1) { | ||
| 79 | + CHAIN(NODE(data0)->EDGE(0, 0)->NODE(reshape)->NODE("NetOutput", "NetOutput")); | ||
| 80 | + CHAIN(NODE(data1)->EDGE(0, 1)->NODE(reshape)); | ||
| 81 | + }; | ||
| 82 | + auto cg = ToComputeGraph(g1); | ||
| 83 | + for (auto &node : cg->GetAllNodes()) { | ||
| 84 | + if (node->GetType() == DATA) { | ||
| 85 | + node->GetOpDesc()->MutableOutputDesc(0)->SetPlacement(kPlacementHost); | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + SetNoStorage(cg, "data0", {FORMAT_ND, DT_FLOAT16, {-1, -1, -1, -1}}, 0); | ||
| 89 | + SetNoStorage(cg, "data1", {FORMAT_ND, DT_INT64, {2}}, 1); | ||
| 90 | + auto reshape_node = cg->FindNode("reshape"); | ||
| 91 | + if (reshape_node != nullptr) { | ||
| 92 | + reshape_node->GetOpDesc()->AppendIrInput("x", ge::kIrInputRequired); | ||
| 93 | + reshape_node->GetOpDesc()->AppendIrInput("shape", ge::kIrInputRequired); | ||
| 94 | + } | ||
| 95 | + return cg; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + void RunSymbolize(const ComputeGraphPtr &cg, const std::vector<GeTensor> &graph_inputs) { | ||
| 99 | + GetThreadLocalContext().SetGraphOption({ | ||
| 100 | + {INPUT_HINT_SHAPE, "0:[5, 1, 20, 20];1:[]"}, | ||
| 101 | + {INPUT_HINT_VALUE, "1:[5, 400]"}, | ||
| 102 | + }); | ||
| 103 | + ASSERT_EQ(SymbolicShapeSymbolizer::Symbolize(cg, graph_inputs), SUCCESS); | ||
| 104 | + SymbolicShapeInference ssi; | ||
| 105 | + ASSERT_EQ(ssi.Infer(cg), SUCCESS); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + private: | ||
| 109 | + std::map<std::string, std::string> global_options_; | ||
| 110 | + std::map<std::string, std::string> graph_options_; | ||
| 111 | + std::map<std::string, std::string> session_options_; | ||
| 112 | +}; | ||
| 113 | + | ||
| 114 | +// 空 graph_inputs data + option → Reshape 符号化推导成功 | ||
| 115 | +TEST_F(SymbolicValueInferenceUT, compile_path_reshape_with_hint_value) { | ||
| 116 | + auto cg = CreateReshapeGraph(); | ||
| 117 | + ASSERT_NE(cg, nullptr); | ||
| 118 | + std::vector<GeTensor> graph_inputs; | ||
| 119 | + graph_inputs.emplace_back(BuildGeTensor<float, DT_FLOAT16>({5, 1, 20, 20}, {})); | ||
| 120 | + graph_inputs.emplace_back(BuildGeTensor<int64_t, DT_INT64>({2}, {})); | ||
| 121 | + RunSymbolize(cg, graph_inputs); | ||
| 122 | + | ||
| 123 | + auto shape_env = cg->GetAttrsGroup<ShapeEnvAttr>(); | ||
| 124 | + ASSERT_NE(shape_env, nullptr); | ||
| 125 | + ShapeEnvGuarder guarder(shape_env); | ||
| 126 | + auto reshape_sym = cg->FindNode("reshape")->GetOpDesc()->MutableOutputDesc(0)->GetAttrsGroup<SymbolicDescAttr>(); | ||
| 127 | + ASSERT_NE(reshape_sym, nullptr); | ||
| 128 | + auto out_shape = reshape_sym->symbolic_tensor.GetOriginSymbolShape(); | ||
| 129 | + ASSERT_EQ(out_shape.GetDimNum(), 2U); | ||
| 130 | + int64_t hint = -1; | ||
| 131 | + EXPECT_EQ(out_shape.GetDim(0).GetHint(hint), true); | ||
| 132 | + EXPECT_EQ(hint, 5); | ||
| 133 | + hint = -1; | ||
| 134 | + EXPECT_EQ(out_shape.GetDim(1).GetHint(hint), true); | ||
| 135 | + EXPECT_EQ(hint, 400); | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | +// graph_inputs 有真实 data + option → 以真实 data 为准 | ||
| 139 | +TEST_F(SymbolicValueInferenceUT, execute_path_reshape_with_real_data) { | ||
| 140 | + auto cg = CreateReshapeGraph(); | ||
| 141 | + ASSERT_NE(cg, nullptr); | ||
| 142 | + std::vector<GeTensor> graph_inputs; | ||
| 143 | + graph_inputs.emplace_back(BuildGeTensor<float, DT_FLOAT16>({5, 1, 20, 20}, {})); | ||
| 144 | + std::vector<int64_t> shape_data = {100, 20}; | ||
| 145 | + graph_inputs.emplace_back(BuildGeTensor<int64_t, DT_INT64>({2}, shape_data)); | ||
| 146 | + RunSymbolize(cg, graph_inputs); | ||
| 147 | + | ||
| 148 | + auto shape_env = cg->GetAttrsGroup<ShapeEnvAttr>(); | ||
| 149 | + ASSERT_NE(shape_env, nullptr); | ||
| 150 | + ShapeEnvGuarder guarder(shape_env); | ||
| 151 | + auto reshape_sym = cg->FindNode("reshape")->GetOpDesc()->MutableOutputDesc(0)->GetAttrsGroup<SymbolicDescAttr>(); | ||
| 152 | + ASSERT_NE(reshape_sym, nullptr); | ||
| 153 | + auto out_shape = reshape_sym->symbolic_tensor.GetOriginSymbolShape(); | ||
| 154 | + ASSERT_EQ(out_shape.GetDimNum(), 2U); | ||
| 155 | + int64_t hint = -1; | ||
| 156 | + EXPECT_EQ(out_shape.GetDim(0).GetHint(hint), true); | ||
| 157 | + EXPECT_EQ(hint, 100); | ||
| 158 | + hint = -1; | ||
| 159 | + EXPECT_EQ(out_shape.GetDim(1).GetHint(hint), true); | ||
| 160 | + EXPECT_EQ(hint, 20); | ||
| 161 | +} | ||
| 162 | + | ||
| 163 | +} // namespace ge | ||
| @@ -411,8 +411,9 @@ TEST_F(JitExecutorUT, run_success_when_input_graph_contain_one_reshape_node) { | |||
| 411 | td.SetOriginShape(Shape(shape_dim)); | 411 | td.SetOriginShape(Shape(shape_dim)); |
| 412 | Tensor tensor(td); | 412 | Tensor tensor(td); |
| 413 | std::vector<int64_t> input_data_2{2, 3, 3, 2}; | 413 | std::vector<int64_t> input_data_2{2, 3, 3, 2}; |
| 414 | - TensorDesc desc_2(Shape({4}), FORMAT_NCHW, DT_INT32); | 414 | + TensorDesc desc_2(Shape({4}), FORMAT_NCHW, DT_INT64); |
| 415 | desc_2.SetOriginShape(Shape({4})); | 415 | desc_2.SetOriginShape(Shape({4})); |
| 416 | + desc_2.SetPlacement(Placement::kPlacementHost); | ||
| 416 | Tensor input_tensor_2{desc_2}; | 417 | Tensor input_tensor_2{desc_2}; |
| 417 | input_tensor_2.SetData(reinterpret_cast<uint8_t *>(input_data_2.data()), input_data_2.size() * sizeof(int64_t)); | 418 | input_tensor_2.SetData(reinterpret_cast<uint8_t *>(input_data_2.data()), input_data_2.size() * sizeof(int64_t)); |
| 418 | std::vector<Tensor> inputs{tensor, input_tensor_2}; | 419 | std::vector<Tensor> inputs{tensor, input_tensor_2}; |
| @@ -567,8 +568,9 @@ TEST_F(JitExecutorUT, run_success_when_input_graph_contain_one_reshape_two_relu_ | |||
| 567 | std::vector<int64_t> input_data_1(36, 0); | 568 | std::vector<int64_t> input_data_1(36, 0); |
| 568 | tensor.SetData(reinterpret_cast<uint8_t *>(input_data_1.data()), 36 * sizeof(int64_t)); | 569 | tensor.SetData(reinterpret_cast<uint8_t *>(input_data_1.data()), 36 * sizeof(int64_t)); |
| 569 | std::vector<int64_t> input_data_2{2, 3, 3, 2}; | 570 | std::vector<int64_t> input_data_2{2, 3, 3, 2}; |
| 570 | - TensorDesc desc_2(Shape({4}), FORMAT_NCHW, DT_INT32); | 571 | + TensorDesc desc_2(Shape({4}), FORMAT_NCHW, DT_INT64); |
| 571 | desc_2.SetOriginShape(Shape({4})); | 572 | desc_2.SetOriginShape(Shape({4})); |
| 573 | + desc_2.SetPlacement(Placement::kPlacementHost); | ||
| 572 | Tensor input_tensor_2{desc_2}; | 574 | Tensor input_tensor_2{desc_2}; |
| 573 | input_tensor_2.SetData(reinterpret_cast<uint8_t *>(input_data_2.data()), input_data_2.size() * sizeof(int64_t)); | 575 | input_tensor_2.SetData(reinterpret_cast<uint8_t *>(input_data_2.data()), input_data_2.size() * sizeof(int64_t)); |
| 574 | std::vector<int64_t> data3_shape_dim = {2, 3, 3}; | 576 | std::vector<int64_t> data3_shape_dim = {2, 3, 3}; |
| @@ -625,8 +627,9 @@ TEST_F(JitExecutorUT, run_success_when_input_graph_contain_two_reshape_node) { | |||
| 625 | td.SetOriginShape(Shape(shape_dim)); | 627 | td.SetOriginShape(Shape(shape_dim)); |
| 626 | Tensor tensor(td); | 628 | Tensor tensor(td); |
| 627 | std::vector<int64_t> input_data_2{2, 3, 3, 2}; | 629 | std::vector<int64_t> input_data_2{2, 3, 3, 2}; |
| 628 | - TensorDesc desc_2(Shape({4}), FORMAT_NCHW, DT_INT32); | 630 | + TensorDesc desc_2(Shape({4}), FORMAT_NCHW, DT_INT64); |
| 629 | desc_2.SetOriginShape(Shape({4})); | 631 | desc_2.SetOriginShape(Shape({4})); |
| 632 | + desc_2.SetPlacement(Placement::kPlacementHost); | ||
| 630 | Tensor input_tensor_2{desc_2}; | 633 | Tensor input_tensor_2{desc_2}; |
| 631 | input_tensor_2.SetData(reinterpret_cast<uint8_t *>(input_data_2.data()), input_data_2.size() * sizeof(int64_t)); | 634 | input_tensor_2.SetData(reinterpret_cast<uint8_t *>(input_data_2.data()), input_data_2.size() * sizeof(int64_t)); |
| 632 | std::vector<Tensor> inputs{tensor, input_tensor_2}; | 635 | std::vector<Tensor> inputs{tensor, input_tensor_2}; |
| @@ -680,8 +683,9 @@ TEST_F(JitExecutorUT, run_success_when_input_graph_contain_two_reshape_one_const | |||
| 680 | td.SetOriginShape(Shape(shape_dim)); | 683 | td.SetOriginShape(Shape(shape_dim)); |
| 681 | Tensor tensor(td); | 684 | Tensor tensor(td); |
| 682 | std::vector<int64_t> input_data_2 = {2, 3, 3, 2}; | 685 | std::vector<int64_t> input_data_2 = {2, 3, 3, 2}; |
| 683 | - TensorDesc desc_2(Shape({4}), FORMAT_NCHW, DT_INT32); | 686 | + TensorDesc desc_2(Shape({4}), FORMAT_NCHW, DT_INT64); |
| 684 | desc_2.SetOriginShape(Shape({4})); | 687 | desc_2.SetOriginShape(Shape({4})); |
| 688 | + desc_2.SetPlacement(Placement::kPlacementHost); | ||
| 685 | Tensor input_tensor_2{desc_2}; | 689 | Tensor input_tensor_2{desc_2}; |
| 686 | input_tensor_2.SetData(reinterpret_cast<uint8_t *>(input_data_2.data()), input_data_2.size() * sizeof(int64_t)); | 690 | input_tensor_2.SetData(reinterpret_cast<uint8_t *>(input_data_2.data()), input_data_2.size() * sizeof(int64_t)); |
| 687 | std::vector<Tensor> inputs{tensor, input_tensor_2}; | 691 | std::vector<Tensor> inputs{tensor, input_tensor_2}; |
| @@ -922,28 +922,6 @@ TEST_F(UserGraphsManagerlUT, add_graph_verify_options_flow_to_ep_after_slicing) | |||
| 922 | EXPECT_EQ(graph_manager.Finalize(), SUCCESS); | 922 | EXPECT_EQ(graph_manager.Finalize(), SUCCESS); |
| 923 | } | 923 | } |
| 924 | 924 | ||
| 925 | -static void VerifyEpOptions(const std::vector<std::unique_ptr<ge::ExecutionPoint>> &slice_graphs) { | ||
| 926 | - EXPECT_GE(slice_graphs.size(), 2U) << "should have first + last EPs"; | ||
| 927 | - | ||
| 928 | - auto &first_opts = slice_graphs.front()->GetEpGraphOptions(); | ||
| 929 | - EXPECT_NE(first_opts.find("ge.inputShape"), first_opts.end()); | ||
| 930 | - EXPECT_EQ(first_opts.size(), 3U); | ||
| 931 | - | ||
| 932 | - for (size_t i = 1; i < slice_graphs.size() - 1; ++i) { | ||
| 933 | - auto &mid_opts = slice_graphs[i]->GetEpGraphOptions(); | ||
| 934 | - EXPECT_EQ(mid_opts.find("ge.inputShape"), mid_opts.end()); | ||
| 935 | - EXPECT_EQ(mid_opts.find("ge.outputDatatype"), mid_opts.end()); | ||
| 936 | - EXPECT_NE(mid_opts.find("my.custom"), mid_opts.end()); | ||
| 937 | - EXPECT_EQ(mid_opts.size(), 1U); | ||
| 938 | - } | ||
| 939 | - | ||
| 940 | - auto &last_opts = slice_graphs.back()->GetEpGraphOptions(); | ||
| 941 | - EXPECT_EQ(last_opts.find("ge.inputShape"), last_opts.end()); | ||
| 942 | - EXPECT_NE(last_opts.find("ge.outputDatatype"), last_opts.end()); | ||
| 943 | - EXPECT_NE(last_opts.find("my.custom"), last_opts.end()); | ||
| 944 | - EXPECT_EQ(last_opts.size(), 2U); | ||
| 945 | -} | ||
| 946 | - | ||
| 947 | TEST_F(UserGraphsManagerlUT, add_graph_verify_multi_ep_options_seperation) { | 925 | TEST_F(UserGraphsManagerlUT, add_graph_verify_multi_ep_options_seperation) { |
| 948 | ModelExecutor model_executor; | 926 | ModelExecutor model_executor; |
| 949 | model_executor.Initialize({}, 0); | 927 | model_executor.Initialize({}, 0); |
| @@ -967,8 +945,7 @@ TEST_F(UserGraphsManagerlUT, add_graph_verify_multi_ep_options_seperation) { | |||
| 967 | gert::kOnDeviceHbm, | 945 | gert::kOnDeviceHbm, |
| 968 | ge::DT_FLOAT, | 946 | ge::DT_FLOAT, |
| 969 | data0.data()}; | 947 | data0.data()}; |
| 970 | - inputs[1] = { | 948 | + inputs[1] = {{{4}, {4}}, {ge::FORMAT_ND, ge::FORMAT_FRACTAL_NZ, {}}, gert::kOnHost, ge::DT_INT64, shape_data.data()}; |
| 971 | - {{4}, {4}}, {ge::FORMAT_ND, ge::FORMAT_FRACTAL_NZ, {}}, gert::kOnDeviceHbm, ge::DT_INT64, shape_data.data()}; | ||
| 972 | 949 | ||
| 973 | std::promise<Status> promise; | 950 | std::promise<Status> promise; |
| 974 | auto future = promise.get_future(); | 951 | auto future = promise.get_future(); |
| @@ -980,7 +957,12 @@ TEST_F(UserGraphsManagerlUT, add_graph_verify_multi_ep_options_seperation) { | |||
| 980 | promise.set_value(FAILED); | 957 | promise.set_value(FAILED); |
| 981 | return FAILED; | 958 | return FAILED; |
| 982 | } | 959 | } |
| 983 | - VerifyEpOptions(ctrl->order_.slice_graphs_); | 960 | + EXPECT_EQ(ctrl->order_.slice_graphs_.size(), 1U) << "reshape not break since value symbolization"; |
| 961 | + auto &opts = ctrl->order_.slice_graphs_.front()->GetEpGraphOptions(); | ||
| 962 | + EXPECT_NE(opts.find("ge.inputShape"), opts.end()); | ||
| 963 | + EXPECT_NE(opts.find("ge.outputDatatype"), opts.end()); | ||
| 964 | + EXPECT_NE(opts.find("my.custom"), opts.end()); | ||
| 965 | + EXPECT_EQ(opts.size(), 3U); | ||
| 984 | promise.set_value(status); | 966 | promise.set_value(status); |
| 985 | return SUCCESS; | 967 | return SUCCESS; |
| 986 | }; | 968 | }; |
| @@ -992,24 +974,6 @@ TEST_F(UserGraphsManagerlUT, add_graph_verify_multi_ep_options_seperation) { | |||
| 992 | EXPECT_EQ(graph_manager.Finalize(), SUCCESS); | 974 | EXPECT_EQ(graph_manager.Finalize(), SUCCESS); |
| 993 | } | 975 | } |
| 994 | 976 | ||
| 995 | -static void VerifyThreeEpOptions(const std::vector<std::unique_ptr<ge::ExecutionPoint>> &slice_graphs) { | ||
| 996 | - ASSERT_GE(slice_graphs.size(), 3U) << "should have at least 3 EPs (first + middle + ...)"; | ||
| 997 | - | ||
| 998 | - auto &first_opts = slice_graphs.front()->GetEpGraphOptions(); | ||
| 999 | - EXPECT_NE(first_opts.find("ge.inputShape"), first_opts.end()); | ||
| 1000 | - EXPECT_EQ(first_opts.size(), 3U); | ||
| 1001 | - | ||
| 1002 | - for (size_t i = 1; i < slice_graphs.size(); ++i) { | ||
| 1003 | - auto &mid_opts = slice_graphs[i]->GetEpGraphOptions(); | ||
| 1004 | - EXPECT_EQ(mid_opts.find("ge.inputShape"), mid_opts.end()); | ||
| 1005 | - EXPECT_NE(mid_opts.find("my.custom"), mid_opts.end()); | ||
| 1006 | - if (i < slice_graphs.size() - 1) { | ||
| 1007 | - EXPECT_EQ(mid_opts.find("ge.outputDatatype"), mid_opts.end()); | ||
| 1008 | - EXPECT_EQ(mid_opts.size(), 1U); | ||
| 1009 | - } | ||
| 1010 | - } | ||
| 1011 | -} | ||
| 1012 | - | ||
| 1013 | TEST_F(UserGraphsManagerlUT, add_graph_verify_three_ep_middle_options) { | 977 | TEST_F(UserGraphsManagerlUT, add_graph_verify_three_ep_middle_options) { |
| 1014 | ModelExecutor model_executor; | 978 | ModelExecutor model_executor; |
| 1015 | model_executor.Initialize({}, 0); | 979 | model_executor.Initialize({}, 0); |
| @@ -1033,19 +997,23 @@ TEST_F(UserGraphsManagerlUT, add_graph_verify_three_ep_middle_options) { | |||
| 1033 | gert::kOnDeviceHbm, | 997 | gert::kOnDeviceHbm, |
| 1034 | ge::DT_FLOAT, | 998 | ge::DT_FLOAT, |
| 1035 | data0.data()}; | 999 | data0.data()}; |
| 1036 | - inputs[1] = { | 1000 | + inputs[1] = {{{4}, {4}}, {ge::FORMAT_ND, ge::FORMAT_FRACTAL_NZ, {}}, gert::kOnHost, ge::DT_INT64, shape_data.data()}; |
| 1037 | - {{4}, {4}}, {ge::FORMAT_ND, ge::FORMAT_FRACTAL_NZ, {}}, gert::kOnDeviceHbm, ge::DT_INT64, shape_data.data()}; | ||
| 1038 | 1001 | ||
| 1039 | std::promise<Status> promise; | 1002 | std::promise<Status> promise; |
| 1040 | auto future = promise.get_future(); | 1003 | auto future = promise.get_future(); |
| 1041 | auto *ugm_ptr = &user_graph_manager; | 1004 | auto *ugm_ptr = &user_graph_manager; |
| 1042 | const RunAsyncCallbackV2 callback = [&](Status status, std::vector<gert::Tensor> &outputs) { | 1005 | const RunAsyncCallbackV2 callback = [&](Status status, std::vector<gert::Tensor> &outputs) { |
| 1043 | auto *ctrl = ugm_ptr->ids_to_user_graph_ctrl_[user_graph_id].get(); | 1006 | auto *ctrl = ugm_ptr->ids_to_user_graph_ctrl_[user_graph_id].get(); |
| 1044 | - if (ctrl == nullptr || ctrl->order_.slice_graphs_.size() < 3U) { | 1007 | + if (ctrl == nullptr || ctrl->order_.slice_graphs_.empty()) { |
| 1045 | promise.set_value(FAILED); | 1008 | promise.set_value(FAILED); |
| 1046 | return FAILED; | 1009 | return FAILED; |
| 1047 | } | 1010 | } |
| 1048 | - VerifyThreeEpOptions(ctrl->order_.slice_graphs_); | 1011 | + EXPECT_EQ(ctrl->order_.slice_graphs_.size(), 1U) << "reshape not break since value symbolization"; |
| 1012 | + auto &opts = ctrl->order_.slice_graphs_.front()->GetEpGraphOptions(); | ||
| 1013 | + EXPECT_NE(opts.find("ge.inputShape"), opts.end()); | ||
| 1014 | + EXPECT_NE(opts.find("ge.outputDatatype"), opts.end()); | ||
| 1015 | + EXPECT_NE(opts.find("my.custom"), opts.end()); | ||
| 1016 | + EXPECT_EQ(opts.size(), 3U); | ||
| 1049 | promise.set_value(SUCCESS); | 1017 | promise.set_value(SUCCESS); |
| 1050 | return SUCCESS; | 1018 | return SUCCESS; |
| 1051 | }; | 1019 | }; |


所有的值依赖输入都做d2h拷贝吗,这个要评估影响