o
    i e=9                     @   sz   d Z ddlZddlZddlZddlmZ dddZ		dddZd	d
 Z	dddZ
	dddZdd Zdd Zdd ZdS )z/Utilities related to layer/model functionality.    N)nestc                    s   t | ds| S |du s|r| j\}}}|js| gS |j| }|jr't|jS g }| D ]!\}}}} t| ||}|D ] t	 fdd|D rM|
  q;q-|S )a  Returns the list of input tensors necessary to compute `tensor`.

  Output will always be a list of tensors
  (potentially with 1 element).

  Args:
      tensor: The tensor to start from.
      layer: Origin layer of the tensor. Will be
          determined via tensor._keras_history if not provided.
      node_index: Origin node index of the tensor.

  Returns:
      List of input tensors.
  _keras_historyNc                 3   s    | ]} |uV  qd S N ).0txr   X/var/www/myenv/lib/python3.10/site-packages/tensorflow/python/keras/utils/layer_utils.py	<genexpr>;   s    z$get_source_inputs.<locals>.<genexpr>)hasattrr   _inbound_nodesis_inputr   flatteninput_tensorsiterate_inboundget_source_inputsallappend)tensorlayer
node_index_nodesource_tensorsprevious_sourcesr   r   r
   r      s$   


r   Fc                 C   st   |r| du rdS |rt | rdS t| tr| |v rdS |rdnd}||r&dnd7 }|d|f 7 }td||| |f )z0Validates the correctness of a string-based arg.Nz`None`,  za `Callable`, z"or one of the following values: %szQThe %s argument of layer %s received an invalid value %s. Allowed values are: %s.)callable
isinstancestr
ValueError)
input_dataallowable_strings
layer_namearg_name
allow_noneallow_callablesallowed_argsr   r   r
   validate_string_arg@   s   
r(   c                 C   sD   dd | D   }dd |D }dd |D }ttdd |D S )zCount the total number of scalars composing the weights.

  Args:
      weights: An iterable containing the weights on which to compute params

  Returns:
      The total number of scalars composing the weights
  c                 S   s   i | ]}t ||qS r   )idr   wr   r   r
   
<dictcomp>_       z count_params.<locals>.<dictcomp>c                 S   s   g | ]}|j  qS r   )shapeas_listr*   r   r   r
   
<listcomp>`   r-   z count_params.<locals>.<listcomp>c                 S   s   g | ]	}d d |D qS )c                 S   s   g | ]
}|d u r
dn|qS )Nr   r   )r   w_ir   r   r
   r0   b   s    z+count_params.<locals>.<listcomp>.<listcomp>r   r*   r   r   r
   r0   a   s    c                 s   s    | ]}t |V  qd S r   )npprodr   pr   r   r
   r   d   s    zcount_params.<locals>.<genexpr>)valuesintsum)weightsunique_weightsweight_shapesstandardized_weight_shapesr   r   r
   count_paramsV   s   	r=   c                    s  du rt | jjdkrd}nT| jsd}nNd}| j }g }|D ]"}t|dks:t|dkr>tt|d j	dkr>d} n||7 }q |rc| j
D ]}d}	|jD ]}
|
|v r]|	r[d} nd}	qO|sb nqH|r phd png dd	 dkr~ fd
dD g d}n+ pd pg dd	 dkr fddD g d}g | j D ]}|7 qfddd| j d   | d   fdd}fdd}| j
}tt|D ]'}|r|||  n|||  |t|d krd   qd   qt| drt| j}nt| j}t| j}d||  d| d| d   dS )aZ  Prints a summary of a model.

  Args:
      model: Keras model instance.
      line_length: Total length of printed lines
          (e.g. set this to adapt the display to different
          terminal window sizes).
      positions: Relative or absolute positions of log elements in each line.
          If not provided, defaults to `[.33, .55, .67, 1.]`.
      print_fn: Print function to use.
          It will be called on each line of the summary.
          You can set it to a custom function
          in order to capture the string summary.
          It defaults to `print` (prints to stdout).
  N
SequentialT   r   FA   )g?g333333?      ?c                       g | ]}t  | qS r   r7   r4   line_lengthr   r
   r0          z!print_summary.<locals>.<listcomp>)Layer (type)Output ShapeParam #b   )gQ?g?gq=
ףp?rA   c                    rC   r   rD   r4   rE   r   r
   r0      rG   )rH   rI   rJ   zConnected toc                    sr   d}t t| D ]*}|dkr|d d d }|t| | 7 }|d ||  }|d|| t|  7 }q | d S )Nr   r   rB    )rangelenr   )fields	positionslinei)print_fnr   r
   	print_row   s   z print_summary.<locals>.print_rowzModel: "{}"r   =c                    s   z| j }W n ty   d}Y n ty   d}Y nw | j}| jj}| js.t| dds.d}n|  }|d | d ||g}|  dS )	zQPrints a summary for a single layer.

    Args:
        layer: target layer.
    multiple?_is_graph_networkFz
0 (unused) ()N)	output_shapeAttributeErrorRuntimeErrorname	__class____name__builtgetattrr=   )r   r[   r^   cls_nameparamsrO   )rP   rT   r   r
   print_layer_summary   s   
z*print_summary.<locals>.print_layer_summaryc              	      s   z| j }W n ty   d}Y nw g }| jD ]}r|vrq| D ]\}}}}|d|j|| q#q| j}| jj}	|sBd}
n|d }
|d |	 d || 	 |
g}|  t
|dkrvtdt
|D ]}ddd|| g}|  qfdS dS )	zuPrints a summary for a single layer (including topological connections).

    Args:
        layer: target layer.
    rV   z
{}[{}][{}]r   r   rY   rZ   r?   N)r[   r\   r   r   r   formatr^   r_   r`   r=   rN   rM   )r   r[   connectionsr   inbound_layerr   tensor_indexr   r^   rc   first_connectionrO   rR   )rP   rT   relevant_nodesr   r
   $print_layer_summary_with_connections   s:   


z;print_summary.<locals>.print_layer_summary_with_connections_collected_trainable_weightszTotal params: {:,}zTrainable params: {:,}zNon-trainable params: {:,})printr_   r`   rX   _nodes_by_depthr6   rN   r   r   keras_inputslayersr   rf   r^   rM   r   r=   rm   trainable_weightsnon_trainable_weights)modelrF   rP   rS   sequential_likenodes_by_depthnodesvr   flagr   
to_displayre   rl   rq   rR   trainable_countnon_trainable_countr   )rF   rP   rS   rT   rk   r
   print_summaryg   s   







$

r}   channels_firstc                 C   s   |dv sJ |   \}}t|jd D ]M}|dkr5|\}}}|||f}	|dd|f |	}
t|
d}
n|\}}}|||f}	|dd|f |	}
t|
d}
t|
t|f|dd|f< q| ||g dS )a=  Utility useful when changing a convnet's `data_format`.

  When porting the weights of a convnet from one data format to the other,
  if the convnet includes a `Flatten` layer
  (applied to the last convolutional feature map)
  followed by a `Dense` layer, the weights of that `Dense` layer
  should be updated to reflect the new dimension ordering.

  Args:
      dense: The target `Dense` layer.
      previous_feature_map_shape: A shape tuple of 3 integers,
          e.g. `(512, 7, 7)`. The shape of the convolutional
          feature map right before the `Flatten` layer that
          came before the target `Dense` layer.
      target_data_format: One of "channels_last", "channels_first".
          Set it "channels_last"
          if converting a "channels_first" model to "channels_last",
          or reciprocally.
  >   channels_lastr~   r?   r~   N)   r   r?   )r?   r   r   )get_weightsrM   r.   reshaper2   	transposer3   set_weights)denseprevious_feature_map_shapetarget_data_formatkernelbiasrR   chr+   original_fm_shapekir   r   r
   !convert_dense_weights_data_format  s   



"r   c                 C   s$   t | dd sdS | jdko| jdkS )N_keras_api_namesF)zkeras.layers.Layer)rb   r   _keras_api_names_v1)r   r   r   r
   is_builtin_layer6  s
   
r   c                    s*   t   t fdd} |_|S )a'
  Lightweight decorator for caching lazily constructed properties.

  When to use:
  This decorator provides simple caching with minimal overhead. It is designed
  for properties which are expensive to compute and static over the life of a
  class instance, and provides no mechanism for cache invalidation. Thus it is
  best suited for lazily exposing derived properties of other static data.

  For classes with custom getattr / setattr behavior (such as trackable
  objects), storing cache results as object attributes is not performant.
  Instead, a specialized cache can significantly reduce property lookup
  overhead. (While still allowing the decorated property to be lazily computed.)
  Consider the following class:

  ```
  class MyClass(object):
    def __setattr__(self, key, value):
      # Some expensive class specific code
      # ...
      # ...

      super(MyClass, self).__setattr__(key, value)

    @property
    def thing(self):
      # `thing` is expensive to compute (and may not even be requested), so we
      # want to lazily compute it and then cache it.
      output = getattr(self, '_thing', None)
      if output is None:
        self._thing = output = compute_thing(self)
      return output
  ```

  It's also worth noting that ANY overriding of __setattr__, even something as
  simple as:
  ```
    def __setattr__(self, key, value):
      super(MyClass, self).__setattr__(key, value)
  ```

  Slows down attribute assignment by nearly 10x.

  By contrast, replacing the definition of `thing` with the following sidesteps
  the expensive __setattr__ altogether:

  '''
  @property
  @tracking.cached_per_instance
  def thing(self):
    # `thing` is expensive to compute (and may not even be requested), so we
    # want to lazily compute it and then cache it.
    return compute_thing(self)
  '''

  Performance:
  The overhead for this decorator is ~0.4 us / call. A much lower overhead
  implementation (~0.085 us / call) can be achieved by using a custom dict type:

  ```
  def dict_based_cache(f):
    class Cache(dict):
      __slots__ = ()
      def __missing__(self, key):
        self[key] = output = f(key)
        return output

    return property(Cache().__getitem__)
  ```

  However, that implementation holds class instances as keys, and as a result
  blocks garbage collection. (And modifying it to use weakref's as keys raises
  the lookup overhead to ~0.4 us) As a result, the WeakKeyDictionary
  implementation below turns out to be more prudent.

  Args:
    f: The function to cache.

  Returns:
    f decorated with simple caching behavior.
  c                    s&     | }|d u r|   | < }|S r   )get)itemoutputcachefr   r
   wrapped  s   
z$cached_per_instance.<locals>.wrapped)weakrefWeakKeyDictionary	functoolswrapsr   )r   r   r   r   r
   cached_per_instance@  s
   Rr   c                 c   s    t  }| ddd }|rC| }t||v rq|t| t|dr-t|ts-|V  nt|ddp4g }||ddd  |sdS dS )z4Filter out empty Layer-like containers and uniquify.NrB   	_is_layerrq   )	setpopr)   addr   r   typerb   extend)
layer_listexistingto_visitobj
sub_layersr   r   r
   filter_empty_layer_containers  s   r   )NN)FF)NNN)r~   )__doc__r   r   numpyr2   tensorflow.python.utilr   r   r(   r=   r}   r   r   r   r   r   r   r   r
   <module>   s"   
*

 +
'
_