
    BVh=9                     j    d Z ddlZddlZddlZddlmZ ddZ	 	 ddZd Z	ddZ
	 ddZd	 Zd
 Zd Zy)z/Utilities related to layer/model functionality.    N)nestc                    t        | d      s| S ||r| j                  \  }}}|j                  s| gS |j                  |   }|j                  rt	        j
                  |j                        S g }|j                         D ]A  \  }}}} t        | ||      }|D ](  t        fd|D              s|j                         * C |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_historyc              3   &   K   | ]  }|u 
 y wN ).0txs     Y/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/keras/utils/layer_utils.py	<genexpr>z$get_source_inputs.<locals>.<genexpr>;   s     4!4s   )hasattrr   _inbound_nodesis_inputr   flatteninput_tensorsiterate_inboundget_source_inputsallappend)tensorlayer
node_index_nodesource_tensorsprevious_sourcesr   s          @r   r   r      s     
)	*M
]j!00E:q			8O
+D}}\\$,,--n*.*>*>*@ %
&%Q,VUJG! 	%A4^44!!!$	%%     c                     |r| y|rt        |       ryt        | t              r| |v ry|rdnd}||rdndz  }|d|z  }t        d|d|d| d	|d
	      )z0Validates the correctness of a string-based arg.Nz`None`,  za `Callable`, z or one of the following values: zThe z argument of layer z received an invalid value z. Allowed values are: .)callable
isinstancestr
ValueError)
input_dataallowable_strings
layer_namearg_name
allow_noneallow_callablesallowed_argss          r   validate_string_argr-   @   su     J&
8J/
*c"z5F'F
!+:L$R?L<MOOL

JF G Gr   c                 F   | D ci c]  }t        |      | c}j                         }|D cg c]  }|j                  j                          }}|D cg c]  }|D cg c]  }|dn|
 c} }}}t	        t        d |D                    S c c}w c c}w c c}w c c}}w )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
  r   c              3   F   K   | ]  }t        j                  |        y wr   )npprod)r	   ps     r   r   zcount_params.<locals>.<genexpr>d   s     @@s   !)idvaluesshapeas_listintsum)weightswunique_weightsweight_shapesw_istandardized_weight_shapess         r   count_paramsr?   V   s     '..BqE1H.557..<=177??$=-=8E 34A.SCKqS .    
S@%?@@	AA /=. s"   B!B	BB+BBc                    t         | j                  j                  dk(  rd}n| j                  sd}nd}| j                  j                         }g }|D ]U  }t        |      dkD  s<t        |      dk(  r2t        t        j                  |d   j                              dkD  rd} n||z  }W |r5| j                  D ]&  }d}	|j                  D ]  }
|
|v s|	rd} nd}	 |r& n |r7|xs d}xs g dd	   dk  rD cg c]  }t        ||z         c}g d
}n\|xs d}xs g dd	   dk  rD cg c]  }t        ||z         c}g d}g | j                  j                         D ]  }|z  	 fd dj                  | j                                d|z          |        d|z         fd}fd}| j                  }t        t        |            D ]C  }|r |||          n |||          |t        |      dz
  k(  r d|z         9 d|z         E t!        | d      rt#        | j$                        }nt#        | j&                        }t#        | j(                        } dj                  ||z                 dj                  |              dj                  |              d|z         yc c}w c c}w )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?      ?)Layer (type)Output ShapeParam #b   )gQ?g?gq=
ףp?rD   )rF   rG   rH   zConnected toc                     d}t        t        |             D ]?  }|dkD  r|d d dz   }|t        | |         z  }|d ||    }|d||   t        |      z
  z  z  }A  |       y )Nr    r   rE    )rangelenr$   )fields	positionslineiprint_fns       r   	print_rowz print_summary.<locals>.print_row   s}    D3v; /	
QCRy3
c&)nd-9Q< d
cYq\CI-..d/ TNr   zModel: "{}"r   =c                 $   	 | j                   }| j                  }| j                  j
                  }| j                  st        | dd      sd}n| j                         }|dz   |z   dz   ||g} |       y# t        $ r d}Y st        $ r d}Y w xY w)	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paramsrN   rO   rS   s         r   print_layer_summaryz*print_summary.<locals>.print_layer_summary   s    ''l
 ::D''H;;wu.A5I f!!#fTkH$s*L&AFfi    l ls   A5 5B
BBc           	         	 | j                   }g }| j                  D ]O  }r|vr
|j                         D ]3  \  }}}}|j	                  dj                  |j                  ||             5 Q | j                  }| j                  j                  }	|sd}
n|d   }
|dz   |	z   dz   || j                         |
g} |       t        |      dkD  r-t        dt        |            D ]  }ddd||   g} |        yy# t        $ r d}Y w xY w)	zuPrints a summary for a single layer (including topological connections).

    Args:
        layer: target layer.
    rV   z
{}[{}][{}]r    r   rY   rZ   rB   N)r[   r\   r   r   r   formatr^   r_   r`   r?   rM   rL   )r   r[   connectionsr   inbound_layerr   tensor_indexr   r^   rc   first_connectionrN   rQ   rO   rS   relevant_nodess                r   $print_layer_summary_with_connectionsz;print_summary.<locals>.print_layer_summary_with_connections   sF    ''l K$$ >	D68<8L8L8N >
4-\1<..}/A/A:/;= 	>>> ::D''H$Qth$l.F fi 
;!QK() %!b"k!n-&)$% /   l s   C= =D
D_collected_trainable_weightszTotal params: {:,}zTrainable params: {:,}zNon-trainable params: {:,})printr_   r`   rX   _nodes_by_depthr4   rM   r   r   keras_inputslayersr   r7   rg   r^   rL   r   r?   rn   trainable_weightsnon_trainable_weights)modelline_lengthrO   rR   sequential_likenodes_by_depthnodesvr   flagr   r2   
to_displayre   rm   rr   rQ   trainable_countnon_trainable_countrS   rl   s     ``               @@r   print_summaryr   g   s     H
__-O"" OO**113NE 
a&1*#a&A+dll1Q4+<+<=>B  qje << 
%(( 	DU] %od	 

 #K+^I}1:;A3{Q';i<J#K00I}1:;A3{Q';iLJN""))+ n =

+,
3J	"
3!."%H <<&V "a&)$*6!95CK!Os[ !s[ !" U23"5#E#EFO"5#:#:;O$U%@%@A
&&9L'LMN
#**?;<
'../BCD
3[ < <s   K:Kc                    |dv sJ | j                         \  }}t        |j                  d         D ]  }|dk(  r:|\  }}}|||f}	|dd|f   j                  |	      }
t	        j
                  |
d      }
n9|\  }}}|||f}	|dd|f   j                  |	      }
t	        j
                  |
d      }
t	        j                  |
t	        j                  |      f      |dd|f<    | j                  ||g       y)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_lastchannels_firstrB   r   N)   r   rB   )rB   r   r   )get_weightsrL   r5   reshaper0   	transposer1   set_weights)denseprevious_feature_map_shapetarget_data_formatkernelbiasrQ   chr:   original_fm_shapekis              r   !convert_dense_weights_data_formatr     s   , 
B	BB	B""$,&$a! Ja--*gaAa)!Q$< 12b<<I&b*gaAa)!Q$< 12b<<I&b::b277+E#F"HIF1a4LJ VTN#r   c                 ^    t        | dd       sy| j                  dk7  xr | j                  dk7  S )N_keras_api_namesF)zkeras.layers.Layer)rb   r   _keras_api_names_v1)r   s    r   is_builtin_layerr   6  s=    	*D	1 
 
 $;
; ?

#
#'>
>@r   c                 |     t        j                         t        j                          f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                 H    j                  |       }| |       x| <   }|S r   )get)itemoutputcachefs     r   wrappedz$cached_per_instance.<locals>.wrapped  s,    YYt_F~tW$eDkFMr   )weakrefWeakKeyDictionary	functoolswrapsr   )r   r   r   s   ` @r   cached_per_instancer   @  s=    d 
#
#
%%??1  '-	.r   c              #   >  K   t               }| ddd   }|r|j                         }t        |      |v r |j                  t        |             t	        |d      rt        |t              s| n(t        |dd      xs g }|j                  |ddd          |ryyw)z4Filter out empty Layer-like containers and uniquify.NrE   	_is_layerrr   )	setpopr3   addr   r#   typerb   extend)
layer_listexistingto_visitobj
sub_layerss        r   filter_empty_layer_containersr     s      U("(
,,.C	#w(LLCsK C)>i3$/52j ooj2&' 	s   BBB)NN)FF)NNN)r   )__doc__r   r   numpyr0   tensorflow.python.utilr   r   r-   r?   r   r   r   r   r   r   r   r   <module>r      sU     6    '#T $)(-G,B"eT :J$$N@\~(r   