Call `metric_value_fn` in the correct control flow context.
(distribution, *a)
| 280 | def _aggregate_across_replicas(metrics_collections, metric_value_fn, *args): |
| 281 | """Aggregate metric value across replicas.""" |
| 282 | def fn(distribution, *a): |
| 283 | """Call `metric_value_fn` in the correct control flow context.""" |
| 284 | if hasattr(distribution.extended, '_outer_control_flow_context'): |
| 285 | # If there was an outer context captured before this method was called, |
| 286 | # then we enter that context to create the metric value op. If the |
| 287 | # caputred context is `None`, ops.control_dependencies(None) gives the |
| 288 | # desired behavior. Else we use `Enter` and `Exit` to enter and exit the |
| 289 | # captured context. |
| 290 | # This special handling is needed because sometimes the metric is created |
| 291 | # inside a while_loop (and perhaps a TPU rewrite context). But we don't |
| 292 | # want the value op to be evaluated every step or on the TPU. So we |
| 293 | # create it outside so that it can be evaluated at the end on the host, |
| 294 | # once the update ops have been evaluted. |
| 295 | |
| 296 | # pylint: disable=protected-access |
| 297 | if distribution.extended._outer_control_flow_context is None: |
| 298 | with ops.control_dependencies(None): |
| 299 | metric_value = metric_value_fn(distribution, *a) |
| 300 | else: |
| 301 | distribution.extended._outer_control_flow_context.Enter() |
| 302 | metric_value = metric_value_fn(distribution, *a) |
| 303 | distribution.extended._outer_control_flow_context.Exit() |
| 304 | # pylint: enable=protected-access |
| 305 | else: |
| 306 | metric_value = metric_value_fn(distribution, *a) |
| 307 | if metrics_collections: |
| 308 | ops.add_to_collections(metrics_collections, metric_value) |
| 309 | return metric_value |
| 310 | |
| 311 | return distribution_strategy_context.get_replica_context().merge_call( |
| 312 | fn, args=args) |