Helper class for constructing a TF graph function from the Keras graph. Arguments: inputs: Feed placeholders to the computation graph. outputs: Output tensors to fetch. updates: Additional update ops to be run at function call. name: A name to help users identify what this functio
| 3489 | |
| 3490 | |
| 3491 | class EagerExecutionFunction(object): |
| 3492 | """Helper class for constructing a TF graph function from the Keras graph. |
| 3493 | |
| 3494 | Arguments: |
| 3495 | inputs: Feed placeholders to the computation graph. |
| 3496 | outputs: Output tensors to fetch. |
| 3497 | updates: Additional update ops to be run at function call. |
| 3498 | name: A name to help users identify what this function does. |
| 3499 | session_kwargs: Unsupported. |
| 3500 | """ |
| 3501 | |
| 3502 | def __init__(self, inputs, outputs, updates=None, name=None): |
| 3503 | self.name = name |
| 3504 | self._inputs_structure = inputs |
| 3505 | inputs = nest.flatten(inputs, expand_composites=True) |
| 3506 | self._outputs_structure = outputs |
| 3507 | outputs = nest.flatten(outputs, expand_composites=True) |
| 3508 | |
| 3509 | updates = updates or [] |
| 3510 | if not isinstance(updates, (list, tuple)): |
| 3511 | raise TypeError('`updates` in a Keras backend function ' |
| 3512 | 'should be a list or tuple.') |
| 3513 | |
| 3514 | if updates and not outputs: |
| 3515 | # Edge case; never happens in practice |
| 3516 | raise ValueError('Cannot create a Keras backend function with updates' |
| 3517 | ' but no outputs during eager execution.') |
| 3518 | graphs = { |
| 3519 | i.graph |
| 3520 | for i in nest.flatten([inputs, outputs, updates]) |
| 3521 | if hasattr(i, 'graph') |
| 3522 | } |
| 3523 | if len(graphs) > 1: |
| 3524 | raise ValueError('Cannot create an execution function which is comprised ' |
| 3525 | 'of elements from multiple graphs.') |
| 3526 | |
| 3527 | source_graph = graphs.pop() |
| 3528 | global_graph = get_graph() |
| 3529 | |
| 3530 | updates_ops = [] |
| 3531 | legacy_update_ops = [] |
| 3532 | for update in updates: |
| 3533 | # For legacy reasons it is allowed to pass an update as a tuple |
| 3534 | # `(variable, new_value)` (this maps to an assign op). Otherwise it |
| 3535 | # is assumed to already be an op -- we cannot control its execution |
| 3536 | # order. |
| 3537 | if isinstance(update, tuple): |
| 3538 | legacy_update_ops.append(update) |
| 3539 | else: |
| 3540 | if hasattr(update, 'op'): |
| 3541 | update = update.op |
| 3542 | if update is not None: |
| 3543 | # `update.op` may have been None in certain cases. |
| 3544 | updates_ops.append(update) |
| 3545 | |
| 3546 | self._freezable_vars_to_feed = [] |
| 3547 | self._freezable_vars_values = [] |
| 3548 | freezable_vars_from_keras_graph = object_identity.ObjectIdentitySet( |