B
    ӻd	                 @   s  d Z ddlZddlZddlZddlZddlmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddl m!Z" ddl#m$Z% ddl&m'Z' ddl(m)Z) G dd dej*Z+dd Z,dd Z-dd Z.d d! Z/d"d# Z0d$d% Z1d&d' Z2d0d(d)Z3d1d*d+Z4d,d- Z5G d.d/ d/ej6Z7dS )2zHA `Network` is way to compose layers: the topological form of a `Model`.    N)context)dtypes)ops)backend)
base_layer)base_layer_utils)input_layer)
input_spec)node)training)training_utils)network_serialization)generic_utils)
tf_inspect)tf_utils)	array_ops)math_ops)
tf_logging)base)nest)doc_controlsc                   s  e Zd ZdZeedejj	Z	e
jdB fdd	Ze
jdd Zed	d
 Zedd Zedd Zejdd Zedd Zedd Zdd Zedd Ze
jjf fdd	Z fddZdd Zedd Zd d! ZejdCd"d#Z d$d% Z!dDd&d'Z"dEd(d)Z#d*d+ Z$d,d- Z%d.d/ Z&e'dFd0d1Z(d2d3 Z)dGd4d5Z*d6d7 Z+d8d9 Z,d:d; Z-d<d= Z.ed>d? Z/dH fd@dA	Z0  Z1S )I
Functionala\  A `Functional` model is a `Model` defined as a directed graph of layers.

  Three types of `Model` exist: subclassed `Model`, `Functional` model,
  and `Sequential` (a special case of `Functional`).
  In general, more Keras features are supported with `Functional`
  than with subclassed `Model`s, specifically:

  - Model cloning (`keras.models.clone`)
  - Serialization (`model.get_config()/from_config`, `model.to_json()`
  - Whole-model saving (`model.save()`)

  A `Functional` model can be instantiated by passing two arguments to
  `__init__`. The first argument is the `keras.Input` Tensors that represent
  the inputs to the model. The second argument specifies the output
  tensors that represent the outputs of this model. Both arguments can be a
  nested structure of tensors.

  Example:

  ```
  inputs = {'x1': keras.Input(shape=(10,)), 'x2': keras.Input(shape=(1,))}
  t = keras.layers.Dense(1, activation='relu')(inputs['x1'])
  outputs = keras.layers.Add()([t, inputs['x2'])
  model = keras.Model(inputs, outputs)
  ```

  A `Functional` model constructed using the Functional API can also include raw
  TensorFlow functions, with the exception of functions that create Variables
  or assign ops.

  Example:

  ```
  inputs = keras.Input(shape=(10,))
  x = keras.layers.Dense(1)(inputs)
  outputs = tf.nn.relu(x)
  model = keras.Model(inputs, outputs)
  ```

  Args:
    inputs: List of input tensors (must be created via `tf.keras.Input()`).
    outputs: List of output tensors.
    name: String, optional. Name of the model.
    trainable: Boolean, optional. If the model's variables should be trainable.
  )_layer_call_argspecsZ_compiled_trainable_state_output_mask_cache_output_tensor_cache_output_shape_cacheNTc                sD   | dd}|rd S t|i  tt| j||d | || d S )N	skip_initF)name	trainable)popr   Zvalidate_kwargssuperr   __init___init_graph_network)selfinputsoutputsr   r   kwargsr   )	__class__ [/var/www/html/venv/lib/python3.7/site-packages/tensorflow/python/keras/engine/functional.pyr!   g   s    zFunctional.__init__c             C   s  d| _ t|tr*tt|dkr*|d }t|trNtt|dkrN|d }|| _|| _t|| _t|| _	t
| jsd| _n^t| jttfrtdd | jD sd| _n2t| jtrtdd | j D sd| _nd| _t stdd | j	D rt| j |   d| _td	d
 || _d| _d| _d| _d| _g | _g | _g | _g | _i | _ i | _!i | _"x:| j	D ]0}|j#\}}}| j$| | j$|||f qzW xV| jD ]L}|j#\}}}|dkst%|dkst%| j$| | j$|||f qW t&| j| j	\}}}	}
|| _'|| _(|	| _)i | _*x"| j)D ]}t+,|j-| j*|< q<W | .  g | _/g | _0g | _1g | _2xP| jD ]F}| j/$|j3 |j4r| j0$|j3 | j2$|j5 | j1$|j6 qW | 7  | 8| j t9:| j; d S )NT   r   c             s   s   | ]}t |V  qd S )N)r   	is_nested).0tr(   r(   r)   	<genexpr>   s    z1Functional._init_graph_network.<locals>.<genexpr>c             s   s   | ]}t |V  qd S )N)r   r+   )r,   r-   r(   r(   r)   r.      s    Fc             s   s   | ]}t |d  V  qdS )_keras_historyN)hasattr)r,   tensorr(   r(   r)   r.      s    c             S   s   | j S )N)shape)xr(   r(   r)   <lambda>       z0Functional._init_graph_network.<locals>.<lambda>)<Z_is_graph_network
isinstancelistlenr   flatten_nested_inputs_nested_outputsr$   r%   r+   _enable_dict_to_input_mappingtupleanydictvaluesr   #executing_eagerly_outside_functionsr   create_keras_history"_validate_graph_inputs_and_outputsZbuiltmap_structureZ_build_input_shapeZ _compute_output_and_mask_jointly_expects_training_arg_expects_mask_argZ	_autocast_input_layers_output_layers_input_coordinates_output_coordinatesr   r   r   r/   appendAssertionError_map_graph_network_network_nodes_nodes_by_depth_self_tracked_trackablesr   r   getfullargspeccall_set_output_namesZinput_namesZ_feed_input_namesZ_feed_inputsZ_feed_input_shapesr   Zis_placeholderZ_batch_input_shapeinput_compute_tensor_usage_countZ_set_save_specr   assert_no_legacy_layerslayers)r#   r$   r%   r3   layer
node_indextensor_indexnodesnodes_by_depthrW   _r(   r(   r)   r"   u   s    
zFunctional._init_graph_networkc             C   s   | j S )aF  Retrieves the input tensor(s) of a layer.

    Only applicable if the layer has exactly one input,
    i.e. if it is connected to one incoming layer.

    Returns:
        Input tensor or list of input tensors.

    Raises:
      RuntimeError: If called in Eager mode.
      AttributeError: If no inbound nodes are found.
    )r:   )r#   r(   r(   r)   rT      s    zFunctional.inputc             C   s   t tj| jS )a  Retrieves the input shape(s) of a layer.

    Only applicable if the layer has exactly one input,
    i.e. if it is connected to one incoming layer, or if all inputs
    have the same shape.

    Returns:
        Input shape, as an integer shape tuple
        (or list of shape tuples, one tuple per input tensor).

    Raises:
        AttributeError: if the layer has no defined input_shape.
        RuntimeError: if called in Eager mode.
    )r   rD   r   	int_shaperT   )r#   r(   r(   r)   input_shape   s    zFunctional.input_shapec                sz   t  dr jS t jtttfr:t jt jkr:d S t jtrft	 j
 } fdd|D S dd  jD S d S )N_manual_input_specc                s&   g | ]}t jt j| d |dqS )T)r2   allow_last_axis_squeezer   )r	   	InputSpecshape_with_no_batch_sizer:   )r,   r   )r#   r(   r)   
<listcomp>  s   z)Functional.input_spec.<locals>.<listcomp>c             S   s&   g | ]}t jt|d |jjjdqS )T)r2   ra   r   )r	   rb   rc   r/   rX   r   )r,   r3   r(   r(   r)   rd     s   )r0   r`   r6   r:   r?   r7   r=   r8   r$   sortedkeys)r#   namesr(   )r#   r)   r	     s    

zFunctional.input_specc             C   s
   || _ d S )N)r`   )r#   valuer(   r(   r)   r	     s    c             C   s   | j S )am  Retrieves the output tensor(s) of a layer.

    Only applicable if the layer has exactly one output,
    i.e. if it is connected to one incoming layer.

    Returns:
      Output tensor or list of output tensors.

    Raises:
      AttributeError: if the layer is connected to more than one incoming
        layers.
      RuntimeError: if called in Eager mode.
    )r;   )r#   r(   r(   r)   output   s    zFunctional.outputc             C   s   t tj| jS )a  Retrieves the output shape(s) of a layer.

    Only applicable if the layer has one output,
    or if all outputs have the same shape.

    Returns:
        Output shape, as an integer shape tuple
        (or list of shape tuples, one tuple per output tensor).

    Raises:
        AttributeError: if the layer has no defined output shape.
        RuntimeError: if called in Eager mode.
    )r   rD   r   r^   ri   )r#   r(   r(   r)   output_shape1  s    zFunctional.output_shapec             C   sz   g }t  }i }x`| jD ]V}|j}x6||krV||jd}d|j|}|d ||j< q"W || || qW || _dS )zAssigns unique names to the Network's outputs.

    Output layers with multiple output tensors would otherwise lead to duplicate
    names in self.output_names.
    r*   z{}_{}N)setrH   r   getformataddrK   output_names)r#   Z
uniquifiedro   Zprefix_countrX   ZproposalZexisting_countr(   r(   r)   rS   B  s    

zFunctional._set_output_namesc          	   C   sh   d}t  }xVt| jD ]H\}}y|jr<||d| < |d7 }W n tk
rR   Y nX ||d| < qW |S )zBDictionary of layer dependencies to be included in the checkpoint.r   zlayer_with_weights-%dr*   zlayer-%d)collectionsOrderedDict	enumeraterW   weights
ValueError)r#   Zweight_layer_indexdependenciesZlayer_indexrX   r(   r(   r)   _layer_checkpoint_dependenciesU  s    z)Functional._layer_checkpoint_dependenciesc                s$   | j }|tt| j|f| |S )N)rv   updater    r   _trackable_children)r#   	save_typer&   ru   )r'   r(   r)   rx   m  s    zFunctional._trackable_childrenc                s&   | j }||kr|| S tt| |S )N)rv   r    r   _lookup_dependency)r#   r   Zlayer_dependencies)r'   r(   r)   rz   u  s    zFunctional._lookup_dependencyc             C   sD   | j }dd | D }x&|D ]}||kr| j|| |d qW dS )z@Handles layer checkpoint dependencies that are added after init.c             S   s   i | ]\}}||qS r(   r(   )r,   kvr(   r(   r)   
<dictcomp>~  s    zBFunctional._handle_deferred_layer_dependencies.<locals>.<dictcomp>)r   	trackableN)rv   itemsZ_handle_deferred_dependencies)r#   rW   Zlayer_checkpoint_dependenciesZlayer_to_namerX   r(   r(   r)   #_handle_deferred_layer_dependencies{  s    

z.Functional._handle_deferred_layer_dependenciesc             C   s   dS )NTr(   )r#   r(   r(   r)   _should_compute_mask  s    zFunctional._should_compute_maskc             C   s   | j ||d}tdd |S )N)maskc             S   s   t | dd S )N_keras_mask)getattr)r-   r(   r(   r)   r4     r5   z)Functional.compute_mask.<locals>.<lambda>)_run_internal_graphr   rD   )r#   r$   r   output_tensorsr(   r(   r)   compute_mask  s    
zFunctional.compute_maskc             C   s   | j |||dS )a^  Calls the model on new inputs.

    In this case `call` just reapplies
    all ops in the graph to the new inputs
    (e.g. build a new computational graph from the provided inputs).

    Args:
        inputs: A tensor or list of tensors.
        training: Boolean or boolean scalar tensor, indicating whether to run
          the `Network` in training mode or inference mode.
        mask: A mask or list of masks. A mask can be
            either a tensor or None (no mask).

    Returns:
        A tensor if there is a single output, or
        a list of tensors if there are more than one outputs.
    )r   r   )r   )r#   r$   r   r   r(   r(   r)   rR     s    zFunctional.callc             C   s`  t j|dd}tt|tt| jkrRtdt| d tt| j d y*tt j|dd}|| j	krz| j	| S W n tk
r   Y nX i }x0t
| jt|D ]\}}|jd }|||< qW t| j }|jdd t|d	kr\x|D ]}| j| }	x|	D ]}
|
j}|| jkr&qg }|
jd
 }x@t|D ]2}|j}|jjd|j|jf  }|||  q@W t||}t j|dd}||}t j|dd}|j|
}x6tt|D ]$\}}|jd||f  }|||< qW qW qW g }xHtt| jD ]6}| j| \}}}|jd||f  }|||  q
W t| j|}|| j	|< |S )NF)Z	to_tupleszInvalid input_shape argument z: model has z tensor inputs.TZ_0_0)reverser*   r   z_%s_%s)r   Zconvert_shapesr8   r   r9   rG   rt   strr=   r   zipr   r7   rO   rf   sortrX   	call_argsr/   rY   rZ   rK   pack_sequence_ascompute_output_shape_inbound_nodesindexrr   rangerH   rJ   r;   )r#   r_   	cache_keyZlayers_to_output_shapesrX   r2   Z	shape_key
depth_keysdepthr[   r
   Zlayer_input_shapesZlayer_inputsZlayer_inputZkhZinput_layer_keyZlayer_output_shapesrY   jZoutput_shapesirZ   r(   r(   r)   r     sd    








zFunctional.compute_output_shapec             C   s<   |s2| j j}| j tkrd}tjt||d| _n|| _d S )NModel)
zero_based)r'   __name__r   r   Zunique_object_namer   Zto_snake_case_name)r#   r   r   cls_namer(   r(   r)   _init_set_name  s    
zFunctional._init_set_namec                s  |  |}|dkr"dgt| }n
|  |}xt||D ]\}}||_q8W i  | j}xDt| j|D ]4\}}| j||d}tt|}	|g||	   |	< qbW | j	}
t
|
 }|jdd x|D ]}|
| }x||D ]t}|jrqt fdd|jD rq| \}}|j||}x2t|jt|D ]\}	}|g||	   |	< q$W qW qW g }xH| jD ]>}tt|}	|	 kstdt| | |	   qXW t| j|S )a5  Computes output tensors for new inputs.

    # Note:
        - Can be run on non-Keras tensors.

    Args:
        inputs: Tensor or nested structure of Tensors.
        training: Boolean learning phase.
        mask: (Optional) Tensor or nested structure of Tensors.

    Returns:
        output_tensors
    N)	ref_inputT)r   c             3   s   | ]}| kV  qd S )Nr(   )r,   Zt_id)tensor_dictr(   r)   r.   '  s    z1Functional._run_internal_graph.<locals>.<genexpr>zCould not compute output )_flatten_to_reference_inputsr8   r   r   _tensor_usage_countr$   _conform_to_reference_inputr   idrO   r7   rf   r   is_inputr>   Zflat_input_idsZmap_argumentsrX   Zflat_output_idsr   r9   r%   rL   rK   r   r   r;   )r#   r$   r   r   masksinput_ttensor_usage_countr3   yZx_idr\   r   r   r[   r
   argsr&   r%   r   r(   )r   r)   r     s@    




 zFunctional._run_internal_graphc                s   | j rttr| j}t|s(| jg}t|tr@t|  ndd |D  tt krt	
d fdd D  yfdd D S  tk
r   tS X tS )z1Maps `tensors` to their respective `keras.Input`.c             S   s   g | ]}|j jjqS r(   )r/   rX   r   )r,   Zinpr(   r(   r)   rd   G  s    z;Functional._flatten_to_reference_inputs.<locals>.<listcomp>zdInput dict contained keys {} which did not match any model input. They will be ignored by the model.c                s   g | ]}| kr|qS r(   r(   )r,   n)ref_input_namesr(   r)   rd   N  s    c                s   g | ]} | qS r(   r(   )r,   r   )tensorsr(   r)   rd   S  s    )r<   r6   r?   r:   r   r+   re   rf   r8   warningswarnrm   KeyErrorr9   )r#   r   Z
ref_inputsr(   )r   r   r)   r   9  s     

z'Functional._flatten_to_reference_inputsc       	   
   C   s<  t |tjr|j}|j}|j}|j}t|dd}|dk	r|dk	r||d krh|d dkrhtj|dd}n&||d kr|d dkrtj|dd}|dk	r||_	t
 sy||j|j W n, tk
r   td|j||j Y nX tj||jd}n<t|r8t|dd}|dk	r8|tjkr8tj||d}|S )	z,Set shape and dtype based on `keras.Input`s.r/   Nr*   )ZaxiszkModel was constructed with shape {} for input {}, but it was called on an input with incompatible shape {}.)dtyper   )r6   r   ZTensorr2   rankr   r   Z
squeeze_v2Zexpand_dims_v2r/   r   Zexecuting_eagerly	set_shapeZ
merge_withrt   loggingwarningrm   r   castr   r   Zis_extension_typer   variant)	r#   r1   r   Zt_shapeZt_rankZ	ref_shapeZref_rankZkeras_historyZref_input_dtyper(   r(   r)   r   [  s4    z&Functional._conform_to_reference_inputc             C   s   t t| S )N)copydeepcopyget_network_config)r#   r(   r(   r)   
get_config  s    zFunctional.get_configc          	   C   sF   t  4 t||\}}}| |||dd}t|| |S Q R X dS )a  Instantiates a Model from its config (output of `get_config()`).

    Args:
        config: Model config dictionary.
        custom_objects: Optional dictionary mapping names
            (strings) to custom classes or functions to be
            considered during deserialization.

    Returns:
        A model instance.

    Raises:
        ValueError: In case of improperly formatted config dict.
    r   )r$   r%   r   N)r   ZSharedObjectLoadingScopereconstruct_from_configrl   connect_ancillary_layers)clsconfigcustom_objectsinput_tensorsr   created_layersmodelr(   r(   r)   from_config  s    

zFunctional.from_configc             C   s`  t dd | jD t | jkr0tdt| j x| jD ]}t|dsn| jj}td| d d t| d |jj}t |j	d	ks|j	r8|j	d
 j
s8| jj}t|d | j d |j d t|j  q8W dd | jD }d}x:|D ]2}|dk	r|dk	r||krtd||}qW x<| jD ]2}t|ds&| jj}td| d t| q&W dS )z4Validates the inputs and outputs of a Graph Network.c             S   s   h | ]}t |qS r(   )r   )r,   r   r(   r(   r)   	<setcomp>  s    z@Functional._validate_graph_inputs_and_outputs.<locals>.<setcomp>z`The list of inputs passed to the model is redundant. All inputs should only appear once. Found: r/   zInput tensors to a  z+must come from `tf.keras.Input`. Received: z# (missing previous layer metadata).r*   r   z model inputs must come from `tf.keras.Input` (thus holding past layer metadata), they cannot be the output of a previous non-Input layer. Here, a tensor specified as input to "z5" was not an Input tensor, it was generated by layer zw.
Note that input tensors are instantiated via `tensor = tf.keras.Input(shape)`.
The tensor that caused the issue was: c             S   s   g | ]}t |jjqS r(   )r   Zget_static_batch_sizer/   rX   )r,   r3   r(   r(   r)   rd     s   zAFunctional._validate_graph_inputs_and_outputs.<locals>.<listcomp>NzUThe specified batch sizes of the Input Layers are incompatible. Found batch sizes: {}zOutput tensors of a z] model must be the output of a TensorFlow `Layer` (thus holding past layer metadata). Found: )r8   r$   rt   r   r0   r'   r   r/   rX   r   r   r   r   r   rm   r%   )r#   r3   r   rX   Zinput_batch_sizesZconsistent_batch_sizeZ
batch_sizer(   r(   r)   rC     s<    
	,



z-Functional._validate_graph_inputs_and_outputsc                s  t |}t| i x.| j D ] \ } fdd|D  q$W |s`t dd |D }t|t	  fdd}t

|}d}x|r|d7 }|d	krtd
|d}||  dkr|| qt|jj|jj|}|| jkr |< | j| | j  | qW t| j}	g }
xJ|D ]B}||	kr4| j| |
| t|j| j|< |	| q4W | |
 |   dS )a  Inserts Layers into the Network after Network creation.

    This is only valid for Keras Graph Networks.  Layers added via this function
    will be included in the `call` computation and `get_config` of this Network.
    They will not be added to the Network's outputs.


    Args:
      layers: Arbitrary nested structure of Layers. Layers must be reachable
        from one or more of the `keras.Input` Tensors that correspond to this
        Network's inputs.
      relevant_nodes: Nodes from the Layers that should be considered part of
        this Network. If `None`, all Nodes will be considered part of this
        Network.

    Raises:
      ValueError: If the layers depend on `Input`s not found in this Model.
    c                s   i | ]
} |qS r(   r(   )r,   r
   )r   r(   r)   r}     s    z-Functional._insert_layers.<locals>.<dictcomp>c             S   s   g | ]
}|j qS r(   )r   )r,   rX   r(   r(   r)   rd     s    z-Functional._insert_layers.<locals>.<listcomp>c                sX   d}xJ|   D ]>\}}}}|j| }|kr<t|| }q| krHqqdS qW |d S )z5Gets the minimum depth at which node can be computed.r   Nr*   )Ziterate_inboundr   min)r
   Z	min_depthrX   Znode_idr]   inbound_node)network_nodesnode_to_depthr(   r)   _get_min_depth  s    
z1Functional._insert_layers.<locals>._get_min_depthr   r*   i'  z6Layers could not be added due to missing dependencies.N)r   r9   r   rV   rO   r   rw   rk   r7   rf   r   rt   r   rK   _make_node_keyrX   r   r   r   rN   rn   rP   r   rQ   rR   r   r   rU   )r#   rW   relevant_nodesr[   r   unprocessed_nodesr   r
   node_keyZ	layer_setZdeferred_layersrX   r(   )r   r   r   r)   _insert_layers  sH    










zFunctional._insert_layersc       	      C   s  t  }tdd | jD }t| j }|jdd |dd }x|D ]}x| j| D ]z}dd t	|j
D }||rXx,t	|j
D ]}|tt|  d7  < qW x&t	|jD ]}|tt| qW qXW qHW x&| jD ]}|tt|  d7  < qW || _dS )	a  Compute the #. of tensor usages for all the output tensors of layers.

    The computed tensor usage count is saved as `self._tensor_usage_count`. This
    is later used for saving memory in eager computation by releasing
    no-longer-needed tensors as early as possible.
    c             s   s   | ]}t t|V  qd S )N)r   r   )r,   r1   r(   r(   r)   r.   3  s    z9Functional._compute_tensor_usage_count.<locals>.<genexpr>T)r   r*   Nc             S   s   h | ]}t t|qS r(   )r   r   )r,   r1   r(   r(   r)   r   ;  s   z9Functional._compute_tensor_usage_count.<locals>.<setcomp>)rp   Counterrk   r$   r7   rO   rf   r   r   r9   keras_inputsissubsetr   r   r%   rn   r   )	r#   r   Zavailable_tensorsr   r   r
   r   r1   Zoutput_tensorr(   r(   r)   rU   +  s"    

z&Functional._compute_tensor_usage_countc             C   s   d S )Nr(   )r#   r(   r(   r)   _assert_weights_createdJ  s    z"Functional._assert_weights_createdc             C   sP   t | j|g\}}tjd|jd}|| ||j || | || d S )NF)Zunconditionalr   )	_map_subgraph_networkr$   r   ZAddLossr   extendinbound_nodesrK   r   )r#   Zsymbolic_loss	new_nodes
new_layersZadd_loss_layerr(   r(   r)   _graph_network_add_lossO  s    
z"Functional._graph_network_add_lossc             C   sR   t | j|g\}}tj|||jd}|| ||j || | || d S )N)r   )	r   r$   r   Z	AddMetricr   r   r   rK   r   )r#   rh   Zaggregationr   r   r   Zadd_metric_layerr(   r(   r)   _graph_network_add_metricZ  s    
z$Functional._graph_network_add_metricc             C   s
   t | S )N)r   ZNetworkSavedModelSaver)r#   r(   r(   r)   _trackable_saved_model_saverc  s    z'Functional._trackable_saved_model_saverc                s    t | ddrd}tt| |S )NZ_has_explicit_input_shapeTF)r   r    r   _get_save_spec)r#   Zdynamic_batch)r'   r(   r)   r   g  s    zFunctional._get_save_spec)NT)NN)T)NN)N)N)T)2r   
__module____qualname____doc__	frozenset	itertoolschaintraining_libr   Z_TF_MODULE_IGNORED_PROPERTIESr~   Z no_automatic_dependency_trackingr!   r"   propertyrT   r_   r	   setterri   rj   rS   rv   ZSaveType
CHECKPOINTrx   rz   r   r   r   r   Zdo_not_doc_inheritablerR   r   r   r   r   r   r   classmethodr   rC   r   rU   r   r   r   r   r   __classcell__r(   r(   )r'   r)   r   /   sL   -o	L

:",8
Q	r   c             C   s   | d t | S )Nz_ib-)r   )
layer_namerY   r(   r(   r)   r   o  s    r   c                s  t |\} dd |D }i }i }xtt|D ]h}||d}||jd}t||}|||j< |||< x,|jD ]"}	||	d}t|d |||	< qnW q,W xN| D ]F}
|
jd }||krd||< d |< d||jd < |	t
|jd qW tt}x"| D ]\}}|| | qW tt}x$| D ]\}}|| | q*W t| }|jdd g }x4|D ],}|| }|j fdd	d
 || qhW t| }|jdd t }x| D ]}|	t| qW g }x|D ]}x|| D ]}|j}|r|jsxJt|jD ]:}t||krtdt| d |j d t| qW x$t|jD ]}|	t| q^W ||j qW qW dd |D }x@|D ]8}||dkrtd| d t|| d qW ||||fS )a  Validates a network's topology and gather its layers and nodes.

  Args:
    inputs: List of input tensors.
    outputs: List of outputs tensors.

  Returns:
    A tuple `(nodes, nodes_by_depth, layers, layers_by_depth)`.
    - nodes: list of Node instances.
    - nodes_by_depth: dict mapping ints (depth) to lists of node instances.
    - layers: list of Layer instances.
    - layers_by_depth: dict mapping ints (depth) to lists of layer instances.

  Raises:
    ValueError: In case the network is not valid (e.g. disconnected graph).
  c             S   s$   h | ]}t |jj|jj|qS r(   )r   rX   r   r   r   )r,   r
   r(   r(   r)   r     s   z%_map_graph_network.<locals>.<setcomp>r   r*   r   T)r   c                s    |  S )Nr(   )r3   )layer_indicesr(   r)   r4     r5   z$_map_graph_network.<locals>.<lambda>)keyz3Graph disconnected: cannot obtain value for tensor z at layer "z>". The following previous layers were accessed without issue: c             S   s   g | ]
}|j qS r(   )r   )r,   rX   r(   r(   r)   rd     s    z&_map_graph_network.<locals>.<listcomp>z
The name "z
" is used z6 times in the model. All layer names should be unique.)
_build_mapreversed
setdefaultrl   rX   maxZparent_nodesr/   r   rn   r   r   rp   defaultdictr7   r   rK   rf   r   r   rk   r   r   r   r9   r   rt   r   r%   count)r$   r%   nodes_in_decreasing_depthr   Znodes_depthsZlayers_depthsr
   r   Zprevious_depthZnode_depr   r   r\   Zlayers_by_depthrX   r   rW   Zlayers_for_depthZcomputable_tensorsr3   Zlayers_with_complete_inputZ	all_namesr   r(   )r   r)   rM   s  st    









&rM   c             C   s@   t  }t  }g }i }x"t| D ]}t||||| q W ||fS )a  This method topologically sorts nodes in order from inputs to outputs.

  It uses a depth-first search to topologically sort nodes that appear in the
  _keras_history connectivity metadata of `outputs`.

  Args:
    outputs: the output tensors whose _keras_history metadata should be walked.
    This may be an arbitrary nested structure.

  Returns:
    A tuple like (ordered_nodes, layer_to_first_traversal_index)
    ordered_nodes: list of nodes appearing in the keras history, topologically
      sorted from original inputs to the `outputs`.
      (If outputs have different sets of ancestors, the inputs to one output
      may appear after a different output).
    layer_to_first_traversal_index:
      A dict mapping layer to the traversal index in the DFS where it is
      seen. Note: if a layer is shared by several nodes, the dict will only
      store the index corresponding to the *first* time the layer seen.
  )rk   r   r9   _build_map_helper)r%   finished_nodesnodes_in_progressr   r   ri   r(   r(   r)   r     s    r   c       	      C   s   | j \}}}|j| }||kr"dS ||krHtdt|  d |j d ||kr\t|||< || |jsx|jD ]} t	| |||| qtW || |
| || dS )z"Recursive helper for `_build_map`.NzThe tensor z at layer "z" is part of a cycle.)r/   r   rt   r   r   r8   rn   r   r   r   removerK   )	r1   r   r   r   r   rX   rY   r]   r
   r(   r(   r)   r     s"    



r   c             C   s@   t  st| t| |\}}}}tdd | D |fS )zReturns the nodes and layers in the topology from `inputs` to `outputs`.

  Args:
    inputs: List of input tensors.
    outputs: List of output tensors.

  Returns:
    A tuple of List{Node] and List[Layer].
  c             S   s   g | ]}|qS r(   r(   )r,   r[   r(   r(   r)   rd   9  s    z)_map_subgraph_network.<locals>.<listcomp>)r   rA   r   rB   rM   r   r9   r@   )r$   r%   r]   r\   rW   r(   r(   r)   r   +  s    

r   c             C   s0   | j r"t| to t| j d tjS t| tS dS )zCReturns True if the first layer node should not be saved or loaded.r   N)rP   r6   r   input_layer_module
InputLayer)rX   r(   r(   r)   _should_skip_first_node<  s
    

r   c                sB    fdd|  D }|r>tdd |  D } ||  S )z?Adds layers that are not connected to the outputs to the model.c                s   g | ]}| j kr|qS r(   )rW   )r,   rX   )r   r(   r)   rd   N  s    z,connect_ancillary_layers.<locals>.<listcomp>c             S   s(   g | ] }t |r|jd d n|jqS )r*   N)r   r   )r,   rX   r(   r(   r)   rd   R  s   )r@   r   r9   r   )r   r   Zancillary_layersr   r(   )r   r)   r   J  s    r   c                s  p
t  i i i fddfddfdd  fdd}fd	d
}x| d D ]}|| qnW xLrxB| d D ]6}|d  }|krx|D ]}||| qW qW qW g }g }	tj| d dd}
x`t|
D ]R}| \}}}|kst| }||}|j	| j
}|t||  qW tj| d dd}xbt|D ]T}| \}}}|kst| }||}|j	| j
}|	t||  qfW t|
|}t||	}	||	fS )aq  Reconstructs graph from config object.

  Args:
    config: Dictionary returned from Network.get_config()
    custom_objects: Optional dictionary mapping names (strings) to custom
      classes or functions to be considered during deserialization.
    created_layers: Optional dictionary mapping names to Layer objects. Any
      layer not in this dictionary will be created and added to the dict.
      This function will add new nodes to all layers (excluding InputLayers),
      instead of re-using pre-existing nodes in the layers.

  Returns:
    Tuple of (input tensors, output tensors, dictionary of created layers)
  c                s&   |  kr|g | < n |   | d S )N)rK   )rX   	node_data)r   r(   r)   add_unprocessed_nodey  s    z5reconstruct_from_config.<locals>.add_unprocessed_nodec                s"   t | tjrdS  | j|fdS )zBReturns node index in layer (might differ from config_node_index).r   N)r6   r   r   rl   r   )rX   Zconfig_node_index)node_index_mapr(   r)   get_node_index  s    z/reconstruct_from_config.<locals>.get_node_indexc                s(    fdd}t j| dd} t|| S )z-Deserializes Keras Tensors passed to `call`..c                sh   t | tjrd|  } | d }| d }| d }| } ||}|dkrJt|j| }t|j| S | S )z4Deserializes a single Keras Tensor passed to `call`.r   r*      N)	r6   r   ListWrapperas_list
IndexErrorr   r   r9   r%   )r-   r   rY   rZ   rX   new_node_indexr
   )r   	layer_mapr(   r)   _deserialize_keras_tensor  s    
	
z^reconstruct_from_config.<locals>._deserialize_keras_tensors.<locals>._deserialize_keras_tensorT)wrap)r   convert_inner_node_datar   rD   )r&   r  r  )r   )r  r)   _deserialize_keras_tensors  s    z;reconstruct_from_config.<locals>._deserialize_keras_tensorsc          	      s`  g }xt |D ]}| }|d }|d }|d }t|dkrFi }nLt|dkr|d }y |}W q tk
r   | | dS X ntd|tjkr| }||}|dkrĈ| | dS |j| }	|	t |	j
|  q|	| qW t ||}|dk	r\| jst|}| |f|}
t |
d jj}|| j|  f< |   d7  < dS )zDeserialize a node.

    Args:
        layer: layer instance.
        node_data: Nested structure of `ListWrapper`.

    Raises:
        ValueError: In case of improperly formatted `node_data`.
    r   r*   r         Nz"Improperly formatted model config.)r   r9   r   r8   r  rt   node_moduleZ_CONSTANT_VALUEr   rK   r%   r   Z#_preserve_input_structure_in_configr   Zunnest_if_single_tensorr/   rY   r   )rX   r   r   Z
input_dataZinbound_layer_nameZinbound_node_indexZinbound_tensor_indexr&   Zinbound_layerr   r   Zoutput_index)r  r   r   r   node_count_by_layerr   r(   r)   process_node  sD    







z-reconstruct_from_config.<locals>.process_nodec                s|   | d }|kr| }n ddl m} || d}||< tt||< | d }tj|dd}x|D ]} || qfW dS )	zDeserializes a layer, then call it on appropriate inputs.

    Args:
        layer_data: layer config dict.

    Raises:
        ValueError: In case of improperly formatted `layer_data` dict.
    r   r   )deserialize)r   r   T)r  N)Ztensorflow.python.keras.layersr  intr   r   r  )
layer_datar   rX   Zdeserialize_layerZinbound_nodes_datar   )r   r   r   r  r(   r)   process_layer  s    	


z.reconstruct_from_config.<locals>.process_layerrW   r   input_layersT)r  output_layers)rp   rq   r   r   r  r   r9   r   rL   r   r   rK   r   )r   r   r   r  r  r  rX   r   r   r   r  r   rY   rZ   Zlayer_output_tensorsr  r(   )r  r   r   r   r   r  r   r   r)   r   Z  sP    8"

r   c          	   C   sT  |pt j}d| ji}i }x\| jD ]R}t|r0dnd}x<t|jD ].\}}t|j|}|| jkr@|||< |d7 }q@W q W g }	t 	  x| jD ]v}g }
xHt|jD ]:\}}t|j|}|| jkr|j
s|t|}|
| qW ||}|j|d< |
|d< |	| qW |	|d< W dQ R X g }xdtt| jD ]R}| j| \}}}t|j|}|| jkr\q,|| }|t|j||g q,W t| j|}t|s|g}t|}||d< g }xdtt| jD ]R}| j| \}}}t|j|}|| jkrq|| }|t|j||g qW t| j|}t|s>|g}t|}||d< |S )	zBuilds the config, which consists of the node graph and serialized layers.

  Args:
    network: A Network object.
    serialize_layer_fn: Function used to serialize layers.

  Returns:
    Config dictionary.
  r   r*   r   r   rW   Nr  r  )r   Zserialize_keras_objectr   rW   r   rr   r   r   rN   ZSharedObjectSavingScoper   	serializerK   r   r8   rG   rI   r   r   r   r   r:   r+   r  rH   rJ   r;   )networkZserialize_layer_fnr   Znode_conversion_maprX   Z
kept_nodesZoriginal_node_indexr
   r   Zlayer_configsZfiltered_inbound_nodesr   Zlayer_configZmodel_inputsr   rY   rZ   r  Zmodel_outputsr(   r(   r)   r   &  sj    






r   c             C   s*   | j jd krd S | j  }|r&d |d< |S )Nr   )r2   r   r   )r3   r2   r(   r(   r)   rc   s  s    
rc   c                   s*   e Zd ZdZd fdd	Zdd Z  ZS )ModuleWrapperzFWrapper for `tf.Module`s to support the Functional and Sequential API.Nc                s   t t| jf | |dkr8t|dr*d}nt|dr8d}|dksJt||sZtd|||| _|| _t||}t	
|}d|jkp|jdk	| _d|jkp|jdk	| _dS )a  Initializes the wrapper Layer for this module.

    Args:
      module: The `tf.Module` instance to be wrapped.
      method_name: (Optional) str. The name of the method to use as the forward
        pass of the module. If not set, defaults to '__call__' if defined, or
        'call'.
      **kwargs: Additional keywrod arguments. See `tf.keras.layers.Layer`.

    Raises:
      ValueError: If `method` is not defined on `module`.
    N__call__rR   z{} is not defined on object {}r   r   )r    r  r!   r0   rt   rm   _module_method_namer   r   rQ   r   varkwrE   rF   )r#   modulemethod_namer&   methodZmethod_arg_spec)r'   r(   r)   r!     s"    






zModuleWrapper.__init__c             O   sD   d|kr| j s|d d|kr0| js0|d t| j| j||S )Nr   r   )rE   r   rF   r   r  r  )r#   r   r&   r(   r(   r)   rR     s
    

zModuleWrapper.call)N)r   r   r   r   r!   rR   r   r(   r(   )r'   r)   r  |  s   "r  )NN)N)8r   rp   r   r   r   Ztensorflow.python.eagerr   Ztensorflow.python.frameworkr   r   Ztensorflow.python.kerasr   Ztensorflow.python.keras.enginer   r   r   r   r	   r
   r
  r   r   r   Z*tensorflow.python.keras.saving.saved_modelr   Ztensorflow.python.keras.utilsr   r   r   Ztensorflow.python.opsr   r   Ztensorflow.python.platformr   r   Ztensorflow.python.trackabler   r~   Ztensorflow.python.utilr   Ztensorflow.tools.docsr   r   r   r   rM   r   r   r   r   r   r   r   rc   ZLayerr  r(   r(   r(   r)   <module>   sX         Fz
 M
M	