The gradient of scalar multiplication.
(op, grad)
| 1159 | |
| 1160 | @ops.RegisterGradient("Mul") |
| 1161 | def _MulGrad(op, grad): |
| 1162 | """The gradient of scalar multiplication.""" |
| 1163 | y = op.inputs[1] |
| 1164 | skip_input_indices = None |
| 1165 | try: |
| 1166 | skip_input_indices = op.skip_input_indices |
| 1167 | if skip_input_indices is not None and 1 in skip_input_indices and _IsScalar( |
| 1168 | y): |
| 1169 | return gen_math_ops.mul(grad, math_ops.conj(y)), None |
| 1170 | except AttributeError: |
| 1171 | # No gradient skipping, so do the full gradient computation |
| 1172 | pass |
| 1173 | x = op.inputs[0] |
| 1174 | if (isinstance(grad, ops.Tensor) and |
| 1175 | _ShapesFullySpecifiedAndEqual(x, y, grad) and |
| 1176 | grad.dtype in (dtypes.int32, dtypes.float32)): |
| 1177 | return gen_math_ops.mul(grad, y), gen_math_ops.mul(grad, x) |
| 1178 | assert x.dtype.base_dtype == y.dtype.base_dtype, (x.dtype, " vs. ", y.dtype) |
| 1179 | |
| 1180 | (sx, rx, must_reduce_x), (sy, ry, must_reduce_y) = ( |
| 1181 | SmartBroadcastGradientArgs(x, y, grad)) |
| 1182 | x = math_ops.conj(x) |
| 1183 | y = math_ops.conj(y) |
| 1184 | if skip_input_indices is not None and 0 in skip_input_indices: |
| 1185 | gx = None |
| 1186 | elif not must_reduce_x: |
| 1187 | gx = gen_math_ops.mul(grad, y) |
| 1188 | else: |
| 1189 | gx = array_ops.reshape( |
| 1190 | math_ops.reduce_sum(gen_math_ops.mul(grad, y), rx), sx) |
| 1191 | if skip_input_indices is not None and 1 in skip_input_indices: |
| 1192 | gy = None |
| 1193 | elif not must_reduce_y: |
| 1194 | gy = gen_math_ops.mul(x, grad) |
| 1195 | else: |
| 1196 | gy = array_ops.reshape( |
| 1197 | math_ops.reduce_sum(gen_math_ops.mul(x, grad), ry), sy) |
| 1198 | return (gx, gy) |
| 1199 | |
| 1200 | |
| 1201 | @ops.RegisterGradient("MulNoNan") |
nothing calls this directly
no test coverage detected