o
    "j3                     @   s   d dl Z d dlmZ d dl mZ d dlmZ d dlmZm	Z	 dd Z
dd Zd	d
 Z			dddZdd Z					dddZdS )    N)	framework)data_feeder)_get_global_group_warn_cur_rank_not_in_groupc                 C   s2   |r	|j || S |j || |}|r|  |S )N)process_groupZ all_to_all_tensor_on_calc_streamZall_to_all_tensorwait)
out_tensor	in_tensorgroupsync_opuse_calc_streamtask r   s/var/www/html/Deteccion_Ine/venv/lib/python3.10/site-packages/paddle/distributed/communication/stream/all_to_all.py_all_to_all_tensor_in_dygraph   s   r   c                 C   sd   t |dkr
tdt | dkr| dd |D 7 } |r"|j| |S |j| ||}|r0|  |S )Nr   *The input tensor_list should not be empty.c                 S   s   g | ]}t |qS r   )paddleZ
empty_like).0Ztensorr   r   r   
<listcomp>/   s    
z*_all_to_all_in_dygraph.<locals>.<listcomp>)lenRuntimeErrorr   Zall_to_all_on_calc_stream
all_to_allr   )Zout_tensor_listZin_tensor_listr
   r   r   r   r   r   r   _all_to_all_in_dygraph(   s    r   c                 C   sL  d}|d u rdn|j }t }tj|fi t }|}	t|trBt|dkr*t	dt|d j
dkr;tj|dd}	ntj|dd}	| }
t| trZt| dkrStd|j|	jd}
t|	dg dd	 |j|d
|	gid|
gi||dd t| tr|stj|
dd t|d j
dkr| t|
d d S | t|
|d d S d S )Nalltoallr   r   )Zaxisz;The 'out_tensor_list' for all_to_all must be an empty list.)dtyper	   )Zfloat16Zfloat32Zfloat64Zint32Zint64r   XZOut)ring_idr   )typeZinputsZoutputsattrsF)r   )iddistget_world_sizer   ZLayerHelperlocals
isinstancelistr   r   shaper   stackconcat
ValueErrorZ"create_variable_for_type_inferencer   r   Zcheck_variable_and_dtypeZ	append_opr   extendZunstacksplit)out_tensor_or_tensor_listin_tensor_or_tensor_listr
   r   r   Zop_typer   Znrankshelperr	   r   r   r   r   _all_to_all_in_static_modeA   sV   


r.   TFc                 C   s   t |rdS |s|rtd| du rtd|du rtdt rQ|du r)t n|}t| }t|}|rA|rAt| ||||S |sM|sMt| ||||S td|du sYJ dt	| ||||S )a  

    Scatter a tensor (or a tensor list) across devices and gather outputs to another tensor (or a tensor list, respectively).

    Args:
        out_tensor_or_tensor_list (Union[Tensor, List[Tensor]]): The output. If it is a tensor, it should be correctly-sized.
        If it is a list, it should be empty or contain correctly-sized tensors. Its data type should be the same as the input.
        in_tensor_or_tensor_list (Union[Tensor, List[Tensor]]): The input to scatter (must be specified on the source rank).
            If it is a tensor, it should be correctly-sized. If it is a list, it should contain correctly-sized tensors. Support
            float16, float32, float64, int32, int64, int8, uint8 or bool as the input data type.
        group (Group, optional): Communicate in which group. If none is given, use the global group as default.
        sync_op (bool, optional): Indicate whether the communication is sync or not. If none is given, use true as default.
        use_calc_stream (bool, optional): Indicate whether the communication is done on calculation stream. If none is given, use false as default. This
            option is designed for high performance demand, be careful to turn it on except you are clearly know its meaning.

    Returns:
        Return a task object.

    Examples:
        .. code-block:: python

            >>> # doctest: +REQUIRES(env: DISTRIBUTED)
            >>> import paddle
            >>> import paddle.distributed as dist

            >>> dist.init_parallel_env()
            >>> out_tensor_list = []
            >>> if dist.get_rank() == 0:
            ...     data1 = paddle.to_tensor([[1, 2, 3], [4, 5, 6]])
            ...     data2 = paddle.to_tensor([[7, 8, 9], [10, 11, 12]])
            >>> else:
            ...     data1 = paddle.to_tensor([[13, 14, 15], [16, 17, 18]])
            ...     data2 = paddle.to_tensor([[19, 20, 21], [22, 23, 24]])
            >>> task = dist.stream.alltoall(out_tensor_list, [data1, data2], sync_op=False)
            >>> task.wait()
            >>> print(out_tensor_list)
            >>> # [[[1, 2, 3], [4, 5, 6]], [[13, 14, 15], [16, 17, 18]]]    (2 GPUs, out for rank 0)
            >>> # [[[7, 8, 9], [10, 11, 12]], [[19, 20, 21], [22, 23, 24]]] (2 GPUs, out for rank 1)
    N5use_calc_stream can only be true in sync op behavior.zThe output should be specified.zThe input should be specified.z:The output and input should be both tensor or tensor list.z3Group can not be used in static graph mode for now.)
r   r   r   in_dynamic_moder   r   Z	is_tensorr   r   r.   )r+   r,   r
   r   r   Zout_is_tensorZin_is_tensorr   r   r   r      sV   .


r   c                    s   t ||d u rfddtD }|d u r% fddtD }|r0|j ||S |j |||}|r@|  |S )Nc                       g | ]	} j d   qS r   r%   r   _)r   
world_sizer   r   r          z/_alltoall_single_in_dygraph.<locals>.<listcomp>c                    r1   r2   r3   r4   )r	   r6   r   r   r      r7   )r    r!   ranger   Z all_to_all_single_on_calc_streamZall_to_all_singler   )r   r	   out_split_sizesin_split_sizesr
   r   r   r   r   )r	   r   r6   r   _alltoall_single_in_dygraph   s&   
	
r;   c                 C   sR   t |rdS |s|rtdt r%|du rt n|}t| ||||||S td)a  

    Split and Scatter the splitted input tensor to the out tensor across devices.

    Args:
        out_tensor(Tensor): The output tensor. Its data type should be the same as the input.
        in_tensor (Tensor): The input tensor. Its data type should be float16, float32, float64, int32, int64, int8, uint8 or bool.
        out_split_sizes (List[int], optional): Split sizes of out_tensor for dim[0]. If not given, dim[0] of out_tensor must be divisible
            by group size and out_tensor will be gathered averagely from all participators. If none is given, use a empty list as default.
        in_split_sizes (List[int], optional): Split sizes of in_tensor for dim[0]. If not given, dim[0] of in_tensor must be divisible
        by group size and in_tensor will be scattered averagely to all participators. If none is given, use a empty list as default.
        group (Group, optional): Communicate in which group. If none is given, use the global group as default.
        sync_op (bool, optional): Indicate whether the communication is sync or not. If none is given, use true as default.
        use_calc_stream (bool, optional): Indicate whether the communication is done on calculation stream. If none is given, use false as default. This
            option is designed for high performance demand, be careful to turn it on except you are clearly know its meaning.

    Returns:
        Return a task object.

    Warning:
        This API only supports the dygraph mode now.

    Examples:
        .. code-block:: python

            >>> # doctest: +REQUIRES(env: DISTRIBUTED)
            >>> import paddle
            >>> import paddle.distributed as dist

            >>> dist.init_parallel_env()
            >>> local_rank = dist.get_rank()

            >>> # case 1
            >>> output = paddle.empty([2], dtype="int64")
            >>> if local_rank == 0:
            ...     data = paddle.to_tensor([0, 1])
            >>> else:
            ...     data = paddle.to_tensor([2, 3])
            >>> task = dist.stream.alltoall_single(output, data, sync_op=False)
            >>> task.wait()
            >>> out = output.numpy()
            >>> print(out)
            >>> # [0, 2] (2 GPUs, out for rank 0)
            >>> # [1, 3] (2 GPUs, out for rank 1)

            >>> # case 2
            >>> size = dist.get_world_size()
            >>> output = paddle.empty([(local_rank + 1) * size, size], dtype='float32')
            >>> if local_rank == 0:
            ...     data = paddle.to_tensor([[0., 0.], [0., 0.], [0., 0.]])
            >>> else:
            ...     data = paddle.to_tensor([[1., 1.], [1., 1.], [1., 1.]])
            >>> out_split_sizes = [local_rank + 1 for i in range(size)]
            >>> in_split_sizes = [i + 1 for i in range(size)]
            >>> task = dist.stream.alltoall_single(output,
            ...                                 data,
            ...                                 out_split_sizes,
            ...                                 in_split_sizes,
            ...                                 sync_op=False)
            >>> task.wait()
            >>> out = output.numpy()
            >>> print(out)
            >>> # [[0., 0.], [1., 1.]]                     (2 GPUs, out for rank 0)
            >>> # [[0., 0.], [0., 0.], [1., 1.], [1., 1.]] (2 GPUs, out for rank 1)
    Nr/   zPpaddle.distributed.stream.alltoall_single is only supported in dygraph mode now.)r   r   r   r0   r   r;   )r   r	   r9   r:   r
   r   r   r   r   r   alltoall_single   s(   J
r<   )NTF)NNNTF)r   Zpaddle.distributeddistributedr    r   Zpaddle.baser   Z&paddle.distributed.communication.groupr   r   r   r   r.   r   r;   r<   r   r   r   r   <module>   s&   A
`$