
    2Vh1                         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  ed       G d	 d
e             Zd Zy)    N)parse)backend)keras_export)Layer)convert_to_numpy)convert_to_tensorzkeras.layers.TorchModuleWrapperc                   n     e Zd ZdZd fd	ZddZd ZdddZd Zd	 Z	 fd
Z
 fdZed        Z x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                 4   t        |   dd|i| dd lm} ddlm} t        ||j                  j                  j                        r|j                         rt        d|       |j                   |             | _        | j                          || _        y )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__s          K/home/dcms/DCMS/lib/python3.12/site-packages/keras/src/utils/torch_utils.pyr   zTorchModuleWrapper.__init__U   s    -d-f-; vrzz>>?//1==CHF  ii
-%%'(    c                 :    | j                   j                  |      S )N)recurse)r   
parameters)r   r$   s     r!   r%   zTorchModuleWrapper.parametersi   s    {{%%g%66r"   c                     | j                   j                         D ]4  }t        j                  ||j                        }| j                  |       6 d| _        y )N)initializer	trainableT)r   r%   r   Variablerequires_grad_track_variablebuilt)r   paramvariables      r!   r   z+TorchModuleWrapper._track_module_parametersl   sT    [[++- 	+E ''!U-@-@H   *	+ 
r"   )trainingc                p    |du r| j                          n| j                           | j                  |i |S )NF)evaltrainr   )r   r/   argsr   s       r!   callzTorchModuleWrapper.callv   s2    uIIKJJLt{{D+F++r"   c                     | j                   j                         }|j                         D ]  }t        ||         ||<    y)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   storer6   keys       r!   save_own_variablesz%TorchModuleWrapper.save_own_variables}   s>     [[++-
??$ 	;C)*S/:E#J	;r"   c                     i }|j                         D ]3  }t        |t              r|j                         }t	        ||         ||<   5 | j
                  j                  |       y)z%Loads model's state via `state_dict`.N)r7   r   bytesdecoder   r   load_state_dictr8   s       r!   load_own_variablesz%TorchModuleWrapper.load_own_variables   sW    
::< 	<C#u%jjl/c
;JsO	< 	##J/r"   c                 R    | j                   t        | 	  |      S | j                   S )N)r   r   compute_output_shape)r   input_shaper    s     r!   rB   z'TorchModuleWrapper.compute_output_shape   s+    $7/<<   r"   c                     t         |          }dd l}t        j                         }|j                  | j                  |       |j                         | j                  d}i ||S )Nr   )r   r   )	r   
get_configtorchioBytesIOsaver   getvaluer   )r   base_configrF   bufferconfigr    s        r!   rE   zTorchModuleWrapper.get_config   s\    g(*

4;;'oo' --
 )+(((r"   c                 ~    dd l }d|v r.t        j                  |d         }|j                  |d      |d<    | di |S )Nr   r   F)weights_onlyr   )rF   rG   rH   load)clsrM   rF   rL   s       r!   from_configzTorchModuleWrapper.from_config   sC    vZZx 01F$zz&uzEF8}V}r"   )NN)T)__name__
__module____qualname____doc__r   r%   r   r4   r;   r@   rB   rE   classmethodrR   __classcell__)r    s   @r!   r
   r
      sK    EN)(7 $( ,;0!

)  r"   r
   c                 r    dd l }t        |j                        t        d      k\  r|j                  |       S | S )Nr   z2.1.0)rF   r   __version__no_grad)	orig_funcrF   s     r!   r[   r[      s1    U5>1}}Y''r"   )rG   packaging.versionr   	keras.srcr   keras.src.api_exportr   keras.src.layersr   keras.src.opsr   r   r
   r[   r   r"   r!   <module>rb      sD    	 #  - " * + /0[ [ 1[|r"   