U
    Jc$                     @   s2  U d dl mZmZ d dlmZ d dlZd dlmZmZm	Z	m
Z
 d dlZddlmZmZmZmZ d dlmZ d dlm  m  m  mZ d dlmZ e
rd d	lmZ G d
d deZeG dd deZG dd deZi Z ee!eeef f e"d< dd Z#edddZ$dd Z%eG dd deZ&dd Z'dS )    )ABCabstractmethod)	dataclassN)CallableDictListTYPE_CHECKING   )check_tensorget_chunked_dim_sizeget_split_size(validate_non_overlapping_shards_metadata)ShardMetadata)_decorator_func)ShardedTensorc                   @   s   e Zd ZdZdS )PlacementSpecz
    Base class representing the placement of an entity. Subclasses of this
    class can be used to specify customized placements which might not be
    covered by existing APIs.
    N)__name__
__module____qualname____doc__ r   r   N/tmp/pip-unpacked-wheel-gikjz4vx/torch/distributed/_shard/sharding_spec/api.pyr      s   r   c                   @   s&   e Zd ZU dZejjed< dd ZdS )DevicePlacementSpecz
    Associates placement of an entity with a single device.

    Args:
        device(:class:`torch.distributed._remote_device`): The device to place the entity on.
    devicec                 C   s$   t | jtjjs tj| j| _d S N)
isinstancer   torchdistributed_remote_device)selfr   r   r   __post_init__,   s    z!DevicePlacementSpec.__post_init__N)	r   r   r   r   r   r   r   __annotations__r    r   r   r   r   r   !   s   
r   c                   @   sF   e Zd ZdZeejejej	dddZ
edejeddd	d
ZdS )ShardingSpecz:
    Base class representing sharding specifications.
    tensor_sizestensor_propertiesreturnc                 C   s   dS )a  
        Given a global tensor size, define how to shard a tensor like this shape
        across ranks, return ShardedTensorMetadata
        Args:
            tensor_sizes (:class:`torch.Size`):
                The tensor shape to shard on, a `torch.Size` object that represents the
                tensor shape to be sharded according to the ShardingSpec.
            tensor_properties(:class:`torch.distributed._shard.sharded_tensor.TensorProperties):
                Tensor properties used to create a ShardedTensor.
        Returns:
            A :class:`ShardedTensorMetadata` object that encodes the information about
            the layout of the ShardedTensor and its properties.
        Nr   r   r$   r%   r   r   r   build_metadata4   s    zShardingSpec.build_metadatar   Nr   tensorsrc_rankr&   c                 C   s   dS )a  
        Given a global tensor on src_rank, shard this tensor
        across ranks within the process group, return a ShardedTensor.
        Args:
            tensor (:class:`torch.Tensor`): Tensor needs to be sharded.
        Keyword args:
            src_rank (int, optional): The source rank which is used as the ground truth of
                the data for the parameter that would be sharded and scattered
                across the rest of the ranks.
                Default: 0.
            process_group (ProcessGroup, optional): The process group to work on. If None,
                the default process group will be used.
        Returns:
            A :class:`ShardedTensor` sharded from the given tensor.
        Nr   r   r*   r+   process_groupr   r   r   shardG   s    zShardingSpec.shard)r   N)r   r   r   r   r   r   Sizesharded_tensor_metaTensorPropertiesShardedTensorMetadatar(   Tensorintr.   r   r   r   r   r"   0   s   r"   _CUSTOM_SHARDING_SPEC_OPSc                 C   s   t | j}|tko|t| kS )zQ
    Returns whether or not the ShardingSpec has a custom op implementation.
    )typer   r5   )sharding_specop
class_namer   r   r   _has_custom_op\   s    
r:   )r8   c                 C   sB   t | j}t| |s(td| d| t| | }|||||S )zA
    Calls the custom op for this ShardingSpec if it exists.
    zCustom op: z not registered for )r6   r   r:   RuntimeErrorr5   )r7   r8   typesargskwargsr-   r9   funcr   r   r   _dispatch_custom_opc   s
    

r@   c                 C   s*   | j }|tkri t|< tjt|t| dS )z
    Decorator to allow custom registration of ops.
    Args:
        sharding_spec_class(type): The ShardingSpec for which we need to add this custom op.
        func(Callable): The op to override (ex: torch.bmm)
    )r8   Zop_table)r   r5   	functoolspartialr   )Zsharding_spec_classr?   r9   r   r   r   custom_sharding_spec_opm   s    rC   c                   @   sT   e Zd ZU dZee ed< dd Zej	e
je
jdddZdejed
dddZd	S )EnumerableShardingSpeca@  
    This is a type of PlacementSpec that allows users to specify a generic
    sharding scheme by enumerating exactly how each shard is laid out.

    Args:
        shards(List[ShardMetadata]): List of :class:`ShardMetadata` objects representing
            each shard. Note that none of the shards should overlap.
    shardsc                 C   sv   t | jdkrtd| j d}| jD ]>}|dkr\|t |jkr\td| dt |j t |j}q(t| j d S )Nr   zEmpty shard list provided: z%Found inconsistent ranks for shards: z and )lenrE   
ValueErrorshard_offsetsr   )r   Zrankr.   r   r   r   r       s    
z$EnumerableShardingSpec.__post_init__r#   c                 C   s   t | j| t| j||S r   )r
   rE   r0   r2   r'   r   r   r   r(      s    z%EnumerableShardingSpec.build_metadatar   Nr   r)   c                 C   s   t dd S )Nz1EnumerableShardingSpec.shard not implemented yet!)NotImplementedErrorr,   r   r   r   r.      s    zEnumerableShardingSpec.shard)r   N)r   r   r   r   r   r   r!   r    r   r/   r0   r1   r2   r(   r3   r4   r.   r   r   r   r   rD   ~   s   
	rD   c                    sD  g }d g }g }| D ]}| |j |j}| t| | |j dd t|D }t|dkrdqt|dkrxd  q s|d  q |d krd  qq dk	r<dd tt||dd d	D }dd
l	m
} | |d}t fdd|D }	t|	t|}
t|
tfddtt|D }|	|kr<|S t| S )a  
    Infer the sharding spec from the metadata of each shard of a ShardedTensor.
    If the tensor is sharded only on one dimension, we can then verify whether it's
    a ChunkShardingSpec or not. The way to verify it is to first get the total length
    and perform a chunk sharding with the given placements to see if we can have the
    same chunk size as the given shards_metadata. If not, we assume it's enum sharded.

    Args:
        shards_metadata (List[ShardMetadata]): List of Metadata of local shards.

    Returns:
        A :class:`torch.distributed._shard.sharding_spec.ShardingSpec` object of sharding
            spec for one sharded tensor.
    Nc                 S   s   g | ]\}}|d kr|qS )r   r   ).0idxer   r   r   
<listcomp>   s      z=_infer_sharding_spec_from_shards_metadata.<locals>.<listcomp>r   r	   c                 S   s   g | ]\}}|qS r   r   )rK   _xr   r   r   rN      s    c                 S   s   | d S )Nr   r   )rM   r   r   r   <lambda>       z;_infer_sharding_spec_from_shards_metadata.<locals>.<lambda>)key)ChunkShardingSpec)Zdim
placementsc                    s   g | ]}|  qS r   r   )rK   rP   )chunk_sharding_dimr   r   rN      s     c                    s   g | ]}t  |qS r   )r   )rK   rL   )shard_total_length
split_sizer   r   rN      s   )appendZ	placementrI   sumshard_sizes	enumeraterG   sortedzipZchunk_sharding_specrT   r   rangerD   )Zshards_metadatarU   Zchunk_offset_listZshard_size_listZshard_metadataZlocal_offsetsZ
shard_dimsrT   Z
chunk_specr[   chunksZchunk_shard_sizesr   )rV   rW   rX   r   )_infer_sharding_spec_from_shards_metadata   sR    




ra   )(abcr   r   Zdataclassesr   rA   typingr   r   r   r   r   Z
_internalsr
   r   r   r   Z!torch.distributed._shard.metadatar   Z0torch.distributed._shard.sharded_tensor.metadatar   Z_shardZsharded_tensormetadatar0   Z*torch.distributed._shard.op_registry_utilsr   Z'torch.distributed._shard.sharded_tensorr   r   r   r"   r5   strr!   r:   r@   rC   rD   ra   r   r   r   r   <module>   s,    	*
*