a
    Sic                    @   s  d Z ddlZddlZddlZddlZddlZddlZddlZddl	m
  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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/m0Z0 ddl/m1Z1 ddl/m2Z2 ddl/m3Z3 ddl/m4Z4 ddl/m5Z5 ddl6m7Z7 ddl8m9Z9 ddl:m;Z< dd l=m>Z> dd!l?m@Z@ zddlAZAW n eBy   dZAY n0 e>d"d#G d$d% d%ejCe5jDZEdKd'd(ZFdLd)d*ZGd+d, ZHd-d. ZId/d0 ZJd1d2 ZKd3d4 ZLd5d6 ZMd7d8 ZNd9d: ZOd;d< ZPd=d> ZQd?d@ ZRdAdB ZSdCdD ZTdEdF ZUdGdH ZVdIdJ ZWdS )Mz*Training-related part of the Keras engine.    N)backend)	callbacks)
optimizers)
layout_map)
base_layer)base_layer_utils)compile_utils)data_adapter)input_layer)training_utils)loss_scale_optimizer)optimizer_v1)	optimizer)hdf5_format)pickle_utils)save)saving_utils)
saving_lib)
json_utils)model_serialization)generic_utils)io_utils)layer_utils)tf_utils)traceback_utils)version_utils)ModeKeys)context)
tf_logging)keras_export)doc_controlszkeras.Modelzkeras.models.Modelc                       s  e Zd ZdZeedejj	Z	dZ
 fddZejjjej fddZejjjdd	 Z fd
dZ fddZ fddZdd Zej fddZej fddZejdddZejdddZdd Z ejjjdd Z!ejjjd d! Z"e#d"d# Z$e#d$d% Z%e#d&d' Z&e#d(d) Z'e#d*d+ Z(e(j)d,d+ Z(d-d. Z*d/d0 Z+dd1d2Z,d3d4 Z-dd5d6Z.ejdd=d>Z/d?d@ Z0ddAdBZ1ejddCdDZ2dEdF Z3ddGdHZ4ejddIdJZ5dKdL Z6ddMdNZ7ddOdPZ8dQdR Z9ej:ddSdTZ;ej:ddUdVZ<ej:ddWdXZ=e#dYdZ Z>e#d[d\ Z? fd]d^Z@ejdd_d`ZAejddadbZBejddcddZCdedf ZDdgdh ZEeFddidjZGdkdl ZHdmdn ZIdodp ZJe#ej:dqdr ZKe#dsdt ZLe#dudv ZMddwdxZNe#dydz ZOeOj)d{dz ZOdd|d}ZPd~d ZQejjjd fdd	ZRdddZSdd ZTdd ZUdd ZVdd ZWdd ZXdd ZYdd ZZdddZ[e#dd Z\d fdd	Z]dd Z^dddZ_dd Z`dd Zae#dd Zbdd Zc  ZdS )ModelaY  `Model` groups layers into an object with training and inference features.

    Args:
        inputs: The input(s) of the model: a `keras.Input` object or list of
            `keras.Input` objects.
        outputs: The output(s) of the model. See Functional API example below.
        name: String, the name of the model.

    There are two ways to instantiate a `Model`:

    1 - With the "Functional API", where you start from `Input`,
    you chain layer calls to specify the model's forward pass,
    and finally you create your model from inputs and outputs:

    ```python
    import tensorflow as tf

    inputs = tf.keras.Input(shape=(3,))
    x = tf.keras.layers.Dense(4, activation=tf.nn.relu)(inputs)
    outputs = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x)
    model = tf.keras.Model(inputs=inputs, outputs=outputs)
    ```

    Note: Only dicts, lists, and tuples of input tensors are supported. Nested
    inputs are not supported (e.g. lists of list or dicts of dict).

    A new Functional API model can also be created by using the
    intermediate tensors. This enables you to quickly extract sub-components
    of the model.

    Example:

    ```python
    inputs = keras.Input(shape=(None, None, 3))
    processed = keras.layers.RandomCrop(width=32, height=32)(inputs)
    conv = keras.layers.Conv2D(filters=2, kernel_size=3)(processed)
    pooling = keras.layers.GlobalAveragePooling2D()(conv)
    feature = keras.layers.Dense(10)(pooling)

    full_model = keras.Model(inputs, feature)
    backbone = keras.Model(processed, conv)
    activations = keras.Model(conv, feature)
    ```

    Note that the `backbone` and `activations` models are not
    created with `keras.Input` objects, but with the tensors that are originated
    from `keras.Input` objects. Under the hood, the layers and weights will
    be shared across these models, so that user can train the `full_model`, and
    use `backbone` or `activations` to do feature extraction.
    The inputs and outputs of the model can be nested structures of tensors as
    well, and the created models are standard Functional API models that support
    all the existing APIs.

    2 - By subclassing the `Model` class: in that case, you should define your
    layers in `__init__()` and you should implement the model's forward pass
    in `call()`.

    ```python
    import tensorflow as tf

    class MyModel(tf.keras.Model):

      def __init__(self):
        super().__init__()
        self.dense1 = tf.keras.layers.Dense(4, activation=tf.nn.relu)
        self.dense2 = tf.keras.layers.Dense(5, activation=tf.nn.softmax)

      def call(self, inputs):
        x = self.dense1(inputs)
        return self.dense2(x)

    model = MyModel()
    ```

    If you subclass `Model`, you can optionally have
    a `training` argument (boolean) in `call()`, which you can use to specify
    a different behavior in training and inference:

    ```python
    import tensorflow as tf

    class MyModel(tf.keras.Model):

      def __init__(self):
        super().__init__()
        self.dense1 = tf.keras.layers.Dense(4, activation=tf.nn.relu)
        self.dense2 = tf.keras.layers.Dense(5, activation=tf.nn.softmax)
        self.dropout = tf.keras.layers.Dropout(0.5)

      def call(self, inputs, training=False):
        x = self.dense1(inputs)
        if training:
          x = self.dropout(x, training=training)
        return self.dense2(x)

    model = MyModel()
    ```

    Once the model is created, you can config the model with losses and metrics
    with `model.compile()`, train the model with `model.fit()`, or use the model
    to do prediction with `model.predict()`.
    )_train_counter_test_counter_predict_counter_steps_per_executionFc                    sT   t ||r2| tkr2ddlm} |j|ddi|S tt| j| g|R i |S d S )Nr   
functional	skip_initT)is_functional_model_init_paramsr!   keras.enginer'   
Functionalsuper__new__)clsargskwargsr'   	__class__ Q/var/www/html/django/DPS/env/lib/python3.9/site-packages/keras/engine/training.pyr-      s    zModel.__new__c           	         s  d| _ tjdd ddlm} t| rt| |j	sg d fdd D } fdd D }t
| j |j	j| g|R i | g }d	}| jjD ]$}t||j	rd}q|r|| q|r|D ]}|j| g|R i | qn|rtd
|d S tjdd t h d t jf i   d	| _d | _d | _d | _d | _d	| _d | _d | _d | _d	| _| dd	 | dd  t j!" rt j!# | _$nd | _$d | _%d | _&| '  d | _(d | _)d | _*t j+j,t-.| d| _/d | _0| 1  d| _2d | _3t45 | _6d S )NTmodelr   r&   )inputsoutputsname	trainabler(   c                    s   i | ]}|v r| | qS r3   r3   .0kr0   supported_kwargsr3   r4   
<dictcomp>   s   z"Model.__init__.<locals>.<dictcomp>c                    s   i | ]}|vr| | qS r3   r3   r:   r=   r3   r4   r?      s   FzGThe following keyword arguments passed to `Model` aren't supported: {}.zModel subclass>   autocastr6   r7   dtyper9   r8   dynamic_is_compiledr   )root)7_is_model_for_instrumentationr   keras_api_gaugeget_cellsetr*   r'   r)   
isinstancer+   inject_functional_model_classr2   __init__	__bases__
issubclassappend	TypeErrorformatr   validate_kwargsr,   _is_graph_networkr6   r7   input_namesoutput_namesstop_traininghistorycompiled_losscompiled_metrics _compute_output_and_mask_jointly_maybe_create_attributetf
distributehas_strategyget_strategy_distribution_strategy_cluster_coordinator_run_eagerly_reset_compile_cache_training_state_saved_model_inputs_spec_saved_model_arg_spectrain
Checkpointweakrefref_checkpointr%   _init_batch_counters_base_model_initialized_jit_compilelayout_map_libget_current_layout_map_layout_map)	selfr/   r0   r'   model_kwargsother_kwargsclz_to_initfound_functional_classclzr1   r=   r4   rK      s    
zModel.__init__c                 C   sB   t jj}t jdd|d| _t jdd|d| _t jdd|d| _d S )Nr   int64rA   aggregation)r[   VariableAggregationONLY_FIRST_REPLICAVariabler"   r#   r$   )rq   aggr3   r3   r4   rk   I  s    zModel._init_batch_countersc                    sp   t | ddst || d S tdd tj|D r^z
| j W n ty\   t	dY n0 t || d S )N_self_setattr_trackingTc                 s   s*   | ]"}t |tjtjfp t|V  qd S N)rI   r   Layerr[   r|   r   has_weights)r;   vr3   r3   r4   	<genexpr>W  s   z$Model.__setattr__.<locals>.<genexpr>zsIt looks like you are subclassing `Model` and you forgot to call `super().__init__()`. Always start with this line.)
getattrr,   __setattr__allr[   nestflattenrl   AttributeErrorRuntimeError)rq   r8   valuer1   r3   r4   r   R  s    


zModel.__setattr__c                    s$   | j rtjt| fS t  S d S r   )builtr   deserialize_model_from_bytecodeserialize_model_as_bytecoder,   
__reduce__rq   r1   r3   r4   r   g  s
    zModel.__reduce__c                    sl   | j r$tjt|  }||t| < nDt  ^}}}|| }||t| < |rhtj|d |d}|	| |S )Nr   )memo)
r   r   r   r   idr,   r   copydeepcopy__setstate__)rq   r   newdeserializer
serializedreststater1   r3   r4   __deepcopy__w  s    
zModel.__deepcopy__c                 C   s
   |  i S r   )r   r   r3   r3   r4   __copy__  s    zModel.__copy__c           
         s  | j rt | dS |du r&tdtttjtf}t	||sPtd
t||r| jst rttjd}nt }| V t	|trtdd |D rt|}t	|trdd |D }n(t	|trd	d
 | D }n
t|}i }| jj}|j}t|dkrb|jr,|dt|j  }n|dd }|D ]"}|dkrTd|d< ntdq<nt|dk rxtdz| j|fi | W n> tjjtfy }	 ztd|	 dW Y d}	~	n
d}	~	0 0 W d   n1 s0    Y  t | dS )a  Builds the model based on input shapes received.

        This is to be used for subclassed models, which do not know at
        instantiation time what their inputs look like.

        This method only exists for users who want to call `model.build()` in a
        standalone way (as a substitute for calling the model on real data to
        build it). It will never be called by the framework (and thus it will
        never throw unexpected errors in an unrelated workflow).

        Args:
         input_shape: Single tuple, `TensorShape` instance, or list/dict of
           shapes, where shapes are tuples, integers, or `TensorShape`
           instances.

        Raises:
          ValueError:
            1. In case of invalid user-provided data (not of type tuple,
               list, `TensorShape`, or dict).
            2. If the model requires call arguments that are agnostic
               to the input shapes (positional or keyword arg in call
               signature).
            3. If not all layers were properly built.
            4. If float type inputs are not supported within the layers.

          In each of these cases, the user should build their model by calling
          it on real tensor data.
        NzIInput shape must be defined when calling `build()` on a `Model` subclass.zSpecified input shape is not one of the valid types. Please specify a batch input shape of type tuple or list of input shapes. User provided input type: {}.build_graphc                 s   s    | ]}|d u pt |tV  qd S r   )rI   int)r;   dr3   r3   r4   r     s   zModel.build.<locals>.<genexpr>c                 S   s   g | ]}t |qS r3   r    generate_placeholders_from_shape)r;   shaper3   r3   r4   
<listcomp>  s   zModel.build.<locals>.<listcomp>c                 S   s   i | ]\}}|t |qS r3   r   )r;   r<   r   r3   r3   r4   r?     s   zModel.build.<locals>.<dictcomp>   trainingFaq  Currently, you cannot build your model if it has positional or keyword arguments that are not inputs to the model, but are required for its `call()` method. Instead, in order to instantiate and build your model, `call()` your model on real tensor data with all expected call arguments. The argument for `call()` can be a single list/tuple that contains multiple inputs.z[You can only call `build()` on a model if its `call()` method accepts an `inputs` argument.zYou cannot build your model by calling `build` if your layers do not support float type inputs. Instead, in order to instantiate and build your model, call your model on real tensor data (of the correct dtype).

The actual error from `call` is: .) rR   r,   build
ValueErrortuplelistr[   TensorShapedictrI   rP   typer6   executing_eagerly__internal__	FuncGraphr   	get_graph
as_defaultr   itemsr   r   
_call_specfull_argspecr/   lendefaultscallerrorsInvalidArgumentErrorrO   )
rq   input_shapevalid_typesgraphxr0   call_signature	call_argsarger1   r3   r4   r     sx    





:zModel.buildc                    s   | j d ur| jst|}t|}| j||\}}}dd }tj||}tj||}tj||}t	| j * t
 j|g|R i | W d    n1 s0    Y  t| | j  t
 j|i |S )Nc                 S   s0   t | tjtjttfr,t| } t	| j
S d S r   )rI   r[   Tensornpndarrayfloatr   convert_to_tensorinput_layer_moduleInputr   r   r3   r3   r4   _convert_to_graph_inputs  s    
z0Model.__call__.<locals>._convert_to_graph_inputs)rp   r   r   r   split_out_first_argr[   r   map_structurern   layout_map_scoper,   __call___map_subclass_model_variable)rq   r/   r0   Zcopied_argsZcopied_kwargsr6   r   r1   r3   r4   r   	  s(    

8zModel.__call__Nc                 C   s   t ddS )ae  Calls the model on new inputs and returns the outputs as tensors.

        In this case `call()` just reapplies
        all ops in the graph to the new inputs
        (e.g. build a new computational graph from the provided inputs).

        Note: This method should not be called directly. It is only meant to be
        overridden when subclassing `tf.keras.Model`.
        To call a model on an input, always use the `__call__()` method,
        i.e. `model(inputs)`, which relies on the underlying `call()` method.

        Args:
            inputs: Input tensor, or dict/list/tuple of input tensors.
            training: Boolean or boolean scalar tensor, indicating whether to
              run the `Network` in training mode or inference mode.
            mask: A mask or list of masks. A mask can be either a boolean tensor
              or None (no mask). For more details, check the guide
              [here](https://www.tensorflow.org/guide/keras/masking_and_padding).

        Returns:
            A tensor if there is a single output, or
            a list of tensors if there are more than one outputs.
        zUnimplemented `tf.keras.Model.call()`: if you intend to create a `Model` with the Functional API, please provide `inputs` and `outputs` arguments. Otherwise, subclass `Model` with an overridden `call()` method.N)NotImplementedError)rq   r6   r   maskr3   r3   r4   r   /  s    z
Model.callrmspropc	                 K   s  t jdd | j  d|	v r>td |s>|	d}|	dd}
| j	||fi |	 || _
| || _t|tjr|| _ntj||| jd| _tj||| j|
d| _| |pd	 |   d| _|pi | _| j
s| jr|rtd
n|| _W d   n1 s
0    Y  dS )aZ  Configures the model for training.

        Example:

        ```python
        model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),
                      loss=tf.keras.losses.BinaryCrossentropy(),
                      metrics=[tf.keras.metrics.BinaryAccuracy(),
                               tf.keras.metrics.FalseNegatives()])
        ```

        Args:
            optimizer: String (name of optimizer) or optimizer instance. See
              `tf.keras.optimizers`.
            loss: Loss function. May be a string (name of loss function), or
              a `tf.keras.losses.Loss` instance. See `tf.keras.losses`. A loss
              function is any callable with the signature `loss = fn(y_true,
              y_pred)`, where `y_true` are the ground truth values, and
              `y_pred` are the model's predictions.
              `y_true` should have shape
              `(batch_size, d0, .. dN)` (except in the case of
              sparse loss functions such as
              sparse categorical crossentropy which expects integer arrays of
              shape `(batch_size, d0, .. dN-1)`).
              `y_pred` should have shape `(batch_size, d0, .. dN)`.
              The loss function should return a float tensor.
              If a custom `Loss` instance is
              used and reduction is set to `None`, return value has shape
              `(batch_size, d0, .. dN-1)` i.e. per-sample or per-timestep loss
              values; otherwise, it is a scalar. If the model has multiple
              outputs, you can use a different loss on each output by passing a
              dictionary or a list of losses. The loss value that will be
              minimized by the model will then be the sum of all individual
              losses, unless `loss_weights` is specified.
            metrics: List of metrics to be evaluated by the model during
              training and testing. Each of this can be a string (name of a
              built-in function), function or a `tf.keras.metrics.Metric`
              instance. See `tf.keras.metrics`. Typically you will use
              `metrics=['accuracy']`.
              A function is any callable with the signature `result = fn(y_true,
              y_pred)`. To specify different metrics for different outputs of a
              multi-output model, you could also pass a dictionary, such as
              `metrics={'output_a':'accuracy', 'output_b':['accuracy', 'mse']}`.
              You can also pass a list to specify a metric or a list of metrics
              for each output, such as
              `metrics=[['accuracy'], ['accuracy', 'mse']]`
              or `metrics=['accuracy', ['accuracy', 'mse']]`. When you pass the
              strings 'accuracy' or 'acc', we convert this to one of
              `tf.keras.metrics.BinaryAccuracy`,
              `tf.keras.metrics.CategoricalAccuracy`,
              `tf.keras.metrics.SparseCategoricalAccuracy` based on the loss
              function used and the model output shape. We do a similar
              conversion for the strings 'crossentropy' and 'ce' as well.
              The metrics passed here are evaluated without sample weighting; if
              you would like sample weighting to apply, you can specify your
              metrics via the `weighted_metrics` argument instead.
            loss_weights: Optional list or dictionary specifying scalar
              coefficients (Python floats) to weight the loss contributions of
              different model outputs. The loss value that will be minimized by
              the model will then be the *weighted sum* of all individual
              losses, weighted by the `loss_weights` coefficients.  If a list,
              it is expected to have a 1:1 mapping to the model's outputs. If a
              dict, it is expected to map output names (strings) to scalar
              coefficients.
            weighted_metrics: List of metrics to be evaluated and weighted by
              `sample_weight` or `class_weight` during training and testing.
            run_eagerly: Bool. Defaults to `False`. If `True`, this `Model`'s
              logic will not be wrapped in a `tf.function`. Recommended to leave
              this as `None` unless your `Model` cannot be run inside a
              `tf.function`. `run_eagerly=True` is not supported when using
              `tf.distribute.experimental.ParameterServerStrategy`.
            steps_per_execution: Int. Defaults to 1. The number of batches to
              run during each `tf.function` call. Running multiple batches
              inside a single `tf.function` call can greatly improve performance
              on TPUs or small models with a large Python overhead. At most, one
              full epoch will be run each execution. If a number larger than the
              size of the epoch is passed, the execution will be truncated to
              the size of the epoch. Note that if `steps_per_execution` is set
              to `N`, `Callback.on_batch_begin` and `Callback.on_batch_end`
              methods will only be called every `N` batches (i.e. before/after
              each `tf.function` execution).
            jit_compile: If `True`, compile the model training step with XLA.
              [XLA](https://www.tensorflow.org/xla) is an optimizing compiler
              for machine learning.
              `jit_compile` is not enabled for by default.
              This option cannot be enabled with `run_eagerly=True`.
              Note that `jit_compile=True`
              may not necessarily work for all models.
              For more information on supported operations please refer to the
              [XLA documentation](https://www.tensorflow.org/xla).
              Also refer to
              [known XLA issues](https://www.tensorflow.org/xla/known_issues)
              for more details.
            **kwargs: Arguments supported for backwards compatibility only.
        compileT experimental_steps_per_executionzThe argument `steps_per_execution` is no longer experimental. Pass `steps_per_execution` instead of `experimental_steps_per_execution`.from_serializedF)rT   )rT   r      zCYou cannot enable `run_eagerly` and `jit_compile` at the same time.N)r   rF   rG   rH   distribute_strategyscopeloggingwarningpop_validate_compilera   _get_optimizerr   rI   r   LossesContainerrW   rT   MetricsContainerrX   _configure_steps_per_executionrb   rC   lossrB   r   rm   )rq   r   r   metricsloss_weightsweighted_metricsrun_eagerlysteps_per_executionjit_compiler0   r   r3   r3   r4   r   P  sD    l
zModel.compilec                    s    fdd}t j||S )z7Wraps `optimizer` in `LossScaleOptimizer` if necessary.c                    s0   t | }  jjdkr,t| tjs,t| } | S )Nmixed_float16)r   getdtype_policyr8   rI   lsoBaseLossScaleOptimizer)optr   r3   r4   _get_single_optimizer  s    

z3Model._get_optimizer.<locals>._get_single_optimizerr[   r   r   )rq   r   r   r3   r   r4   r     s    
zModel._get_optimizerc                 C   s&   d | _ d | _d | _d | _|  | _d S r   )train_functiontest_functionpredict_functiontrain_tf_function_get_trainable_state_compiled_trainable_stater   r3   r3   r4   rb     s
    zModel._reset_compile_cachec                 C   s   t j|dt jjd| _d S )Nrw   rx   )r[   r|   rz   r{   r%   )rq   r   r3   r3   r4   r     s
    z$Model._configure_steps_per_executionc                 C   s   dS )NFr3   r   r3   r3   r4   _should_compute_mask  s    zModel._should_compute_maskc                 C   sT   g }| j r6| jdur || jj7 }| jdur6|| jj7 }|  D ]}||j q>|S )ag  Returns the model's metrics added using `compile()`, `add_metric()` APIs.

        Note: Metrics passed to `compile()` are available only after a
        `keras.Model` has been trained/evaluated on actual data.

        Examples:

        >>> inputs = tf.keras.layers.Input(shape=(3,))
        >>> outputs = tf.keras.layers.Dense(2)(inputs)
        >>> model = tf.keras.models.Model(inputs=inputs, outputs=outputs)
        >>> model.compile(optimizer="Adam", loss="mse", metrics=["mae"])
        >>> [m.name for m in model.metrics]
        []

        >>> x = np.random.random((2, 3))
        >>> y = np.random.randint(0, 2, (2, 2))
        >>> model.fit(x, y)
        >>> [m.name for m in model.metrics]
        ['loss', 'mae']

        >>> inputs = tf.keras.layers.Input(shape=(3,))
        >>> d = tf.keras.layers.Dense(2, name='out')
        >>> output_1 = d(inputs)
        >>> output_2 = d(inputs)
        >>> model = tf.keras.models.Model(
        ...    inputs=inputs, outputs=[output_1, output_2])
        >>> model.add_metric(
        ...    tf.reduce_sum(output_2), name='mean', aggregation='mean')
        >>> model.compile(optimizer="Adam", loss="mse", metrics=["mae", "acc"])
        >>> model.fit(x, (y, y))
        >>> [m.name for m in model.metrics]
        ['loss', 'out_loss', 'out_1_loss', 'out_mae', 'out_acc', 'out_1_mae',
        'out_1_acc', 'mean']

        N)rC   rW   r   rX   _flatten_layersextend_metrics)rq   r   lr3   r3   r4   r     s    %

zModel.metricsc                 C   s   dd | j D S )a  Returns the model's display labels for all outputs.

        Note: `metrics_names` are available only after a `keras.Model` has been
        trained/evaluated on actual data.

        Examples:

        >>> inputs = tf.keras.layers.Input(shape=(3,))
        >>> outputs = tf.keras.layers.Dense(2)(inputs)
        >>> model = tf.keras.models.Model(inputs=inputs, outputs=outputs)
        >>> model.compile(optimizer="Adam", loss="mse", metrics=["mae"])
        >>> model.metrics_names
        []

        >>> x = np.random.random((2, 3))
        >>> y = np.random.randint(0, 2, (2, 2))
        >>> model.fit(x, y)
        >>> model.metrics_names
        ['loss', 'mae']

        >>> inputs = tf.keras.layers.Input(shape=(3,))
        >>> d = tf.keras.layers.Dense(2, name='out')
        >>> output_1 = d(inputs)
        >>> output_2 = d(inputs)
        >>> model = tf.keras.models.Model(
        ...    inputs=inputs, outputs=[output_1, output_2])
        >>> model.compile(optimizer="Adam", loss="mse", metrics=["mae", "acc"])
        >>> model.fit(x, (y, y))
        >>> model.metrics_names
        ['loss', 'out_loss', 'out_1_loss', 'out_mae', 'out_acc', 'out_1_mae',
        'out_1_acc']

        c                 S   s   g | ]
}|j qS r3   r8   )r;   mr3   r3   r4   r   p      z'Model.metrics_names.<locals>.<listcomp>)r   r   r3   r3   r4   metrics_namesJ  s    &zModel.metrics_namesc                 C   s   | j ptj S )z:The `tf.distribute.Strategy` this model was created under.)r_   r[   r\   r^   r   r3   r3   r4   r   r  s    zModel.distribute_strategyc                 C   sL   | j r| jdkrtd| jr,| jr,td| j pJ| jpJtj oJ| jdu S )a  Settable attribute indicating whether the model should run eagerly.

        Running eagerly means that your model will be run step by step,
        like Python code. Your model might run slower, but it should become
        easier for you to debug it by stepping into individual layer calls.

        By default, we will attempt to compile your model to a static graph to
        deliver the best execution performance.

        Returns:
          Boolean, whether the model should run eagerly.
        FzYour model contains layers that can only be successfully run in eager execution (layers constructed with `dynamic=True`). You cannot set `run_eagerly=False`.zRWhen using `Model` with `ParameterServerStrategy`, `run_eagerly` is not supported.N)rB   ra   r   r`   r[   configfunctions_run_eagerlyr   r3   r3   r4   r   w  s    zModel.run_eagerlyc                 C   s
   || _ d S r   )ra   )rq   r   r3   r3   r4   r     s    c                 C   s6   | j r"|du r"td| j  dn|du r2tddS )aH  Raises error if target or loss is not found.

        This method verifies that the target and loss are properly populated
        when applicable, or raises errors.

        Args:
          y: the target for training.
          loss: the total loss tensor including loss added via `compile` and
            `add_loss`.
        Nz:Target data is missing. Your model was compiled with loss=z>, and therefore expects target data to be provided in `fit()`.z]No loss found. You may have forgotten to provide a `loss` argument in the `compile()` method.)r   r   )rq   yr   r3   r3   r4   _validate_target_and_loss  s    	zModel._validate_target_and_lossc                 C   s   t |\}}}t ,}| |dd}| ||||}W d   n1 sJ0    Y  | || | jj|| j|d | 	||||S )aR  The logic for one training step.

        This method can be overridden to support custom training logic.
        For concrete examples of how to override this method see
        [Customizing what happens in fit](
        https://www.tensorflow.org/guide/keras/customizing_what_happens_in_fit).
        This method is called by `Model.make_train_function`.

        This method should contain the mathematical logic for one step of
        training.  This typically includes the forward pass, loss calculation,
        backpropagation, and metric updates.

        Configuration details for *how* this logic is run (e.g. `tf.function`
        and `tf.distribute.Strategy` settings), should be left to
        `Model.make_train_function`, which can also be overridden.

        Args:
          data: A nested structure of `Tensor`s.

        Returns:
          A `dict` containing values that will be passed to
          `tf.keras.callbacks.CallbackList.on_train_batch_end`. Typically, the
          values of the `Model`'s metrics are returned. Example:
          `{'loss': 0.2, 'accuracy': 0.7}`.
        Tr   N)tape)
r	   unpack_x_y_sample_weightr[   GradientTapecompute_lossr  r   minimizetrainable_variablescompute_metrics)rq   datar   r  sample_weightr  y_predr   r3   r3   r4   
train_step  s    
.zModel.train_stepc                 C   s   ~| j |||| jdS )a   Compute the total loss, validate it, and return it.

        Subclasses can optionally override this method to provide custom loss
        computation logic.

        Example:
        ```python
        class MyModel(tf.keras.Model):

          def __init__(self, *args, **kwargs):
            super(MyModel, self).__init__(*args, **kwargs)
            self.loss_tracker = tf.keras.metrics.Mean(name='loss')

          def compute_loss(self, x, y, y_pred, sample_weight):
            loss = tf.reduce_mean(tf.math.squared_difference(y_pred, y))
            loss += tf.add_n(self.losses)
            self.loss_tracker.update_state(loss)
            return loss

          def reset_metrics(self):
            self.loss_tracker.reset_states()

          @property
          def metrics(self):
            return [self.loss_tracker]

        tensors = tf.random.uniform((10, 10)), tf.random.uniform((10,))
        dataset = tf.data.Dataset.from_tensor_slices(tensors).repeat().batch(1)

        inputs = tf.keras.layers.Input(shape=(10,), name='my_input')
        outputs = tf.keras.layers.Dense(10)(inputs)
        model = MyModel(inputs, outputs)
        model.add_loss(tf.reduce_sum(outputs))

        optimizer = tf.keras.optimizers.SGD()
        model.compile(optimizer, loss='mse', steps_per_execution=10)
        model.fit(dataset, epochs=2, steps_per_epoch=10)
        print('My custom loss: ', model.loss_tracker.result().numpy())
        ```

        Args:
          x: Input data.
          y: Target data.
          y_pred: Predictions returned by the model (output of `model(x)`)
          sample_weight: Sample weights for weighting the loss function.

        Returns:
          The total loss as a `tf.Tensor`, or `None` if no loss results (which
          is the case when called by `Model.test_step`).
        )regularization_losses)rW   losses)rq   r   r  r  r  r3   r3   r4   r    s    3
zModel.compute_lossc                 C   sN   ~| j ||| i }| jD ],}| }t|tr>|| q|||j< q|S )aV  Update metric states and collect all metrics to be returned.

        Subclasses can optionally override this method to provide custom metric
        updating and collection logic.

        Example:
        ```python
        class MyModel(tf.keras.Sequential):

          def compute_metrics(self, x, y, y_pred, sample_weight):

            # This super call updates `self.compiled_metrics` and returns
            # results for all metrics listed in `self.metrics`.
            metric_results = super(MyModel, self).compute_metrics(
                x, y, y_pred, sample_weight)

            # Note that `self.custom_metric` is not listed in `self.metrics`.
            self.custom_metric.update_state(x, y, y_pred, sample_weight)
            metric_results['custom_metric_name'] = self.custom_metric.result()
            return metric_results
        ```

        Args:
          x: Input data.
          y: Target data.
          y_pred: Predictions returned by the model (output of `model.call(x)`)
          sample_weight: Sample weights for weighting the loss function.

        Returns:
          A `dict` containing values that will be passed to
          `tf.keras.callbacks.CallbackList.on_train_batch_end()`. Typically, the
          values of the metrics listed in `self.metrics` are returned. Example:
          `{'loss': 0.2, 'accuracy': 0.7}`.
        )rX   update_stater   resultrI   r   updater8   )rq   r   r  r  r  return_metricsmetricr  r3   r3   r4   r     s    #

zModel.compute_metricsc                    s    j dur|s j S  fdd jdu s< j  dkr fdd jsdtjdd _ jr| fd	d
 _ q _ nn jrć fdd jstjdd _ fdd
 _ n. fdd jstjdd _ _  j S )a  Creates a function that executes one step of training.

        This method can be overridden to support custom training logic.
        This method is called by `Model.fit` and `Model.train_on_batch`.

        Typically, this method directly controls `tf.function` and
        `tf.distribute.Strategy` settings, and delegates the actual training
        logic to `Model.train_step`.

        This function is cached the first time `Model.fit` or
        `Model.train_on_batch` is called. The cache is cleared whenever
        `Model.compile` is called. You can skip the cache and generate again the
        function with `force=True`.

        Args:
          force: Whether to regenerate the train function and skip the cached
            function if available.

        Returns:
          Function. The function created by this method should accept a
          `tf.data.Iterator`, and return a `dict` containing values that will
          be passed to `tf.keras.Callbacks.on_train_batch_end`, such as
          `{'loss': 0.2, 'accuracy': 0.7}`.
        Nc                    sP    fdd}j r"tj|ddd}t|} jj||fd}t|jdd}|S )zRuns a single training step.c                    sH     | }tt|  jd W d    n1 s:0    Y  |S Nr   )r  r[   control_dependencies_minimum_control_depsr"   
assign_addr  r7   r5   r3   r4   run_stepn  s    
*zBModel.make_train_function.<locals>.step_function.<locals>.run_stepTr   reduce_retracingr/   first	reductionrm   r[   functionnextr   runreduce_per_replicar5   iteratorr  r  r7   r   r  r4   step_functionk  s    z0Model.make_train_function.<locals>.step_functionr   c                    s
    | S )z-Runs a training execution with a single step.r3   r*  rq   r+  r3   r4   r     s    z1Model.make_train_function.<locals>.train_functionTr  c                    s    j j| fdS Nr   r`   scheduleitrq   r   r3   r4   <lambda>  s   z+Model.make_train_function.<locals>.<lambda>c                    s   t |D ]} | }q
|S z.Runs a training execution with multiple steps.r[   ranger*  r   _r7   r-  r3   r4   r     s    c                    s    j j|  j fdS r/  r`   r1  r%   r   r2  r4  r3   r4   r5    s   c                    s    t  jD ]} | }q|S r6  r[   r8  r%   r*  r:  r7   r-  r3   r4   r     s    )	r   r%   numpyitemr   r[   r%  r   r`   rq   forcer3   )rq   r+  r   r4   make_train_functionO  sB    zModel.make_train_functionr   auto        Tr   
   c           "      C   s  t jdd tdd |   | d td t	|| j
}|rn|du rntj|||f|d\\}}}}|rt|\}}}| j
jrtjjj| j
| _| j
  t|  tj||||||||	|
|||| | jd}t|tjstj|d|dk| |||jd}d	| _|  | _ | j!"d |#  d}|p@|j}| $||\|_%|_&d}|' D ]\}}| (  |)| |*  |j&p| + |_&|, D ]}tj-jj.d
|||ddh |/| |  |}|j0rt12  |}||j3 }|4|| | jrW d    q<W d   n1 s.0    Y  qW d   n1 sR0    Y  t56|}|du rxt7dt88|} |r| 9||rt:| dddu rtj||||p||dd|||| | jd| _;| j<||||p||||||ddd}!dd |!= D }!| >|! |?||  | }| jrb q8qbt| j@tAjBrV| j@C| jD t:| dddurl| `;|jE|d | jFW  d   W  d   S 1 s0    Y  W d   n1 s0    Y  dS )a8  Trains the model for a fixed number of epochs (iterations on a dataset).

        Args:
            x: Input data. It could be:
              - A Numpy array (or array-like), or a list of arrays
                (in case the model has multiple inputs).
              - A TensorFlow tensor, or a list of tensors
                (in case the model has multiple inputs).
              - A dict mapping input names to the corresponding array/tensors,
                if the model has named inputs.
              - A `tf.data` dataset. Should return a tuple
                of either `(inputs, targets)` or
                `(inputs, targets, sample_weights)`.
              - A generator or `keras.utils.Sequence` returning `(inputs,
                targets)` or `(inputs, targets, sample_weights)`.
              - A `tf.keras.utils.experimental.DatasetCreator`, which wraps a
                callable that takes a single argument of type
                `tf.distribute.InputContext`, and returns a `tf.data.Dataset`.
                `DatasetCreator` should be used when users prefer to specify the
                per-replica batching and sharding logic for the `Dataset`.
                See `tf.keras.utils.experimental.DatasetCreator` doc for more
                information.
              A more detailed description of unpacking behavior for iterator
              types (Dataset, generator, Sequence) is given below. If these
              include `sample_weights` as a third component, note that sample
              weighting applies to the `weighted_metrics` argument but not the
              `metrics` argument in `compile()`. If using
              `tf.distribute.experimental.ParameterServerStrategy`, only
              `DatasetCreator` type is supported for `x`.
            y: Target data. Like the input data `x`,
              it could be either Numpy array(s) or TensorFlow tensor(s).
              It should be consistent with `x` (you cannot have Numpy inputs and
              tensor targets, or inversely). If `x` is a dataset, generator,
              or `keras.utils.Sequence` instance, `y` should
              not be specified (since targets will be obtained from `x`).
            batch_size: Integer or `None`.
                Number of samples per gradient update.
                If unspecified, `batch_size` will default to 32.
                Do not specify the `batch_size` if your data is in the
                form of datasets, generators, or `keras.utils.Sequence`
                instances (since they generate batches).
            epochs: Integer. Number of epochs to train the model.
                An epoch is an iteration over the entire `x` and `y`
                data provided
                (unless the `steps_per_epoch` flag is set to
                something other than None).
                Note that in conjunction with `initial_epoch`,
                `epochs` is to be understood as "final epoch".
                The model is not trained for a number of iterations
                given by `epochs`, but merely until the epoch
                of index `epochs` is reached.
            verbose: 'auto', 0, 1, or 2. Verbosity mode.
                0 = silent, 1 = progress bar, 2 = one line per epoch.
                'auto' defaults to 1 for most cases, but 2 when used with
                `ParameterServerStrategy`. Note that the progress bar is not
                particularly useful when logged to a file, so verbose=2 is
                recommended when not running interactively (eg, in a production
                environment).
            callbacks: List of `keras.callbacks.Callback` instances.
                List of callbacks to apply during training.
                See `tf.keras.callbacks`. Note
                `tf.keras.callbacks.ProgbarLogger` and
                `tf.keras.callbacks.History` callbacks are created automatically
                and need not be passed into `model.fit`.
                `tf.keras.callbacks.ProgbarLogger` is created or not based on
                `verbose` argument to `model.fit`.
                Callbacks with batch-level calls are currently unsupported with
                `tf.distribute.experimental.ParameterServerStrategy`, and users
                are advised to implement epoch-level calls instead with an
                appropriate `steps_per_epoch` value.
            validation_split: Float between 0 and 1.
                Fraction of the training data to be used as validation data.
                The model will set apart this fraction of the training data,
                will not train on it, and will evaluate
                the loss and any model metrics
                on this data at the end of each epoch.
                The validation data is selected from the last samples
                in the `x` and `y` data provided, before shuffling. This
                argument is not supported when `x` is a dataset, generator or
                `keras.utils.Sequence` instance.
                If both `validation_data` and `validation_split` are provided,
                `validation_data` will override `validation_split`.
                `validation_split` is not yet supported with
                `tf.distribute.experimental.ParameterServerStrategy`.
            validation_data: Data on which to evaluate
                the loss and any model metrics at the end of each epoch.
                The model will not be trained on this data. Thus, note the fact
                that the validation loss of data provided using
                `validation_split` or `validation_data` is not affected by
                regularization layers like noise and dropout.
                `validation_data` will override `validation_split`.
                `validation_data` could be:
                  - A tuple `(x_val, y_val)` of Numpy arrays or tensors.
                  - A tuple `(x_val, y_val, val_sample_weights)` of NumPy
                    arrays.
                  - A `tf.data.Dataset`.
                  - A Python generator or `keras.utils.Sequence` returning
                  `(inputs, targets)` or `(inputs, targets, sample_weights)`.
                `validation_data` is not yet supported with
                `tf.distribute.experimental.ParameterServerStrategy`.
            shuffle: Boolean (whether to shuffle the training data
                before each epoch) or str (for 'batch'). This argument is
                ignored when `x` is a generator or an object of tf.data.Dataset.
                'batch' is a special option for dealing
                with the limitations of HDF5 data; it shuffles in batch-sized
                chunks. Has no effect when `steps_per_epoch` is not `None`.
            class_weight: Optional dictionary mapping class indices (integers)
                to a weight (float) value, used for weighting the loss function
                (during training only).
                This can be useful to tell the model to
                "pay more attention" to samples from
                an under-represented class.
            sample_weight: Optional Numpy array of weights for
                the training samples, used for weighting the loss function
                (during training only). You can either pass a flat (1D)
                Numpy array with the same length as the input samples
                (1:1 mapping between weights and samples),
                or in the case of temporal data,
                you can pass a 2D array with shape
                `(samples, sequence_length)`,
                to apply a different weight to every timestep of every sample.
                This argument is not supported when `x` is a dataset, generator,
                or `keras.utils.Sequence` instance, instead provide the
                sample_weights as the third element of `x`.
                Note that sample weighting does not apply to metrics specified
                via the `metrics` argument in `compile()`. To apply sample
                weighting to your metrics, you can specify them via the
                `weighted_metrics` in `compile()` instead.
            initial_epoch: Integer.
                Epoch at which to start training
                (useful for resuming a previous training run).
            steps_per_epoch: Integer or `None`.
                Total number of steps (batches of samples)
                before declaring one epoch finished and starting the
                next epoch. When training with input tensors such as
                TensorFlow data tensors, the default `None` is equal to
                the number of samples in your dataset divided by
                the batch size, or 1 if that cannot be determined. If x is a
                `tf.data` dataset, and 'steps_per_epoch'
                is None, the epoch will run until the input dataset is
                exhausted.  When passing an infinitely repeating dataset, you
                must specify the `steps_per_epoch` argument. If
                `steps_per_epoch=-1` the training will run indefinitely with an
                infinitely repeating dataset.  This argument is not supported
                with array inputs.
                When using `tf.distribute.experimental.ParameterServerStrategy`:
                  * `steps_per_epoch=None` is not supported.
            validation_steps: Only relevant if `validation_data` is provided and
                is a `tf.data` dataset. Total number of steps (batches of
                samples) to draw before stopping when performing validation
                at the end of every epoch. If 'validation_steps' is None,
                validation will run until the `validation_data` dataset is
                exhausted. In the case of an infinitely repeated dataset, it
                will run into an infinite loop. If 'validation_steps' is
                specified and only part of the dataset will be consumed, the
                evaluation will start from the beginning of the dataset at each
                epoch. This ensures that the same validation samples are used
                every time.
            validation_batch_size: Integer or `None`.
                Number of samples per validation batch.
                If unspecified, will default to `batch_size`.
                Do not specify the `validation_batch_size` if your data is in
                the form of datasets, generators, or `keras.utils.Sequence`
                instances (since they generate batches).
            validation_freq: Only relevant if validation data is provided.
              Integer or `collections.abc.Container` instance (e.g. list, tuple,
              etc.).  If an integer, specifies how many training epochs to run
              before a new validation run is performed, e.g. `validation_freq=2`
              runs validation every 2 epochs. If a Container, specifies the
              epochs on which to run validation, e.g.
              `validation_freq=[1, 2, 10]` runs validation at the end of the
              1st, 2nd, and 10th epochs.
            max_queue_size: Integer. Used for generator or
              `keras.utils.Sequence` input only. Maximum size for the generator
              queue.  If unspecified, `max_queue_size` will default to 10.
            workers: Integer. Used for generator or `keras.utils.Sequence` input
                only. Maximum number of processes to spin up
                when using process-based threading. If unspecified, `workers`
                will default to 1.
            use_multiprocessing: Boolean. Used for generator or
                `keras.utils.Sequence` input only. If `True`, use process-based
                threading. If unspecified, `use_multiprocessing` will default to
                `False`. Note that because this implementation relies on
                multiprocessing, you should not pass non-picklable arguments to
                the generator as they can't be passed easily to children
                processes.

        Unpacking behavior for iterator-like inputs:
            A common pattern is to pass a tf.data.Dataset, generator, or
          tf.keras.utils.Sequence to the `x` argument of fit, which will in fact
          yield not only features (x) but optionally targets (y) and sample
          weights.  Keras requires that the output of such iterator-likes be
          unambiguous. The iterator should return a tuple of length 1, 2, or 3,
          where the optional second and third elements will be used for y and
          sample_weight respectively. Any other type provided will be wrapped in
          a length one tuple, effectively treating everything as 'x'. When
          yielding dicts, they should still adhere to the top-level tuple
          structure.
          e.g. `({"x0": x0, "x1": x1}, y)`. Keras will not attempt to separate
          features, targets, and weights from the keys of a single dict.
            A notable unsupported data type is the namedtuple. The reason is
          that it behaves like both an ordered datatype (tuple) and a mapping
          datatype (dict). So given a namedtuple of the form:
              `namedtuple("example_tuple", ["y", "x"])`
          it is ambiguous whether to reverse the order of the elements when
          interpreting the value. Even worse is a tuple of the form:
              `namedtuple("other_tuple", ["x", "y", "z"])`
          where it is unclear if the tuple was intended to be unpacked into x,
          y, and sample_weight or passed through as a single element to `x`. As
          a result the data processing code will simply raise a ValueError if it
          encounters a namedtuple. (Along with instructions to remedy the
          issue.)

        Returns:
            A `History` object. Its `History.history` attribute is
            a record of training loss values and metrics values
            at successive epochs, as well as validation loss values
            and validation metrics values (if applicable).

        Raises:
            RuntimeError: 1. If the model was never compiled or,
            2. If `model.fit` is  wrapped in `tf.function`.

            ValueError: In case of mismatch between the provided input data
                and what the model expects or when the input data is empty.
        fitTr!   N)validation_split)r   r  r  
batch_sizesteps_per_epochinitial_epochepochsshuffleclass_weightmax_queue_sizeworkersuse_multiprocessingr5   r   r   add_historyadd_progbarr5   verboserK  stepsFrf   r   )	epoch_numstep_numrH  _rzUnexpected result of `train_function` (Empty logs). Please use `Model.compile(..., run_eagerly=True)`, or `tf.config.run_functions_eagerly(True)` for more information of where went wrong, or file a issue/bug to `tf.keras`._eval_data_handlerr   r  r  rH  rI  rJ  rK  rN  rO  rP  r5   r   )r   r  r  rH  rU  r   rN  rO  rP  return_dict_use_cached_eval_datasetc                 S   s   i | ]\}}d | |qS )val_r3   )r;   r8   valr3   r3   r4   r?   S  s   zModel.fit.<locals>.<dictcomp>logs)Gr   rF   rG   rH   r   disallow_legacy_graph_assert_compile_was_called_check_call_args_disallow_inside_tf_function_get_verbosityr   r	   train_validation_splitr  _should_use_with_coordinatorr[   r\   experimentalcoordinatorClusterCoordinatorr`   r   r   RespectCompiledTrainableStateget_data_handlerr%   rI   callbacks_moduleCallbackListinferred_stepsrU   rB  r   r"   assignon_train_begin&_maybe_load_initial_counters_from_ckpt_initial_epochZ_initial_stepenumerate_epochsreset_metricson_epoch_begincatch_stop_iteration"_maybe_load_initial_step_from_ckptrU  profilerTraceon_train_batch_beginshould_syncr   
async_waitstep_incrementon_train_batch_endr   sync_to_numpy_or_python_typer   r   _should_evalr   rY  evaluater   r  on_epoch_endr   optimizer_experimental	Optimizerfinalize_variable_valuesr
  on_train_endrV   )"rq   r   r  rH  rK  rT  r   rG  validation_datarL  rM  r  rJ  rI  validation_stepsvalidation_batch_sizevalidation_freqrN  rO  rP  val_xval_yval_sample_weightdata_handlertraining_logsZsteps_per_epoch_inferredr`  epochr*  steptmp_logsend_step
epoch_logsval_logsr3   r3   r4   rF    s&    z










V





z	Model.fitc                 C   s<   t |\}}}| |dd}| |||| | ||||S )a]  The logic for one evaluation step.

        This method can be overridden to support custom evaluation logic.
        This method is called by `Model.make_test_function`.

        This function should contain the mathematical logic for one step of
        evaluation.
        This typically includes the forward pass, loss calculation, and metrics
        updates.

        Configuration details for *how* this logic is run (e.g. `tf.function`
        and `tf.distribute.Strategy` settings), should be left to
        `Model.make_test_function`, which can also be overridden.

        Args:
          data: A nested structure of `Tensor`s.

        Returns:
          A `dict` containing values that will be passed to
          `tf.keras.callbacks.CallbackList.on_train_batch_end`. Typically, the
          values of the `Model`'s metrics are returned.
        Fr  )r	   r  r  r  )rq   r  r   r  r  r  r3   r3   r4   	test_steph  s    zModel.test_stepc                    s    j dur|s j S  fdd jdu s< j  dkr~ fdd js^tjdd jrv fd	d
 _ q _ nb jr fdd jstjdd fdd
 _ n( fdd jstjdd _  j S )a  Creates a function that executes one step of evaluation.

        This method can be overridden to support custom evaluation logic.
        This method is called by `Model.evaluate` and `Model.test_on_batch`.

        Typically, this method directly controls `tf.function` and
        `tf.distribute.Strategy` settings, and delegates the actual evaluation
        logic to `Model.test_step`.

        This function is cached the first time `Model.evaluate` or
        `Model.test_on_batch` is called. The cache is cleared whenever
        `Model.compile` is called. You can skip the cache and generate again the
        function with `force=True`.

        Args:
          force: Whether to regenerate the test function and skip the cached
            function if available.

        Returns:
          Function. The function created by this method should accept a
          `tf.data.Iterator`, and return a `dict` containing values that will
          be passed to `tf.keras.Callbacks.on_test_batch_end`.
        Nc                    sP    fdd}j r"tj|ddd}t|} jj||fd}t|jdd}|S )Runs a single evaluation step.c                    sH     | }tt|  jd W d    n1 s:0    Y  |S r  )r  r[   r  r  r#   r  r  r  r3   r4   r    s    
*zAModel.make_test_function.<locals>.step_function.<locals>.run_stepTr  r   r!  r"  r$  r)  r   r  r4   r+    s    z/Model.make_test_function.<locals>.step_functionr   c                    s
    | S )z)Runs a test execution with a single step.r3   r,  r-  r3   r4   r     s    z/Model.make_test_function.<locals>.test_functionTr.  c                    s    j j| fdS r/  r0  r2  rq   r   r3   r4   r5    s   z*Model.make_test_function.<locals>.<lambda>c                    s   t |D ]} | }q
|S z*Runs a test execution with multiple steps.r7  r9  r-  r3   r4   r     s    c                    s    j j|  j fdS r/  r;  r2  r  r3   r4   r5    s   c                    s    t  jD ]} | }q|S r  r<  r=  r-  r3   r4   r     s    )r   r%   r>  r?  r   r[   r%  r`   r@  r3   )rq   r+  r   r4   make_test_function  s<    zModel.make_test_functionc                 K   sd  t jdd tdd |   | d | || t	d |
dd}|rjtdt|  | jjrtjjj| j| _t|| j}| j  |rt| dddur| j}n$tj|||||d	d
||	|
| | jd}t|tjstj|d|d	k| |d
|j d}i }| ! | _"| j#$d	 |%  |& D ]\}}| '  |(  |) D ]z}tj*jj+d|d
dN |,| | "|}|j-rt./  |}||j0 }|1|| W d   n1 s0    Y  qXW d   n1 s0    Y  q6t23|}|j4|d |r&|W  d   S t5|| j6W  d   S W d   n1 sV0    Y  dS )am  Returns the loss value & metrics values for the model in test mode.

        Computation is done in batches (see the `batch_size` arg.)

        Args:
            x: Input data. It could be:
              - A Numpy array (or array-like), or a list of arrays
                (in case the model has multiple inputs).
              - A TensorFlow tensor, or a list of tensors
                (in case the model has multiple inputs).
              - A dict mapping input names to the corresponding array/tensors,
                if the model has named inputs.
              - A `tf.data` dataset. Should return a tuple
                of either `(inputs, targets)` or
                `(inputs, targets, sample_weights)`.
              - A generator or `keras.utils.Sequence` returning `(inputs,
                targets)` or `(inputs, targets, sample_weights)`.
              A more detailed description of unpacking behavior for iterator
              types (Dataset, generator, Sequence) is given in the `Unpacking
              behavior for iterator-like inputs` section of `Model.fit`.
            y: Target data. Like the input data `x`, it could be either Numpy
              array(s) or TensorFlow tensor(s). It should be consistent with `x`
              (you cannot have Numpy inputs and tensor targets, or inversely).
              If `x` is a dataset, generator or `keras.utils.Sequence` instance,
              `y` should not be specified (since targets will be obtained from
              the iterator/dataset).
            batch_size: Integer or `None`. Number of samples per batch of
              computation. If unspecified, `batch_size` will default to 32. Do
              not specify the `batch_size` if your data is in the form of a
              dataset, generators, or `keras.utils.Sequence` instances (since
              they generate batches).
            verbose: `"auto"`, 0, 1, or 2. Verbosity mode.
                0 = silent, 1 = progress bar, 2 = single line.
                `"auto"` defaults to 1 for most cases, and to 2 when used with
                `ParameterServerStrategy`. Note that the progress bar is not
                particularly useful when logged to a file, so `verbose=2` is
                recommended when not running interactively (e.g. in a production
                environment).
            sample_weight: Optional Numpy array of weights for the test samples,
              used for weighting the loss function. You can either pass a flat
              (1D) Numpy array with the same length as the input samples
                (1:1 mapping between weights and samples), or in the case of
                  temporal data, you can pass a 2D array with shape `(samples,
                  sequence_length)`, to apply a different weight to every
                  timestep of every sample. This argument is not supported when
                  `x` is a dataset, instead pass sample weights as the third
                  element of `x`.
            steps: Integer or `None`. Total number of steps (batches of samples)
              before declaring the evaluation round finished. Ignored with the
              default value of `None`. If x is a `tf.data` dataset and `steps`
              is None, 'evaluate' will run until the dataset is exhausted. This
              argument is not supported with array inputs.
            callbacks: List of `keras.callbacks.Callback` instances. List of
              callbacks to apply during evaluation. See
              [callbacks](/api_docs/python/tf/keras/callbacks).
            max_queue_size: Integer. Used for generator or
              `keras.utils.Sequence` input only. Maximum size for the generator
              queue. If unspecified, `max_queue_size` will default to 10.
            workers: Integer. Used for generator or `keras.utils.Sequence` input
              only. Maximum number of processes to spin up when using
              process-based threading. If unspecified, `workers` will default to
              1.
            use_multiprocessing: Boolean. Used for generator or
              `keras.utils.Sequence` input only. If `True`, use process-based
              threading. If unspecified, `use_multiprocessing` will default to
              `False`. Note that because this implementation relies on
              multiprocessing, you should not pass non-picklable arguments to
              the generator as they can't be passed easily to children
              processes.
            return_dict: If `True`, loss and metric results are returned as a
              dict, with each key being the name of the metric. If `False`, they
              are returned as a list.
            **kwargs: Unused at this time.

        See the discussion of `Unpacking behavior for iterator-like inputs` for
        `Model.fit`.

        Returns:
            Scalar test loss (if the model has a single output and no metrics)
            or list of scalars (if the model has multiple outputs
            and/or metrics). The attribute `model.metrics_names` will give you
            the display labels for the scalar outputs.

        Raises:
            RuntimeError: If `model.evaluate` is wrapped in a `tf.function`.
        r  Tr!   r\  FzInvalid keyword arguments: rY  Nr   r   rZ  rQ  test)rW  rX  r_  )7r   rF   rG   rH   r   ra  rb  rc  _check_sample_weight_warningrd  r   rO   r   keysr   rg  r[   r\   rh  ri  rj  r`   re  r   r   rY  r	   rl  r%   rI   rm  rn  ro  r  r   r#   rp  on_test_beginrt  ru  rw  rU  ry  rz  on_test_batch_beginr|  r   r}  r~  on_test_batch_endr   r  on_test_endflatten_metrics_in_orderr   )rq   r   r  rH  rT  r  rU  r   rN  rO  rP  r[  r0   use_cached_eval_datasetr  r`  r:  r*  r  r  r  r3   r3   r4   r    s    f







T
zModel.evaluatec                 C   s   t |\}}}| |ddS )a  The logic for one inference step.

        This method can be overridden to support custom inference logic.
        This method is called by `Model.make_predict_function`.

        This method should contain the mathematical logic for one step of
        inference.  This typically includes the forward pass.

        Configuration details for *how* this logic is run (e.g. `tf.function`
        and `tf.distribute.Strategy` settings), should be left to
        `Model.make_predict_function`, which can also be overridden.

        Args:
          data: A nested structure of `Tensor`s.

        Returns:
          The result of one inference step, typically the output of calling the
          `Model` on data.
        Fr  )r	   r  )rq   r  r   r:  r3   r3   r4   predict_step  s    zModel.predict_stepc                    sz    j dur|s j S  fdd jdu s< j  dkrL fdd}n fdd} jsntj|dd	}| _  j S )
a  Creates a function that executes one step of inference.

        This method can be overridden to support custom inference logic.
        This method is called by `Model.predict` and `Model.predict_on_batch`.

        Typically, this method directly controls `tf.function` and
        `tf.distribute.Strategy` settings, and delegates the actual evaluation
        logic to `Model.predict_step`.

        This function is cached the first time `Model.predict` or
        `Model.predict_on_batch` is called. The cache is cleared whenever
        `Model.compile` is called. You can skip the cache and generate again the
        function with `force=True`.

        Args:
          force: Whether to regenerate the predict function and skip the cached
            function if available.

        Returns:
          Function. The function created by this method should accept a
          `tf.data.Iterator`, and return the outputs of the `Model`.
        Nc                    sP    fdd}j r"tj|ddd}t|} jj||fd}t|jdd}|S )r  c                    sH     | }tt|  jd W d    n1 s:0    Y  |S r  )r  r[   r  r  r$   r  r  r  r3   r4   r    s    
*zDModel.make_predict_function.<locals>.step_function.<locals>.run_stepTr  r   concatr"  r$  r)  r   r  r4   r+    s    z2Model.make_predict_function.<locals>.step_functionr   c                    s
    | S )z0Runs an evaluation execution with a single step.r3   r,  r-  r3   r4   r     s    z5Model.make_predict_function.<locals>.predict_functionc                    sf    | }t  jd D ]F}t jjj|t jdd |fgd  | }t jdd ||}q|S )z1Runs an evaluation execution with multiple steps.r   c                 S   s   t j| ddjS )NT)dynamic_batch)r   get_tensor_specr   )tr3   r3   r4   r5    s   zGModel.make_predict_function.<locals>.predict_function.<locals>.<lambda>)shape_invariantsc                 S   s   t | |gS r   )r  )t1t2r3   r3   r4   r5    r   )r[   r8  r%   	autographrh  set_loop_optionsr   r   )r*  r7   r:  step_outputsr-  r3   r4   r     s     


Tr.  )r   r%   r>  r?  r   r[   r%  )rq   rA  r   r3   r-  r4   make_predict_function  s    zModel.make_predict_functionc	                 C   s  t jdd tdd | d td d}	| jj	rH| j}	d| _
| jrTd| _t|| j}d}
| j  tjjjjtjjf}|  st| jrt||rz,tj }tjjjj}||j_||}W n  ty   tjddd Y n0 t j!|||dd	|||| | j"d

}t|t#j$s<t#j$|d|dk| |d	|j%d}| & | _'| j()d |*  d}|+ D ]\}}|,  |- D ]~}|.| | '|}|j/rt01  |}|
du rtj23dd |}
ntj4j25|dd |
| ||j6 }|7|d|i qW d   n1 s0    Y  qf|du r6td|8  W d   n1 sT0    Y  tj4j25|t9|
}|	dur|	| _
t:;|S )a  Generates output predictions for the input samples.

        Computation is done in batches. This method is designed for batch
        processing of large numbers of inputs. It is not intended for use inside
        of loops that iterate over your data and process small numbers of inputs
        at a time.

        For small numbers of inputs that fit in one batch,
        directly use `__call__()` for faster execution, e.g.,
        `model(x)`, or `model(x, training=False)` if you have layers such as
        `tf.keras.layers.BatchNormalization` that behave differently during
        inference. You may pair the individual model call with a `tf.function`
        for additional performance inside your inner loop.
        If you need access to numpy array values instead of tensors after your
        model call, you can use `tensor.numpy()` to get the numpy array value of
        an eager tensor.

        Also, note the fact that test loss is not affected by
        regularization layers like noise and dropout.

        Note: See [this FAQ entry](
        https://keras.io/getting_started/faq/#whats-the-difference-between-model-methods-predict-and-call)
        for more details about the difference between `Model` methods
        `predict()` and `__call__()`.

        Args:
            x: Input samples. It could be:
              - A Numpy array (or array-like), or a list of arrays
                (in case the model has multiple inputs).
              - A TensorFlow tensor, or a list of tensors
                (in case the model has multiple inputs).
              - A `tf.data` dataset.
              - A generator or `keras.utils.Sequence` instance.
              A more detailed description of unpacking behavior for iterator
              types (Dataset, generator, Sequence) is given in the `Unpacking
              behavior for iterator-like inputs` section of `Model.fit`.
            batch_size: Integer or `None`.
                Number of samples per batch.
                If unspecified, `batch_size` will default to 32.
                Do not specify the `batch_size` if your data is in the
                form of dataset, generators, or `keras.utils.Sequence` instances
                (since they generate batches).
            verbose: `"auto"`, 0, 1, or 2. Verbosity mode.
                0 = silent, 1 = progress bar, 2 = single line.
                `"auto"` defaults to 1 for most cases, and to 2 when used with
                `ParameterServerStrategy`. Note that the progress bar is not
                particularly useful when logged to a file, so `verbose=2` is
                recommended when not running interactively (e.g. in a production
                environment).
            steps: Total number of steps (batches of samples)
                before declaring the prediction round finished.
                Ignored with the default value of `None`. If x is a `tf.data`
                dataset and `steps` is None, `predict()` will
                run until the input dataset is exhausted.
            callbacks: List of `keras.callbacks.Callback` instances.
                List of callbacks to apply during prediction.
                See [callbacks](/api_docs/python/tf/keras/callbacks).
            max_queue_size: Integer. Used for generator or
                `keras.utils.Sequence` input only. Maximum size for the
                generator queue. If unspecified, `max_queue_size` will default
                to 10.
            workers: Integer. Used for generator or `keras.utils.Sequence` input
                only. Maximum number of processes to spin up when using
                process-based threading. If unspecified, `workers` will default
                to 1.
            use_multiprocessing: Boolean. Used for generator or
                `keras.utils.Sequence` input only. If `True`, use process-based
                threading. If unspecified, `use_multiprocessing` will default to
                `False`. Note that because this implementation relies on
                multiprocessing, you should not pass non-picklable arguments to
                the generator as they can't be passed easily to children
                processes.

        See the discussion of `Unpacking behavior for iterator-like inputs` for
        `Model.fit`. Note that Model.predict uses the same interpretation rules
        as `Model.fit` and `Model.evaluate`, so inputs must be unambiguous for
        all three methods.

        Returns:
            Numpy array(s) of predictions.

        Raises:
            RuntimeError: If `model.predict` is wrapped in a `tf.function`.
            ValueError: In case of mismatch between the provided
                input data and the model's expectations,
                or in case a stateful model receives a number of samples
                that is not a multiple of the batch size.
        predictTr!   NzUsing Model.predict with MultiWorkerMirroredStrategy or TPUStrategy and AutoShardPolicy.FILE might lead to out-of-order result. Consider setting it to AutoShardPolicy.DATA.r   
stacklevelr   r   )
r   rH  rI  rJ  rK  rN  rO  rP  r5   r   rQ  c                 S   s   | gS r   r3   )batch_outputr3   r3   r4   r5    r   zModel.predict.<locals>.<lambda>c                 S   s
   |  |S r   )rN   )outputr  r3   r3   r4   r5    s   r7   zUnexpected result of `predict_function` (Empty batch_outputs). Please use `Model.compile(..., run_eagerly=True)`, or `tf.config.run_functions_eagerly(True)` for more information of where went wrong, or file a issue/bug to `tf.keras`.)<r   rF   rG   rH   r   ra  rc  rd  r   rg  r_   r`   re  r   r[   compatv1r  Dataset_in_multi_worker_mode_is_tpu_multi_hostrI   Optionsrh  AutoShardPolicyDATAexperimental_distributeauto_shard_policywith_optionsr   warningswarnr	   rl  r%   rm  rn  ro  r  r   r$   rp  on_predict_beginrt  rw  rU  on_predict_batch_beginr|  r   r}  r   r   r   map_structure_up_tor~  on_predict_batch_endon_predict_endpotentially_ragged_concatr   r  )rq   r   rH  rT  rU  r   rN  rO  rP  original_pss_strategyr7   dataset_typesoptionsdata_optionr  batch_outputsr:  r*  r  tmp_batch_outputsr  all_outputsr3   r3   r4   r    s    d








,
(
zModel.predictc                 C   s   | j D ]}|  qdS )a  Resets the state of all the metrics in the model.

        Examples:

        >>> inputs = tf.keras.layers.Input(shape=(3,))
        >>> outputs = tf.keras.layers.Dense(2)(inputs)
        >>> model = tf.keras.models.Model(inputs=inputs, outputs=outputs)
        >>> model.compile(optimizer="Adam", loss="mse", metrics=["mae"])

        >>> x = np.random.random((2, 3))
        >>> y = np.random.randint(0, 2, (2, 2))
        >>> _ = model.fit(x, y, verbose=0)
        >>> assert all(float(m.result()) for m in model.metrics)

        >>> model.reset_metrics()
        >>> assert all(float(m.result()) == 0 for m in model.metrics)

        N)r   reset_state)rq   r   r3   r3   r4   ru    s    
zModel.reset_metricsc           	   	   C   s   |    | d td |r&|   | j b t| 8 t	| j||||}| 
 | _| |}W d   n1 sz0    Y  W d   n1 s0    Y  t|}|r|S t|| jS dS )a.  Runs a single gradient update on a single batch of data.

        Args:
            x: Input data. It could be:
              - A Numpy array (or array-like), or a list of arrays
                  (in case the model has multiple inputs).
              - A TensorFlow tensor, or a list of tensors
                  (in case the model has multiple inputs).
              - A dict mapping input names to the corresponding array/tensors,
                  if the model has named inputs.
            y: Target data. Like the input data `x`, it could be either Numpy
              array(s) or TensorFlow tensor(s).
            sample_weight: Optional array of the same length as x, containing
              weights to apply to the model's loss for each sample. In the case
              of temporal data, you can pass a 2D array with shape (samples,
              sequence_length), to apply a different weight to every timestep of
              every sample.
            class_weight: Optional dictionary mapping class indices (integers)
              to a weight (float) to apply to the model's loss for the samples
              from this class during training. This can be useful to tell the
              model to "pay more attention" to samples from an under-represented
              class.
            reset_metrics: If `True`, the metrics returned will be only for this
              batch. If `False`, the metrics will be statefully accumulated
              across batches.
            return_dict: If `True`, loss and metric results are returned as a
              dict, with each key being the name of the metric. If `False`, they
              are returned as a list.

        Returns:
            Scalar training loss
            (if the model has a single output and no metrics)
            or list of scalars (if the model has multiple outputs
            and/or metrics). The attribute `model.metrics_names` will give you
            the display labels for the scalar outputs.

        Raises:
          RuntimeError: If `model.train_on_batch` is wrapped in a `tf.function`.
        train_on_batchN)rb  rc  rd  ru  r   r   r   rk  r	   single_batch_iteratorrB  r   r   r  r  r   )	rq   r   r  r  rM  ru  r[  r*  r`  r3   r3   r4   r  	  s"    0

F
zModel.train_on_batchc                 C   s   |    | d td |r&|   | j 6 t| j|||}|  | _	| 	|}W d   n1 sl0    Y  t
|}|r|S t|| jS dS )a?  Test the model on a single batch of samples.

        Args:
            x: Input data. It could be:
              - A Numpy array (or array-like), or a list of arrays (in case the
                  model has multiple inputs).
              - A TensorFlow tensor, or a list of tensors (in case the model has
                  multiple inputs).
              - A dict mapping input names to the corresponding array/tensors,
                  if the model has named inputs.
            y: Target data. Like the input data `x`, it could be either Numpy
              array(s) or TensorFlow tensor(s). It should be consistent with `x`
              (you cannot have Numpy inputs and tensor targets, or inversely).
            sample_weight: Optional array of the same length as x, containing
              weights to apply to the model's loss for each sample. In the case
              of temporal data, you can pass a 2D array with shape (samples,
              sequence_length), to apply a different weight to every timestep of
              every sample.
            reset_metrics: If `True`, the metrics returned will be only for this
              batch. If `False`, the metrics will be statefully accumulated
              across batches.
            return_dict: If `True`, loss and metric results are returned as a
              dict, with each key being the name of the metric. If `False`, they
              are returned as a list.

        Returns:
            Scalar test loss (if the model has a single output and no metrics)
            or list of scalars (if the model has multiple outputs
            and/or metrics). The attribute `model.metrics_names` will give you
            the display labels for the scalar outputs.

        Raises:
            RuntimeError: If `model.test_on_batch` is wrapped in a
              `tf.function`.
        test_on_batchN)rb  rc  rd  ru  r   r   r	   r  r  r   r   r  r  r   )rq   r   r  r  ru  r[  r*  r`  r3   r3   r4   r  U	  s    +


(
zModel.test_on_batchc                 C   sh   |  d td | j 2 t| j|}|  | _| |}W d   n1 sT0    Y  t	|S )a  Returns predictions for a single batch of samples.

        Args:
            x: Input data. It could be:
              - A Numpy array (or array-like), or a list of arrays (in case the
                  model has multiple inputs).
              - A TensorFlow tensor, or a list of tensors (in case the model has
                  multiple inputs).

        Returns:
            Numpy array(s) of predictions.

        Raises:
            RuntimeError: If `model.predict_on_batch` is wrapped in a
              `tf.function`.
        predict_on_batchN)
rc  rd  r   r   r	   r  r  r   r   r  )rq   r   r*  r7   r3   r3   r4   r  	  s    

(zModel.predict_on_batchc                 C   s4   t jddd | j|||||||||	|
||||dS )zFits the model on data yielded batch-by-batch by a Python generator.

        DEPRECATED:
          `Model.fit` now supports generators, so there is no longer any need to
          use this endpoint.
        z`Model.fit_generator` is deprecated and will be removed in a future version. Please use `Model.fit`, which supports generators.r   r  )rI  rK  rT  r   r  r  r  rM  rN  rO  rP  rL  rJ  )r  r  rF  )rq   	generatorrI  rK  rT  r   r  r  r  rM  rN  rO  rP  rL  rJ  r3   r3   r4   fit_generator	  s(    zModel.fit_generatorc              	   C   s0   t jddd | d | j|||||||dS )zEvaluates the model on a data generator.

        DEPRECATED:
          `Model.evaluate` now supports generators, so there is no longer any
          need to use this endpoint.
        z`Model.evaluate_generator` is deprecated and will be removed in a future version. Please use `Model.evaluate`, which supports generators.r   r  evaluate_generatorrU  rN  rO  rP  rT  r   )r  r  rc  r  rq   r  rU  r   rN  rO  rP  rT  r3   r3   r4   r  	  s    
zModel.evaluate_generatorc              	   C   s&   t jddd | j|||||||dS )zGenerates predictions for the input samples from a data generator.

        DEPRECATED:
          `Model.predict` now supports generators, so there is no longer any
          need to use this endpoint.
        z`Model.predict_generator` is deprecated and will be removed in a future version. Please use `Model.predict`, which supports generators.r   r  r  )r  r  r  r  r3   r3   r4   predict_generator	  s    zModel.predict_generatorc                 C   s@   |    | jsg S g }| jD ]}||j7 }q|| j7 }| |S r   )_assert_weights_created
_trainable_self_tracked_trackablesr
  _trainable_weights_dedup_weights)rq   r
  trackable_objr3   r3   r4   trainable_weights%
  s    

zModel.trainable_weightsc                 C   sl   |    g }| jD ]}||j7 }q| jsXg }| jD ]}||j7 }q2|| j | | j }n
|| j }| |S r   )r  r  non_trainable_variablesr  r
  r  _non_trainable_weightsr  )rq   r  r  r
  r3   r3   r4   non_trainable_weights0
  s&    

zModel.non_trainable_weightsc                    s8   | j   t  W  d   S 1 s*0    Y  dS )zgRetrieves the weights of the model.

        Returns:
            A flat list of Numpy arrays.
        N)r   r   r,   get_weightsr   r1   r3   r4   r  J
  s    zModel.get_weightsc              
   C   s   t | ||||||| dS )a  Saves the model to Tensorflow SavedModel or a single HDF5 file.

        Please see `tf.keras.models.save_model` or the
        [Serialization and Saving guide](
        https://keras.io/guides/serialization_and_saving/)
        for details.

        Args:
            filepath: String, PathLike, path to SavedModel or H5 file to save
                the model.
            overwrite: Whether to silently overwrite any existing file at the
                target location, or provide the user with a manual prompt.
            include_optimizer: If True, save optimizer's state together.
            save_format: Either `'tf'` or `'h5'`, indicating whether to save the
                model to Tensorflow SavedModel or HDF5. Defaults to 'tf' in TF
                2.X, and 'h5' in TF 1.X.
            signatures: Signatures to save with the SavedModel. Applicable to
                the 'tf' format only. Please see the `signatures` argument in
                `tf.saved_model.save` for details.
            options: (only applies to SavedModel format)
                `tf.saved_model.SaveOptions` object that specifies options for
                saving to SavedModel.
            save_traces: (only applies to SavedModel format) When enabled, the
                SavedModel will store the function traces for each layer. This
                can be disabled, so that only the configs of each layer are
                stored.  Defaults to `True`. Disabling this will decrease
                serialization time and reduce file size, but it requires that
                all custom layers/models implement a `get_config()` method.

        Example:

        ```python
        from keras.models import load_model

        model.save('my_model.h5')  # creates a HDF5 file 'my_model.h5'
        del model  # deletes the existing model

        # returns a compiled model
        # identical to the previous one
        model = load_model('my_model.h5')
        ```
        N)r   
save_model)rq   filepath	overwriteinclude_optimizersave_format
signaturesr  save_tracesr3   r3   r4   r   S
  s    7z
Model.savec           
      C   sd  |    t|}t|}|du r4|r.d}qld}n8|  }|dv rNd}n|dv r\d}ntd| d|dkr|rtd| d	|dkrtdu rt	d
|dkr|d }n|}|st
j|rt|}|sdS |dkrt|d}	t|	|  W d   n1 s0    Y  nBt s0t  | jj||d tjjjt
j||d|gd dS )a%  Saves all layer weights.

        Either saves in HDF5 or in TensorFlow format based on the `save_format`
        argument.

        When saving in HDF5 format, the weight file has:
          - `layer_names` (attribute), a list of strings
              (ordered names of model layers).
          - For every layer, a `group` named `layer.name`
              - For every such layer group, a group attribute `weight_names`,
                  a list of strings
                  (ordered names of weights tensor of the layer).
              - For every weight in the layer, a dataset
                  storing the weight value, named after the weight tensor.

        When saving in TensorFlow format, all objects referenced by the network
        are saved in the same format as `tf.train.Checkpoint`, including any
        `Layer` instances or `Optimizer` instances assigned to object
        attributes. For networks constructed from inputs and outputs using
        `tf.keras.Model(inputs, outputs)`, `Layer` instances used by the network
        are tracked/saved automatically. For user-defined classes which inherit
        from `tf.keras.Model`, `Layer` instances must be assigned to object
        attributes, typically in the constructor. See the documentation of
        `tf.train.Checkpoint` and `tf.keras.Model` for details.

        While the formats are the same, do not mix `save_weights` and
        `tf.train.Checkpoint`. Checkpoints saved by `Model.save_weights` should
        be loaded using `Model.load_weights`. Checkpoints saved using
        `tf.train.Checkpoint.save` should be restored using the corresponding
        `tf.train.Checkpoint.restore`. Prefer `tf.train.Checkpoint` over
        `save_weights` for training checkpoints.

        The TensorFlow format matches objects and variables by starting at a
        root object, `self` for `save_weights`, and greedily matching attribute
        names. For `Model.save` this is the `Model`, and for `Checkpoint.save`
        this is the `Checkpoint` even if the `Checkpoint` has a model attached.
        This means saving a `tf.keras.Model` using `save_weights` and loading
        into a `tf.train.Checkpoint` with a `Model` attached (or vice versa)
        will not match the `Model`'s variables. See the
        [guide to training checkpoints](
        https://www.tensorflow.org/guide/checkpoint) for details on
        the TensorFlow format.

        Args:
            filepath: String or PathLike, path to the file to save the weights
                to. When saving in TensorFlow format, this is the prefix used
                for checkpoint files (multiple files are generated). Note that
                the '.h5' suffix causes weights to be saved in HDF5 format.
            overwrite: Whether to silently overwrite any existing file at the
                target location, or provide the user with a manual prompt.
            save_format: Either 'tf' or 'h5'. A `filepath` ending in '.h5' or
                '.keras' will default to HDF5 if `save_format` is `None`.
                Otherwise `None` defaults to 'tf'.
            options: Optional `tf.train.CheckpointOptions` object that specifies
                options for saving weights.

        Raises:
            ImportError: If `h5py` is not available when attempting to save in
                HDF5 format.
        Nh5r[   )
tensorflowr[   )hdf5r  kerasz(Unknown format. Received: `save_format`=z$. Was expecting one of {"tf", "h5"}.zBsave_weights got save_format="tf"/"tensorflow", but the filepath (zT) looks like an HDF5 file. Omit the ".h5"/".keras" when saving in TensorFlow format.zi`save_weights` requires h5py when saving in hdf5, but h5py is not available. Try installing h5py package.z.indexw)r  T)save_dirmodel_checkpoint_pathsave_relative_pathsall_model_checkpoint_paths)r  r   path_to_stringr   is_hdf5_filepathlowerstripr   h5pyImportErrorospathisfileask_to_proceed_with_overwriteFiler   save_weights_to_hdf5_groupr[   r   r   get_sessionrj   writer   rf   update_checkpoint_statedirname)
rq   r  r  r  r  filepath_is_h5user_formatcheck_filepathproceedfr3   r3   r4   save_weights
  sX    @





.

zModel.save_weightsc                 C   sZ  t | jr<| jjjdkr<t|s<| jjj}td| |rL|sLtdt|\}}|dkr| j	
||}|rztdt st  }tjjj||d |  nd}tdu rtd| js| jstd	|   t|d
L}	d|	jvrd|	v r|	d }	|rt|	| | nt|	|  W d   n1 s60    Y  | jD ]}
|
  qF|S )am
  Loads all layer weights, either from a TensorFlow or an HDF5 weight file.

        If `by_name` is False weights are loaded based on the network's
        topology. This means the architecture should be the same as when the
        weights were saved.  Note that layers that don't have weights are not
        taken into account in the topological ordering, so adding or removing
        layers is fine as long as they don't have weights.

        If `by_name` is True, weights are loaded into layers only if they share
        the same name. This is useful for fine-tuning or transfer-learning
        models where some of the layers have changed.

        Only topological loading (`by_name=False`) is supported when loading
        weights from the TensorFlow format. Note that topological loading
        differs slightly between TensorFlow and HDF5 formats for user-defined
        classes inheriting from `tf.keras.Model`: HDF5 loads based on a
        flattened list of weights, while the TensorFlow format loads based on
        the object-local names of attributes to which layers are assigned in the
        `Model`'s constructor.

        Args:
            filepath: String, path to the weights file to load. For weight files
                in TensorFlow format, this is the file prefix (the same as was
                passed to `save_weights`). This can also be a path to a
                SavedModel saved from `model.save`.
            by_name: Boolean, whether to load weights by name or by topological
                order. Only topological loading is supported for weight files in
                TensorFlow format.
            skip_mismatch: Boolean, whether to skip loading of layers where
                there is a mismatch in the number of weights, or a mismatch in
                the shape of the weight (only valid when `by_name=True`).
            options: Optional `tf.train.CheckpointOptions` object that specifies
                options for loading weights.

        Returns:
            When loading a weight file in TensorFlow format, returns the same
            status object as `tf.train.Checkpoint.restore`. When graph building,
            restore ops are run automatically as soon as the network is built
            (on first call for user-defined classes inheriting from `Model`,
            immediately if it is already built).

            When loading weights in HDF5 format, returns `None`.

        Raises:
            ImportError: If `h5py` is not available and the weight file is in
              HDF5 format.
            ValueError: If `skip_mismatch` is set to `True` when `by_name` is
              `False`.
        r   zmLoad weights is not implemented with TPUStrategy with `steps_per_run` greater than 1. The `steps_per_run` is z\When calling model.load_weights, skip_mismatch can only be set to True when by_name is True.r[   zWeights may only be loaded based on topology into Models when loading TensorFlow-formatted weights (got by_name=True to load_weights).)statussessionNzY`load_weights` requires h5py package when loading weights from HDF5. Try installing h5py.zUnable to load weights saved in HDF5 format into a subclassed Model which has not created its variables yet. Call the Model first, then load the weights.rlayer_namesmodel_weights)r   is_tpu_strategyr_   extendedsteps_per_runr   r  r   _detect_save_formatrj   readr   r[   r   r  r   trackingstreaming_restoreassert_nontrivial_matchr  r  rR   r   r  r   attrsr   $load_weights_from_hdf5_group_by_nameload_weights_from_hdf5_grouplayersfinalize_state)rq   r  by_nameskip_mismatchr  Zsprr  r  r  r
  layerr3   r3   r4   load_weights  s`    5

,
zModel.load_weightsc                 C   s.   ddl m} |  }| jj||t d}|S )zUtil shared between different serialization methods.

        Returns:
            Model config with Keras version information added.
        r   )__version__)
class_namer   keras_versionr   )r  r"  
get_configr2   __name__r   )rq   r$  r   model_configr3   r3   r4   _updated_config  s    zModel._updated_configc                 C   sJ   i }t jrF| jr t | j|d< | jr6t | j|d< | jrF| j|d< |S )a  Returns the config of the `Model`.

        Config is a Python dictionary (serializable) containing the
        configuration of an object, which in this case is a `Model`. This allows
        the `Model` to be be reinstantiated later (without its trained weights)
        from this configuration.

        Note that `get_config()` does not guarantee to return a fresh copy of
        dict every time it is called. The callers should make a copy of the
        returned dict if they want to modify it.

        Developers of subclassed `Model` are advised to override this method,
        and continue to update the dict from `super(MyModel, self).get_config()`
        to provide the proper configuration of this `Model`. The default config
        is an empty dict. Optionally, raise `NotImplementedError` to allow Keras
        to attempt a default serialization.

        Returns:
            Python dictionary containing the configuration of this `Model`.
        r   r   r   )r   _ENABLEDr   serialize_keras_objectrW   r   _build_input_shape)rq   r   r3   r3   r4   r%    s    
zModel.get_configc                    s`  d\}}  di }|r"t|}  di }|r<t|}  di }ddlm} t  g d}	t fdd	|	D r| |\}
}}| |
| 	d
d}|
|| nVz| f i  }W nB ty } z(td|  d| j d| W Y d }~n
d }~0 0 tjr8|s|r(|j||d |r8|| |W  d    S 1 sR0    Y  d S )N)NNr   r   r   r   r&   )r8   r  input_layersoutput_layersc                 3   s   | ]}| v V  qd S r   r3   )r;   keyr   r3   r4   r     r   z$Model.from_config.<locals>.<genexpr>r8   )r6   r7   r8   zUnable to revive model from config. When overriding the `get_config()`, make sure that the returned config contains all items used as arguments in the constructor to z, which is the default behavior. You can override this default behavior by defining a `from_config` method to specify how to create an instance of z> from the config. 

Error encountered during deserialization:
)r   r   )r   r   deserialize_keras_objectr*   r'   r   SharedObjectLoadingScoper   reconstruct_from_configr   connect_ancillary_layersrO   r&  r)  r   r   )r.   r   custom_objectsr   r   Zoptimizer_dict	loss_dictr   r'   Zfunctional_model_keysr6   r7   r  r5   r   r3   r/  r4   from_config  sJ    



	
zModel.from_configc                 K   s    |   }tj|fdtji|S )ab  Returns a JSON string containing the network configuration.

        To load a network from a JSON save file, use
        `keras.models.model_from_json(json_string, custom_objects={})`.

        Args:
            **kwargs: Additional keyword arguments to be passed to
                *`json.dumps()`.

        Returns:
            A JSON string.
        default)r(  jsondumpsr   get_json_type)rq   r0   r'  r3   r3   r4   to_json  s    zModel.to_jsonc                 K   s   t ddS )a  Returns a yaml string containing the network configuration.

        Note: Since TF 2.6, this method is no longer supported and will raise a
        RuntimeError.

        To load a network from a yaml save file, use
        `keras.models.model_from_yaml(yaml_string, custom_objects={})`.

        `custom_objects` should be a dictionary mapping
        the names of custom losses / layers / etc to the corresponding
        functions / classes.

        Args:
            **kwargs: Additional keyword arguments
                to be passed to `yaml.dump()`.

        Returns:
            A YAML string.

        Raises:
            RuntimeError: announces that the method poses a security risk
        zMethod `model.to_yaml()` has been removed due to security risk of arbitrary code execution. Please use `model.to_json()` instead.N)r   )rq   r0   r3   r3   r4   to_yaml  s    zModel.to_yamlc                 C   s.   | j D ]"}t|drt|ddr|  qd S )Nreset_statesstatefulF)r  hasattrr   r=  )rq   r   r3   r3   r4   r=  /  s
    
zModel.reset_statesc                 C   sB   t jddd g }| jD ]$}t|ddrt|dr||j7 }q|S )a9  Deprecated, do NOT use!

        Returns the `updates` from all layers that are stateful.

        This is useful for separating training updates and
        state updates, e.g. when we need to update a layer's internal state
        during prediction.

        Returns:
            A list of update ops.
        z`Model.state_updates` will be removed in a future version. This property should not be used in TensorFlow 2.0, as `updates` are applied automatically.r   r  r>  Fupdates)r  r  r  r   r?  r@  )rq   state_updatesr   r3   r3   r4   rA  6  s    

zModel.state_updatesc                 C   s   |  | jS )zReturns the list of all layer variables/weights.

        Note: This will not track the weights of nested `tf.Modules` that are
        not themselves Keras layers.

        Returns:
          A list of variables.
        )r  _undeduplicated_weightsr   r3   r3   r4   weightsQ  s    
zModel.weightsc                 C   s6   |    g }| jD ]}||j7 }q|| j| j 7 }|S )z?Returns the undeduplicated list of all layer variables/weights.)r  r  	variablesr  r  )rq   rC  r   r3   r3   r4   rB  ]  s    
zModel._undeduplicated_weightsc              	   C   s*   | j stdtj| ||||||d dS )a  Prints a string summary of the network.

        Args:
            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. Defaults to `print`.
                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.
            expand_nested: Whether to expand the nested models.
                If not provided, defaults to `False`.
            show_trainable: Whether to show if a layer is trainable.
                If not provided, defaults to `False`.
            layer_range: a list or tuple of 2 strings,
                which is the starting layer name and ending layer name
                (both inclusive) indicating the range of layers to be printed
                in summary. It also accepts regex patterns instead of exact
                name. In such case, start predicate will be the first element
                it matches to `layer_range[0]` and the end predicate will be
                the last element it matches to `layer_range[1]`.
                By default `None` which considers all layers of model.

        Raises:
            ValueError: if `summary()` is called before the model is built.
        zyThis model has not yet been built. Build the model first by calling `build()` or by calling the model on a batch of data.)line_length	positionsprint_fnexpand_nestedshow_trainablelayer_rangeN)r   r   r   print_summary)rq   rE  rF  rG  rH  rI  rJ  r3   r3   r4   summaryg  s    &zModel.summaryc                 C   s   t | jdddS )NF)include_self	recursive)r   r   r   r3   r3   r4   r    s    zModel.layersc                 C   s   t dd S )NzU`Model.layers` attribute is reserved and should not be used. Please use another name.)r   )rq   r:  r3   r3   r4   r    s    c                 C   s   |dur&|dur&t d| d| d|durdt| j|krZt d| dt| j dn
| j| S |dur| jD ]}|j|krr|  S qrt d| d	td
d | jD  dt ddS )ax  Retrieves a layer based on either its name (unique) or index.

        If `name` and `index` are both provided, `index` will take precedence.
        Indices are based on order of horizontal graph traversal (bottom-up).

        Args:
            name: String, name of layer.
            index: Integer, index of layer.

        Returns:
            A layer instance.
        Nz<Provide only a layer name or a layer index. Received: index=z, name=r   z%Was asked to retrieve layer at index z but model only has z layers.zNo such layer: z. Existing layers are: c                 s   s   | ]}|j V  qd S r   r   )r;   r   r3   r3   r4   r     r   z"Model.get_layer.<locals>.<genexpr>z:Provide either a layer name or layer index at `get_layer`.)r   r   r  r8   r   )rq   r8   indexr   r3   r3   r4   	get_layer  s8    



zModel.get_layerc                 C   sX   i }t jj|  \}}|D ]4}t|t jr|| }ddd |D }|||< q|S )a  Retrieve all the variables and their paths for the model.

        The variable path (string) is a stable key to indentify a `tf.Variable`
        instance owned by the model. It can be used to specify variable-specific
        configurations (e.g. DTensor, quantization) from a global view.

        This method returns a dict with weight object paths as keys
        and the corresponding `tf.Variable` instances as values.

        Note that if the model is a subclassed model and the weights haven't
        been initialized, an empty dict will be returned.

        Returns:
            A dict where keys are variable paths and values are `tf.Variable`
             instances.

        Example:

        ```python
        class SubclassModel(tf.keras.Model):

          def __init__(self, name=None):
            super().__init__(name=name)
            self.d1 = tf.keras.layers.Dense(10)
            self.d2 = tf.keras.layers.Dense(20)

          def call(self, inputs):
            x = self.d1(inputs)
            return self.d2(x)

        model = SubclassModel()
        model(tf.zeros((10, 10)))
        weight_paths = model.get_weight_paths()
        # weight_paths:
        # {
        #    'd1.kernel': model.d1.kernel,
        #    'd1.bias': model.d1.bias,
        #    'd2.kernel': model.d2.kernel,
        #    'd2.bias': model.d2.bias,
        # }

        # Functional model
        inputs = tf.keras.Input((10,), batch_size=10)
        x = tf.keras.layers.Dense(20, name='d1')(inputs)
        output = tf.keras.layers.Dense(30, name='d2')(x)
        model = tf.keras.Model(inputs, output)
        d1 = model.layers[1]
        d2 = model.layers[2]
        weight_paths = model.get_weight_paths()
        # weight_paths:
        # {
        #    'd1.kernel': d1.kernel,
        #    'd1.bias': d1.bias,
        #    'd2.kernel': d2.kernel,
        #    'd2.bias': d2.bias,
        # }
        ```
        r   c                 S   s   g | ]
}|j qS r3   r   )r;   r  r3   r3   r4   r     r   z*Model.get_weight_paths.<locals>.<listcomp>)r[   r   r  ObjectGraphViewbreadth_first_traversalrI   r|   join)rq   r  descendantsobject_paths_dict
descendanttrackable_referencesobject_pathr3   r3   r4   get_weight_paths  s    ;
zModel.get_weight_pathsc           	         s   | j durdS |pg }|pi }| j}|s2t|}tj|}g }t||D ]\}}|t	j
|d|d qLtj||}t ||| | jjdkr| jdu rtjdd || _dS )aQ  Defines the save spec so that serialization is able to trace model call.

        The TensorSpecs of the call function `inputs`, `args`, and `kwargs` are
        saved into a tuple of `([inputs] + args, kwargs)`. The input
        `TensorSpec` names are updated to match the built `input_names`.

        The specs can be retrieved with the `save_spec` property.

        Args:
          inputs: possibly nested inputs passed into the call function.
          args: a list of positional arguments passed into call.
          kwargs: a dictionary of keyword arguments passed into call.
        NF)r  r8   
Sequentialc                 S   s   | d u rd S | j S r   )r   r   r3   r3   r4   r5  C  r   z&Model._set_save_spec.<locals>.<lambda>)rd   rS   r   create_pseudo_input_namesr[   r   r   ziprN   r   r  pack_sequence_asr,   _set_save_specr2   r&  r+  r   )	rq   r6   r/   r0   rS   flat_inputsinputs_specr8   tensorr1   r3   r4   r^    s,    


zModel._set_save_specc                 C   s   | j |ddS )aN  Returns the `tf.TensorSpec` of call inputs as a tuple `(args, kwargs)`.

        This value is automatically defined after calling the model for the
        first time. Afterwards, you can use it when exporting the model for
        serving:

        ```python
        model = tf.keras.Model(...)

        @tf.function
        def serve(*args, **kwargs):
          outputs = model(*args, **kwargs)
          # Apply postprocessing steps, or add additional outputs.
          ...
          return outputs

        # arg_specs is `[tf.TensorSpec(...), ...]`. kwarg_specs, in this
        # example, is an empty dict since functional models do not use keyword
        # arguments.
        arg_specs, kwarg_specs = model.save_spec()

        model.save(path, signatures={
          'serving_default': serve.get_concrete_function(*arg_specs,
                                                         **kwarg_specs)
        })
        ```

        Args:
          dynamic_batch: Whether to set the batch sizes of all the returned
            `tf.TensorSpec` to `None`. (Note that when defining functional or
            Sequential models with `tf.keras.Input([...], batch_size=X)`, the
            batch size will always be preserved). Defaults to `True`.
        Returns:
          If the model inputs are defined, returns a tuple `(args, kwargs)`. All
          elements in `args` and `kwargs` are `tf.TensorSpec`.
          If the model inputs are not defined, returns `None`.
          The model inputs are automatically set when calling the model,
          `model.fit`, `model.evaluate` or `model.predict`.
        F)inputs_only)_get_save_spec)rq   r  r3   r3   r4   	save_specF  s    (zModel.save_specc                 C   s<   | j r
dS d| jjv r8| jtkr8| js8td| j ddS )a  Asserts that all the weights for the model have been created.

        For a non-dynamic model, the weights must already be created after the
        layer has been called. For a dynamic model, the exact list of weights
        can never be known for certain since it may change at any time during
        execution.

        We run this check right before accessing weights or getting the Numpy
        value for the current weights. Otherwise, if the layer has never been
        called, the user would just get an empty list, which is misleading.

        Raises:
          ValueError: if the weights of the network have not yet been created.
        Nr   zWeights for model z have not yet been created. Weights are created when the Model is first called on inputs or `build()` is called with an `input_shape`.)rB   r2   __dict__r!   r   r   r8   r   r3   r3   r4   r  p  s    
	zModel._assert_weights_createdc                 C   sp   | j j}|jr&|jdt|j  }n|j}d|v r>|d t|dkrl|dd }td| d| ddS )z0Check that `call()` has only one positional arg.Nr   r   zModels passed to `z^` can only have `training` and the first argument in `call()` as positional arguments, found: r   )r   r   r   r/   r   remover   )rq   method_namefullargspecpositional_args
extra_argsr3   r3   r4   rc    s    
zModel._check_call_argsc                 K   s  t dd tj|D r*td| d|dd |dd |dd}|durftd	| d
|dd}|durtd| d
t|dh }|rtd|f d| jrtj	
 rtj	 }| jD ]&}|j|std| d| dq| j}tj|D ]>}	t|	dg D ]*}|j|std|	 d| dqqtj|D ]>}
t|
dg D ]*}|j|sdtd| d| dqdqTdS )z7Performs validation checks for the default `compile()`.c                 s   s   | ]}t |tjV  qd S r   )rI   r   r  )r;   r   r3   r3   r4   r     s   z*Model._validate_compile.<locals>.<genexpr>z `tf.compat.v1.keras` Optimizer (zs) is not supported when eager execution is enabled. Use a `tf.keras` Optimizer instead, or disable eager execution.cloningNexperimental_run_tf_functionr\   z}`distribute` argument in compile is not available in TF 2.0. Please create the model under the `strategy.scope()`. Received: r   target_tensorszM`target_tensors` argument is not supported when executing eagerly. Received: sample_weight_modez,Invalid keyword argument(s) in `compile()`: z. Valid keyword arguments include "cloning", "experimental_run_tf_function", "distribute", "target_tensors", or "sample_weight_mode".z
Variable (z9) was not created in the distribution strategy scope of (z). It is most likely because some layers, model, or optimizer was being created outside the distribution strategy scope. Try to make sure your code looks similar to the following.
with strategy.scope():
  model=_create_model()
  model.compile(...)rD  zMetric (z) passed to `model.compile` was created inside a different distribution strategy scope than the model. All metrics must be created in the same distribution strategy scope as the model (in this case z). If you pass in a string identifier for a metric to compile, the metric will automatically be created in the correct distribution strategy scope._weightszOptimizer (z) passed to `model.compile` was created inside a different distribution strategy scope than the model. All optimizers must be created in the same distribution strategy scope as the model (in this case z). If you pass in a string identifier for an optimizer to compile, the optimizer will automatically be created in the correct distribution strategy scope.)anyr[   r   r   r   r   rH   rO   r   r\   r]   r^   rD  r  variable_created_in_scoper   r   )rq   r   r   r0   Zdistribute_argZtarget_tensor_arginvalid_kwargsstrategyr   r  r   r3   r3   r4   r     sn    



zModel._validate_compilec                 C   s*   d}| j dur"| j j||tjdS ||fS )a  Maybe load initial epoch from ckpt considering possible worker recovery.

        Refer to tensorflow/python/keras/distribute/worker_training_state.py
        for more information.

        Args:
          steps_per_epoch: The number of step per epoch.
          initial_epoch: The original initial_epoch user passes in `fit()`.
          mode: The mode for running `model.fit()`.

        Returns:
          If the training is recovering from previous failure under multi-worker
          training setting, return the (epoch, step) the training is supposed to
          continue at. Otherwise, return the `initial_epoch, initial_step` the
          user passes in.
        r   N)mode)rc   Z%maybe_load_initial_counters_from_ckptr   TRAIN)rq   rI  rJ  Zinitial_stepr3   r3   r4   rr    s    
z,Model._maybe_load_initial_counters_from_ckptc                 C   s"   t | dddkr| j d S dS )N_callback_stepr   r   )r   rv  r>  r   r3   r3   r4   rx    s    z(Model._maybe_load_initial_step_from_ckptc                 C   s   | j stdd S )NzZYou must compile your model before training/testing. Use `model.compile(optimizer, loss)`.)rC   r   r   r3   r3   r4   rb    s    z Model._assert_compile_was_calledc                 C   sN   |d up.t |tjjo.t |jto.t|jdk}|rJ| jjd u rJt	
d d S )N   a  `evaluate()` received a value for `sample_weight`, but `weighted_metrics` were not provided.  Did you mean to pass metrics to `weighted_metrics` in `compile()`?  If this is intentional you can pass `weighted_metrics=[]` to `compile()` in order to silence this warning.)rI   r[   r  r  element_specr   r   rX   _user_weighted_metricsr   r   )rq   r   r  Zsample_weight_presentr3   r3   r4   r  (  s    

z"Model._check_sample_weight_warningc                 C   s   |  | dS )zLThis method is for compat with Modelv1. Only inputs are needed
        here.N)r^  )rq   r6   r7   r   r3   r3   r4   _set_inputs=  s    zModel._set_inputsc                 C   s
   t | S r   )r   ModelSavedModelSaverr   r3   r3   r4   _trackable_saved_model_saverB  s    z"Model._trackable_saved_model_saver
checkpointc                    sp   |dkr8| j }| j}| j}| j}d | _ d | _d | _d | _t j|fi |}|dkrl|| _ || _|| _|| _|S )N
savedmodel)r   r   r   r   r,   _trackable_children)rq   	save_typer0   r   r   r   r   childrenr1   r3   r4   r  F  s     zModel._trackable_childrenc                 C   sN   |d }t |tr|| dkS t |tr0||v S td| dt| dd S )Nr   r   zJExpected `validation_freq` to be a list or int. Received: validation_freq=z of the type r   )rI   r   r   r   r   )rq   r  r  r3   r3   r4   r  \  s    

zModel._should_evalc                 C   sZ   |    | jj}| jj}|s<|dur,| jj}|dur<| jj}| j| jj||| jj	d}|S )a*  Used for saving or cloning a Model.

        Args:
          user_metrics: Whether to return user-supplied metrics or `Metric`
            objects. Defaults to returning the user-supplied metrics.

        Returns:
          Dictionary of arguments that were used when compiling the model.
        N)r   r   r   r   r   )
rb  rX   _user_metricsry  r   _weighted_metricsr   rW   _user_losses_user_loss_weights)rq   user_metricssaved_metricssaved_weighted_metricscompile_argsr3   r3   r4   _get_compile_argsm  s    
zModel._get_compile_argsc                 C   s   | S r   r3   r   r3   r3   r4   _get_callback_model  s    zModel._get_callback_modelc                 C   s   | j j S r   )r   r  r  r   r3   r3   r4   r    s    zModel._in_multi_worker_modec                 C   s   | j S r   )rC   r   r3   r3   r4   _compile_was_called  s    zModel._compile_was_calledc                 C   s   t | |S r   )r   r   )rq   dirpathr3   r3   r4   	_save_new  s    zModel._save_new)NN)r   NNNNNNN)NNNN)F)NNNr   rC  NrD  NTNNr   NNNr   rE  r   F)F)NNNrC  NNNrE  r   FF)F)NrC  NNrE  r   F)NNNTF)NNTF)Nr   r   NNNr   NrE  r   FTr   )NNrE  r   Fr   )NNrE  r   Fr   )TTNNNT)TNN)FFN)N)NNNFFN)NN)NN)T)NN)r}  )T)er&  
__module____qualname____doc__	frozenset	itertoolschainr   r   _TF_MODULE_IGNORED_PROPERTIESZ_SCALAR_UPRANKING_ONr-   r[   r   r   no_automatic_dependency_trackingr   filter_tracebackrK   rk   r   r   r   r   r   r7  r   r   r    doc_in_current_and_subclassesr   r   r   rb   r   propertyr   r   r   r   r   setterr  r  r  r  rB  rF  r  r  r  r  r  r  ru  r  r  r  do_not_generate_docsr  r  r  r  r  r  r   r  r!  r(  r%  classmethodr6  r;  r<  r=  rA  rC  rB  rL  r  rP  rY  r^  rd  r  rc  r   rr  rx  rb  r  rz  r|  r  r  r  r  r  r  r  __classcell__r3   r3   r1   r4   r!   E   s  g
 
~%          



1
'

'
!$
8/
o                      ,
l            8
[        _     
G    
=             .      "      %


	      A y r+B

      
6


+I)
*"V



r!   r!  c                    s    fdd}t j|| S )a  Attempt to reduce the structure `values` to single values.

    Given `values` (a `tf.Tensor` or a `PerReplica` structure),
    which represents the values across all the replicas, `reduce_per_replica`
    attempts to "reduce" those values and returns the corresponding structure
    that represents only single values.

    Currently, `reduce_per_replica` is only used for reducing the metric results
    from `tf.distribute.Strategy.run()`. Depending on the underlying
    `Strategy` implementation, `values` may be a `PerReplica` object,
     which can be thought of as a collection of values across the replicas,
    or a `tf.Tensor`, if the strategy has already conducted the reduction
    for the downstream library.

    There are three possible outcomes of reduction:

    1) if the `values` is a structure of simple `tf.Tensor`s, meaning that
       reduction is not actually needed, `reduce_per_replica` returns the
       structure as-is.
    2) else, if `reduction="first"`, then `reduce_per_replica`
       returns the values of the first replica. This is used in the case of
       training and evaluation, where `values` is expected to hold the same
       value across the replicas as a result of `Strategy`'s synchronization
       across the replicas.
       `reduce_per_replica` does not synchronize the values.
    3) else, if `reduction="concat"`, then `reduce_per_replica`
       returns the concatenation of the values across the replicas, along the
       axis of dimension 0. This is used in the inference case (`predict()`).

    Args:
      values: Structure of `PerReplica` objects or `tf.Tensor`s. `tf.Tensor`s
        are returned as-is.
      strategy: `tf.distribute.Strategy` object.
      reduction: One of `"first"`, `"concat"`.

    Returns:
      Structure of `Tensor`s, representing the result of reduction.

    Raises:
      ValueError: if the reduction method is not supported.
    c                    sz    dkrt rt| S t| s&| S  dkr<| d S  dkrftrVt| S t| S ntd  ddS )z$Reduce a single `PerReplica` object.r  r!  r   z=`reduction` must be "first" or "concat". Received: reduction=r   N)#_collective_all_reduce_multi_worker_multi_worker_concat_is_per_replica_instanceexperimental_local_resultsr  _tpu_multi_host_concatr  r   )r   r#  rs  r3   r4   _reduce  s"    


z#reduce_per_replica.<locals>._reducer   )valuesrs  r#  r  r3   r  r4   r(    s    +r(  c                 C   s.   t | d tjr tjj|| dS tj| |dS )zConcats `tensor`s along `axis`.r   axis	sp_inputsr  )rI   r[   SparseTensorsparser  )tensorsr  r3   r3   r4   r    s    r  c                 C   s  t | dkr| d S t| d tjr4tjjd| dS t| d tjrRtj| ddS tjj	 sltj| ddS t
dd | D }tjj||dd kdd}tj|  rtj| ddS |  ddd d	}|dkrd}n| d j| d }tjjd
d | D |dddS )a  Concats `Tensor`s along their first dimension.

    Args:
      tensors: List of `Tensor`s.

    Returns:
      Concatenation of the inputs along the first dimension -- of type `Tensor`
      if all input shapes are compatible, or `RaggedTensor` if not.
    r   r   r  r  c                 S   s   g | ]}t |d d qS )r   N)r[   r   r;   ra  r3   r3   r4   r     r   z-potentially_ragged_concat.<locals>.<listcomp>NFc                 S   s   g | ]}|  qS r3   )r>  r  r3   r3   r4   r   
  r   )inner_shape)r   rI   r[   r  r  r  RaggedTensorr   tf2enabledstackmath
reduce_allr>  r?  tolistrO  r   raggedconstant
merge_dims)r  Znon_batch_shapesZconstant_dimsZconstant_inner_dimensionsZconstant_inner_shaper3   r3   r4   r    s0    
r  c                 C   s>   | dkr|j rtd|  | dkr:|j s2t s6dS dS | S )z*Find the right verbosity value for 'auto'.r   ze`verbose=1` is not allowed with `ParameterServerStrategy` for performance reasons. Received: verbose=rC  r   )rg  r   r   is_interactive_logging_enabled)rT  r   r3   r3   r4   re    s    re  c                 C   s   t | o| jjdkS r  )r   r  r  	num_hostsrs  r3   r3   r4   r  "  s    r  c                 C   s>   | | }|jj}g }t|D ]}|||d| 7 }qt|S )z'Correctly order TPU PerReplica objects.N)r  r  num_replicas_per_hostr8  r  )r   rs  replicasr  ordered_replicas
replica_idr3   r3   r4   r  &  s    
r  c                 C   s   t | tjjo| j S r   )rI   r[   r\   MultiWorkerMirroredStrategyr  r  r  r3   r3   r4   r  5  s    r  c                 C   s   |j | dd}t| r@tjdd | jD dd}|j |dd}n"|j tjt| d dddd}tj|||jd}g }t	|j
j}t|D ]}|||d| 7 }qt|S )zDOrder PerReplica objects for CollectiveAllReduceStrategy and concat.r   r  c                 S   s$   g | ]}t jt |d  d dqS )r   r  )r[   expand_dimsr   )r;   single_valuer3   r3   r4   r   C  s   z(_multi_worker_concat.<locals>.<listcomp>)num_or_size_splitsnumN)gatherr  r[   r  r  r  r   splitnum_replicas_in_syncr   r  worker_devicesr8  )r   rs  r  shapes
all_shapesr  num_replicas_per_workerr  r3   r3   r4   r  =  s,    r  c                 C   s   t | tjtjfo| jjdkS )Nr   )rI   r[   r   r|   r   rankr   r3   r3   r4   
_is_scalar\  s    r  c                 C   s@   t  rg S t jj| dd} | D ]}t|t js |g  S q g S )zBReturns the minimum control dependencies to ensure step succeeded.T)expand_composites)r[   r   r   r   rI   r|   )r7   outr3   r3   r4   r  `  s    r  c                 C   s    t  rdj| d}t|d S )NaI  Detected a call to `Model.{method_name}` inside a `tf.function`. `Model.{method_name} is a high-level endpoint that manages its own `tf.function`. Please move the call to `Model.{method_name}` outside of all enclosing `tf.function`s. Note that you can call a `Model` directly on `Tensor`s inside a `tf.function` like: `model(x)`.)rg  )r[   inside_functionrP   r   )rg  	error_msgr3   r3   r4   rd  l  s    rd  c                 C   s|   t | } t| r| dfS t| r*d}nJtj| rptj	
| tjjtjj}t|r`|} d}qttd| nd}| |fS )z-Returns path to weights file and save format.r  r[   zUnable to load weights. filepath {} appears to be a SavedModel directory, but checkpoint either doesn't exist, or is incorrectly formatted.)r   r  r   r  _is_readable_tf_checkpointr[   saved_modelcontains_saved_modelr  r  rS  VARIABLES_DIRECTORYVARIABLES_FILENAMEr   rP   )r  r  	ckpt_pathr3   r3   r4   r  y  s*    

r  c                 C   s4   zt jjj|  W dS  t jjy.   Y dS 0 d S )NTF)r[   r  r  rf   NewCheckpointReaderr   DataLossError)r  r3   r3   r4   r    s
    r  c                 C   sd   g }|D ]}|| v r| | |  qt|  D ]}||vr0| | |  q0t|dkr`|d S |S )zFTurns the `logs` dict into a list as per key order of `metrics_names`.r   r   )rN   sortedr  r   )r`  r   resultsr8   r.  r3   r3   r4   r    s    r  c                 C   s   t | tjjot | tjjS r   )rI   r[   r\   DistributedValuesr   CompositeTensor)objr3   r3   r4   r    s    r  c                    s    fdd}t jjj |dS )z6Decorator that disallows multi-worker use of `method`.c                    s.   |   rt j d | g|R i |S )Nz is not supported in multi-worker mode. Please use a non-multi-worker `tf.distribute.Strategy` such as `tf.distribute.MirroredStrategy`.)r  r   r&  )rq   r/   r0   methodr3   r4   _method_wrapper  s
    
z-disable_multi_worker.<locals>._method_wrapper)targetdecorator_func)r[   r   	decoratormake_decorator)r  r  r3   r  r4   disable_multi_worker  s    
r  c                 C   s`   ddl m} ddl m} | tks*| |jkr0|jS | tkr<tS tdd | jD | _| |  | S )z?Inject `Functional` into the hierarchy of this class if needed.r   r&   )training_v1c                 s   s   | ]}t |V  qd S r   )rJ   )r;   baser3   r3   r4   r     s   z0inject_functional_model_class.<locals>.<genexpr>)	r*   r'   r  r!   r+   objectr   rL   r-   )r.   r'   r  r3   r3   r4   rJ     s    

rJ   c                 C   s0   t | dkp.t | dkr d|v p.d|v o.d|v S )Nr   r   r7   r6   )r   )r/   r0   r3   r3   r4   r)     s    r)   )r!  )r   )Xr  r   r  r8  r  r  rh   r>  r   tensorflow.compat.v2r  v2r[   r  r   r   rm  r   keras.dtensorr   rn   r*   r   r   r   r	   r
   r   r   keras.mixed_precisionr   r   Zkeras.optimizersr   'keras.optimizers.optimizer_experimentalr   r  Zkeras.savingr   r   r   r   keras.saving.experimentalr   keras.saving.saved_modelr   r   keras.utilsr   r   r   r   r   r   Zkeras.utils.mode_keysr   tensorflow.python.eagerr   tensorflow.python.platformr   r    tensorflow.python.util.tf_exportr   tensorflow.tools.docsr    r  r  r   ModelVersionSelectorr!   r(  r  r  re  r  r  r  r  r  r  rd  r  r  r  r  r  rJ   r)   r3   r3   r3   r4   <module>   s   
                            p
C
*"	