xingzhaohu's picture
Add files using upload-large-folder tool
e0a61be verified
Raw
History Blame Contribute Delete
3.94 kB
# Copyright (c) OpenMMLab. All rights reserved.
from typing import Any, Tuple
import torch
import torch.distributed as dist
from torch import Tensor
from torch.distributed.distributed_c10d import (_get_pg_default_device,
_object_to_tensor,
_tensor_to_object)
# Modified from https://github.com/microsoft/DeepSpeed/blob/ffd0a0e3ef24bfd00c2e5f35019d2674cc01ec14/deepspeed/sequence/layer.py#L15 # noqa: E501
def _all_to_all(
input: Tensor,
world_size: int,
group: dist.ProcessGroup,
scatter_dim: int,
gather_dim: int,
):
input_list = [
t.contiguous()
for t in torch.tensor_split(input, world_size, scatter_dim)
]
output_list = [torch.empty_like(input_list[0]) for _ in range(world_size)]
dist.all_to_all(output_list, input_list, group=group)
return torch.cat(output_list, dim=gather_dim).contiguous()
class _AllToAll(torch.autograd.Function):
"""All-to-all communication.
Args:
input: Input tensor
sp_group: Sequence parallel process group
scatter_dim: Scatter dimension
gather_dim: Gather dimension
"""
@staticmethod
def forward(ctx: Any, input: Tensor, sp_group: dist.ProcessGroup,
scatter_dim: int, gather_dim: int):
ctx.sp_group = sp_group
ctx.scatter_dim = scatter_dim
ctx.gather_dim = gather_dim
ctx.world_size = dist.get_world_size(sp_group)
output = _all_to_all(input, ctx.world_size, sp_group, scatter_dim,
gather_dim)
return output
@staticmethod
def backward(ctx: Any, grad_output: Tensor) -> Tuple:
grad_output = _all_to_all(
grad_output,
ctx.world_size,
ctx.sp_group,
ctx.gather_dim,
ctx.scatter_dim,
)
return (
grad_output,
None,
None,
None,
)
def all_to_all(
input: Tensor,
sp_group: dist.ProcessGroup,
scatter_dim: int = 2,
gather_dim: int = 1,
):
"""Convenience function to apply the all-to-all operation with scatter and
gather dimensions.
Notes:
We have wrapped the `torch.distributed.all_to_all` function to
enable automatic differentiation of the all-to-all operation.
Args:
input: The input tensor for which all-to-all communication is performed
sp_group: The sequence parallel process group.
scatter_dim: The dimension along which the input tensor is scattered
(default: 2).
gather_dim: The dimension along which the output tensor is gathered
(default: 1).
Returns:
The output tensor after the all-to-all communication.
"""
return _AllToAll.apply(input, sp_group, scatter_dim, gather_dim)
def all_to_all_list(object_list, group=None):
current_device = _get_pg_default_device(group)
rank = dist.get_rank(group)
world_size = dist.get_world_size(group)
tensor_list, size_list = zip(
*
[_object_to_tensor(obj, current_device, group) for obj in object_list])
tensor_list = list(tensor_list)
size_list = torch.cat(size_list)
buffer = [None] * world_size
dist.all_gather_object(buffer, size_list, group=group)
size_this_rank = []
for size_list in buffer:
size_this_rank.append(size_list[rank])
target_tensor_list = [
torch.empty(size.item(), dtype=torch.uint8, device=current_device)
for size in size_this_rank
]
dist.all_to_all(target_tensor_list, tensor_list, group=group)
for i in range(len(target_tensor_list)):
obj_view = target_tensor_list[i].type(torch.uint8)
target_tensor_list[i] = _tensor_to_object(obj_view, size_this_rank[i],
group)
return target_tensor_list