B
    ӻd9                 @   s   d Z ddlZddlZddlZddlmZ ddlmZ ed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)nest)keras_exportzkeras.utils.get_source_inputsc                s   t | ds| S |dks|r&| j\}}}|js2| gS |j| }|jrNt|jS g }xR| D ]F\}}}} t| ||}x,|D ]$ t	 fdd|D rz|
  qzW q\W |S d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   | ]} |k	V  qd S )N ).0t)xr   [/var/www/html/venv/lib/python3.7/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   sx   |r| dkrdS |r t | r dS t| tr6| |kr6dS |r>dnd}||rLdnd7 }|d|f 7 }td||| |f dS )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_argB   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>a   s    z count_params.<locals>.<dictcomp>c             S   s   g | ]}|j  qS r   )shapeas_list)r   r   r   r   r	   
<listcomp>b   s    z count_params.<locals>.<listcomp>c             S   s   g | ]}d d |D qS )c             S   s   g | ]}|d krdn|qS )Nr   r   )r   Zw_ir   r   r	   r"   d   s    z+count_params.<locals>.<listcomp>.<listcomp>r   )r   r   r   r   r	   r"   d   s    c             s   s   | ]}t |V  qd S )N)npprod)r   pr   r   r	   r
   f   s    zcount_params.<locals>.<genexpr>)valuesintsum)weightsZunique_weightsZweight_shapesZstandardized_weight_shapesr   r   r	   count_paramsX   s    	r*   c                s  dkrt | jjdkrd}n| js*d}nd}| j }g }xJ|D ]B}t|dksvt|dkr|tt|d j	dkr|d}P ||7 }qBW |rx@| j
D ]6}d}	x&|jD ]}
|
|kr|	rd}P qd}	qW |sP qW |r pd pdd	d
gd dkr
 fddD dddg}nj pd p0dddd
gd dkrR fddD ddddg}g x| j D ]}|7 qnW fddd| j d   | d   fdd}fdd}| j
}xbtt|D ]R}|r|||  n|||  |t|d kr4d   nd   qW t| 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?g      ?c                s   g | ]}t  | qS r   )r'   )r   r%   )line_lengthr   r	   r"      s    z!print_summary.<locals>.<listcomp>zLayer (type)zOutput ShapezParam #b   gQ?g?gq=
ףp?c                s   g | ]}t  | qS r   )r'   )r   r%   )r.   r   r	   r"      s    zConnected toc                sv   d}xdt t| D ]T}|dkr.|d d d }|t| | 7 }|d ||  }|d|| t|  7 }qW  | d S )Nr   r   r-    )rangelenr   )fields	positionslinei)print_fnr   r	   	print_row   s    z print_summary.<locals>.print_rowzModel: "{}"r   =c                s   y
| j }W n. tk
r"   d}Y n tk
r8   d}Y nX | 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)z ()N)	output_shapeAttributeErrorRuntimeErrorname	__class____name__Zbuiltgetattrr*   )r   r>   rA   cls_nameparamsr3   )r4   r8   r   r	   print_layer_summary   s    

z*print_summary.<locals>.print_layer_summaryc          	      s   y
| j }W n tk
r"   d}Y nX g }xL| jD ]B}rB|krBq0x.| D ]"\}}}}|d|j|| qLW q0W | j}| jj}	|sd}
n|d }
|d |	 d || 	 |
g}|  t
|dkrx0tdt
|D ]}ddd|| g}|  qW dS )	zuPrints a summary for a single layer (including topological connections).

    Args:
        layer: target layer.
    r:   z
{}[{}][{}]r   r   z (r=   r+   N)r>   r?   r   r   r   formatrA   rB   rC   r*   r2   r1   )r   r>   connectionsr   Zinbound_layerr   Ztensor_indexr   rA   rE   Zfirst_connectionr3   r6   )r4   r8   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: {:,})printrB   rC   r<   Z_nodes_by_depthr&   r2   r   r   Zkeras_inputslayersr   rH   rA   r1   r   r*   rL   Ztrainable_weightsZnon_trainable_weights)modelr.   r4   r7   Zsequential_likeZnodes_by_depthZnodesvr   flagr   
to_displayrG   rK   rN   r6   Ztrainable_countZnon_trainable_countr   )r.   r4   r7   r8   rJ   r	   print_summaryi   s~    




$

rS   channels_firstc             C   s   |dkst |  \}}xt|jd D ]}|dkrl|\}}}|||f}	|dd|f |	}
t|
d}
n6|\}}}|||f}	|dd|f |	}
t|
d}
t|
t|f|dd|f< q(W | ||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.
  >   rT   channels_lastr+   rT   N)   r   r+   )r+   rV   r   )	AssertionErrorZget_weightsr1   r    Zreshaper#   Z	transposer$   Zset_weights)ZdenseZprevious_feature_map_shapeZtarget_data_formatZkernelZbiasr6   chr   Zoriginal_fm_shapeZkir   r   r	   !convert_dense_weights_data_format  s    



$rZ   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)rD   r[   Z_keras_api_names_v1)r   r   r   r	   is_builtin_layer8  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 kr"|   | < }|S )N)get)itemoutput)cachefr   r	   wrapped  s    
z$cached_per_instance.<locals>.wrapped)weakrefWeakKeyDictionary	functoolswrapsr`   )ra   rb   r   )r`   ra   r	   cached_per_instanceB  s    Rrg   c             c   s   t  }| ddd }xl|r| }t||kr0q|t| t|drZt|tsZ|V  qt|ddphg }||ddd  qW dS )z4Filter out empty Layer-like containers and uniquify.Nr-   Z	_is_layerrN   )	setpopr   addr   r   typerD   extend)Z
layer_listexistingZto_visitobjZ
sub_layersr   r   r	   filter_empty_layer_containers  s    ro   )NN)FF)NNN)rT   )__doc__re   rc   numpyr#   Ztensorflow.python.utilr   Z tensorflow.python.util.tf_exportr   r   r   r*   rS   rZ   r\   rg   ro   r   r   r   r	   <module>   s    * 

 +
%
_