
    6bicX                        S r SSKrSSKrSSKrSSKrSSKJs  Jr  SSK	J
r  SSK	Jr  SSK	Jr  SSKJr  SSKJr  / SQr\R&                  " 5       qS	 r\" S
/ S9 " S S\R,                  R.                  5      5       r\R2                  R                   \R4                  l         \R6                  S 5       rS rS rS rS r S r!S r"S r#S r$g)z5Library for map layout and corresponding tf.Variable.    N)dtensor_api)lazy_variable)utils)
base_layer)keras_export)_self_tracked_trackables_trainable_weights_non_trainable_weights_captured_weight_regularizerc                  $    [        [        SS 5      $ )N
layout_map)getattr_LAYOUT_MAP     Y/home/james-whalen/.local/lib/python3.13/site-packages/tf_keras/src/dtensor/layout_map.pyget_current_layout_mapr   0   s    ;d33r   z$keras.dtensor.experimental.LayoutMap)v1c                   L    \ rS rSrSrSS jrS rS rS rS r	S	 r
S
 rS rSrg)	LayoutMap4   a  A dict-like object that maps string to `Layout` instances.

`LayoutMap` uses a string as key and a `Layout` as value. There is a
behavior difference between a normal Python dict and this class. The string
key will be treated as a regex when retrieving the value. See the docstring
of `get` for more details.

See below for a usage example. You can define the naming schema
of the `Layout`, and then retrieve the corresponding `Layout` instance.

To use the `LayoutMap` with a `Model`, please see the docstring of
`tf.keras.dtensor.experimental.layout_map_scope`.

```python
map = LayoutMap(mesh=None)
map['.*dense.*kernel'] = layout_2d
map['.*dense.*bias'] = layout_1d
map['.*conv2d.*kernel'] = layout_4d
map['.*conv2d.*bias'] = layout_1d

layout_1 = map['dense_1.kernel']    #   layout_1 == layout_2d
layout_2 = map['dense_1.bias']      #   layout_2 == layout_1d
layout_3 = map['dense_2.kernel']    #   layout_3 == layout_2d
layout_4 = map['dense_2.bias']      #   layout_4 == layout_1d
layout_5 = map['my_model/conv2d_123/kernel']    #   layout_5 == layout_4d
layout_6 = map['my_model/conv2d_123/bias']      #   layout_6 == layout_1d
```

Args:
  mesh: An optional `Mesh` that can be used to create all replicated
    layout as default when there isn't a layout found based on the input
    string query.
Nc                 D    [         R                  " 5       U l        Xl        g N)collectionsOrderedDict_layout_map_default_mesh)selfmeshs     r   __init__LayoutMap.__init__X   s    &224!r   c                     XR                   ;   a  U R                   U   $ U R                    H/  n[        R                  " X!5      (       d  M   U R                   U   s  $    g)a  Retrieve the corresponding layout by the string key.

When there isn't an exact match, all the existing keys in the layout map
will be treated as a regex and map against the input key again. The
first match will be returned, based on the key insertion order. Return
None if there isn't any match found.

Args:
  key: the string key as the query for the layout.

Returns:
  Corresponding layout based on the query.
N)r   rematch)r   keyks      r   __getitem__LayoutMap.__getitem__\   sV     """##C((!!Axx''** " r   c                     XR                   ;   a  [        U SU R                   U    S35      e[        U[        R                  5      (       d  [        U S[        U5       35      eX R                   U'   g )Nz+ already exist in the LayoutMap with value z.. Please make sure to not use duplicated keys.z& should be a dtensor.Layout type, got )r   
ValueError
isinstancedtensorLayouttype)r   r%   layouts      r   __setitem__LayoutMap.__setitem__r   s    """% ))#./ 0++ 
 &'..11(@fO  !'r   c                 8    U R                   R                  U5      $ r   )r   pop)r   r%   s     r   __delitem__LayoutMap.__delitem__   s    ##C((r   c                 ,    [        U R                  5      $ r   )lenr   r   s    r   __len__LayoutMap.__len__   s    4##$$r   c                 ,    [        U R                  5      $ r   )iterr   r8   s    r   __iter__LayoutMap.__iter__   s    D$$%%r   c                     U R                   $ )zReturn the default `Mesh` set at instance creation.

The `Mesh` can be used to create default replicated `Layout` when there
isn't a match of the input string query.
)r   r8   s    r   get_default_meshLayoutMap.get_default_mesh   s     !!!r   c                     [        U 5      $ )a	  Apply layout to all `tf.Variable` instances created under the scope.

All `tf.Variable` instances created under this scope
will be lazily initialized first. Once they are attached as the model
or layer attributes, and there is a stable layout mapping for it, the
variables will be reinitialized into a
`tf.experimental.dtensor.DVariable` with corresponding layout.

Note that the layout mapping will use object/attribute names as the
keys to map the variable to the layout.

For subclassed models, the full object/attribute name is used as the
key. For Functional/Sequential models, we use `layer.name` as
the key for the layer, followed by the attribute name. TF-Keras ensures
name uniqueness among the layers within a Functional/Sequential model.

See the following examples that show variable object names
for different TF-Keras model types:

```python
layout_map = layout_map_lib.LayoutMap(mesh=self.mesh)
layout_map['d1.kernel'] = layout_1
layout_map['d1.bias'] = layout_2
layout_map['d2.kernel'] = layout_3
layout_map['d2.bias'] = layout_4

## Subclassed model
class SubclassModel(tf.keras.Model):

  def __init__(self, name=None):
    super().__init__(name=name)
    self.d1 = tf.keras.layers.Dense(1000)
    self.d2 = tf.keras.layers.Dense(1000)

  def call(self, inputs):
    x = self.d1(inputs)
    return self.d2(x)

with layout_map.scope():
  model = SubclassModel()
inputs = tf.zeros((10, 10))
results = model(inputs)

model.d1.kernel.layout == layout_1
model.d1.bias.layout == layout_2
model.d2.kernel.layout == layout_3
model.d2.bias.layout == layout_4

## Functional model
with layout_map.scope():
  inputs = tf.keras.Input((10,), batch_size=10)
  x = tf.keras.layers.Dense(20, name='d1')(inputs)
  output = tf.keras.layers.Dense(30, name='d2')(x)

  model = tf.keras.Model(inputs, output)

d1 = model.layers[1]
d2 = model.layers[2]

d1.kernel.layout == layout_1
d1.bias.layout == layout_2
d1.kernel.layout == layout_3
d1.bias.layout == layout_4

## Sequential model
with layout_map.scope():
  model = tf.keras.Sequential([
      tf.keras.layers.Dense(20, name='d1', input_shape=(10,)),
      tf.keras.layers.Dense(30, name='d2')
  ])

d1 = model.layers[0]
d2 = model.layers[1]

d1.kernel.layout == layout_1
d1.bias.layout == layout_2
d1.kernel.layout == layout_3
d1.bias.layout == layout_4
```

Returns:
  A context that will lazily initialize all `tf.Variable` objects
  within the model, with their attributed layouts.
)layout_map_scoper8   s    r   scopeLayoutMap.scope   s    j  %%r   )r   r   r   )__name__
__module____qualname____firstlineno____doc__r    r'   r0   r4   r9   r=   r@   rD   __static_attributes__r   r   r   r   r   4   s1     D",')%&"U&r   r   c              #      #    [        5       nU [        l        [        R                  " 5           Sv   U[        l         SSS5        g! U[        l        f = f! , (       d  f       g= f7f)a
  Apply the layout to all the tf.Variables created under the scope.

Create a scope that all the tf.Variable created under this scope
will be lazily inited, and initialized later on with proper layout when the
object path in the model is stable/finalized.

Note that the layout mapping will use the object/attribute names as the key
to map the variable against the layout.

For subclassed models, the full object/attribute name is used as the key.
For Functional/Sequential models, since the layers within the model do not
get assigned to a meaningful attribute, we use `layer.name` as the key for
the layer, followed by the attribute name. TF-Keras ensures name uniqueness
among the layers in all Functional/Sequential models.

See the following examples that show the variable object names
for different TF-Keras model types:

```python
layout_map = layout_map_lib.LayoutMap(mesh=self.mesh)
layout_map['d1.kernel'] = layout_1
layout_map['d1.bias'] = layout_2
layout_map['d2.kernel'] = layout_3
layout_map['d2.bias'] = layout_4

## Subclassed model
class SubclassModel(tf.keras.Model):

  def __init__(self, name=None):
    super().__init__(name=name)
    self.d1 = tf.keras.layers.Dense(1000)
    self.d2 = tf.keras.layers.Dense(1000)

  def call(self, inputs):
    x = self.d1(inputs)
    return self.d2(x)

with layout_map_scope(layout_map):
  model = SubclassModel()
# Triggering the creation of weights within or outside of the scope works
inputs = tf.zeros((10, 10))
results = model(inputs)

model.d1.kernel.layout == layout_1
model.d1.bias.layout == layout_2
model.d2.kernel.layout == layout_3
model.d2.bias.layout == layout_4

## Functional model
with layout_map_scope(layout_map):
  inputs = tf.keras.Input((10,), batch_size=10)
  x = tf.keras.layers.Dense(20, name='d1')(inputs)
  output = tf.keras.layers.Dense(30, name='d2')(x)

  model = tf.keras.Model(inputs, output)

d1 = model.layers[1]
d2 = model.layers[2]

d1.kernel.layout == layout_1
d1.bias.layout == layout_2
d1.kernel.layout == layout_3
d1.bias.layout == layout_4

## Sequential model
with layout_map_scope(layout_map):
  model = tf.keras.Sequential([
      tf.keras.layers.Dense(20, name='d1', input_shape=(10,)),
      tf.keras.layers.Dense(30, name='d2')
  ])

d1 = model.layers[0]
d2 = model.layers[1]

d1.kernel.layout == layout_1
d1.bias.layout == layout_2
d1.kernel.layout == layout_3
d1.bias.layout == layout_4
```

Args:
  layout_map: a LayoutMap which contains the variable_object_path (string)
    -> Layout. When a layout is not found for the variable, a default all
    replicated layout will be created for the variable.

Yields:
  A context that will lazily initialize all `tf.Variable` objects
  within the model, with their attributed layouts.
N)r   r   r   r   lazy_init_scope)r   previous_layout_maps     r   rC   rC      sQ     v 12'K		&	&	(	9%8K"	 
)	( &9K"	 
)	(s1   +A)AAA	A)AA
A&"A)c           	          0 nU R                  [        SS9 Hz  u  p4[         Vs/ s H  oUU;   d  M
  UPM     sn(       a  M*  SR                  U Vs/ s H  n[	        U5      PM     sn5      n[        XU5      n[        XU5        X[        U5      '   M|     U R                  S S9 H  n	[        X5        M     U R                  [        SS9 H  u  p4U[        U5         n
[        XU
5        M!     [        X5        [        X5        U $ s  snf s  snf )z0Map/Replace LazyInitVariable for subclass model.T	predicate	with_path.c                 6    [        U [        R                  5      $ r   )r+   r   Layeros    r   <lambda>._map_subclass_model_variable.<locals>.<lambda>i  s    Jq**:*:;r   rQ   )_flatten_is_lazy_init_variable_KERAS_ATTRIBUTES_TO_SKIPjoinstr_create_dvariable_set_object_by_pathid _config_dvariable_regularization_init_state_variable_for_rng_update_trackable_reference)modelr   %lazy_init_variable_to_tf_variable_mappathvariableaitemobject_pathnew_variablelayertf_variables              r   _map_subclass_model_variablerp   S  s   ,.)  ..( )  1>0!IA0>hhd;ddD	d;<((KE6>Jbl; ;    	)	
  ..( )  <BxLIE5 !3ML5 ?  <s   	DDD
c           
      @   0 nU R                    H  nUR                  nUR                  [        SS9 H  u  pV[         Vs/ s H  owU;   d  M
  UPM     sn(       a  M*  SR                  U Vs/ s H  n[        U5      PM     sn5      n	US-   U	-   n	[        XU5      n
[        X5U
5        X[        U5      '   M     [        X25        UR                  [        SS9 H  u  pVU[        U5         n[        X5U5        M!     M     [        X5        [        X5        U $ s  snf s  snf )z=Map/Replace LazyInitVariable for functional/sequential model.TrP   rS   )layersnamer[   r\   r]   r^   r_   r`   ra   rb   rc   rd   re   )rf   r   rg   rn   
layer_namerh   ri   rj   rk   rl   rm   ro   s               r   _map_functional_model_variableru   |  s   ,.) ZZ
#nn, - 
ND 5B4aT	4B(($#?$$CI$#?@K$s*[8K,ZhOL\:BN"X,?!
$ 	)	
 $nn, - 
ND @8MK[9
= J !3ML7 C $@s   	DD+Dc                    U R                  S S9 H  nUR                  nUR                  (       a  UR                  c  [	        S5      e[        US5      (       aV  [        UR                  R                  5      (       a2  [        USUR                  R                  5      UR                  l        M  [        R                  " UR                  5       5         UR                  5         SSS5        M     g! , (       d  f       M  = f)a!  Init the state variable in tf.ranodm.Generator.

Since the BaseRandomLayer in keras explicitly untrack the
tf.random.Generator, the variable in it will stay as LazyInitVariable, which
cause runtime error if we don't replace them with proper DVariable. Since
user usually are not aware the existence of those variable, we will just
give them replicated layout since they are tiny.

Args:
  model: the model whose layers will be checked to find the
    BaseRandomLayers.
  layout_map: used to get the default mesh information to create DVariable.
c                 6    [        U [        R                  5      $ r   )r+   r   BaseRandomLayerrV   s    r   rX   ._init_state_variable_for_rng.<locals>.<lambda>  s    Jq**D*DEr   rZ   NzKeras is expected to use tf.random.Generator when using DTensor API. Please call `tf.keras.backend.experimental.enable_tf_random_generator` at the beginning of your program.
_generator )r[   _random_generator_builtrz   r*   hasattrr\   
_state_varr`   r,   default_meshr@   _maybe_init)rf   r   lkeras_generators       r   rd   rd     s     ^^E   --!!o&@&@&H1  ?L116L&&117
 7
 5FB : : E E5O&&1 %%j&A&A&CD++- ED-, EDs   C22
D	c                     U R                    HD  u  p#n[        U5      (       d  [        SU 35      eU[        U5         nU R	                  X%U5        MF     / U l         g)a8  Update the weights regularizer for newly created `DVariable`.

The weight regularization usually happens when `layer.add_weight()` is
called, at which point the library will first create a `LazyInitVariable`,
and then replace it with a `DVariable`. We will defer the creation of those
losses, until the DVariable is created.

See `layer._captured_weight_regularizer` for more details.

Args:
  layer: the layer instance for DVariable regularization config.
  lazy_init_variable_to_tf_variable_map: the dict between LazyInitVariable
    ID and newly created DVariable.
zFExpect the regularization loss are created from LazyInitVariable, got N)r   r\   r*   rb   _handle_weight_regularization)rn   rg   rs   ri   regualarizer
d_variables         r   rc   rc     sk    $ ).(J(J$%h//))1
4  ;2h<H
++DlK )K *,E&r   c                    X   nUcB  UR                   R                  n[        R                  R	                  U R                  5       US9nUR                  n[        U5      (       a5  [        R                  " 5          [        R                  " XS5      nSSS5        O[        R                  " XS5      nUR                  nUR                  S5      (       a  USS n[        R                  " XRR                   US9nU$ ! , (       d  f       NV= f)a  Create a new variable instead of using the LazyInitVariable.

We choose to do this since even the LazyInitVariable might behavior like
a normal tf.Variable/DVariable, it is not future proof for any new changes
to variable class. It will also fail the instance type check in python,
which could affect user's code when they do any filtering based on type to
find any variables.

Args:
  layout_map: a LayoutMap which contains the variable_object_path (string)
    -> Layout.
  object_path: string, the object attribute path for the variable.
  variable: LazyInitVariable which will be replaced by the newly created
    tf.Variable.
Returns:
  A new tf.Variable with correct layout information.
N)r   rankz:0)	trainablers   )shaper   r,   r-   
replicatedr@   _initial_valuecallabler   disable_init_variable_creatorr   call_with_layoutcopy_to_meshrs   endswith	DVariabler   )r   rl   ri   r/   variable_rankinit_valvariable_namerm   s           r   r`   r`     s    ( $F~ ++**,,.] + 
 &&H88:--h?H ;:
 ''9 MMMd##%cr*$$..]L  ;:s   ;C99
Dc                     [        U5       Hf  u  p4U[        U5      S-
  :X  a)  [        U[        5      (       a  X U'   M2  [	        XU5        M@  [        U[        5      (       a  X   n M[  [        X5      n Mh     g)a  Set the attribute of instance to the object.

Args:
  object_to_set: the instance whose attribute should be set.
  path: the tuple/list of string and ints, representing the attribute names.
    Int means that the attribute to set is a item a list.
  value: the value of the attribute.
   N)	enumerater7   r+   intsetattrr   )object_to_setrh   valuei	attr_names        r   ra   ra     sd     "$D	A)S)) ,1i(%8)S)) - 8 ' A (r   c                 8   [         R                  R                  R                  U 5      nUR	                  5       u  p4U HY  nUR                  5       R                  5        H4  u  pg[        U5      (       d  M  UR                  U[        U5         USS9  M6     M[     g)a  Update the trackable object references for the model.

Note that this method is only needed because of a corner case for model
checkpoint, where it could accidently catch a LazyInitVariable in checkpoint
dependency and not visible to the model attribute graph itself.

Args:
  model: the keras model instance whose checkpoint dependency will be
    examed.
  lazy_init_variable_to_tf_variable_map: the dict between LazyInitVariable
    ID and newly created DVariable.
T)	overwriteN)
tf__internal__trackingObjectGraphViewbreadth_first_traversal_trackable_childrenitemsr\   _track_trackablerb   )rf   rg   object_graph
trackables_	trackableref_namerefs           r   re   re   9  s     ??++;;EBL 88:MJ	&::<BBDMH%c****9"S'B" +  E  r   c                 6    [        U [        R                  5      $ r   )r+   r   LazyInitVariable)objs    r   r\   r\   T  s    c=99::r   )%rJ   r   
contextlibr#   	threadingtensorflow.compat.v2compatv2r   tf_keras.src.dtensorr   r,   r   r   tf_keras.src.enginer    tensorflow.python.util.tf_exportr   r]   localr   r   abcMutableMappingr   r'   getcontextmanagerrC   rp   ru   rd   rc   r`   ra   re   r\   r   r   r   <module>r      s    <   	  ! ! 7 . & * :  oo4 4<r&.. r& =r&j "--55	  b9 b9J&R+\&.R,<*ZB66;r   