o
    i e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.
  _compile_metricsNc                 S   s   i | ]}|j |qS  )name).0mr   r   Z/var/www/myenv/lib/python3.10/site-packages/tensorflow/python/keras/saving/saving_utils.py
<dictcomp>2   s    z)extract_model_metrics.<locals>.<dictcomp>)getattr_compile_metric_functionsmodelr   r   r   extract_model_metrics"   s   r   Fc                 C   sF   | j | d}|du rdS t|}t|tjjr t|dkr |S |g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.
  )dynamic_batchN   )_get_save_spec_enforce_names_consistency
isinstancecollectionsabcSequencelen)r   keep_original_batch_sizeinput_specsr   r   r   model_input_signature6   s   r$   c                 C   s   t d| )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formatr   r   r   r   raise_model_input_errorY   s   r'   c                    s\    du rt jtjrjj  du rt  du 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   n1 s+w   Y  j}|du rBddlm} ||}t	
|}d	d
 t||D S )z<A concrete tf.function that wraps the model's call function.r   r   FT)inputsbuild_graphtrainingsaving)r+   N)compile_utilsc                 S   s   i | ]\}}||qS r   r   )r   r   outputr   r   r   r          z<trace_model_call.<locals>._wrapped_model.<locals>.<dictcomp>)r!   listr   call_contextenteroutput_namestensorflow.python.keras.enginer-   create_pseudo_output_namesr   flattenzip)argsr)   outputsr3   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   trace_model_calla   s   
r?   Tc           
   
   C   s  ddl m} ddlm} d| jji}z|  |d< W n ty0 } z
|r&|W Y d}~nd}~ww tt	|t
 |d}| jr|rt| jtjrOtd |S | jr| jd	d
}|dd t||d< t| j|jrotd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)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.)rB   rC   optimizer_config)tensorflow.python.kerasr@   $tensorflow.python.keras.optimizer_v2rA   	__class____name__
get_configNotImplementedErrordictstrKr   rG   r   r   TFOptimizerloggingwarning_compile_was_called_get_compile_argspop_serialize_nested_configRestoredOptimizerr   get_registered_name)
r   include_optimizerrequire_configrD   rA   rE   emetadatarH   rI   r   r   r   model_metadata   sF   
r`   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   rf   c                 C   s   |du ri }t |T | d }t|}d}| dd}|dur'ttj|}d}| dd}|dur8tt|}d}| dd}	|	durItt|	}t| drR| d nd}
| d }W d   n1 sbw   Y  t	||||||
dS )	z4Return model.compile arguments from training config.NrI   lossmetricsweighted_metricssample_weight_modeloss_weights)rG   rg   rh   ri   rk   rj   )
r   CustomObjectScoper   deserializeget_deserialize_nested_configr   _deserialize_metrichasattrrP   )rH   custom_objectsrI   rG   rg   loss_configrh   metrics_configri   weighted_metrics_configrj   rk   r   r   r   !compile_args_from_training_config   sD   


rv   c                    sl   dd }|du r
dS ||r |S t |tr" fdd| D S t |ttfr2 fdd|D S td)	z=Deserializes arbitrary Keras `config` using `deserialize_fn`.c                 S   s(   t | trd| v rdS t | trdS dS )NrB   TF)r   rP   rQ   objr   r   r   _is_single_object   s
   
z5_deserialize_nested_config.<locals>._is_single_objectNc                    s   i | ]
\}}|t  |qS r   ro   )r   kvdeserialize_fnr   r   r      s    
z._deserialize_nested_config.<locals>.<dictcomp>c                    s   g | ]}t  |qS r   rz   )r   rx   r}   r   r   
<listcomp>  r/   z._deserialize_nested_config.<locals>.<listcomp>z#Saved configuration not understood.)r   rP   itemstupler0   r%   )r~   rC   ry   r   r}   r   ro      s   

ro   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   serialize_keras_objectrw   r   r   r   _serialize_fn  s   
z/_serialize_nested_config.<locals>._serialize_fn)r   map_structure)rC   r   r   r   r   rY   
  s   rY   c                 C   s"   ddl m} | dv r| S || S )z7Deserialize metrics, leaving special strings untouched.r   )rh   )accuracyacccrossentropyce)rJ   rh   rm   )metric_configmetrics_moduler   r   r   rp     s   
rp   c                    s\   dd  dd }t | }t fdd|D o#t fdd|D  }|r,t || } | S )z5Enforces that either all specs have names or none do.c                 S   s   t | do	| jd uS Nr   )rq   r   specr   r   r   	_has_name"  s   z-_enforce_names_consistency.<locals>._has_namec                 S   s   t | } t| drd | _| S r   )copydeepcopyrq   _namer   r   r   r   _clear_name%  s   

z/_enforce_names_consistency.<locals>._clear_namec                 3       | ]} |V  qd S r   r   r   sr   r   r   	<genexpr>-      z-_enforce_names_consistency.<locals>.<genexpr>c                 3   r   r   r   r   r   r   r   r   .  r   )r   r6   anyallr   )specsr   
flat_specsname_inconsistencyr   r   r   r     s   
r   c                 C   sp   t | s4| jd ur6z| jjs| j| j | jjs&| j| j| j W d S W d S    td Y d S d S 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	   is_v1_layer_or_modelr9   compiled_lossbuiltbuildcompiled_metricsrT   rU   r   r   r   r   try_build_compiled_arguments5  s   


r   c                 C   s   |  dp|  dp|  dS )Nz.h5z.kerasz.hdf5)endswith)rd   r   r   r   is_hdf5_filepathD  s   r   )Fr   )TT)%__doc__r   r   ra   tensorflow.python.eagerr   rJ   r   rR   r   r   r   r4   r   tensorflow.python.keras.utilsr   r	   &tensorflow.python.keras.utils.io_utilsr
   tensorflow.python.platformr   rT   tensorflow.python.utilr   r   r$   r'   r?   r`   rf   rv   ro   rY   rp   r   r   r   r   r   r   r   <module>   s8   
#

.1
)
