o
    2h                     @   s   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 ed	G d
d de	Zdd ZdS )    N)parse)backend)keras_export)Layer)convert_to_numpy)convert_to_tensor)in_safe_modezkeras.layers.TorchModuleWrapperc                       sv   e Zd ZdZd fdd	ZdddZdd	 Zdd
ddZdd Zdd Z	 fddZ
 fddZedd Z  ZS )TorchModuleWrappera	  Torch module wrapper layer.

    `TorchModuleWrapper` is a wrapper class that can turn any
    `torch.nn.Module` into a Keras layer, in particular by making its
    parameters trackable by Keras.

    `TorchModuleWrapper` is only compatible with the PyTorch backend and
    cannot be used with the TensorFlow or JAX backends.

    Args:
        module: `torch.nn.Module` instance. If it's a `LazyModule`
            instance, then its parameters must be initialized before
            passing the instance to `TorchModuleWrapper` (e.g. by calling
            it once).
        output_shape :The shape of the output of this layer. It helps Keras
            perform automatic shape inference.
        name: The name of the layer (string).

    Example:

    Here's an example of how the `TorchModuleWrapper` can be used with vanilla
    PyTorch modules.

    ```python
    import torch
    import torch.nn as nn
    import torch.nn.functional as F

    import keras
    from keras.layers import TorchModuleWrapper

    class Classifier(keras.Model):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            # Wrap `torch.nn.Module`s with `TorchModuleWrapper`
            # if they contain parameters
            self.conv1 = TorchModuleWrapper(
                nn.Conv2d(in_channels=1, out_channels=32, kernel_size=(3, 3))
            )
            self.conv2 = TorchModuleWrapper(
                nn.Conv2d(in_channels=32, out_channels=64, kernel_size=(3, 3))
            )
            self.pool = nn.MaxPool2d(kernel_size=(2, 2))
            self.flatten = nn.Flatten()
            self.dropout = nn.Dropout(p=0.5)
            self.fc = TorchModuleWrapper(nn.Linear(1600, 10))

        def call(self, inputs):
            x = F.relu(self.conv1(inputs))
            x = self.pool(x)
            x = F.relu(self.conv2(x))
            x = self.pool(x)
            x = self.flatten(x)
            x = self.dropout(x)
            x = self.fc(x)
            return F.softmax(x, dim=1)


    model = Classifier()
    model.build((1, 28, 28))
    print("Output shape:", model(torch.ones(1, 1, 28, 28).to("cuda")).shape)

    model.compile(
        loss="sparse_categorical_crossentropy",
        optimizer="adam",
        metrics=["accuracy"]
    )
    model.fit(train_loader, epochs=5)
    ```
    Nc                    st   t  jdd|i| dd lm} ddlm} t||jjj	r*|
 r*td| || | _|   || _d S )Nnamer   )
get_devicezmLazyModules are not supported unless they are already initialized. Received uninitialized LazyModule: module= )super__init__torch.nnnnkeras.src.backend.torch.corer   
isinstancemoduleslazyLazyModuleMixinhas_uninitialized_params
ValueErrortomodule_track_module_parametersoutput_shape)selfr   r
   r   kwargsr   r   	__class__r   V/var/www/html/chatgem/venv/lib/python3.10/site-packages/keras/src/utils/torch_utils.pyr   W   s   
zTorchModuleWrapper.__init__Tc                 C   s   | j j|dS )N)recurse)r   
parameters)r   r!   r   r   r    r"   k   s   zTorchModuleWrapper.parametersc                 C   s4   | j  D ]}tj||jd}| | qd| _d S )N)initializer	trainableT)r   r"   r   Variablerequires_grad_track_variablebuilt)r   paramvariabler   r   r    r   n   s   
z+TorchModuleWrapper._track_module_parameters)trainingc                O   s*   |du r	|    n|   | j|i |S )NF)evaltrainr   )r   r+   argsr   r   r   r    callx   s   
zTorchModuleWrapper.callc                 C   s,   | j  }| D ]
}t|| ||< q	dS )zSaves model's state from `state_dict`.
        `model.parameters` excludes some of model's state like
        `BatchNorm` mean and variance. So, use `state_dict` to obtain
        all of model's state.
        N)r   
state_dictkeysr   r   storer0   keyr   r   r    save_own_variables   s   
z%TorchModuleWrapper.save_own_variablesc                 C   sD   i }|  D ]}t|tr| }t|| ||< q| j| dS )z%Loads model's state via `state_dict`.N)r1   r   bytesdecoder   r   load_state_dictr2   r   r   r    load_own_variables   s   
z%TorchModuleWrapper.load_own_variablesc                    s   | j d u rt |S | j S )N)r   r   compute_output_shape)r   input_shaper   r   r    r:      s   
z'TorchModuleWrapper.compute_output_shapec                    sT   t   }dd l}t }|| j| t|	 
d}|| jd}i ||S )Nr   ascii)r   r   )r   
get_configtorchioBytesIOsaver   base64	b64encodegetvaluer7   r   )r   base_configr>   buffer
buffer_b64configr   r   r    r=      s   
zTorchModuleWrapper.get_configc                 C   s\   dd l }d|v r't rtdt|d d}t|}|j|dd|d< | di |S )Nr   r   ad  Requested the deserialization of a `torch.nn.Module` object via `torch.load()`. This carries a potential risk of arbitrary code execution and thus it is disallowed by default. If you trust the source of the artifact, you can override this error by passing `safe_mode=False` to the loading function, or calling `keras.config.enable_unsafe_deserialization().r<   F)weights_onlyr   )	r>   r   r   rB   	b64decodeencoder?   r@   load)clsrH   r>   buffer_bytesrF   r   r   r    from_config   s   
zTorchModuleWrapper.from_config)NN)T)__name__
__module____qualname____doc__r   r"   r   r/   r5   r9   r:   r=   classmethodrO   __classcell__r   r   r   r    r	      s    G


	r	   c                 C   s(   dd l }t|jtdkr|| S | S )Nr   z2.1.0)r>   r   __version__no_grad)	orig_funcr>   r   r   r    rW      s   
rW   )rB   r?   packaging.versionr   	keras.srcr   keras.src.api_exportr   keras.src.layersr   keras.src.opsr   r   "keras.src.saving.serialization_libr   r	   rW   r   r   r   r    <module>   s     .