B
    ӻd1                 @   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 ddlm	Z	 ddlm
Z
 ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ dd Zd*ddZdd Zd+ddZd,ddZdd Zd-ddZdd Zd d! Z d"d# Z!d$d% Z"d&d' Z#d(d) Z$dS ).z$Utils related to keras model saving.    N)def_function)backend)losses)optimizer_v1)
optimizers)base_layer_utils)generic_utils)version_utils)ask_to_proceed_with_overwrite)
tf_logging)nestc             C   s    t | ddrdd | jD S dS )aB  Convert metrics from a Keras model `compile` API to dictionary.

  This is used for converting Keras models to Estimators and SavedModels.

  Args:
    model: A `tf.keras.Model` object.

  Returns:
    Dictionary mapping metric names to metric instances. May return `None` if
    the model does not contain any metrics.
  Z_compile_metricsNc             S   s   i | ]}||j qS  )name).0mr   r   ]/var/www/html/venv/lib/python3.7/site-packages/tensorflow/python/keras/saving/saving_utils.py
<dictcomp>2   s    z)extract_model_metrics.<locals>.<dictcomp>)getattrZ_compile_metric_functions)modelr   r   r   extract_model_metrics"   s    r   Fc             C   sJ   | j | d}|dkrdS t|}t|tjjr@t|dkr@|S |gS dS )aM  Inspect model to get its input signature.

  The model's input signature is a list with a single (possibly-nested) object.
  This is due to the Keras-enforced restriction that tensor inputs must be
  passed in as the first argument.

  For example, a model with input {'feature1': <Tensor>, 'feature2': <Tensor>}
  will have input signature: [{'feature1': TensorSpec, 'feature2': TensorSpec}]

  Args:
    model: Keras Model object.
    keep_original_batch_size: A boolean indicating whether we want to keep using
      the original batch size or set it to None. Default is `False`, which means
      that the batch dim of the returned input signature will always be set to
      `None`.

  Returns:
    A list containing either a single TensorSpec or an object with nested
    TensorSpecs. This list does not contain the `training` argument.
  )Zdynamic_batchN   )Z_get_save_spec_enforce_names_consistency
isinstancecollectionsabcSequencelen)r   Zkeep_original_batch_sizeZinput_specsr   r   r   model_input_signature6   s    r   c             C   s   t d| d S )NzModel {} cannot be saved because the input shapes have not been set. Usually, input shapes are automatically determined from calling `.fit()` or `.predict()`. To manually set the shapes, call `model.build(input_shape)`.)
ValueErrorformat)r   r   r   r   raise_model_input_errorY   s    r    c                s\    dkrt jtjrjj  dkr.t  dkr>t tj d fdd}|S )a  Trace the model call to create a tf.function for exporting a Keras model.

  Args:
    model: A Keras model.
    input_signature: optional, a list of tf.TensorSpec objects specifying the
      inputs to the model.

  Returns:
    A tf.function wrapping the model's call function with input signatures set.

  Raises:
    ValueError: if input signature cannot be inferred from the model.
  N)input_signaturec           	      s   t  dkr| d nt| }t j|dddd |dd}W dQ R X j}|dkrpddlm} ||}t	
|}d	d
 t||D S )z<A concrete tf.function that wraps the model's call function.r   r   FT)inputsZbuild_graphtrainingZsaving)r#   N)compile_utilsc             S   s   i | ]\}}||qS r   r   )r   r   outputr   r   r   r      s    z<trace_model_call.<locals>._wrapped_model.<locals>.<dictcomp>)r   listr   Zcall_contextZenteroutput_namestensorflow.python.keras.enginer$   Zcreate_pseudo_output_namesr   flattenzip)argsr"   outputsr'   r$   )r!   r   r   r   _wrapped_modely   s    

z(trace_model_call.<locals>._wrapped_model)r   callr   Functionr!   r   r    function)r   r!   r-   r   )r!   r   r   trace_model_calla   s    r1   Tc       
   
   C   s  ddl m} ddlm} d| jji}y|  |d< W n* tk
r^ } z|rN|W dd}~X Y nX tt	|t
 |d}| jr|rt| jtjrtd nj| jr| jd	d
}|dd t||d< t| j|jrtdnt| jj| j d}	|	|d d< |S )z3Returns a dictionary containing the model metadata.r   )__version__)optimizer_v2
class_nameconfigN)keras_versionr   model_configa<  TensorFlow optimizers do not make it possible to access optimizer attributes or optimizer state after instantiation. As a result, we cannot save the optimizer as part of the model save file. You will have to compile your model again after loading it. Prefer using a Keras optimizer instead (see keras.io/optimizers).F)Zuser_metrics	optimizertraining_configzAs of now, Optimizers loaded from SavedModel cannot be saved. If you're calling `model.save` or `tf.keras.models.save_model`, please set the `include_optimizer` option to `False`. For `tf.saved_model.save`, delete the optimizer from the model.)r4   r5   optimizer_config)tensorflow.python.kerasr2   Z$tensorflow.python.keras.optimizer_v2r3   	__class____name__Z
get_configNotImplementedErrordictstrKr   r8   r   r   ZTFOptimizerloggingwarningZ_compile_was_calledZ_get_compile_argspop_serialize_nested_configZRestoredOptimizerr   Zget_registered_name)
r   Zinclude_optimizerZrequire_configr6   r3   r7   emetadatar9   r:   r   r   r   model_metadata   s6    	rH   c             C   s   |st j| rt| S dS )z3Returns whether the filepath should be overwritten.T)ospathisfiler
   )filepath	overwriter   r   r   should_overwrite   s    rN   c          	   C   s   |dkri }t | | d }t|}d}| dd}|dk	rNttj|}d}| dd}|dk	rptt|}d}| dd}	|	dk	rtt|	}t| dr| d nd}
| d }W dQ R X t	||||||
dS )	z4Return model.compile arguments from training config.Nr:   lossmetricsweighted_metricssample_weight_modeloss_weights)r8   rO   rP   rQ   rS   rR   )
r   ZCustomObjectScoper   deserializeget_deserialize_nested_configr   _deserialize_metrichasattrr?   )r9   Zcustom_objectsr:   r8   rO   Zloss_configrP   Zmetrics_configrQ   Zweighted_metrics_configrR   rS   r   r   r   !compile_args_from_training_config   s8    

rY   c                sp   dd }|dkrdS ||r$ |S t |trD fdd| D S t |ttfrd fdd|D S tddS )	z=Deserializes arbitrary Keras `config` using `deserialize_fn`.c             S   s(   t | trd| krdS t | tr$dS dS )Nr4   TF)r   r?   r@   )objr   r   r   _is_single_object   s
    
z5_deserialize_nested_config.<locals>._is_single_objectNc                s   i | ]\}}t  ||qS r   )rV   )r   kv)deserialize_fnr   r   r      s   z._deserialize_nested_config.<locals>.<dictcomp>c                s   g | ]}t  |qS r   )rV   )r   rZ   )r^   r   r   
<listcomp>  s    z._deserialize_nested_config.<locals>.<listcomp>z#Saved configuration not understood.)r   r?   itemstupler&   r   )r^   r5   r[   r   )r^   r   rV      s    

rV   c             C   s   dd }t || S )z/Serialized a nested structure of Keras objects.c             S   s   t | rt| S | S )N)callabler   Zserialize_keras_object)rZ   r   r   r   _serialize_fn  s    
z/_serialize_nested_config.<locals>._serialize_fn)r   map_structure)r5   rc   r   r   r   rE   
  s    rE   c             C   s"   ddl m} | dkr| S || S )z7Deserialize metrics, leaving special strings untouched.r   )rP   )ZaccuracyaccZcrossentropyZce)r;   rP   rT   )Zmetric_configZmetrics_moduler   r   r   rW     s    rW   c                s\   dd  dd }t | }t fdd|D oFt fdd|D  }|rXt || } | S )z5Enforces that either all specs have names or none do.c             S   s   t | do| jd k	S )Nr   )rX   r   )specr   r   r   	_has_name"  s    z-_enforce_names_consistency.<locals>._has_namec             S   s   t | } t| drd | _| S )Nr   )copydeepcopyrX   _name)rf   r   r   r   _clear_name%  s    

z/_enforce_names_consistency.<locals>._clear_namec             3   s   | ]} |V  qd S )Nr   )r   s)rg   r   r   	<genexpr>-  s    z-_enforce_names_consistency.<locals>.<genexpr>c             3   s   | ]} |V  qd S )Nr   )r   rl   )rg   r   r   rm   .  s    )r   r)   anyallrd   )specsrk   Z
flat_specsZname_inconsistencyr   )rg   r   r     s    
r   c             C   sd   t | s`| jd k	r`y4| jjs,| j| j | jjsF| j| j| j W n   td Y nX d S )NzCompiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.)	r	   Zis_v1_layer_or_modelr,   Zcompiled_lossZbuiltbuildZcompiled_metricsrB   rC   )r   r   r   r   try_build_compiled_arguments5  s    

rr   c             C   s   |  dp|  dp|  dS )Nz.h5z.kerasz.hdf5)endswith)rL   r   r   r   is_hdf5_filepathD  s    rt   )F)N)TT)N)%__doc__r   rh   rI   Ztensorflow.python.eagerr   r;   r   rA   r   r   r   r(   r   Ztensorflow.python.keras.utilsr   r	   Z&tensorflow.python.keras.utils.io_utilsr
   Ztensorflow.python.platformr   rB   Ztensorflow.python.utilr   r   r   r    r1   rH   rN   rY   rV   rE   rW   r   rr   rt   r   r   r   r   <module>   s6   
#
.
1
)
