
    6bi)                     N    S r SSKrSSKJs  Jr  SSKJr  / SQr	S r
S rS rS rg)	z(Keras Utilities for DTensor related API.    N)dtensor_api)alphabetabias	depthwise
embeddingsgammakernelmoving_meanmoving_variance	pointwise	recurrentc                 `   ^  U 4S jn[         R                  R                  R                  T US9$ )aw  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                 &  > [         R                  " T5      n0 n[         H=  nUS-   UR                  ;   d  M  UR	                  US-   S 5      nU(       d  M6  XdUS-   '   M?     T" U /UQ70 UD6  UR                  5        H  u  pv[        XU5        M     g )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/home/james-whalen/.local/lib/python3.13/site-packages/tf_keras/src/dtensor/utils.py_wrap_function0allow_initializer_layout.<locals>._wrap_functionU   s    %%k2	 2M~-1E1EEMI$=tD6=C	 9:	 2 	N4T4V4 *5):):)<%Nv> *=    targetdecorator_functf__internal__	decoratormake_decoratorr!   r#   s   ` r"   allow_initializer_layoutr/   )   s2    X?$ ??$$33> 4  r%   c                 `   ^  U 4S jn[         R                  R                  R                  T US9$ )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   > UR                  SS 5      nUb  X0l        T" U /UQ70 UD6  g )Nmesh)r   _mesh)instancer   r   r2   r!   s       r"   r#   #inject_mesh.<locals>._wrap_function   s2    zz&$' !NH.t.v.r%   r&   r)   r.   s   ` r"   inject_meshr6   l   s1    :/ ??$$33> 4  r%   c                     U(       aH  [         R                  " UR                  5         U " U0 UD6n[         R                  " XA5      sSSS5        $ U " U0 UD6$ ! , (       d  f       N= f)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_meshr2   relayout)fnr   r   r   results        r"   call_with_layoutr=      sY     !!&++.((F##F3 /. tv /.s   A
A&c                      [         R                  R                  5       (       d  g[         R                  R                  5       n [	        U SS5      SL$ )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.
Fr3   N)r*   
distributehas_strategyget_strategygetattr)strategys    r"   running_with_dtensor_strategyrD      sB     ==%%''}}))+H 8Wd+477r%   )__doc__r   tensorflow.compat.v2compatv2r*   tf_keras.src.dtensorr   r8   r   r/   r6   r=   rD    r%   r"   <module>rK      s5    /  ! ! 7
 @F(V&8r%   