o
    i e,                     @   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   sz    d| fV  |  d dr9|  d d}|  d dD ]}t|D ]\}}|r0d||f n|}||fV  q$qdS 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layersub_name_scopesublayer r   S/var/www/myenv/lib/python3.10/site-packages/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u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)maybe_layersr   r   r   _norm_to_list_of_layersd   s   r   c                    sf  | d}| dstdt| | d | d}| d}| d}t|o)|}	t|}
|
rN|	rNt||D ]\}}t |}t| |d }|||< q8n1|
r^|	s^t| |d d d }n!|
s|r|	rt|d	ksrJ d
t| |d }t |}|||< |	r|rt|} fdd|D }|| < n| 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lenr   )r   model_layerinput_to_in_layermodel_name_to_outputprev_node_namelayer_configr   r   r   is_functional_modelis_parent_functional_modelinput_layerinbound_nodeinput_layer_nameinbound_node_namer   layer_names
last_layerlast_layer_nameoutput_noder   r   r   _update_dictsx   sP   











r4   c                 C   s  i }i }t  }d}t| D ]\}}t|r!t|||||\}}}q|d}t||d}|j }	||	_|ddurK|d	d}
|
|	j
d _|d}|durht|tsht|d}|j|	j
d _|ddur|dD ]/}t|}|D ]&\}}}}t||}|||g}|t|k r|| n|d	 }|	j| q|qtn
|dur|	j| ||v r|	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asciikeras_classdtyper   r    )r   r
   r   r4   r	   r   nodeaddr   encodeattrsr   dictr   as_dtypeas_datatype_enumtyper   r$   inputappend)r   input_to_layerr'   gr(   r   r   r)   r   node_defkeras_cls_namedtype_or_policytf_dtypemaybe_inbound_noder   r   sizeindex_inbound_nameinbound_node_names
input_namer   r   r   keras_model_to_graph_def   sh   




rQ   N)__doc__"tensorboard.compat.proto.graph_pb2r   "tensorboard.compat.tensorflow_stubr   r
   r   r   r   r4   rQ   r   r   r   r   <module>   s   I