
    2Vh                          d Z 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Zd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zy)z5Utilities for distribution strategy with JAX backend.    N)layout)global_state)seed_generator)	jax_utils)	rng_utilsc                     | r| j                         nd} t        j                  |       }|D cg c]  }|j                   d|j                    c}S c c}w )a  Return all the available devices based on the device type.

    Note that this should return the global devices in a distributed setting.

    Args:
        device_type: string of `"cpu"`, `"gpu"` or `"tpu"`. Defaults to `"gpu"`
            or `"tpu"` if available when device_type is not provided. Otherwise
            will return the `"cpu"` devices.

    Return:
        List of devices that are available for distribute computation.
    Nbackend:)lowerjaxdevicesplatformid)device_typejax_devicesdevices      V/home/dcms/DCMS/lib/python3.12/site-packages/keras/src/backend/jax/distribution_lib.pylist_devicesr      sL     *5+##%$K++k2K;FGvq,GGGs   "Ac                     t        | |      S )aC  Create a distributed variable for JAX.

    Since JAX doesn't have a variable class, this will just return a `jax.Array`
    with the corresponding layout/sharding specified.

    Note that this function should be used in eager context, not in jitted
    function.

    Args:
        value: the initial value of the variable.
        layout: `TensorLayout` for the created variable, or a
            JAX-supported layout instance
            (e.g. `jax.experimental.layout.Layout`, `jax.sharding.Sharding`).

    Returns:
        jax.Array which is the distributed variable.
    )distribute_tensor)valuer   s     r   distribute_variabler      s    $ UF++    c                    ddl m} t        ||      r|j                  }t	        j
                         r t        j                  j                  | |      S t        | t        j                        rt        |t        j                  j                        r2| j                  j                  |t        | j                              r| S t        |t        j                         rt#        | dd      }||k(  r| S t        j$                  | |      S )a  Distribute the tensor based on the layout.

    Note that this function can be used both in eager context, or within a
    jitted function.

    Args:
        tensor: `jax.Array` that need to be distributed.
        layout: `TensorLayout` for the created variable, or a
            JAX-supported layout instance
            (e.g. `jax.experimental.layout.Layout`, `jax.sharding.Sharding`).

    Returns:
        Distributed value.
    r   TensorLayout)ndimr   N)keras.src.distributionr   
isinstancebackend_layoutr   is_in_jax_tracing_scoper   laxwith_sharding_constraintArrayshardingShardingis_equivalent_tolenshape
jax_layoutLayoutgetattr
device_put)tensorr   r   current_layouts       r   r   r   4   s      4&,'&& ((*ww//?? &#))$CLL))
oo..vC<M.NM
 1 12$VXt<N'>>&&))r   c                 j    ddl m} t        ||      r|j                  }t	        j
                  ||       S )a  Distribute the input data with the corresponding layout.

    Note that the inputs here is a local worker batch. Within the local worker,
    the data need to be further partitioned to map to each of the devices.

    Args:
        inputs: `jax.Array` that is already sharded to a local process size.
        layout: `TensorLayout` for the distribution information, or a
            `jax.sharding.Sharding` instance.

    Returns:
        A global batch distributed according to `layout`.
    r   r   )r   r   r    r!   r   "make_array_from_process_local_data)per_process_batchr   batch_dim_namer   s       r   distribute_data_inputr5   \   s0     4&,'&&11&:KLLr   c                     t        j                         } | t        j                  d      }t        j                  d      }t        j
                  j                  t        j                         g|z  t        j
                  j                        } t        j                  d d|      |      j                  d      } t        j                  |        t        j                  d      }|W|j                         d	   }|At        j                   dt        j"                  | |j$                  |j&                  
             yyy)zInitializes the global random number generator across processes.

    This is required for consistent initialization in multi-host settings.
    Ncpu)dtypec                 B    t         j                  j                  | d      S )Nall)r   r#   psum)xs    r   <lambda>z initialize_rng.<locals>.<lambda>   s    cggll1e, r   r:   )	axis_namer   r   global_seed_generatorseed)r@   namer
   )r   get_random_seedr   r   local_device_countnumpyasarrayr   make_default_seeduint32pmapitemset_random_seedr   get_global_attribute
get_configset_global_attributeSeedGeneratorrA   r
   )global_seedcpu_devicesnum_local_cpu_devices
local_seedr?   r@   s         r   initialize_rngrS   s   s/   
 ++-K  kk%( # 6 6u = YY&&--/03HH))"" ' 



chh,
 	 d1g	 	 	!!+. )== ($//1&9<--',,$.33199  )r   c                     | rHd| v rD| j                  d      } |+|t        |       k7  rt        d|  dt        |        d|       | d   }n| }t        j                  j                  |||       t                y )N,zThe provided job_addresses z has z jobs, but num_processes is r   )coordinator_addressnum_processes
process_id)splitr)   
ValueErrorr   distributed
initializerS   )job_addressesrW   rX   rV   s       r   r\   r\      s    - &++C0 $#m:L)L-m_E}%&&B /# 
 ,A.+OO/#   r   c                  *    t        j                         S )zDReturn the number of processes for the current distribution setting.)r   process_count r   r   rW   rW          r   c                  *    t        j                         S )z;Return the current process ID for the distribution setting.)r   process_indexr`   r   r   rX   rX      ra   r   c                    t        | t        j                        r| S | j                  d      \  }}t        j                  |      }|D ].  }|j
                  |k(  s|j                  t        |      k(  s,|c S  t        d|        )Nr   r	   zDevice not found: )	r    r   DevicerY   r   r   r   intrZ   )device_namer   	device_idr   r   s        r   _to_backend_deviceri      s}    +szz*(..s3Kkk+.G ??k)fii3y>.IM )+7
88r   c                 4   | j                   j                  }| j                   j                         D cg c]  }t        |       }}t	        j
                  |      j                  |      }t        j                  j                  || j                        S c c}w )zConvert the DeviceMesh to JAX backend specific Mesh.

    Args:
        device_mesh: DeviceMesh instance to convert.

    Returns:
        A `jax.sharding.Mesh` instance.
    )r   r*   flattenri   nparrayreshaper   r&   Mesh
axis_names)device_meshr*   dr   s       r   _to_backend_meshrs      sy     %%E.9.A.A.I.I.KL!!$LGLhhw''.G<<Wk&<&<== Ms   Bc                     | j                   t        d      t        j                  j                  | j
                   }| j                   j                  }t        j                  j                  ||      S )zConvert the TensorLayout to JAX backend specific Sharding.

    Args:
        tensor_layout: TensorLayout instance to convert.

    Returns:
        A `jax.sharding.NamedSharding` instance.
    zDCannot create sharding when device mesh is not set for TensorLayout.)rq   rZ   r   r&   PartitionSpecaxesbackend_meshNamedSharding)tensor_layoutpartition_specjax_meshs      r   _to_backend_layoutr|      sf       ( 
 	
 \\//1C1CDN((55H<<%%h??r   )N)__doc__r   rD   rl   jax.experimentalr   r+   keras.src.backend.commonr   keras.src.randomr   keras.src.utilsr   r   r   r   r   r5   rS   r\   rW   rX   ri   rs   r|   r`   r   r   <module>r      sY    ; 
  1 1 + % %H$,*%*PM.+\6

	9>@r   