U
    Vc(                     @   sP   d Z ddlmZ ddlmZ dd Zdd Zdd	 Zd
d Zdd Z	dd Z
dS )aJ  Utilities for handling Keras model in graph plugin.

Two canonical types of Keras model are Functional and Sequential.
A model can be serialized as JSON and deserialized to reconstruct a model.
This utility helps with dealing with the serialized Keras model.

They have distinct structures to the configurations in shapes below:
Functional:
  config
    name: Name of the model. If not specified, it is 'model' with
          an optional suffix if there are more than one instance.
    input_layers: Keras.layers.Inputs in the model.
    output_layers: Layer names that are outputs of the model.
    layers: list of layer configurations.
      layer: [*]
        inbound_nodes: inputs to this layer.

Sequential:
  config
    name: Name of the model. If not specified, it is 'sequential' with
          an optional suffix if there are more than one instance.
    layers: list of layer configurations.
      layer: [*]

[*]: Note that a model can be a layer.
Please refer to https://github.com/tensorflow/tfjs-layers/blob/master/src/keras_format/model_serialization.ts
for more complete definition.
    )GraphDef)dtypesc                 c   st   d| fV  |  d drp|  d d}|  d dD ]4}t|D ]&\}}|r^d||f n|}||fV  qFq:dS )aY  Walks the nested keras layer configuration in preorder.

    Args:
      keras_layer: Keras configuration from model.to_json.

    Yields:
      A tuple of (name_scope, layer_config).
      name_scope: a string representing a scope name, similar to that of tf.name_scope.
      layer_config: a dict representing a Keras layer configuration.
     configlayersname%s/%sN)get_walk_layers)keras_layer
name_scopelayerZsub_name_scopeZsublayer r   H/tmp/pip-unpacked-wheel-g8kmtpbc/tensorboard/plugins/graph/keras_util.pyr
   0   s    
r
   c                 C   s   | rd| |f S |S )a/  Returns scoped name for a node as a string in the form '<scope>/<node
    name>'.

    Args:
      name_scope: a string representing a scope name, similar to that of tf.name_scope.
      node_name: a string representing the current node name.

    Returns
      A string representing a scoped name.
    r   r   )r   	node_namer   r   r   _scoped_nameH   s    r   c                 C   s   |  d ddk	S )zReturns True if layer is a model.

    Args:
      layer: a dict representing a Keras model configuration.

    Returns:
      bool: True if layer is a model.
    r   r   N)r	   )r   r   r   r   	_is_modelX   s    	r   c                 C   s   t | d tfr| S | gS )a  Normalizes to a list of layers.

    Args:
      maybe_layers: A list of data[1] or a list of list of data.

    Returns:
      List of list of data.

    [1]: A Functional model has fields 'inbound_nodes' and 'output_layers' which can
    look like below:
    - ['in_layer_name', 0, 0]
    - [['in_layer_is_model', 1, 0], ['in_layer_is_model', 1, 1]]
    The data inside the list seems to describe [name, size, index].
    r   )
isinstancelist)Zmaybe_layersr   r   r   _norm_to_list_of_layersd   s    r   c                    sj  | d}| dstdt| | d | d}| d}| d}t|oR|}	t|}
|
r|	rt||D ](\}}t |}t| |d }|||< qpnb|
r|	st| |d d d }nB|
s|r|	rt|d	kstd
t| |d }t |}|||< |	r.|r.t|} fdd|D }|| < n2| dd }| d d}t |}|g| < |||fS )a  Updates input_to_in_layer, model_name_to_output, and prev_node_name
    based on the model_layer.

    Args:
      name_scope: a string representing a scope name, similar to that of tf.name_scope.
      model_layer: a dict representing a Keras model configuration.
      input_to_in_layer: a dict mapping Keras.layers.Input to inbound layer.
      model_name_to_output: a dict mapping Keras Model name to output layer of the model.
      prev_node_name: a string representing a previous, in sequential model layout,
                      node name.

    Returns:
      A tuple of (input_to_in_layer, model_name_to_output, prev_node_name).
      input_to_in_layer: a dict mapping Keras.layers.Input to inbound layer.
      model_name_to_output: a dict mapping Keras Model name to output layer of the model.
      prev_node_name: a string representing a previous, in sequential model layout,
                      node name.
    r   r   zlayer is not a model.r   input_layersoutput_layersinbound_nodesr      zhCannot have multi-input Functional model when parent model is not Functional. Number of input layers: %dc                    s   g | ]}t  |d  qS )r   )r   ).0r   r   r   r   
<listcomp>   s     z!_update_dicts.<locals>.<listcomp>)r	   
ValueErrorr   boolziplenAssertionErrorr   )r   Zmodel_layerZinput_to_in_layermodel_name_to_outputprev_node_namelayer_configr   r   r   Zis_functional_modelZis_parent_functional_modelZinput_layerZinbound_nodeZinput_layer_nameZinbound_node_namer   Zlayer_namesZ
last_layerZlast_layer_nameZoutput_noder   r   r   _update_dictsx   sN    









r&   c                 C   st  i }i }t  }d}t| D ]R\}}t|rDt|||||\}}}q|d}t||d}|j }	||	_|ddk	r|d	d}
|
|	j
d _|d}|dk	rt|tst|d}|j|	j
d _|ddk	r6|dD ]F}t|}|D ]4\}}}}t||}|||g}|	j||  qqn|dk	rL|	j| ||krh|	j|| |	j}q|S )	a  Returns a GraphDef representation of the Keras model in a dict form.

    Note that it only supports models that implemented to_json().

    Args:
      keras_layer: A dict from Keras model.to_json().

    Returns:
      A GraphDef representation of the layers in the model.
    Nr   r   
class_nameasciiZkeras_classZdtyper   )r   r
   r   r&   r	   r   nodeaddr   encodeattrsr   dictr   Zas_dtypeZas_datatype_enumtyper   inputappend)r   Zinput_to_layerr#   gr$   r   r   r%   r   Znode_defZkeras_cls_nameZdtype_or_policyZtf_dtypeZmaybe_inbound_noder   r   sizeindex_Zinbound_nameZinbound_node_namesr   r   r   keras_model_to_graph_def   s`    



 
 

r6   N)__doc__Z"tensorboard.compat.proto.graph_pb2r   Z"tensorboard.compat.tensorflow_stubr   r
   r   r   r   r&   r6   r   r   r   r   <module>   s   I