| 796 | REGISTER_GRADIENT_OP("Lgamma", LgammaGrad); |
| 797 | |
| 798 | Status MinOrMaxGrad(const Scope& scope, const Operation& op, |
| 799 | const std::vector<Output>& grad_inputs, |
| 800 | std::vector<Output>* grad_outputs) { |
| 801 | // The partial derivative for any input along a "reduced" dimension |
| 802 | // is 1 when it is the min (or max) and 0 everywhere else. So the |
| 803 | // gradient calculation is identical for both operators. |
| 804 | // |
| 805 | // There's a special case for propagating gradients when there are |
| 806 | // multiple minima (or maxima) - we choose to divide the gradient |
| 807 | // equally among all matching inputs. |
| 808 | // |
| 809 | // Please note this comment |
| 810 | // https://github.com/tensorflow/tensorflow/issues/4886#issuecomment-256836063 |
| 811 | // for details. |
| 812 | |
| 813 | // Running example: |
| 814 | // input: [[5, 5, 5], |
| 815 | // [1, 2, -3]] |
| 816 | // reduction_indices: [1] |
| 817 | auto input = op.input(0); |
| 818 | auto reduction_indices = op.input(1); |
| 819 | |
| 820 | // [2, 3] |
| 821 | auto input_shape = Shape(scope, input); |
| 822 | |
| 823 | // [2, 1] |
| 824 | auto output_shape_kept_dims = |
| 825 | ReducedShapeHelper(scope, input_shape, reduction_indices); |
| 826 | |
| 827 | // for op=min (say) |
| 828 | // output = [5, -3] |
| 829 | // y = [[5], |
| 830 | // [-3]] |
| 831 | auto y = Reshape(scope, op.output(0), output_shape_kept_dims); |
| 832 | |
| 833 | // reshape([g1, g2], [2, 1]) = [[g1], |
| 834 | // [g2]] |
| 835 | auto grad = Reshape(scope, grad_inputs[0], output_shape_kept_dims); |
| 836 | |
| 837 | // indicators = equal(y, input) |
| 838 | // = equal([[5], [[5, 5, 5], |
| 839 | // [-3]], [1, 2, -3]]) |
| 840 | // = [[1, 1, 1], |
| 841 | // [0, 0, 1]] |
| 842 | auto indicators = Cast(scope, Equal(scope, y, input), grad_inputs[0].type()); |
| 843 | |
| 844 | // [[3], |
| 845 | // [1]] |
| 846 | auto num_selected = Reshape(scope, Sum(scope, indicators, reduction_indices), |
| 847 | output_shape_kept_dims); |
| 848 | |
| 849 | // [[1/3, 1/3, 1/3], |
| 850 | // [0, 0, 1]] |
| 851 | auto scale = Div(scope, indicators, num_selected); |
| 852 | |
| 853 | // [[g1/3, g1/3, g1/3], |
| 854 | // [0, 0, g2]] |
| 855 | grad_outputs->push_back(Mul(scope, scale, grad)); |
nothing calls this directly
no test coverage detected