o
    2hD                     @   sj  d dl Z d dlZd dlmZ d dlmZ d dlmZ d dl	m
Z
 d dl	mZ d dl	mZ d dlmZ d d	lmZ d d
lmZ zd dlZd dlmZ d dlmZ d dlmZ d dlmZ W n' ey   dZG dd dZG dd dZG dd dZG dd dZY nw G dd deZedG dd deeZedG dd deeZedG d d! d!eeZdS )"    N)keras_export)clone_model)Model)_routing_enabled)_validate_data)type_of_target)TargetReshaper)_check_model)assert_sklearn_installed)BaseEstimator)ClassifierMixin)RegressorMixin)TransformerMixinc                   @      e Zd ZdS )r   N__name__
__module____qualname__ r   r   ]/var/www/html/chatgem/venv/lib/python3.10/site-packages/keras/src/wrappers/sklearn_wrapper.pyr          r   c                   @   r   )r   Nr   r   r   r   r   r      r   r   c                   @   r   )r   Nr   r   r   r   r   r      r   r   c                   @   r   )r   Nr   r   r   r   r   r   !   r   r   c                       s~   e Zd ZdZ			dddZdd Z fdd	Zd
d Zedd Z	dd Z
dd Zdd Zdd ZdddZdd Z  ZS )SKLBaseaT  Base class for scikit-learn wrappers.

    Note that there are sources of randomness in model initialization and
    training. Refer to [Reproducibility in Keras Models](
    https://keras.io/examples/keras_recipes/reproducibility_recipes/) on how to
    control randomness.

    Args:
        model: `Model`.
            An instance of `Model`, or a callable returning such an object.
            Note that if input is a `Model`, it will be cloned using
            `keras.models.clone_model` before being fitted, unless
            `warm_start=True`.
            The `Model` instance needs to be passed as already compiled.
            If callable, it must accept at least `X` and `y` as keyword
            arguments. Other arguments must be accepted if passed as
            `model_kwargs` by the user.
        warm_start: bool, defaults to `False`.
            Whether to reuse the model weights from the previous fit. If `True`,
            the given model won't be cloned and the weights from the previous
            fit will be reused.
        model_kwargs: dict, defaults to `None`.
            Keyword arguments passed to `model`, if `model` is callable.
        fit_kwargs: dict, defaults to `None`.
            Keyword arguments passed to `model.fit`. These can also be passed
            directly to the `fit` method of the scikit-learn wrapper. The
            values passed directly to the `fit` method take precedence over
            these.

    Attributes:
        model_ : `Model`
            The fitted model.
        history_ : dict
            The history of the fit, returned by `model.fit`.
    FNc                 C   s(   t | jj || _|| _|| _|| _d S N)r
   	__class__r   model
warm_startmodel_kwargs
fit_kwargs)selfr   r   r   r   r   r   r   __init__J   s
   
zSKLBase.__init__c                 C      ddiS )Nnon_deterministicTr   r   r   r   r   
_more_tagsW   s   zSKLBase._more_tagsc                    s   t   }d|_|S NT)super__sklearn_tags__r!   r   tagsr   r   r   r&   Z   s   
zSKLBase.__sklearn_tags__c                 C   s2   t | jr| jnt| j}t| || j| jdS )zeReturn a deep copy of the model.

        This is used by the `sklearn.base.clone` function.
        )r   r   r   )callabler   copydeepcopytyper   r   )r   r   r   r   r   __sklearn_clone___   s   zSKLBase.__sklearn_clone__c                 C   s   t | di ddS )zThe current training epoch.history_epochr   )getattrgetr"   r   r   r   epoch_m   s   zSKLBase.epoch_c                 K   sL   t  stdtjjj| jjd| _|	 D ]\}}| jj
j||d q| S )a  Set requested parameters by the fit method.

        Please see [scikit-learn's metadata routing](
        https://scikit-learn.org/stable/metadata_routing.html) for more
        details.


        Arguments:
            kwargs : dict
                Arguments should be of the form `param_name=alias`, and `alias`
                can be one of `{True, False, None, str}`.

        Returns:
            self
        zThis method is only available when metadata routing is enabled. You can enable it using sklearn.set_config(enable_metadata_routing=True).)owner)paramalias)r   RuntimeErrorsklearnutilsmetadata_routingMetadataRequestr   r   _metadata_requestitemsscoreadd_request)r   kwargsr5   r6   r   r   r   set_fit_requestr   s   zSKLBase.set_fit_requestc                 C   s6   t | jtrt| jS | jpi }| jd||d|S )N)Xyr   )
isinstancer   r   r   r   )r   rB   rC   argsr   r   r   
_get_model   s   

zSKLBase._get_modelc                 K   sf   t | ||\}}| j|dd}| ||}t| | jpi }|| |j||fi || _|| _| S )a%  Fit the model.

        Args:
            X: array-like, shape=(n_samples, n_features)
                The input samples.
            y: array-like, shape=(n_samples,) or (n_samples, n_outputs)
                The targets.
            **kwargs: keyword arguments passed to `model.fit`
        Treset)	r   _process_targetrF   r	   r   updatefitr/   model_)r   rB   rC   r@   r   r   r   r   r   rK      s   


zSKLBase.fitc                 C   s8   ddl m} ||  t| |dd}| j|}| |S )zPredict using the model.r   check_is_fittedFrG   )sklearn.utils.validationrN   r   rL   predict_reverse_process_target)r   rB   rN   
raw_outputr   r   r   rP      s
   
zSKLBase.predictc                 C   s*   t |dd |rt || _| j|S )z-Regressors are NOOP here, classifiers do OHE.Traise_unknown)r   r   rK   _target_encoder	transform)r   rC   rH   r   r   r   rI      s   zSKLBase._process_targetc                 C   s   | j |S )z2Regressors are NOOP here, classifiers reverse OHE.)rU   inverse_transform)r   rC   r   r   r   rQ      s   zSKLBase._reverse_process_target)FNNF)r   r   r   __doc__r   r#   r&   r.   propertyr3   rA   rF   rK   rP   rI   rQ   __classcell__r   r   r)   r   r   %   s"    '


	r   z keras.wrappers.SKLearnClassifierc                       s2   e Zd ZdZd	ddZdd Z fddZ  ZS )
SKLearnClassifiera  scikit-learn compatible classifier wrapper for Keras models.

    Note that there are sources of randomness in model initialization and
    training. Refer to [Reproducibility in Keras Models](
    https://keras.io/examples/keras_recipes/reproducibility_recipes/) on how to
    control randomness.

    Args:
        model: `Model`.
            An instance of `Model`, or a callable returning such an object.
            Note that if input is a `Model`, it will be cloned using
            `keras.models.clone_model` before being fitted, unless
            `warm_start=True`.
            The `Model` instance needs to be passed as already compiled.
            If callable, it must accept at least `X` and `y` as keyword
            arguments. Other arguments must be accepted if passed as
            `model_kwargs` by the user.
        warm_start: bool, defaults to `False`.
            Whether to reuse the model weights from the previous fit. If `True`,
            the given model won't be cloned and the weights from the previous
            fit will be reused.
        model_kwargs: dict, defaults to `None`.
            Keyword arguments passed to `model`, if `model` is callable.
        fit_kwargs: dict, defaults to `None`.
            Keyword arguments passed to `model.fit`. These can also be passed
            directly to the `fit` method of the scikit-learn wrapper. The
            values passed directly to the `fit` method take precedence over
            these.

    Attributes:
        model_ : `Model`
            The fitted model.
        history_ : dict
            The history of the fit, returned by `model.fit`.
        classes_ : array-like, shape=(n_classes,)
            The classes labels.

    Example:
    Here we use a function which creates a basic MLP model dynamically
    choosing the input and output shapes. We will use this to create our
    scikit-learn model.

    ``` python
    from keras.layers import Dense, Input
    from keras.models import Model

    def dynamic_model(X, y, loss, layers=[10]):
        # Creates a basic MLP model dynamically choosing the input and
        # output shapes.
        n_features_in = X.shape[1]
        inp = Input(shape=(n_features_in,))

        hidden = inp
        for layer_size in layers:
            hidden = Dense(layer_size, activation="relu")(hidden)

        n_outputs = y.shape[1] if len(y.shape) > 1 else 1
        out = Dense(n_outputs, activation="softmax")(hidden)
        model = Model(inp, out)
        model.compile(loss=loss, optimizer="rmsprop")

        return model
    ```

    You can then use this function to create a scikit-learn compatible model
    and fit it on some data.

    ``` python
    from sklearn.datasets import make_classification
    from keras.wrappers import SKLearnClassifier

    X, y = make_classification(n_samples=1000, n_features=10)
    est = SKLearnClassifier(
        model=dynamic_model,
        model_kwargs={
            "loss": "categorical_crossentropy",
            "layers": [20, 20, 20],
        },
    )

    est.fit(X, y, epochs=5)
    ```
    Fc                 C   sv   t |dd}|dvrtd| |r5tjt tjjdd|| _	t
|| _t| jdkr5td| j	|S )	zClassifiers do OHE.TrS   )binary
multiclasszDOnly binary and multiclass target types are supported. Target type: F)sparse_output   z6Classifier can't train when only one class is present.)r   
ValueErrorr8   pipelinemake_pipeliner   preprocessingOneHotEncoderrK   rU   npuniqueclasses_lenrV   )r   rC   rH   target_typer   r   r   rI     s(   z!SKLearnClassifier._process_targetc                 C   r    N
poor_scoreTr   r"   r   r   r   r#   -     zSKLearnClassifier._more_tagsc                       t   }d|j_|S r$   )r%   r&   classifier_tagsrl   r'   r)   r   r   r&   1     
z"SKLearnClassifier.__sklearn_tags__rX   )r   r   r   rY   rI   r#   r&   r[   r   r   r)   r   r\      s
    
Tr\   zkeras.wrappers.SKLearnRegressorc                       s(   e Zd ZdZdd Z fddZ  ZS )SKLearnRegressora4  scikit-learn compatible regressor wrapper for Keras models.

    Note that there are sources of randomness in model initialization and
    training. Refer to [Reproducibility in Keras Models](
    https://keras.io/examples/keras_recipes/reproducibility_recipes/) on how to
    control randomness.

    Args:
        model: `Model`.
            An instance of `Model`, or a callable returning such an object.
            Note that if input is a `Model`, it will be cloned using
            `keras.models.clone_model` before being fitted, unless
            `warm_start=True`.
            The `Model` instance needs to be passed as already compiled.
            If callable, it must accept at least `X` and `y` as keyword
            arguments. Other arguments must be accepted if passed as
            `model_kwargs` by the user.
        warm_start: bool, defaults to `False`.
            Whether to reuse the model weights from the previous fit. If `True`,
            the given model won't be cloned and the weights from the previous
            fit will be reused.
        model_kwargs: dict, defaults to `None`.
            Keyword arguments passed to `model`, if `model` is callable.
        fit_kwargs: dict, defaults to `None`.
            Keyword arguments passed to `model.fit`. These can also be passed
            directly to the `fit` method of the scikit-learn wrapper. The
            values passed directly to the `fit` method take precedence over
            these.

    Attributes:
        model_ : `Model`
            The fitted model.

    Example:
    Here we use a function which creates a basic MLP model dynamically
    choosing the input and output shapes. We will use this to create our
    scikit-learn model.

    ``` python
    from keras.layers import Dense, Input
    from keras.models import Model

    def dynamic_model(X, y, loss, layers=[10]):
        # Creates a basic MLP model dynamically choosing the input and
        # output shapes.
        n_features_in = X.shape[1]
        inp = Input(shape=(n_features_in,))

        hidden = inp
        for layer_size in layers:
            hidden = Dense(layer_size, activation="relu")(hidden)

        n_outputs = y.shape[1] if len(y.shape) > 1 else 1
        out = Dense(n_outputs)(hidden)
        model = Model(inp, out)
        model.compile(loss=loss, optimizer="rmsprop")

        return model
    ```

    You can then use this function to create a scikit-learn compatible model
    and fit it on some data.

    ``` python
    from sklearn.datasets import make_regression
    from keras.wrappers import SKLearnRegressor

    X, y = make_regression(n_samples=1000, n_features=10)
    est = SKLearnRegressor(
        model=dynamic_model,
        model_kwargs={
            "loss": "mse",
            "layers": [20, 20, 20],
        },
    )

    est.fit(X, y, epochs=5)
    ```
    c                 C   r    rk   r   r"   r   r   r   r#     rm   zSKLearnRegressor._more_tagsc                    rn   r$   )r%   r&   regressor_tagsrl   r'   r)   r   r   r&     rp   z!SKLearnRegressor.__sklearn_tags__)r   r   r   rY   r#   r&   r[   r   r   r)   r   rq   7  s    Prq   z!keras.wrappers.SKLearnTransformerc                       s0   e Zd ZdZdd Zdd Z fddZ  ZS )SKLearnTransformera
  scikit-learn compatible transformer wrapper for Keras models.

    Note that this is a scikit-learn compatible transformer, and not a
    transformer in the deep learning sense.

    Also note that there are sources of randomness in model initialization and
    training. Refer to [Reproducibility in Keras Models](
    https://keras.io/examples/keras_recipes/reproducibility_recipes/) on how to
    control randomness.

    Args:
        model: `Model`.
            An instance of `Model`, or a callable returning such an object.
            Note that if input is a `Model`, it will be cloned using
            `keras.models.clone_model` before being fitted, unless
            `warm_start=True`.
            The `Model` instance needs to be passed as already compiled.
            If callable, it must accept at least `X` and `y` as keyword
            arguments. Other arguments must be accepted if passed as
            `model_kwargs` by the user.
        warm_start: bool, defaults to `False`.
            Whether to reuse the model weights from the previous fit. If `True`,
            the given model won't be cloned and the weights from the previous
            fit will be reused.
        model_kwargs: dict, defaults to `None`.
            Keyword arguments passed to `model`, if `model` is callable.
        fit_kwargs: dict, defaults to `None`.
            Keyword arguments passed to `model.fit`. These can also be passed
            directly to the `fit` method of the scikit-learn wrapper. The
            values passed directly to the `fit` method take precedence over
            these.

    Attributes:
        model_ : `Model`
            The fitted model.
        history_ : dict
            The history of the fit, returned by `model.fit`.

    Example:
    A common use case for a scikit-learn transformer, is to have a step
    which gives you the embedding of your data. Here we assume
    `my_package.my_model` is a Keras model which takes the input and gives
    embeddings of the data, and `my_package.my_data` is your dataset loader.

    ``` python
    from my_package import my_model, my_data
    from keras.wrappers import SKLearnTransformer
    from sklearn.frozen import FrozenEstimator # requires scikit-learn>=1.6
    from sklearn.pipeline import make_pipeline
    from sklearn.ensemble import HistGradientBoostingClassifier

    X, y = my_data()

    trs = FrozenEstimator(SKLearnTransformer(model=my_model))
    pipe = make_pipeline(trs, HistGradientBoostingClassifier())
    pipe.fit(X, y)
    ```

    Note that in the above example, `FrozenEstimator` prevents any further
    training of the transformer step in the pipeline, which can be the case
    if you don't want to change the embedding model at hand.
    c                 C   s.   ddl m} ||  t| |dd}| j|S )a  Transform the data.

        Args:
            X: array-like, shape=(n_samples, n_features)
                The input samples.

        Returns:
            X_transformed: array-like, shape=(n_samples, n_features)
                The transformed data.
        r   rM   FrG   )rO   rN   r   rL   rP   )r   rB   rN   r   r   r   rV     s   zSKLearnTransformer.transformc                 C   s   dg iS )Npreserves_dtyper   r"   r   r   r   r#     s   zSKLearnTransformer._more_tagsc                    s   t   }g |j_|S r   )r%   r&   transformer_tagsrt   r'   r)   r   r   r&     rp   z#SKLearnTransformer.__sklearn_tags__)r   r   r   rY   rV   r#   r&   r[   r   r   r)   r   rs     s
    ?rs   )r+   numpyrf   keras.src.api_exportr   keras.src.models.cloningr   keras.src.models.modelr   keras.src.wrappers.fixesr   r   r   keras.src.wrappers.utilsr   r	   r
   r8   sklearn.baser   r   r   r   ImportErrorr   r\   rq   rs   r   r   r   r   <module>   s@     s[