| 252 | } |
| 253 | |
| 254 | std::optional<ValueRefList> reshape_grad_rule( |
| 255 | const OpDef& op, Span<ValueRef> inputs, Span<bool> inputs_require_grad, |
| 256 | CustomBackward& backward) { |
| 257 | mgb_assert(inputs.size() == 1 || inputs.size() == 2); |
| 258 | size_t nr_inp = inputs.size(); |
| 259 | std::array<ValueRef, 2> input_shapes; |
| 260 | for (size_t i = 0; i < nr_inp; ++i) { |
| 261 | if (inputs_require_grad[i]) { |
| 262 | input_shapes[i] = get_shape(inputs[i]); |
| 263 | } |
| 264 | } |
| 265 | auto maker = CustomGradMaker(backward, inputs.size()); |
| 266 | maker.output_size(1).output_captured(0, false); |
| 267 | maker.backward([shapes = std::move(input_shapes), nr_inp](Span<ValueRef> grads) { |
| 268 | mgb_assert(grads.size() == 1); |
| 269 | ValueRef grad = grads[0]; |
| 270 | SmallVector<ValueRef> ret(nr_inp); |
| 271 | if (!grad) { |
| 272 | return ret; |
| 273 | } |
| 274 | for (size_t i = 0; i < nr_inp; ++i) { |
| 275 | if (shapes[i]) { |
| 276 | ret[i] = reshape_to(grad, shapes[i]); |
| 277 | } |
| 278 | } |
| 279 | return ret; |
| 280 | }); |
| 281 | maker.finalize(); |
| 282 | return imperative::apply(ApplyOp(op), inputs); |
| 283 | } |
| 284 | |
| 285 | std::optional<ValueRefList> broadcast_grad_rule( |
| 286 | const OpDef& op, Span<ValueRef> inputs, Span<bool> inputs_require_grad, |
nothing calls this directly
no test coverage detected