| 580 | REGISTER_GRADIENT_OP("BroadcastTo", BroadcastToGrad); |
| 581 | |
| 582 | Status TileGrad(const Scope& scope, const Operation& op, |
| 583 | const std::vector<Output>& grad_inputs, |
| 584 | std::vector<Output>* grad_outputs) { |
| 585 | if (op.num_inputs() != 2) { |
| 586 | return errors::InvalidArgument("Tile requires 2 inputs"); |
| 587 | } |
| 588 | if (grad_inputs.size() != 1) { |
| 589 | return errors::InvalidArgument("Tile grad requires 1 grad input"); |
| 590 | } |
| 591 | |
| 592 | Shape::Attrs shape_attrs; |
| 593 | shape_attrs.out_type_ = op.input_type(1); |
| 594 | auto input_shape = Shape(scope, op.input(0), shape_attrs); |
| 595 | // We interleave multiples and input_shape to get split_shape, |
| 596 | // reshape grad to split_shape, and reduce along all even |
| 597 | // dimensions (the tiled dimensions) to get the result |
| 598 | // with shape input_shape. For example |
| 599 | // input_shape = [20, 30, 40] |
| 600 | // multiples = [2, 3, 4] |
| 601 | // split_shape = [2, 20, 3, 30, 4, 40] |
| 602 | // axes = [0, 2, 4] |
| 603 | auto stack = Stack(scope, {op.input(1), input_shape.output}); |
| 604 | auto perm = Range(scope, Sub(scope, Rank(scope, stack), 1), -1, -1); |
| 605 | auto split_shape = Reshape(scope, Transpose(scope, stack, perm), {-1}); |
| 606 | auto axes = Range(scope, Const(scope, 0), Size(scope, split_shape.output), 2); |
| 607 | auto input_grad = ReduceSum( |
| 608 | scope, Reshape(scope, grad_inputs[0], split_shape.output), axes.output); |
| 609 | grad_outputs->push_back(input_grad.output); |
| 610 | grad_outputs->push_back(NoGradient()); |
| 611 | return scope.status(); |
| 612 | } |
| 613 | REGISTER_GRADIENT_OP("Tile", TileGrad); |
| 614 | |
| 615 | // Create a constant of the provided d_type; |
nothing calls this directly
no test coverage detected