
    0h)                     N    d Z ddlZddlmc mZ ddlmZ g dZ	d Z
d Zd Zd Zy)	z(Keras Utilities for DTensor related API.    N)dtensor_api)alphabetabias	depthwise
embeddingsgammakernelmoving_meanmoving_variance	pointwise	recurrentc                 d      fd}t         j                  j                  j                   |      S )a  A decorator for injecting layout information to layer.__init__.

    Layout will be a new param for any of the weights for all the keras layers.
    Adding the param to all the __init__ method will be a big/duplicated work.

    This decorator is design to reduce and code duplication and make it easy to
    add/remove the dtensor feature if needed.

    Sample usage:
    ```python
    class Dense(tf.keras.layer.Layer):

      @allow_initializer_layout
      def __init__(self, units,
                   kernel_initializer='zeros',
                   bias_initializer='zeros',
                   **kwargs):
         super().__init__(**kwargs)

    d = Dense(units=8, kernel_layout=layout1, bias_layout=layout2)
    d.kernel_layout == layout1
    d.bias_layout == layout2
    ```

    By adding this annotation, it will:

    1. Filter out the kwargs based on some keywords, eg if the
      'kernel_initialzer' appears in method signature, then it will try to pop
      the 'kernel_layout' if it presents. Same for "bias" and
      "recurrent_kernel", etc. This will make sure the layout related param is
      not passed to `BaseLayer.__init__`, which will raise error about unexpect
      keyword args.
    2. Set the self.kernel/bias_layout attribute after the `__init__` method is
       called. TF-Keras framework will use those fields to create weights down
       the stream.

    Args:
      init_method: the `__init__` method of the TF-Keras layer to annotate.

    Returns:
      the annotated __init__ method.
    c                    t        j                        }i }t        D ]4  }|dz   |j                  v s|j	                  |dz   d       }|s-|||dz   <   6  | g|i | |j                         D ]  \  }}t        | ||        y )N_initializer_layout)inspect	signatureKERAS_VARIABLE_NAMES
parameterspopitemssetattr)	layer_instanceargskwargsr   layout_argsvariable_namelayoutlayout_param_nameinit_methods	           T/var/www/html/engine/venv/lib/python3.12/site-packages/tf_keras/src/dtensor/utils.py_wrap_functionz0allow_initializer_layout.<locals>._wrap_functionU   s    %%k2	 2 	DM~-1E1EEMI$=tD=CK	 9:		D 	N4T4V4 *5):):)< 	?%vN$5v>	?    targetdecorator_functf__internal__	decoratormake_decoratorr!   r#   s   ` r"   allow_initializer_layoutr.   )   s2    X?$ ??$$33> 4  r$   c                 d      fd}t         j                  j                  j                   |      S )a  Inject DTensor mesh information to an object.

    This is useful for keras object like `Metric` and `Optimizer` which need
    DTensor mesh to create the weights, but doesn't want to change the current
    public API interface.

    This is for temporary usage and eventually the mesh/layout information will
    be public arguments in the `__init__` method.

    Sample usage:
    ```python
    class Accuracy(tf.keras.metrics.Metric):

      @inject_mesh
      def __init__(self, name='accuracy', dtype=None):
         super().__init__(**kwargs)

      acc = Accuracy(mesh=mesh)
      assert acc._mesh == mesh
    ```

    Args:
      init_method: the `__init__` method of the TF-Keras class to annotate.

    Returns:
      the annotated __init__ method.
    c                 T    |j                  dd       }||| _         | g|i | y )Nmesh)r   _mesh)instancer   r   r1   r!   s       r"   r#   z#inject_mesh.<locals>._wrap_function   s4    zz&$' !HNH.t.v.r$   r%   r(   r-   s   ` r"   inject_meshr4   l   s1    :/ ??$$33> 4  r$   c                     |rGt        j                  |j                        5   | |i |}t        j                  ||      cddd       S  | |i |S # 1 sw Y   xY w)a  Invoke the function with inputs and relayout the result.

    Args:
      fn: the function to invoke.
      layout: if not None, the output of the fn will be relayout with this.
      *args: positional arguments to be called with fn.
      **kwargs: keyword arguments to be called with fn.

    Returns:
      The output of fn, with potential relayout with the layout specified.
    N)dtensordefault_meshr1   relayout)fnr   r   r   results        r"   call_with_layoutr;      sd     !!&++. 	4((F##FF3	4 	4 tv	4 	4s   AAc                      t         j                  j                         syt         j                  j                         } t	        | dd      duS )a  Check whether running with a `Strategy` that is backed by DTensor.

    In the DTensor based training, all the tensors are in global context, which
    is different from the local context. Some keras components need to
    behave differently, e.g. BatchNormalization and SyncBatchNormalization, as
    well as optimizers.

    This check will help those layer to branch the logic and keep the correct
    behavior between different context.
    Fr2   N)r)   
distributehas_strategyget_strategygetattr)strategys    r"   running_with_dtensor_strategyrB      s?     ==%%'}}))+H 8Wd+477r$   )__doc__r   tensorflow.compat.v2compatv2r)   tf_keras.src.dtensorr   r6   r   r.   r4   r;   rB    r$   r"   <module>rI      s5    /  ! ! 7
 @F(V&8r$   