Returns the initial gradient to be used for a given output tensor. Args: grad: the original gradient Tensor passed to the gradient function. body_graph_output: the corresponding Tensor in the body graph. while_op_output: the corresponding Tensor output of the While op. Returns:
(grad, body_graph_output, while_op_output)
| 473 | |
| 474 | |
| 475 | def _preprocess_grad(grad, body_graph_output, while_op_output): |
| 476 | """Returns the initial gradient to be used for a given output tensor. |
| 477 | |
| 478 | Args: |
| 479 | grad: the original gradient Tensor passed to the gradient function. |
| 480 | body_graph_output: the corresponding Tensor in the body graph. |
| 481 | while_op_output: the corresponding Tensor output of the While op. |
| 482 | |
| 483 | Returns: |
| 484 | A Tensor or None. |
| 485 | """ |
| 486 | # Set the incoming gradient of non-trainable inputs to None. It is possible |
| 487 | # that we receive non-None gradients for non-trainable types in nested while |
| 488 | # loops because we accumulate outputs of the inner while as variant tensors |
| 489 | # which are trainable and hence receive zeros_like tensors in the gradient |
| 490 | # pass. The non-trainable tensors then receive the popped zeros tensor from |
| 491 | # this zeros variant. The gradient for the loop vars corresponding to these |
| 492 | # tensors is None or zeros (this happens only if the loop var is accumulated |
| 493 | # as well) in _grad_fn so we reset these. |
| 494 | # TODO(b/118712257): Remove once we can handle None output grads in _grad_fn. |
| 495 | if not _is_trainable(body_graph_output): |
| 496 | return None |
| 497 | |
| 498 | # GradientTape initializes resource and variant grads as None instead of |
| 499 | # zeros. Set to zeros so _GradientsHelper computes the gradients instead of |
| 500 | # returning None. |
| 501 | if (while_op_output.dtype in (dtypes.resource, dtypes.variant) |
| 502 | and grad is None): |
| 503 | return _zeros_like(while_op_output) |
| 504 | |
| 505 | return grad |
| 506 | |
| 507 | |
| 508 | # TODO(skyewm): make this return constants if op_output's shape is fully |
no test coverage detected