o
    ?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   j/home/www/facesmatcher.com/pyenv/lib/python3.10/site-packages/tensorflow/python/keras/utils/layer_utils.py	<genexpr>;   s    z$get_source_inputs.<locals>.<genexpr>)hasattrr   _inbound_nodesZis_inputr   flattenZinput_tensorsiterate_inboundget_source_inputsallappend)Ztensorlayer
node_index_nodeZsource_tensorsZ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)Z
input_dataZallowable_stringsZ
layer_nameZarg_name
allow_noneZallow_callablesZ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   Zw_ir   r   r
   r%   b   s    z+count_params.<locals>.<listcomp>.<listcomp>r   r   r   r   r
   r%   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)weightsZunique_weightsZweight_shapesZ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} qC||7 }q |rc| j
D ]}d}	|jD ]}
|
|v r]|	r[d} q^d}	qO|sb qcqH|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).
  NZ
SequentialT   r   FA   )g?g333333?      ?c                       g | ]}t  | qS r   r+   r(   line_lengthr   r
   r%          z!print_summary.<locals>.<listcomp>)Layer (type)Output ShapeParam #b   )gQ?g?gq=
ףp?r1   c                    r3   r   r4   r(   r5   r   r
   r%      r7   )r8   r9   r:   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   r2    )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__Zbuiltgetattrr.   )r   rK   rN   cls_nameparamsr?   )r@   rD   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.
    rF   z
{}[{}][{}]r   r   rI   rJ   r/   N)rK   rL   r   r   r   formatrN   rO   rP   r.   r>   r=   )r   rK   connectionsr   Zinbound_layerr   Ztensor_indexr   rN   rR   Zfirst_connectionr?   rB   )r@   rD   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: {:,})printrO   rP   rH   Z_nodes_by_depthr*   r>   r   r   Zkeras_inputslayersr   rU   rN   r=   r   r.   rY   Ztrainable_weightsZnon_trainable_weights)modelr6   r@   rC   Zsequential_likeZnodes_by_depthnodesvr   flagr   
to_displayrT   rX   r[   rB   Ztrainable_countZnon_trainable_countr   )r6   r@   rC   rD   rW   r
   print_summaryg   s   







$

ra   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.
  >   Zchannels_lastrb   r/   rb   N)   r   r/   )r/   rc   r   )Zget_weightsr=   r#   Zreshaper&   Z	transposer'   Zset_weights)ZdenseZprevious_feature_map_shapeZtarget_data_formatZkernelZbiasrB   chr    Zoriginal_fm_shapeZkir   r   r
   !convert_dense_weights_data_format  s   



"rf   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)rQ   rg   Z_keras_api_names_v1)r   r   r   r
   is_builtin_layer6  s
   
rh   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wrapsrm   )rn   ro   r   rl   r
   cached_per_instance@  s
   Rrt   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.Nr2   Z	_is_layerr[   )	setpopr   addr   r   typerQ   extend)Z
layer_listexistingZto_visitobjZ
sub_layersr   r   r
   filter_empty_layer_containers  s   r|   )NN)FF)NNN)rb   )__doc__rr   rp   numpyr&   Ztensorflow.python.utilr   r   r   r.   ra   rf   rh   rt   r|   r   r   r   r
   <module>   s"   
*

 +
'
_