o
    ={c+  ã                   @   sv   d Z ddlm  mZ ddlmZ ddlmZ	 ddlm
Z
 ddlmZ dZdd	„ Zd
d„ Zdd„ Zdd„ Zdd„ ZdS )z%Utilities for keras functional model.é    N)Úbackend)Úinput_layer)Úkeras_tensor)Únodez´Found unexpected instance while processing input tensors for keras functional model. Expecting KerasTensor which is from tf.keras.Input() or output from keras layer call(). Got: {}c                 C   s    t  | ¡stt | ¡ƒ‚| jjS )aà  Check if tensor is directly generated from `tf.keras.Input`.

    This check is useful when constructing the functional model, since we will
    need to clone Nodes and KerasTensors if the model is building from non input
    tensor.

    Args:
      tensor: A `KerasTensor` as inputs to the functional model.

    Returns:
      bool. Whether the tensor is directly generated from `tf.keras.Input`.

    Raises:
      ValueError: if the tensor is not a KerasTensor instance.
    )Únode_moduleÚis_keras_tensorÚ
ValueErrorÚ"_KERAS_TENSOR_TYPE_CHECK_ERROR_MSGÚformatr   Úis_input©Ztensor© r   ú=lib/python3.10/site-packages/keras/engine/functional_utils.pyÚis_input_keras_tensor   s   
r   c                    s*  t j |¡}t j | ¡}|| D ]}t |¡stt |¡ƒ‚qtdd„ |D ƒƒ}tƒ ‰ g }g }tƒ }|D ]}| 	|j
¡ q4|r| d¡}	t|	ƒ|v rKq=| t|	ƒ¡ | 	|	¡ |	jD ]"}
t|
ƒ|v rjˆ  t|
ƒ¡ qZ|
j
}|jrwtd |
¡ƒ‚| 	|¡ qZ|s?|ˆ kr“‡ fdd„|D ƒ}td |¡ƒ‚|S )a6  Fetch all Nodes in the graph defined by "inputs" and "outputs".

    This method is used to find and then clone Nodes when creating a new
    sub-model from an existing functional model.

    Args:
      inputs: A nested structure of KerasTensor to use as model inputs.
      outputs: A nested structure of KerasTensor to use as model outputs.

    Returns:
      A list of Nodes that are connected to the inputs and outputs.

    Raises:
      ValueError: when inputs and outputs are disconnected or in case of
        unexpected objects in the inputs/outputs.
    c                 S   s   g | ]}t |ƒ‘qS r   ©Úid©Ú.0Úktr   r   r   Ú
<listcomp>T   s    z4find_nodes_by_inputs_and_outputs.<locals>.<listcomp>r   z¢Found input tensor cannot be reached given provided output tensors. Please make sure the tensor {} is included in the model inputs when building functional model.c                    s   g | ]
}t |ƒˆ vr|‘qS r   r   r   ©Zend_ids_foundr   r   r   ~   s    zHFound unvisited input tensors that are disconnected from the outputs: {})ÚtfÚnestÚflattenr   r   r   r	   r
   ÚsetÚappendr   Úpopr   ÚaddZkeras_inputsr   )ÚinputsÚoutputsZstart_keras_tensorsZend_keras_tensorsÚtZend_idsZnodes_to_visitZnodes_in_graphZnode_id_visitedr   r   Zinbound_nodeZunvisited_inputsr   r   r   Ú find_nodes_by_inputs_and_outputs4   sP   
ÿ


üç
ÿþr!   c                 C   s  t | |ƒ}g }g }i }tj | ¡D ]'}|jjr#| |¡ ||t|ƒ< qt|ƒ}t	j
|d}| |¡ ||t|ƒ< qtj | |¡}tj |¡D ]}	t|	ƒ}|	j|_| |¡ ||t|	ƒ< qFtj ||¡}|D ]}
t|
j|ƒ}t|
j|ƒ}t|
j|ƒ}tj|
j|||d qe||fS )a¬  Clone the `Node` between the inputs and output tensors.

    This function is used to create a new functional model from any intermediate
    keras tensors. The clone of the nodes mimic the behavior of reconstructing
    the functional graph network by re-executing all the __call__ methods. The
    cloned nodes will be appended to the layers.

    Note that a new tf.keras.Inputs will be created for any items in the
    `inputs`

    Args:
      inputs: A nested structure of keras_tensors.
      outputs: A nested structure of keras_tensors.

    Returns:
      A pair of inputs and outputs, with cloned keras_tensors. They can be used
      to create a new functional model.
    r   )Ú	call_argsÚcall_kwargsr   )r!   r   r   r   r   r   r   r   Ú_clone_keras_tensorÚinput_layer_moduleZInputÚpack_sequence_asÚ_keras_historyÚclone_keras_tensorsZoutput_tensorsr"   r#   r   ZNodeZlayer)r   r   Znodes_to_cloneZcloned_inputsZcloned_outputsZkt_id_mappingZkt_inputÚcpyZcloned_inputZ	kt_outputr   Zoutput_copyZcall_args_copyZcall_kwargs_copyr   r   r   Úclone_graph_nodesˆ   s<   



ür*   c                 C   sz   g }t j | ¡D ]-}t |¡r0t|ƒ|v r|t|ƒ }nt|ƒ}|j|_||t|ƒ< | |¡ q| |¡ qt j 	| |¡S )aë  Clone the keras tensors from the inputs.

    For any KerasTensor instance in the `args`, a new copy of KerasTensor will
    be created if it has not been cloned yet (by checking the
    `keras_tensor_mapping`). For any other types, the instance will be
    unchanged. This function is useful for cloning the Nodes since KerasTensor
    can't be reused across the models.

    Args:
      args: A nested structure of objects, which could contain KerasTensor.
      keras_tensor_mapping: A dict contains the ID of original KerasTensor, and
        the cloned KerasTensor instance. The dict will be updated with newly
        copied KerasTensor instances within this method.
    Returns:
      Same structure as inputs, with KerasTensor cloned.
    )
r   r   r   r   r   r   r$   r'   r   r&   )ÚargsZkeras_tensor_mappingÚresultÚobjr)   r   r   r   r(   Ó   s   
r(   c              	   C   sx   t  ¡ .}| ¡  t | ¡}t |¡W  d  ƒ W  d  ƒ S 1 s%w   Y  W d  ƒ dS 1 s5w   Y  dS )a(  Create an identical keras_tensor based on the input.

    We use keras_tensor_to_placeholder and keras_tensor_from_tensor to make sure
    inferred shape are not lost during the copy.

    Args:
      kt: the input KerasTensor.

    Returns:
      An identical copy of the input KerasTensor.
    N)r   Z_scratch_graphZ
as_defaultr   Zkeras_tensor_to_placeholderZkeras_tensor_from_tensor)r   Zscratch_graphZplaceholderr   r   r   r$   ô   s   


þÿ"ÿr$   )Ú__doc__Ztensorflow.compat.v2ÚcompatZv2r   Zkerasr   Zkeras.enginer   r%   r   r   r   r	   r   r!   r*   r(   r$   r   r   r   r   Ú<module>   s   ÿTK!