已合并
fix: reduce_min/reduce_max/reduce_prod/reduce_log_sum_exp axis empty onnx plugin #3424
RuiWang_创建于 6月18日
fix: reduce_min/reduce_max/reduce_prod/reduce_log_sum_exp axis empty onnx plugin #3424
已合并
共 4 个文件变更+225-199
| @@ -1,5 +1,5 @@ | |||
| 1 | /** | 1 | /** |
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | + * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 3 | * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 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"). | 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. | 5 | * Please refer to the License for details. You may not use this file except in compliance with the License. |
| @@ -11,28 +11,22 @@ | |||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | -using namespace std; | ||
| 15 | using namespace ge; | 14 | using namespace ge; |
| 16 | using ge::Operator; | 15 | using ge::Operator; |
| 17 | 16 | ||
| 18 | namespace domi { | 17 | namespace domi { |
| 18 | +using NodeProto = ge::onnx::NodeProto; | ||
| 19 | + | ||
| 19 | static Status ParseParamsReduceLogSumExp(const Message* op_src, ge::Operator& op_dest) | 20 | static Status ParseParamsReduceLogSumExp(const Message* op_src, ge::Operator& op_dest) |
| 20 | { | 21 | { |
| 21 | - const ge::onnx::NodeProto* node = dynamic_cast<const ge::onnx::NodeProto*>(op_src); | 22 | + const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); |
| 22 | if (node == nullptr) { | 23 | if (node == nullptr) { |
| 23 | OP_LOGE(GetOpName(op_dest).c_str(), "Dynamic cast op_src to NodeProto failed."); | 24 | OP_LOGE(GetOpName(op_dest).c_str(), "Dynamic cast op_src to NodeProto failed."); |
| 24 | return FAILED; | 25 | return FAILED; |
| 25 | } | 26 | } |
| 26 | 27 | ||
| 27 | - int op_input_size = node->input_size(); | ||
| 28 | - int op_output_size = node->output_size(); | ||
| 29 | - op_dest.DynamicInputRegister("x", op_input_size); | ||
| 30 | - op_dest.DynamicOutputRegister("y", op_output_size); | ||
| 31 | - op_dest.SetAttr("original_type", "ai.onnx::11::ReduceLogSumExp"); | ||
| 32 | - | ||
| 33 | std::vector<int> v_axes = {}; | 28 | std::vector<int> v_axes = {}; |
| 34 | bool keep_dims = true; | 29 | bool keep_dims = true; |
| 35 | - | ||
| 36 | for (const auto& attr : node->attribute()) { | 30 | for (const auto& attr : node->attribute()) { |
| 37 | if (attr.name() == "axes" && attr.type() == ge::onnx::AttributeProto::INTS) { | 31 | if (attr.name() == "axes" && attr.type() == ge::onnx::AttributeProto::INTS) { |
| 38 | for (int i = 0; i < attr.ints_size(); i++) { | 32 | for (int i = 0; i < attr.ints_size(); i++) { |
| @@ -40,26 +34,34 @@ static Status ParseParamsReduceLogSumExp(const Message* op_src, ge::Operator& op | |||
| 40 | } | 34 | } |
| 41 | } else if (attr.name() == "keepdims" && attr.type() == ge::onnx::AttributeProto::INT) { | 35 | } else if (attr.name() == "keepdims" && attr.type() == ge::onnx::AttributeProto::INT) { |
| 42 | keep_dims = (attr.i() == 1); | 36 | keep_dims = (attr.i() == 1); |
| 43 | - } else if ( | 37 | + } |
| 44 | - attr.name() == "noop_with_empty_axes" && attr.type() == ge::onnx::AttributeProto::INT && attr.i() == 1) { | 38 | + if (attr.name() == "noop_with_empty_axes" && attr.type() == ge::onnx::AttributeProto::INT && attr.i() == 1) { |
| 45 | OP_LOGW(GetOpName(op_dest).c_str(), "Only support noop_with_empty_axes=0, but 1 is obtained now"); | 39 | OP_LOGW(GetOpName(op_dest).c_str(), "Only support noop_with_empty_axes=0, but 1 is obtained now"); |
| 46 | } | 40 | } |
| 47 | } | 41 | } |
| 48 | 42 | ||
| 49 | - int64_t len = v_axes.size(); | 43 | + int num = v_axes.size(); |
| 50 | std::vector<int64_t> dims = {}; | 44 | std::vector<int64_t> dims = {}; |
| 51 | - if (len != 0) { | 45 | + if (num != 0) { |
| 52 | - dims.push_back(len); | 46 | + dims.push_back(num); |
| 47 | + } else { | ||
| 48 | + dims.push_back(0); | ||
| 53 | } | 49 | } |
| 54 | - ge::Tensor tensor1 = Vec2Tensor(v_axes, dims, DT_INT32, ge::FORMAT_ND); | 50 | + ge::Tensor tensor = Vec2Tensor(v_axes, dims, ge::DT_INT32, ge::FORMAT_NCHW); |
| 55 | - op_dest.SetAttr("axes", tensor1); | 51 | + |
| 56 | - op_dest.SetAttr("keep_dims", keep_dims); | ||
| 57 | op_dest.SetAttr("name", node->name()); | 52 | op_dest.SetAttr("name", node->name()); |
| 53 | + op_dest.SetAttr("axes", tensor); | ||
| 54 | + op_dest.SetAttr("keep_dims", keep_dims); | ||
| 55 | + const int input = 2; | ||
| 56 | + const int output = 1; | ||
| 57 | + op_dest.DynamicInputRegister("x", input); | ||
| 58 | + op_dest.DynamicOutputRegister("y", output); | ||
| 59 | + op_dest.SetAttr("original_type", "ai.onnx::11::ReduceLogSumExp"); | ||
| 58 | 60 | ||
| 59 | return SUCCESS; | 61 | return SUCCESS; |
| 60 | } | 62 | } |
| 61 | 63 | ||
| 62 | -static Status ParseOpToGraphReduceLogSumExp(const Operator& op, Graph& graph) | 64 | +static Status ParseOpToGraphReduceLogSumExp(const ge::Operator& op, Graph& graph) |
| 63 | { | 65 | { |
| 64 | std::string ori_name; | 66 | std::string ori_name; |
| 65 | if (op.GetAttr("name", ori_name) != SUCCESS) { | 67 | if (op.GetAttr("name", ori_name) != SUCCESS) { |
| @@ -67,45 +69,150 @@ static Status ParseOpToGraphReduceLogSumExp(const Operator& op, Graph& graph) | |||
| 67 | return FAILED; | 69 | return FAILED; |
| 68 | } | 70 | } |
| 69 | 71 | ||
| 70 | - bool flag = false; | 72 | + auto data0 = op::Data((ori_name + "_data0").c_str()).set_attr_index(0); |
| 71 | - ge::Tensor const_value; | 73 | + |
| 72 | - if (op.GetAttr("axes", const_value) != SUCCESS) { | 74 | + ge::Tensor axes; |
| 75 | + if (op.GetAttr("axes", axes) != SUCCESS) { | ||
| 73 | OP_LOGE(GetOpName(op).c_str(), "get axes from op failed"); | 76 | OP_LOGE(GetOpName(op).c_str(), "get axes from op failed"); |
| 74 | return FAILED; | 77 | return FAILED; |
| 75 | } | 78 | } |
| 76 | - if (op.GetAttr("keep_dims", flag) != SUCCESS) { | 79 | + |
| 77 | - OP_LOGE(GetOpName(op).c_str(), "get value of keep_dims from op failed."); | 80 | + auto data1 = op::Const((ori_name + "_data1").c_str()).set_attr_value(axes); |
| 81 | + auto reduce_log_sum_exp = | ||
| 82 | + op::ReduceLogSumExp((ori_name + "_ReduceLogSumExp").c_str()).set_input_x(data0).set_input_axes(data1); | ||
| 83 | + | ||
| 84 | + bool keep_dims = false; | ||
| 85 | + if (op.GetAttr("keep_dims", keep_dims) != SUCCESS) { | ||
| 86 | + OP_LOGE(GetOpName(op).c_str(), "get keep_dims from op failed"); | ||
| 87 | + return FAILED; | ||
| 88 | + } | ||
| 89 | + reduce_log_sum_exp.set_attr_keep_dims(keep_dims); | ||
| 90 | + | ||
| 91 | + std::vector<ge::Operator> inputs{data0}; | ||
| 92 | + std::vector<std::pair<ge::Operator, std::vector<size_t> > > outputs; | ||
| 93 | + outputs.emplace_back(reduce_log_sum_exp, std::vector<std::size_t>{0}); | ||
| 94 | + graph.SetInputs(inputs).SetOutputs(outputs); | ||
| 95 | + | ||
| 96 | + return SUCCESS; | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +static Status ParseParamsReduceLogSumExp13(const Message* op_src, ge::Operator& op_dest) | ||
| 100 | +{ | ||
| 101 | + const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); | ||
| 102 | + if (node == nullptr) { | ||
| 103 | + OP_LOGE("ReduceLogSumExp13", "Dynamic cast op_src to NodeProto failed."); | ||
| 104 | + return FAILED; | ||
| 105 | + } | ||
| 106 | + op_dest.SetAttr("original_type", "ai.onnx::13::ReduceLogSumExp"); | ||
| 107 | + | ||
| 108 | + int input_size = node->input_size(); | ||
| 109 | + bool keep_dims = true; | ||
| 110 | + for (const auto& attr : node->attribute()) { | ||
| 111 | + if (attr.name() == "keepdims" && attr.type() == ge::onnx::AttributeProto::INT) { | ||
| 112 | + keep_dims = (attr.i() == 1); | ||
| 113 | + } | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + // opset 13+: axes changed from attribute to input. | ||
| 117 | + // When input_size == 1, there is no axes input; store an empty axes tensor | ||
| 118 | + // so ParseOpToGraph can retrieve it via GetAttr and pass to Const. | ||
| 119 | + std::vector<int> axes = {}; | ||
| 120 | + std::vector<int64_t> dims = {0}; | ||
| 121 | + ge::Tensor axes_tensor = Vec2Tensor(axes, dims, ge::DT_INT32, ge::FORMAT_NCHW); | ||
| 122 | + op_dest.SetAttr("axes", axes_tensor); | ||
| 123 | + | ||
| 124 | + op_dest.SetAttr("name", node->name()); | ||
| 125 | + op_dest.SetAttr("input_size", input_size); | ||
| 126 | + op_dest.SetAttr("keep_dims", keep_dims); | ||
| 127 | + return SUCCESS; | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | +namespace { | ||
| 131 | +struct ReduceLogSumExp13Prop { | ||
| 132 | + std::string ori_name; | ||
| 133 | + bool keep_dims = false; | ||
| 134 | + int input_num = 1; | ||
| 135 | +}; | ||
| 136 | + | ||
| 137 | +Status GetProperty(const Operator& op, ReduceLogSumExp13Prop& prop) | ||
| 138 | +{ | ||
| 139 | + if (op.GetAttr("name", prop.ori_name) != SUCCESS) { | ||
| 140 | + OP_LOGE(GetOpName(op).c_str(), "get name from op failed."); | ||
| 78 | return FAILED; | 141 | return FAILED; |
| 79 | } | 142 | } |
| 80 | 143 | ||
| 81 | - auto data0 = op::Data((ori_name + "_data0").c_str()).set_attr_index(0); | 144 | + if (op.GetAttr("keep_dims", prop.keep_dims) != SUCCESS) { |
| 82 | - auto const_op = op::Const((ori_name + "_const_data").c_str()).set_attr_value(const_value); | 145 | + OP_LOGE(GetOpName(op).c_str(), "get keep_dims from op failed"); |
| 83 | - auto reduce_log_sum_exp = op::ReduceLogSumExp((ori_name + "_ReduceLogSumExp").c_str()) | 146 | + return FAILED; |
| 84 | - .set_input_x(data0) | 147 | + } |
| 85 | - .set_input_axes(const_op) | 148 | + |
| 86 | - .set_attr_keep_dims(flag); | 149 | + if (op.GetAttr("input_size", prop.input_num) != SUCCESS) { |
| 87 | - std::vector<Operator> inputs{data0, const_op}; | 150 | + OP_LOGE(GetOpName(op).c_str(), "get input_num from op failed"); |
| 88 | - std::vector<std::pair<Operator, std::vector<size_t> > > output_indexs; | 151 | + return FAILED; |
| 89 | - output_indexs.emplace_back(reduce_log_sum_exp, vector<std::size_t>{0}); | 152 | + } |
| 90 | - graph.SetInputs(inputs).SetOutputs(output_indexs); | 153 | + return SUCCESS; |
| 154 | +} | ||
| 155 | + | ||
| 156 | +} // namespace | ||
| 157 | + | ||
| 158 | +static Status ParseOpToGraphReduceLogSumExp13(const Operator& op, Graph& graph) | ||
| 159 | +{ | ||
| 160 | + ReduceLogSumExp13Prop prop; | ||
| 161 | + if (GetProperty(op, prop) != SUCCESS) { | ||
| 162 | + return FAILED; | ||
| 163 | + } | ||
| 164 | + auto data0 = op::Data((prop.ori_name + "_data0").c_str()).set_attr_index(0); | ||
| 165 | + int num_input = 2; | ||
| 166 | + if (prop.input_num == 1) { | ||
| 167 | + ge::Tensor axes; | ||
| 168 | + if (op.GetAttr("axes", axes) != SUCCESS) { | ||
| 169 | + OP_LOGE(GetOpName(op).c_str(), "get axes from op failed"); | ||
| 170 | + return FAILED; | ||
| 171 | + } | ||
| 172 | + auto data1 = op::Const((prop.ori_name + "_data1").c_str()).set_attr_value(axes); | ||
| 173 | + auto reduce_log_sum_exp = op::ReduceLogSumExp((prop.ori_name + "_ReduceLogSumExp").c_str()) | ||
| 174 | + .set_input_x(data0) | ||
| 175 | + .set_input_axes(data1) | ||
| 176 | + .set_attr_keep_dims(prop.keep_dims); | ||
| 177 | + std::vector<Operator> inputs{data0}; | ||
| 178 | + std::vector<std::pair<Operator, std::vector<size_t> > > output_indexs; | ||
| 179 | + output_indexs.emplace_back(reduce_log_sum_exp, vector<std::size_t>{0}); | ||
| 180 | + graph.SetInputs(inputs).SetOutputs(output_indexs); | ||
| 181 | + } else if (prop.input_num == num_input) { | ||
| 182 | + auto data1 = op::Data((prop.ori_name + "_data1").c_str()).set_attr_index(1); | ||
| 183 | + auto reduce_log_sum_exp = op::ReduceLogSumExp((prop.ori_name + "_ReduceLogSumExp").c_str()) | ||
| 184 | + .set_input_x(data0) | ||
| 185 | + .set_input_axes(data1) | ||
| 186 | + .set_attr_keep_dims(prop.keep_dims); | ||
| 187 | + std::vector<Operator> inputs{data0, data1}; | ||
| 188 | + std::vector<std::pair<Operator, std::vector<size_t> > > output_indexs; | ||
| 189 | + output_indexs.emplace_back(reduce_log_sum_exp, vector<std::size_t>{0}); | ||
| 190 | + graph.SetInputs(inputs).SetOutputs(output_indexs); | ||
| 191 | + } else { | ||
| 192 | + OP_LOGE(GetOpName(op).c_str(), "Input num or set attr is error"); | ||
| 193 | + return FAILED; | ||
| 194 | + } | ||
| 91 | return SUCCESS; | 195 | return SUCCESS; |
| 92 | } | 196 | } |
| 93 | 197 | ||
| 94 | // register ReduceLogSumExp op info to GE | 198 | // register ReduceLogSumExp op info to GE |
| 95 | REGISTER_CUSTOM_OP("PartitionedCall") | 199 | REGISTER_CUSTOM_OP("PartitionedCall") |
| 96 | .FrameworkType(ONNX) | 200 | .FrameworkType(ONNX) |
| 97 | - .OriginOpType({ge::AscendString("ai.onnx::8::ReduceLogSumExp"), | 201 | + .OriginOpType( |
| 98 | - ge::AscendString("ai.onnx::9::ReduceLogSumExp"), | 202 | + {ge::AscendString("ai.onnx::8::ReduceLogSumExp"), ge::AscendString("ai.onnx::9::ReduceLogSumExp"), |
| 99 | - ge::AscendString("ai.onnx::10::ReduceLogSumExp"), | 203 | + ge::AscendString("ai.onnx::10::ReduceLogSumExp"), ge::AscendString("ai.onnx::11::ReduceLogSumExp"), |
| 100 | - ge::AscendString("ai.onnx::11::ReduceLogSumExp"), | 204 | + ge::AscendString("ai.onnx::12::ReduceLogSumExp")}) |
| 101 | - ge::AscendString("ai.onnx::12::ReduceLogSumExp"), | ||
| 102 | - ge::AscendString("ai.onnx::13::ReduceLogSumExp"), | ||
| 103 | - ge::AscendString("ai.onnx::14::ReduceLogSumExp"), | ||
| 104 | - ge::AscendString("ai.onnx::15::ReduceLogSumExp"), | ||
| 105 | - ge::AscendString("ai.onnx::16::ReduceLogSumExp"), | ||
| 106 | - ge::AscendString("ai.onnx::17::ReduceLogSumExp"), | ||
| 107 | - ge::AscendString("ai.onnx::18::ReduceLogSumExp")}) | ||
| 108 | .ParseParamsFn(ParseParamsReduceLogSumExp) | 205 | .ParseParamsFn(ParseParamsReduceLogSumExp) |
| 109 | .ParseOpToGraphFn(ParseOpToGraphReduceLogSumExp) | 206 | .ParseOpToGraphFn(ParseOpToGraphReduceLogSumExp) |
| 110 | .ImplyType(ImplyType::TVM); | 207 | .ImplyType(ImplyType::TVM); |
| 111 | -} // namespace domi | 208 | + |
| 209 | +REGISTER_CUSTOM_OP("ReduceLogSumExp") | ||
| 210 | + .FrameworkType(ONNX) | ||
| 211 | + .OriginOpType( | ||
| 212 | + {ge::AscendString("ai.onnx::13::ReduceLogSumExp"), ge::AscendString("ai.onnx::14::ReduceLogSumExp"), | ||
| 213 | + ge::AscendString("ai.onnx::15::ReduceLogSumExp"), ge::AscendString("ai.onnx::16::ReduceLogSumExp"), | ||
| 214 | + ge::AscendString("ai.onnx::17::ReduceLogSumExp"), ge::AscendString("ai.onnx::18::ReduceLogSumExp")}) | ||
| 215 | + .ParseParamsFn(ParseParamsReduceLogSumExp13) | ||
| 216 | + .ParseOpToGraphFn(ParseOpToGraphReduceLogSumExp13) | ||
| 217 | + .ImplyType(ImplyType::TVM); | ||
| 218 | +} // namespace domi | ||
| @@ -17,20 +17,6 @@ using ge::Operator; | |||
| 17 | namespace domi { | 17 | namespace domi { |
| 18 | using NodeProto = ge::onnx::NodeProto; | 18 | using NodeProto = ge::onnx::NodeProto; |
| 19 | 19 | ||
| 20 | -static Status GetInputTensorDimNum(const Operator& data_op, int64_t& dim_num) | ||
| 21 | -{ | ||
| 22 | - ge::TensorDesc input_desc = data_op.GetInputDesc(0); | ||
| 23 | - auto shape = input_desc.GetShape(); | ||
| 24 | - if (shape.GetDimNum() <= 0) { | ||
| 25 | - OP_LOGE("GetInputTensorDimNum", "Get input shape is invalid."); | ||
| 26 | - return FAILED; | ||
| 27 | - } | ||
| 28 | - | ||
| 29 | - dim_num = shape.GetDimNum(); | ||
| 30 | - OP_LOGI(GetOpName(data_op).c_str(), "GetInputTensorDimNum is: %ld", dim_num); | ||
| 31 | - return SUCCESS; | ||
| 32 | -} | ||
| 33 | - | ||
| 34 | static Status ParseParamsReduceMax(const Message* op_src, ge::Operator& op_dest) | 20 | static Status ParseParamsReduceMax(const Message* op_src, ge::Operator& op_dest) |
| 35 | { | 21 | { |
| 36 | const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); | 22 | const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); |
| @@ -65,6 +51,7 @@ static Status ParseParamsReduceMax(const Message* op_src, ge::Operator& op_dest) | |||
| 65 | op_dest.SetAttr("name", node->name()); | 51 | op_dest.SetAttr("name", node->name()); |
| 66 | op_dest.SetAttr("axes", tensor); | 52 | op_dest.SetAttr("axes", tensor); |
| 67 | op_dest.SetAttr("keep_dims", keep_dims); | 53 | op_dest.SetAttr("keep_dims", keep_dims); |
| 54 | + op_dest.SetAttr("noop_with_empty_axes", 0); | ||
| 68 | const int input = 2; | 55 | const int input = 2; |
| 69 | const int output = 1; | 56 | const int output = 1; |
| 70 | op_dest.DynamicInputRegister("x", input); | 57 | op_dest.DynamicInputRegister("x", input); |
| @@ -90,24 +77,6 @@ static Status ParseOpToGraphReduceMax(const ge::Operator& op, Graph& graph) | |||
| 90 | return FAILED; | 77 | return FAILED; |
| 91 | } | 78 | } |
| 92 | 79 | ||
| 93 | - if (axes.GetSize() == 0) { | ||
| 94 | - int64_t input_dim_num = 0; | ||
| 95 | - if (GetInputTensorDimNum(op, input_dim_num) != SUCCESS) { | ||
| 96 | - OP_LOGE(GetOpName(op).c_str(), "Failed to get input tensor dimensions"); | ||
| 97 | - return FAILED; | ||
| 98 | - } | ||
| 99 | - std::vector<int64_t> v_axes; | ||
| 100 | - for (int64_t i = 0; i < input_dim_num; ++i) { | ||
| 101 | - v_axes.push_back(i); | ||
| 102 | - } | ||
| 103 | - int num = v_axes.size(); | ||
| 104 | - std::vector<int64_t> dims = {}; | ||
| 105 | - if (num != 0) { | ||
| 106 | - dims.push_back(num); | ||
| 107 | - } | ||
| 108 | - axes = Vec2Tensor(v_axes, dims, ge::DT_INT64); | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | auto data1 = op::Const((ori_name + "_data1").c_str()).set_attr_value(axes); | 80 | auto data1 = op::Const((ori_name + "_data1").c_str()).set_attr_value(axes); |
| 112 | auto reducemax = op::ReduceMax((ori_name + "_ReduceMax").c_str()).set_input_x(data0).set_input_axes(data1); | 81 | auto reducemax = op::ReduceMax((ori_name + "_ReduceMax").c_str()).set_input_x(data0).set_input_axes(data1); |
| 113 | 82 | ||
| @@ -118,6 +87,13 @@ static Status ParseOpToGraphReduceMax(const ge::Operator& op, Graph& graph) | |||
| 118 | } | 87 | } |
| 119 | reducemax.set_attr_keep_dims(keep_dims); | 88 | reducemax.set_attr_keep_dims(keep_dims); |
| 120 | 89 | ||
| 90 | + int noop_with_empty_axes = 0; | ||
| 91 | + if (op.GetAttr("noop_with_empty_axes", noop_with_empty_axes) != SUCCESS) { | ||
| 92 | + OP_LOGE(GetOpName(op).c_str(), "get noop_with_empty_axes from op failed"); | ||
| 93 | + return FAILED; | ||
| 94 | + } | ||
| 95 | + reducemax.set_attr_noop_with_empty_axes(noop_with_empty_axes); | ||
| 96 | + | ||
| 121 | std::vector<ge::Operator> inputs{data0}; | 97 | std::vector<ge::Operator> inputs{data0}; |
| 122 | std::vector<std::pair<ge::Operator, std::vector<size_t> > > outputs; | 98 | std::vector<std::pair<ge::Operator, std::vector<size_t> > > outputs; |
| 123 | outputs.emplace_back(reducemax, std::vector<std::size_t>{0}); | 99 | outputs.emplace_back(reducemax, std::vector<std::size_t>{0}); |
| @@ -146,6 +122,14 @@ static Status ParseParamsReduceMax13(const Message* op_src, ge::Operator& op_des | |||
| 146 | } | 122 | } |
| 147 | } | 123 | } |
| 148 | 124 | ||
| 125 | + // opset 13+: axes changed from attribute to input. | ||
| 126 | + // When input_size == 1, there is no axes input; store an empty axes tensor | ||
| 127 | + // so ParseOpToGraph can retrieve it via GetAttr and pass to Const. | ||
| 128 | + std::vector<int> axes = {}; | ||
| 129 | + std::vector<int64_t> dims = {0}; | ||
| 130 | + ge::Tensor axes_tensor = Vec2Tensor(axes, dims, ge::DT_INT32, ge::FORMAT_NCHW); | ||
| 131 | + op_dest.SetAttr("axes", axes_tensor); | ||
| 132 | + | ||
| 149 | op_dest.SetAttr("name", node->name()); | 133 | op_dest.SetAttr("name", node->name()); |
| 150 | op_dest.SetAttr("input_size", input_size); | 134 | op_dest.SetAttr("input_size", input_size); |
| 151 | op_dest.SetAttr("keep_dims", keep_dims); | 135 | op_dest.SetAttr("keep_dims", keep_dims); |
| @@ -195,31 +179,20 @@ static Status ParseOpToGraphReduceMax13(const Operator& op, Graph& graph) | |||
| 195 | } | 179 | } |
| 196 | auto data0 = op::Data((prop.ori_name + "_data0").c_str()).set_attr_index(0); | 180 | auto data0 = op::Data((prop.ori_name + "_data0").c_str()).set_attr_index(0); |
| 197 | int num_input = 2; | 181 | int num_input = 2; |
| 198 | - if (prop.input_num == 1 && prop.empty_axes == 0) { | 182 | + if (prop.input_num == 1) { |
| 199 | - int64_t input_dim_num = 0; | 183 | + ge::Tensor axes; |
| 200 | - if (GetInputTensorDimNum(op, input_dim_num) != SUCCESS) { | 184 | + if (op.GetAttr("axes", axes) != SUCCESS) { |
| 201 | - OP_LOGE(GetOpName(op).c_str(), "Failed to get input tensor dimensions"); | 185 | + OP_LOGE(GetOpName(op).c_str(), "get axes from op failed"); |
| 202 | return FAILED; | 186 | return FAILED; |
| 203 | } | 187 | } |
| 204 | - | 188 | + auto data1 = op::Const((prop.ori_name + "_data1").c_str()).set_attr_value(axes); |
| 205 | - std::vector<int64_t> v_axes; | ||
| 206 | - for (int64_t i = 0; i < input_dim_num; ++i) { | ||
| 207 | - v_axes.push_back(i); | ||
| 208 | - } | ||
| 209 | - ge::TensorDesc tensorDesc; | ||
| 210 | - std::vector<int64_t> dims = {input_dim_num}; | ||
| 211 | - ge::Shape shape(dims); | ||
| 212 | - tensorDesc.SetShape(shape); | ||
| 213 | - tensorDesc.SetDataType(DT_INT64); | ||
| 214 | - ge::Tensor tensor(tensorDesc, reinterpret_cast<uint8_t*>(v_axes.data()), v_axes.size() * sizeof(int64_t)); | ||
| 215 | - auto axes = op::Const((prop.ori_name + "_axes").c_str()).set_attr_value(tensor); | ||
| 216 | - std::vector<Operator> inputs{data0, axes}; | ||
| 217 | - std::vector<std::pair<Operator, std::vector<size_t> > > output_indexs; | ||
| 218 | auto reducemax = op::ReduceMax((prop.ori_name + "_ReduceMax").c_str()) | 189 | auto reducemax = op::ReduceMax((prop.ori_name + "_ReduceMax").c_str()) |
| 219 | .set_input_x(data0) | 190 | .set_input_x(data0) |
| 220 | - .set_input_axes(axes) | 191 | + .set_input_axes(data1) |
| 221 | .set_attr_keep_dims(prop.keep_dims) | 192 | .set_attr_keep_dims(prop.keep_dims) |
| 222 | .set_attr_noop_with_empty_axes(prop.empty_axes); | 193 | .set_attr_noop_with_empty_axes(prop.empty_axes); |
| 194 | + std::vector<Operator> inputs{data0}; | ||
| 195 | + std::vector<std::pair<Operator, std::vector<size_t> > > output_indexs; | ||
| 223 | output_indexs.emplace_back(reducemax, vector<std::size_t>{0}); | 196 | output_indexs.emplace_back(reducemax, vector<std::size_t>{0}); |
| 224 | graph.SetInputs(inputs).SetOutputs(output_indexs); | 197 | graph.SetInputs(inputs).SetOutputs(output_indexs); |
| 225 | } else if (prop.input_num == num_input) { | 198 | } else if (prop.input_num == num_input) { |
| @@ -17,20 +17,6 @@ using ge::Operator; | |||
| 17 | namespace domi { | 17 | namespace domi { |
| 18 | using NodeProto = ge::onnx::NodeProto; | 18 | using NodeProto = ge::onnx::NodeProto; |
| 19 | 19 | ||
| 20 | -static Status GetInputTensorDimNum(const Operator& data_op, int64_t& dim_num) | ||
| 21 | -{ | ||
| 22 | - ge::TensorDesc input_desc = data_op.GetInputDesc(0); | ||
| 23 | - auto shape = input_desc.GetShape(); | ||
| 24 | - if (shape.GetDimNum() <= 0) { | ||
| 25 | - OP_LOGE("GetInputTensorDimNum", "Get input shape is invalid."); | ||
| 26 | - return FAILED; | ||
| 27 | - } | ||
| 28 | - | ||
| 29 | - dim_num = shape.GetDimNum(); | ||
| 30 | - OP_LOGI(GetOpName(data_op).c_str(), "GetInputTensorDimNum is: %ld", dim_num); | ||
| 31 | - return SUCCESS; | ||
| 32 | -} | ||
| 33 | - | ||
| 34 | static Status ParseParamsReduceMin(const Message* op_src, ge::Operator& op_dest) | 20 | static Status ParseParamsReduceMin(const Message* op_src, ge::Operator& op_dest) |
| 35 | { | 21 | { |
| 36 | const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); | 22 | const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); |
| @@ -65,6 +51,7 @@ static Status ParseParamsReduceMin(const Message* op_src, ge::Operator& op_dest) | |||
| 65 | op_dest.SetAttr("name", node->name()); | 51 | op_dest.SetAttr("name", node->name()); |
| 66 | op_dest.SetAttr("axes", tensor); | 52 | op_dest.SetAttr("axes", tensor); |
| 67 | op_dest.SetAttr("keep_dims", keep_dims); | 53 | op_dest.SetAttr("keep_dims", keep_dims); |
| 54 | + op_dest.SetAttr("noop_with_empty_axes", 0); | ||
| 68 | const int input = 2; | 55 | const int input = 2; |
| 69 | const int output = 1; | 56 | const int output = 1; |
| 70 | op_dest.DynamicInputRegister("x", input); | 57 | op_dest.DynamicInputRegister("x", input); |
| @@ -90,24 +77,6 @@ static Status ParseOpToGraphReduceMin(const ge::Operator& op, Graph& graph) | |||
| 90 | return FAILED; | 77 | return FAILED; |
| 91 | } | 78 | } |
| 92 | 79 | ||
| 93 | - if (axes.GetSize() == 0) { | ||
| 94 | - int64_t input_dim_num = 0; | ||
| 95 | - if (GetInputTensorDimNum(op, input_dim_num) != SUCCESS) { | ||
| 96 | - OP_LOGE(GetOpName(op).c_str(), "Failed to get input tensor dimensions"); | ||
| 97 | - return FAILED; | ||
| 98 | - } | ||
| 99 | - std::vector<int64_t> v_axes; | ||
| 100 | - for (int64_t i = 0; i < input_dim_num; ++i) { | ||
| 101 | - v_axes.push_back(i); | ||
| 102 | - } | ||
| 103 | - int num = v_axes.size(); | ||
| 104 | - std::vector<int64_t> dims = {}; | ||
| 105 | - if (num != 0) { | ||
| 106 | - dims.push_back(num); | ||
| 107 | - } | ||
| 108 | - axes = Vec2Tensor(v_axes, dims, ge::DT_INT64); | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | auto data1 = op::Const((ori_name + "_data1").c_str()).set_attr_value(axes); | 80 | auto data1 = op::Const((ori_name + "_data1").c_str()).set_attr_value(axes); |
| 112 | auto reducemin = op::ReduceMin((ori_name + "_ReduceMin").c_str()).set_input_x(data0).set_input_axes(data1); | 81 | auto reducemin = op::ReduceMin((ori_name + "_ReduceMin").c_str()).set_input_x(data0).set_input_axes(data1); |
| 113 | 82 | ||
| @@ -118,6 +87,13 @@ static Status ParseOpToGraphReduceMin(const ge::Operator& op, Graph& graph) | |||
| 118 | } | 87 | } |
| 119 | reducemin.set_attr_keep_dims(keep_dims); | 88 | reducemin.set_attr_keep_dims(keep_dims); |
| 120 | 89 | ||
| 90 | + int noop_with_empty_axes = 0; | ||
| 91 | + if (op.GetAttr("noop_with_empty_axes", noop_with_empty_axes) != SUCCESS) { | ||
| 92 | + OP_LOGE(GetOpName(op).c_str(), "get noop_with_empty_axes from op failed"); | ||
| 93 | + return FAILED; | ||
| 94 | + } | ||
| 95 | + reducemin.set_attr_noop_with_empty_axes(noop_with_empty_axes); | ||
| 96 | + | ||
| 121 | std::vector<ge::Operator> inputs{data0}; | 97 | std::vector<ge::Operator> inputs{data0}; |
| 122 | std::vector<std::pair<ge::Operator, std::vector<size_t> > > outputs; | 98 | std::vector<std::pair<ge::Operator, std::vector<size_t> > > outputs; |
| 123 | outputs.emplace_back(reducemin, std::vector<std::size_t>{0}); | 99 | outputs.emplace_back(reducemin, std::vector<std::size_t>{0}); |
| @@ -146,6 +122,14 @@ static Status ParseParamsReduceMin13(const Message* op_src, ge::Operator& op_des | |||
| 146 | } | 122 | } |
| 147 | } | 123 | } |
| 148 | 124 | ||
| 125 | + // opset 13+: axes changed from attribute to input. | ||
| 126 | + // When input_size == 1, there is no axes input; store an empty axes tensor | ||
| 127 | + // so ParseOpToGraph can retrieve it via GetAttr and pass to Const. | ||
| 128 | + std::vector<int> axes = {}; | ||
| 129 | + std::vector<int64_t> dims = {0}; | ||
| 130 | + ge::Tensor axes_tensor = Vec2Tensor(axes, dims, ge::DT_INT32, ge::FORMAT_NCHW); | ||
| 131 | + op_dest.SetAttr("axes", axes_tensor); | ||
| 132 | + | ||
| 149 | op_dest.SetAttr("name", node->name()); | 133 | op_dest.SetAttr("name", node->name()); |
| 150 | op_dest.SetAttr("input_size", input_size); | 134 | op_dest.SetAttr("input_size", input_size); |
| 151 | op_dest.SetAttr("keep_dims", keep_dims); | 135 | op_dest.SetAttr("keep_dims", keep_dims); |
| @@ -195,31 +179,20 @@ static Status ParseOpToGraphReduceMin13(const Operator& op, Graph& graph) | |||
| 195 | } | 179 | } |
| 196 | auto data0 = op::Data((prop.ori_name + "_data0").c_str()).set_attr_index(0); | 180 | auto data0 = op::Data((prop.ori_name + "_data0").c_str()).set_attr_index(0); |
| 197 | int num_input = 2; | 181 | int num_input = 2; |
| 198 | - if (prop.input_num == 1 && prop.empty_axes == 0) { | 182 | + if (prop.input_num == 1) { |
| 199 | - int64_t input_dim_num = 0; | 183 | + ge::Tensor axes; |
| 200 | - if (GetInputTensorDimNum(op, input_dim_num) != SUCCESS) { | 184 | + if (op.GetAttr("axes", axes) != SUCCESS) { |
| 201 | - OP_LOGE(GetOpName(op).c_str(), "Failed to get input tensor dimensions"); | 185 | + OP_LOGE(GetOpName(op).c_str(), "get axes from op failed"); |
| 202 | return FAILED; | 186 | return FAILED; |
| 203 | } | 187 | } |
| 204 | - | 188 | + auto data1 = op::Const((prop.ori_name + "_data1").c_str()).set_attr_value(axes); |
| 205 | - std::vector<int64_t> v_axes; | ||
| 206 | - for (int64_t i = 0; i < input_dim_num; ++i) { | ||
| 207 | - v_axes.push_back(i); | ||
| 208 | - } | ||
| 209 | - ge::TensorDesc tensorDesc; | ||
| 210 | - std::vector<int64_t> dims = {input_dim_num}; | ||
| 211 | - ge::Shape shape(dims); | ||
| 212 | - tensorDesc.SetShape(shape); | ||
| 213 | - tensorDesc.SetDataType(DT_INT64); | ||
| 214 | - ge::Tensor tensor(tensorDesc, reinterpret_cast<uint8_t*>(v_axes.data()), v_axes.size() * sizeof(int64_t)); | ||
| 215 | - auto axes = op::Const((prop.ori_name + "_axes").c_str()).set_attr_value(tensor); | ||
| 216 | - std::vector<Operator> inputs{data0, axes}; | ||
| 217 | - std::vector<std::pair<Operator, std::vector<size_t> > > output_indexs; | ||
| 218 | auto reducemin = op::ReduceMin((prop.ori_name + "_ReduceMin").c_str()) | 189 | auto reducemin = op::ReduceMin((prop.ori_name + "_ReduceMin").c_str()) |
| 219 | .set_input_x(data0) | 190 | .set_input_x(data0) |
| 220 | - .set_input_axes(axes) | 191 | + .set_input_axes(data1) |
| 221 | .set_attr_keep_dims(prop.keep_dims) | 192 | .set_attr_keep_dims(prop.keep_dims) |
| 222 | .set_attr_noop_with_empty_axes(prop.empty_axes); | 193 | .set_attr_noop_with_empty_axes(prop.empty_axes); |
| 194 | + std::vector<Operator> inputs{data0}; | ||
| 195 | + std::vector<std::pair<Operator, std::vector<size_t> > > output_indexs; | ||
| 223 | output_indexs.emplace_back(reducemin, vector<std::size_t>{0}); | 196 | output_indexs.emplace_back(reducemin, vector<std::size_t>{0}); |
| 224 | graph.SetInputs(inputs).SetOutputs(output_indexs); | 197 | graph.SetInputs(inputs).SetOutputs(output_indexs); |
| 225 | } else if (prop.input_num == num_input) { | 198 | } else if (prop.input_num == num_input) { |
| @@ -17,20 +17,6 @@ using ge::Operator; | |||
| 17 | namespace domi { | 17 | namespace domi { |
| 18 | using NodeProto = ge::onnx::NodeProto; | 18 | using NodeProto = ge::onnx::NodeProto; |
| 19 | 19 | ||
| 20 | -static Status GetInputTensorDimNum(const Operator& data_op, int64_t& dim_num) | ||
| 21 | -{ | ||
| 22 | - ge::TensorDesc input_desc = data_op.GetInputDesc(0); | ||
| 23 | - auto shape = input_desc.GetShape(); | ||
| 24 | - if (shape.GetDimNum() <= 0) { | ||
| 25 | - OP_LOGE("GetInputTensorDimNum", "Get input shape is invalid."); | ||
| 26 | - return FAILED; | ||
| 27 | - } | ||
| 28 | - | ||
| 29 | - dim_num = shape.GetDimNum(); | ||
| 30 | - OP_LOGI(GetOpName(data_op).c_str(), "GetInputTensorDimNum is: %ld", dim_num); | ||
| 31 | - return SUCCESS; | ||
| 32 | -} | ||
| 33 | - | ||
| 34 | static Status ParseParamsReduceProd(const Message* op_src, ge::Operator& op_dest) | 20 | static Status ParseParamsReduceProd(const Message* op_src, ge::Operator& op_dest) |
| 35 | { | 21 | { |
| 36 | const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); | 22 | const NodeProto* node = dynamic_cast<const NodeProto*>(op_src); |
| @@ -65,6 +51,7 @@ static Status ParseParamsReduceProd(const Message* op_src, ge::Operator& op_dest | |||
| 65 | op_dest.SetAttr("name", node->name()); | 51 | op_dest.SetAttr("name", node->name()); |
| 66 | op_dest.SetAttr("axes", tensor); | 52 | op_dest.SetAttr("axes", tensor); |
| 67 | op_dest.SetAttr("keep_dims", keep_dims); | 53 | op_dest.SetAttr("keep_dims", keep_dims); |
| 54 | + op_dest.SetAttr("noop_with_empty_axes", 0); | ||
| 68 | const int input = 2; | 55 | const int input = 2; |
| 69 | const int output = 1; | 56 | const int output = 1; |
| 70 | op_dest.DynamicInputRegister("x", input); | 57 | op_dest.DynamicInputRegister("x", input); |
| @@ -90,24 +77,6 @@ static Status ParseOpToGraphReduceProd(const ge::Operator& op, Graph& graph) | |||
| 90 | return FAILED; | 77 | return FAILED; |
| 91 | } | 78 | } |
| 92 | 79 | ||
| 93 | - if (axes.GetSize() == 0) { | ||
| 94 | - int64_t input_dim_num = 0; | ||
| 95 | - if (GetInputTensorDimNum(op, input_dim_num) != SUCCESS) { | ||
| 96 | - OP_LOGE(GetOpName(op).c_str(), "Failed to get input tensor dimensions"); | ||
| 97 | - return FAILED; | ||
| 98 | - } | ||
| 99 | - std::vector<int64_t> v_axes; | ||
| 100 | - for (int64_t i = 0; i < input_dim_num; ++i) { | ||
| 101 | - v_axes.push_back(i); | ||
| 102 | - } | ||
| 103 | - int num = v_axes.size(); | ||
| 104 | - std::vector<int64_t> dims = {}; | ||
| 105 | - if (num != 0) { | ||
| 106 | - dims.push_back(num); | ||
| 107 | - } | ||
| 108 | - axes = Vec2Tensor(v_axes, dims, ge::DT_INT64); | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | auto data1 = op::Const((ori_name + "_data1").c_str()).set_attr_value(axes); | 80 | auto data1 = op::Const((ori_name + "_data1").c_str()).set_attr_value(axes); |
| 112 | auto reduceprod = op::ReduceProd((ori_name + "_ReduceProd").c_str()).set_input_x(data0).set_input_axes(data1); | 81 | auto reduceprod = op::ReduceProd((ori_name + "_ReduceProd").c_str()).set_input_x(data0).set_input_axes(data1); |
| 113 | 82 | ||
| @@ -118,6 +87,13 @@ static Status ParseOpToGraphReduceProd(const ge::Operator& op, Graph& graph) | |||
| 118 | } | 87 | } |
| 119 | reduceprod.set_attr_keep_dims(keep_dims); | 88 | reduceprod.set_attr_keep_dims(keep_dims); |
| 120 | 89 | ||
| 90 | + int noop_with_empty_axes = 0; | ||
| 91 | + if (op.GetAttr("noop_with_empty_axes", noop_with_empty_axes) != SUCCESS) { | ||
| 92 | + OP_LOGE(GetOpName(op).c_str(), "get noop_with_empty_axes from op failed"); | ||
| 93 | + return FAILED; | ||
| 94 | + } | ||
| 95 | + reduceprod.set_attr_noop_with_empty_axes(noop_with_empty_axes); | ||
| 96 | + | ||
| 121 | std::vector<ge::Operator> inputs{data0}; | 97 | std::vector<ge::Operator> inputs{data0}; |
| 122 | std::vector<std::pair<ge::Operator, std::vector<size_t> > > outputs; | 98 | std::vector<std::pair<ge::Operator, std::vector<size_t> > > outputs; |
| 123 | outputs.emplace_back(reduceprod, std::vector<std::size_t>{0}); | 99 | outputs.emplace_back(reduceprod, std::vector<std::size_t>{0}); |
| @@ -146,6 +122,14 @@ static Status ParseParamsReduceProd13(const Message* op_src, ge::Operator& op_de | |||
| 146 | } | 122 | } |
| 147 | } | 123 | } |
| 148 | 124 | ||
| 125 | + // opset 13+: axes changed from attribute to input. | ||
| 126 | + // When input_size == 1, there is no axes input; store an empty axes tensor | ||
| 127 | + // so ParseOpToGraph can retrieve it via GetAttr and pass to Const. | ||
| 128 | + std::vector<int> axes = {}; | ||
| 129 | + std::vector<int64_t> dims = {0}; | ||
| 130 | + ge::Tensor axes_tensor = Vec2Tensor(axes, dims, ge::DT_INT32, ge::FORMAT_NCHW); | ||
| 131 | + op_dest.SetAttr("axes", axes_tensor); | ||
| 132 | + | ||
| 149 | op_dest.SetAttr("name", node->name()); | 133 | op_dest.SetAttr("name", node->name()); |
| 150 | op_dest.SetAttr("input_size", input_size); | 134 | op_dest.SetAttr("input_size", input_size); |
| 151 | op_dest.SetAttr("keep_dims", keep_dims); | 135 | op_dest.SetAttr("keep_dims", keep_dims); |
| @@ -195,31 +179,20 @@ static Status ParseOpToGraphReduceProd13(const Operator& op, Graph& graph) | |||
| 195 | } | 179 | } |
| 196 | auto data0 = op::Data((prop.ori_name + "_data0").c_str()).set_attr_index(0); | 180 | auto data0 = op::Data((prop.ori_name + "_data0").c_str()).set_attr_index(0); |
| 197 | int num_input = 2; | 181 | int num_input = 2; |
| 198 | - if (prop.input_num == 1 && prop.empty_axes == 0) { | 182 | + if (prop.input_num == 1) { |
| 199 | - int64_t input_dim_num = 0; | 183 | + ge::Tensor axes; |
| 200 | - if (GetInputTensorDimNum(op, input_dim_num) != SUCCESS) { | 184 | + if (op.GetAttr("axes", axes) != SUCCESS) { |
| 201 | - OP_LOGE(GetOpName(op).c_str(), "Failed to get input tensor dimensions"); | 185 | + OP_LOGE(GetOpName(op).c_str(), "get axes from op failed"); |
| 202 | return FAILED; | 186 | return FAILED; |
| 203 | } | 187 | } |
| 204 | - | 188 | + auto data1 = op::Const((prop.ori_name + "_data1").c_str()).set_attr_value(axes); |
| 205 | - std::vector<int64_t> v_axes; | ||
| 206 | - for (int64_t i = 0; i < input_dim_num; ++i) { | ||
| 207 | - v_axes.push_back(i); | ||
| 208 | - } | ||
| 209 | - ge::TensorDesc tensorDesc; | ||
| 210 | - std::vector<int64_t> dims = {input_dim_num}; | ||
| 211 | - ge::Shape shape(dims); | ||
| 212 | - tensorDesc.SetShape(shape); | ||
| 213 | - tensorDesc.SetDataType(DT_INT64); | ||
| 214 | - ge::Tensor tensor(tensorDesc, reinterpret_cast<uint8_t*>(v_axes.data()), v_axes.size() * sizeof(int64_t)); | ||
| 215 | - auto axes = op::Const((prop.ori_name + "_axes").c_str()).set_attr_value(tensor); | ||
| 216 | - std::vector<Operator> inputs{data0, axes}; | ||
| 217 | - std::vector<std::pair<Operator, std::vector<size_t> > > output_indexs; | ||
| 218 | auto reduceprod = op::ReduceProd((prop.ori_name + "_ReduceProd").c_str()) | 189 | auto reduceprod = op::ReduceProd((prop.ori_name + "_ReduceProd").c_str()) |
| 219 | .set_input_x(data0) | 190 | .set_input_x(data0) |
| 220 | - .set_input_axes(axes) | 191 | + .set_input_axes(data1) |
| 221 | .set_attr_keep_dims(prop.keep_dims) | 192 | .set_attr_keep_dims(prop.keep_dims) |
| 222 | .set_attr_noop_with_empty_axes(prop.empty_axes); | 193 | .set_attr_noop_with_empty_axes(prop.empty_axes); |
| 194 | + std::vector<Operator> inputs{data0}; | ||
| 195 | + std::vector<std::pair<Operator, std::vector<size_t> > > output_indexs; | ||
| 223 | output_indexs.emplace_back(reduceprod, vector<std::size_t>{0}); | 196 | output_indexs.emplace_back(reduceprod, vector<std::size_t>{0}); |
| 224 | graph.SetInputs(inputs).SetOutputs(output_indexs); | 197 | graph.SetInputs(inputs).SetOutputs(output_indexs); |
| 225 | } else if (prop.input_num == num_input) { | 198 | } else if (prop.input_num == num_input) { |