o
    ={c5                     @   s   d Z ddlZddlZddlZddl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	iZG d
d dZG dd dedg dZdd ZdS )zContains the `Node` class.    N)backend)base_layer_utils)
json_utils)tf_utils_CONSTANT_VALUEZ_TYPEZ	COMPOSITEc                   @   s   e Zd ZdZdddZedd Zedd Zd	d
 Zdd Z	dd Z
edd Zedd Zedd Zedd Zedd Zedd ZdS )Nodea  A `Node` describes a layer `__call__()` event.

    A Functional model is a DAG with `Node` instances as nodes, and
    `KerasTensor` instances as edges. Nodes aren't `Layer` instances, because a
    single layer could be called multiple times, which would result in graph
    cycles.

    A `__call__()` event involves input tensors (and other input arguments),
    the layer that was called, and the resulting output tensors.
    A `Node` will include all this information.

    Since a single `Layer` could be called multiple times, the `Node` instances
    are stored on layers as a list. Each time a layer is called a node is added
    to `layer._inbound_nodes`. Each time the output of a layer is used by
    another layer, a node is added to `layer._outbound_nodes`.

    Every `KerasTensor` instance has a `KerasHistory` object attached,
    which tracks the `Node` that records the `__call__()` event that created
    the tensor. By recursively walking through `Node` instances
    via the `KerasHistory` metadata of `KerasTensor` instances, once can
    retrieve the entire DAG of a Functional model.

    Args:
        layer: The layer that was called in the `Layer.__call__()`
          event that this node represents.
        call_args: The positional arguments the layer was called with.
        call_kwargs: The keyword arguments the layer was called with.
        outputs: The output tensors of the `Layer.__call__()`
    Nc                 C   s  |d u rg n|}|d u ri n|}|d u rg n|}|| _ | o | | _tjdd |}tjdd |}tjdd || _|| _|| _tj| j| jf| _	| j oat
| jdkoat| jd | _tjj s| j	D ]}t|tjrtj|ddrt| qlg | _g | _t| j	D ]\}}t|r| j| tt|}|}	| j||	f q| j j|  | jD ]}
|
jj }|d ur|j|  qt
| j jd }ttj|D ]\}}t |||d	|_qd
d | jD | _!dd tj| jD | _"d S )Nc                 S      | S N tr
   r
   1lib/python3.10/site-packages/keras/engine/node.py<lambda>Q       zNode.__init__.<locals>.<lambda>c                 S   r   r	   r
   r   r
   r
   r   r   R   r   c                 S   r   r	   r
   r   r
   r
   r   r   S   r      r   T)Zignore_call_contextlayer
node_indextensor_indexc                 S      g | ]}t t|qS r
   strid.0r   r
   r
   r   
<listcomp>   s    z!Node.__init__.<locals>.<listcomp>c                 S   r   r
   r   r   r
   r
   r   r      s    )#r   is_inputtfnestmap_structureoutputs	call_argscall_kwargsZflatten_flat_argumentslen	is_tensor _single_positional_tensor_passedcompatZv1Z#executing_eagerly_outside_functions
isinstanceTensorr   Zneeds_keras_historyZcreate_keras_history_keras_inputs_keras_inputs_ids_and_indices	enumerateis_keras_tensorappendr   r   _inbound_nodeskeras_inputs_keras_historyZ_outbound_nodesKerasHistoryZflat_input_idsZflat_output_ids)selfr   r!   r"   r    objiZelekt_idkt_indexktZinbound_layerr   Ztensorr
   r
   r   __init__C   sj   




zNode.__init__c                 C      | j S )zNTensors input to this node that can be traced back to a
        `keras.Input`.)r*   r3   r
   r
   r   r0      s   zNode.keras_inputsc                 C   s<   g }| j D ]}|jj}|jj}|dur||j|  q|S )zNReturns all the `Node`s whose output this node immediately depends
        on.N)r0   r1   r   r   r.   r/   )r3   Z	node_depsr8   r   r   r
   r
   r   parent_nodes   s   
zNode.parent_nodesc                 c   s8    | j D ]}|j}|j}|j}|j}||||fV  qdS )zYields tuples representing the data inbound from other nodes.

        Yields:
          tuples like: (inbound_layer, node_index, tensor_index, tensor).
        N)r0   r1   r   r   r   )r3   r8   Zkeras_historyr   r   r   r
   r
   r   iterate_inbound   s   
zNode.iterate_inboundc                 C   st   | j r| jd \}}||  fi fS t| j}| jD ]\}}||  ||< qtj| j| j	f|\}}||fS )z;Maps Keras Tensors to computed Tensors using `tensor_dict`.r   )
r&   r+   popcopyr#   r   r   Zpack_sequence_asr!   r"   )r3   Ztensor_dictr6   _Zflat_argumentsr7   argskwargsr
   r
   r   map_arguments   s   zNode.map_argumentsc           	         s  | j | j}| jj|\}}tt| jjjdd |}| |fdd t	j
 z
tjtjd W n  ty_   t	j
t}td| jj d d t| d	 w  fd
d}t	j
||}t	j
|s}| jjs}|g}t|}|S )z4Serializes `Node` for Functional API's `get_config`.r   Nc                    s   t | dr | j}|j} |jj|}|d}|jj||jgS t| tj	r*| 
 S t| tjr7t| 
 S t| tjjrGtt | fS | S )z,Serializes a single Tensor passed to `call`.r1   r   )hasattrr1   r   r   namegetr   r(   npZndarraytolistr   r)   r   Z	get_valueZ__internal__ZCompositeTensor_COMPOSITE_TYPEr   ZEncoderencode)r   khr   node_keynew_node_index)make_node_keynode_conversion_mapr
   r   _serialize_keras_tensor   s   
z/Node.serialize.<locals>._serialize_keras_tensor)defaultzLayer z- was passed non-JSON-serializable arguments. zArguments had types: z6. They cannot be serialized out when saving the model.c                    s\   t | r!| j}|j}|jj|}|d}|jj||jg}ntd | g}t	|S )Nr   )
r-   r1   r   r   rE   rF   r   r   r   ZListWrapper)r   rK   r   rL   rM   datarP   rB   rN   rO   r
   r   serialize_first_arg_tensor   s   
z2Node.serialize.<locals>.serialize_first_arg_tensor)r!   r"   r   Z
_call_specZsplit_out_first_argdictzipZ	arg_namesupdater   r   r   jsondumpsr   Zget_json_type	TypeErrortyperE   r   Z	is_nestedZ#_preserve_input_structure_in_configr   Zconvert_inner_node_data)	r3   rN   rO   rA   ZinputsZ	argumentsZkwarg_typesrU   rS   r
   rT   r   	serialize   sH   



zNode.serializec                 C   s   | j r| jgS | jd S )Nr   )r   r    r!   r;   r
   r
   r   input_tensors
  s   
zNode.input_tensorsc                 C   s   | j r| jgS | jS r	   )r   r    r;   r
   r
   r   output_tensors  s   zNode.output_tensorsc                 C   s0   t jtj| j}t|dkr| js|d S |S )Nr   r   )r   r   r   r   	int_shaper^   r$   r   )r3   input_shapesr
   r
   r   ra     s   zNode.input_shapesc                 C   s   t jtj| jS r	   )r   r   r   r   r`   r_   r;   r
   r
   r   output_shapes  s   zNode.output_shapesc                 C   r:   r	   )r   r;   r
   r
   r   outbound_layer#  s   zNode.outbound_layerc                 C   sD   | j rg S dd | jD }tjdd |}t|dkr |d S |S )z2Return all layers that feed into the current node.c                 S   s$   g | ]}t |rt|d r|qS )r1   )r   r%   rD   )r   xr
   r
   r   r   ,  s    z'Node.inbound_layers.<locals>.<listcomp>c                 S   s   | j jS r	   )r1   r   r   r
   r
   r   r   2  s    z%Node.inbound_layers.<locals>.<lambda>r   r   )r   r#   r   r   r   r$   )r3   Ztensor_call_argsinbound_layersr
   r
   r   re   '  s   zNode.inbound_layers)NNN)__name__
__module____qualname____doc__r9   propertyr0   r<   r=   rC   r]   r^   r_   ra   rb   rc   re   r
   r
   r
   r   r   $   s,    
F

R




r   c                   @   s   e Zd ZdZdZdS )r2   a,  Tracks the Layer call that created a Tensor, for Keras Graph Networks.

    During construction of Keras Graph Networks, this metadata is added to
    each Tensor produced as the output of a Layer, starting with an
    `InputLayer`. This allows Keras to track how each Tensor was produced, and
    this information is later retraced by the `keras.engine.Network` class to
    reconstruct the Keras Graph Network.

    Attributes:
      layer: The Layer that produced the Tensor.
      node_index: The specific call to the Layer that produced this Tensor.
        Layers can be called multiple times in order to share weights. A new
        node is created every time a Layer is called. The corresponding node
        that represents the call event that produced the Tensor can be found at
        `layer._inbound_nodes[node_index]`.
      tensor_index: The output index for this Tensor. Always zero if the Layer
        that produced this Tensor only has one output. Nested structures of
        Tensors are deterministically assigned an index via `nest.flatten`.
    r
   N)rf   rg   rh   ri   	__slots__r
   r
   r
   r   r2   9  s    r2   r   c                 C   s
   t | dS )Nr1   )rD   )r4   r
   r
   r   r-   W  s   
r-   )ri   collectionsr?   rY   ZnumpyrG   Ztensorflow.compat.v2r'   Zv2r   Zkerasr   Zkeras.enginer   Zkeras.saving.legacy.saved_modelr   Zkeras.utilsr   r   rI   r   
namedtupler2   r-   r
   r
   r
   r   <module>   s*     
