
    2Vh=                         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  ed      	 	 	 	 dd       Z	 ddZddZ	 ddZy)    )backend)tree)utils)keras_export)Input)
InputLayer)
Functional)functional_like_constructor)
Sequential)serialization_libzkeras.models.clone_modelNc                    |j                  dd      }|r%t        dt        |j                                      t	        | t
              rDt        ||||      }|%t        d| j                  j                   d|       t        | ||      S t	        | t              rAt        ||||      }t        j                  | j                        s|s|rt        | |||      S |s|r(t        d	| j                  j                   d
| d|       |%t        d| j                  j                   d|       t        j                   |       }t        j"                  || j                  j                  | j                  i      S )a  Clone a Functional or Sequential `Model` instance.

    Model cloning is similar to calling a model on new inputs,
    except that it creates new layers (and thus new weights) instead
    of sharing the weights of the existing layers.

    Note that
    `clone_model` will not preserve the uniqueness of shared objects within the
    model (e.g. a single variable attached to two distinct layers will be
    restored as two separate variables).

    Args:
        model: Instance of `Model`
            (could be a Functional model or a Sequential model).
        input_tensors: optional list of input tensors or InputLayer objects
            to build the model upon. If not provided,
            new `Input` objects will be created.
        clone_function: Callable with signature `fn(layer)`
            to be used to clone each layer in the target
            model (except `Input` instances). It takes as argument the
            layer instance to be cloned, and returns the corresponding layer
            instance to be used in the model copy. If unspecified, this callable
            defaults to the following serialization/deserialization function:
            `lambda layer: layer.__class__.from_config(layer.get_config())`.
            By passing a custom callable, you can customize your copy of the
            model, e.g. by wrapping certain layers of interest (you might want
            to replace all `LSTM` instances with equivalent
            `Bidirectional(LSTM(...))` instances, for example).
            Defaults to `None`.
        call_function: Callable with signature
            `fn(layer, *args, **kwargs)` to be used to call each
            cloned layer and a set of inputs. It takes the layer instance,
            the call arguments and keyword arguments, and returns the
            call outputs. If unspecified, this callable defaults to
            the regular `__call__()` method:
            `def fn(layer, *args, **kwargs): return layer(*args, **kwargs)`.
            By passing a custom callable, you can insert new layers before or
            after a given layer. Note: this argument can only be used with
            Functional models.
        recursive: Boolean. Whether to recursively clone any Sequential
            or Functional models encountered in the original
            Sequential/Functional model. If `False`,
            then inner models are cloned by calling `clone_function()`.
            If `True`, then inner models are cloned by calling `clone_model()`
            with the same `clone_function`, `call_function`, and `recursive`
            arguments. Note that in this case, `call_function`
            will not be propagated to any Sequential model
            (since it is not applicable to Sequential models).

    Returns:
        An instance of `Model` reproducing the behavior
        of the original model, on top of new inputs tensors,
        using newly instantiated weights. The cloned model may behave
        differently from the original model if a custom `clone_function`
        or `call_function` modifies a layer or layer call.

    Example:

    ```python
    # Create a test Sequential model.
    model = keras.Sequential([
        keras.layers.Input(shape=(728,)),
        keras.layers.Dense(32, activation='relu'),
        keras.layers.Dense(1, activation='sigmoid'),
    ])
    # Create a copy of the test model (with freshly initialized weights).
    new_model = clone_model(model)
    ```

    Using a `clone_function` to make a model deterministic by setting the
    random seed everywhere:

    ```python
    def clone_function(layer):
        config = layer.get_config()
        if "seed" in config:
            config["seed"] = 1337
        return layer.__class__.from_config(config)

    new_model = clone_model(model, clone_function=clone_function)
    ```

    Using a `call_function` to add a `Dropout` layer after each `Dense` layer
    (without recreating new layers):

    ```python
    def call_function(layer, *args, **kwargs):
        out = layer(*args, **kwargs)
        if isinstance(layer, keras.layers.Dense):
            out = keras.layers.Dropout(0.5)(out)
        return out

    new_model = clone_model(
        model,
        clone_function=lambda x: x,  # Reuse the same layers.
        call_function=call_function,
    )
    ```

    Note that subclassed models cannot be cloned by default,
    since their internal layer structure is not known.
    To achieve equivalent functionality
    as `clone_model` in the case of a subclassed model, simply make sure
    that the model class implements `get_config()`
    (and optionally `from_config()`), and call:

    ```python
    new_model = model.__class__.from_config(model.get_config())
    ```

    In the case of a subclassed model, you cannot using a custom
    `clone_function`.
    cacheNz Unexpected keyword argument(s): )call_function	recursiver   z`call_function` argument is not supported with Sequential models.  In a Sequential model, layers aren't called at model-construction time (they're merely listed). Use `call_function` with Functional models only. Received model of type 'z', with call_function=)clone_functioninput_tensors)r   r   r   zArguments `clone_function` and `input_tensors` are only supported for Sequential models or Functional models. Received model of type 'z', with clone_function=z and input_tensors=zZArgument `call_function` is only supported for Functional models. Received model of type ')custom_objects)pop
ValueErrortuplekeys
isinstancer   _wrap_clone_function	__class____name___clone_sequential_modelr	   r   
is_default
get_config_clone_functional_modelr   serialize_keras_objectdeserialize_keras_object)modelr   r   r   r   kwargsr   configs           H/home/dcms/DCMS/lib/python3.12/site-packages/keras/src/models/cloning.pyclone_modelr&      s   t JJw%E.uV[[]/C.DE
 	
 %$-'	
 $
 112 3!!/ 02  ')'
 	

 %$-'	
 E,,-m*-++	   __--. /,- .*O-
 	
  __--. /+,.
 	
 55e<F55 8 8%//J     c                 4      d }| i  fd}|S )z2Wrapper to handle recursiveness and layer sharing.c                 T    | j                   j                  | j                               S N)r   from_configr   )layers    r%   _clone_layerz*_wrap_clone_function.<locals>._clone_layer   s     ??..u/?/?/ABBr'   c                 (   t        |       v rt        |          S r]t        | t              rt        |       }|t        |       <   |S t        | t              rt        |       }|t        |       <   |S  |       }|t        |       <   |S )N)r   r   )r   r   r   )idr   r   r&   r	   )r,   cloner   r   r   r   s     r%   wrapped_clone_functionz4_wrap_clone_function.<locals>.wrapped_clone_function   s    e9E##%,##1
 $)bi E:.##1"/	 $)bi u% bir'    )r   r   r   r   r-   r1   s   ````  r%   r   r      s/     	C &}4 "!r'   c                    t        | t              st        d|        t        |      st        d|       | j                  D cg c]
  } ||       }}t        | j
                  d   t              r4| j
                  d   }|j                  }|j                  }|j                  }nd}d}d}|pt        |t        t        f      rt        |      dk7  rt        d      |d   }t        |t        j                        st        d|       t        ||      }	|	g|z   }n|t        |||	      }	|	g|z   }t        || j                  | j                   
      }
| j"                  r!| j%                         }|
j'                  |       |
S c c}w )a  Clone a `Sequential` model instance.

    Model cloning is similar to calling a model on new inputs,
    except that it creates new layers (and thus new weights) instead
    of sharing the weights of the existing layers.

    Args:
        model: Instance of `Sequential`.
        input_tensors: optional list of input tensors
            to build the model upon. If not provided,
            placeholders will be created.
        clone_function: callable to be applied on non-input layers in the model.
            By default, it clones the layer (without copying the weights).

    Returns:
        An instance of `Sequential` reproducing the behavior
        of the original model, on top of new inputs tensors,
        using newly instantiated weights.
    zOExpected `model` argument to be a `Sequential` model instance. Received: model=NExpected `clone_function` argument to be a callable. Received: clone_function=r   N   z6Argument `input_tensors` must contain a single tensor.zVArgument `input_tensors` must be a KerasTensor. Received invalid value: input_tensors=)tensornamebatch_shapedtyper7   )r7   	trainable)r   r   r   callablelayers_layersr   r7   r9   _dtypelistr   lenr   KerasTensorr   r;   compiledget_compile_configcompile_from_config)r"   r   r   r,   
new_layersref_input_layer
input_nameinput_batch_shapeinput_dtypeinputscloned_modelcompiled_configs               r%   r   r      s   * eZ($g'
 	
 N#((6'79
 	

 6;\\BE.'BJB%--"J/--*$))
+77%,,
  mdE]3=!Q& L  *!,M-)<)<=99FI   
 X
*
(-!F
 !J.JuL
 ~~224((9[ Cs   Fc                    t              st        d       t        | t              st        d|        |Ut	        d t        j                  |      D              st        d|       	 t        j                  || j                         n!t        j                  d | j                        }fd	}| j                  |||
      }t        | j                        r| j                  ||| j                        }nt        ||| j                        }| j                  r!| j                         }|j!                  |       |S # t        $ r!}t        d| j                   d|       |d}~ww xY w)a  Clone a `Functional` model instance.

    Model cloning is similar to calling a model on new inputs,
    except that it creates new layers (and thus new weights) instead
    of sharing the weights of the existing layers.

    Input layers are always cloned.

    Args:
        model: Instance of `Functional`.
        input_tensors: optional list of input tensors
            to build the model upon. If not provided,
            placeholders will be created.
        clone_function: callable to be applied on non-input layers in the model.
            By default, it clones the layer (without copying the weights).

    Returns:
        An instance of `Functional` reproducing the behavior
        of the original model, on top of new inputs tensors,
        using newly instantiated weights.
    r4   zMExpected `model` argument to be a Functional Model instance. Received: model=Nc              3   P   K   | ]  }t        |t        j                           y wr*   )r   r   rB   ).0xs     r%   	<genexpr>z*_clone_functional_model.<locals>.<genexpr>w  s%      
 q'--.
s   $&z]All entries in `input_tensors` must be KerasTensors. Received invalid values: inputs_tensors=zQ`input_tensors` must have the same structure as model.input
Reference structure: z
Received structure: c                 Z    t        | j                  | j                  | j                        S )Nr8   )r   shaper:   r7   )rQ   s    r%   <lambda>z)_clone_functional_model.<locals>.<lambda>  s    eqwwQVVL r'   c                      |       }|S r*   r2   )r,   	new_layerr   s     r%   operation_fnz-_clone_functional_model.<locals>.operation_fn  s    "5)	r'   )rX   call_fn)r7   )r<   r   r   r	   allr   flattenassert_same_structureinputmap_structure_run_through_graphr
   r   r7   rC   rD   rE   )	r"   r   r   r   erX   output_tensors	new_modelrM   s	    `       r%   r   r   Q  s   2 N#((6'79
 	

 eZ(BBGJ
 	

   
\\-0
 
 ;;H/K 	&&}ekkB **LKK

 --! . N #5??3OO>

 $ 
	 }n5::N	~~224%%o6E  	**/++(9 		s   / E 	E/E**E/)NNNF)NFNr*   )NN)	keras.srcr   r   r   keras.src.api_exportr   keras.src.layersr   r   keras.src.models.functionalr	   r
   keras.src.models.sequentialr   keras.src.savingr   r&   r   r   r   r2   r'   r%   <module>ri      sn       - " ' 2 C 2 . () C *CN @D("VOf >BRr'   