The gradient function for each conditional branch. This function builds the gradient graph of the corresponding forward-pass conditional branch in `func_graph`. This is done by differentiating func_graph's outputs w.r.t. its inputs. Args: func_graph: FuncGraph. The corresponding forwar
(func_graph, grads)
| 338 | |
| 339 | |
| 340 | def _grad_fn(func_graph, grads): |
| 341 | """The gradient function for each conditional branch. |
| 342 | |
| 343 | This function builds the gradient graph of the corresponding forward-pass |
| 344 | conditional branch in `func_graph`. This is done by differentiating |
| 345 | func_graph's outputs w.r.t. its inputs. |
| 346 | |
| 347 | Args: |
| 348 | func_graph: FuncGraph. The corresponding forward-pass function. |
| 349 | grads: The list of input gradient Tensors. |
| 350 | |
| 351 | Returns: |
| 352 | The output gradient Tensors. |
| 353 | """ |
| 354 | # Filter out untrainable function outputs. |
| 355 | # NOTE(skyewm): If we don't do this, the untrainable tensors can sometimes |
| 356 | # cause _GradientsHelper to raise an exception (e.g. the implementation |
| 357 | # doesn't expect 'ys' to contain boolean tensors). |
| 358 | assert len(func_graph.outputs) == len(grads) |
| 359 | ys = [] |
| 360 | grad_ys = [] |
| 361 | for y, grad_y in zip(func_graph.outputs, grads): |
| 362 | if not gradients_util.IsTrainable(y): |
| 363 | continue |
| 364 | ys.append(y) |
| 365 | grad_ys.append(grad_y) |
| 366 | |
| 367 | # Build the gradient graph. Note that this builds the gradient computation of |
| 368 | # func_graph in the current graph, which requires capturing tensors from |
| 369 | # func_graph. The captured func_graph tensors are resolved to external tensors |
| 370 | # in _resolve_grad_inputs. |
| 371 | result = gradients_util._GradientsHelper( |
| 372 | ys, func_graph.inputs, grad_ys=grad_ys, |
| 373 | src_graph=func_graph) |
| 374 | |
| 375 | # Functions can't return None; replace Nones with zero tensors. |
| 376 | # TODO(b/80444525): don't return anything here and make _IfGrad return None if |
| 377 | # both branches have zero gradient. |
| 378 | for i in range(len(result)): |
| 379 | if result[i] is None: |
| 380 | if func_graph.inputs[i].dtype == dtypes.resource: |
| 381 | result[i] = array_ops.zeros( |
| 382 | gen_resource_variable_ops.variable_shape(func_graph.inputs[i]), |
| 383 | dtype=default_gradient.get_zeros_dtype(func_graph.inputs[i])) |
| 384 | else: |
| 385 | result[i] = array_ops.zeros_like(func_graph.inputs[i]) |
| 386 | |
| 387 | return result |
| 388 | |
| 389 | |
| 390 | def _create_grad_func(func_graph, grads, name): |
no test coverage detected