| 173 | } |
| 174 | |
| 175 | std::tuple<SmallVector<LogicalTensorDesc>, bool> infer_output_attrs_fallible( |
| 176 | const OpDef& def, const SmallVector<LogicalTensorDesc>& inputs) { |
| 177 | auto&& op_def = def.cast_final_safe<Reduce>(); |
| 178 | auto axis = op_def.param().axis; |
| 179 | auto keepdim = op_def.keepdim; |
| 180 | |
| 181 | mgb_assert(inputs.size() > 0); |
| 182 | auto&& comp_node = inputs[0].comp_node; |
| 183 | auto&& input_layout = inputs[0].layout; |
| 184 | |
| 185 | if (inputs.size() == 2) { |
| 186 | // fallback to proxy_graph, matters on backward |
| 187 | auto [output_descs, validated] = |
| 188 | proxy_graph_detail::infer_output_attrs_fallible(def, inputs); |
| 189 | if (!inputs[1].value.empty()) { |
| 190 | cg::copy_tensor_value_to_shape(output_descs[0].layout, inputs[1].value); |
| 191 | output_descs[0].layout.init_contiguous_stride(); |
| 192 | } |
| 193 | return {output_descs, validated}; |
| 194 | } |
| 195 | |
| 196 | mgb_assert(inputs.size() == 1); |
| 197 | |
| 198 | if (axis == INT_MAX) { |
| 199 | // reduce to scalar |
| 200 | // ignore keepdim because ndim is 1 |
| 201 | auto&& dtype = input_layout.dtype; |
| 202 | auto&& format = input_layout.format; |
| 203 | auto output_layout = TensorLayout{{1}, dtype, format}; |
| 204 | return {{{output_layout, comp_node}}, true}; |
| 205 | } |
| 206 | |
| 207 | if (input_layout.ndim == 0) { |
| 208 | // shape incomplete |
| 209 | return {{{TensorLayout(input_layout.dtype, input_layout.format), comp_node}}, |
| 210 | false}; |
| 211 | } |
| 212 | |
| 213 | if (axis < 0) { |
| 214 | axis = input_layout.ndim + axis; |
| 215 | } |
| 216 | mgb_assert(axis >= 0 && axis < input_layout.ndim); |
| 217 | |
| 218 | TensorLayout output_layout = input_layout; |
| 219 | bool remove_axis = (!keepdim) && input_layout.ndim > 1; |
| 220 | if (remove_axis) { |
| 221 | output_layout.remove_axis_inplace(axis); |
| 222 | } else { |
| 223 | output_layout.shape[axis] = 1; |
| 224 | } |
| 225 | output_layout.init_contiguous_stride(); |
| 226 | return {{{output_layout, comp_node}}, true}; |
| 227 | } |
| 228 | |
| 229 | SmallVector<VarNode::LayoutConstraintCallback> get_input_layout_constraint( |
| 230 | const OpDef& def, const SmallVector<TensorPtr>& inputs) { |
nothing calls this directly
no test coverage detected