chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
import functools
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import torch
|
||||
|
||||
from fairseq import distributed_utils as dist_utils
|
||||
|
||||
from .utils import objects_are_equal, spawn_and_init
|
||||
|
||||
|
||||
class TestDistributedUtils(unittest.TestCase):
|
||||
def setUp(self):
|
||||
if not torch.cuda.is_available():
|
||||
raise unittest.SkipTest("CUDA not available, skipping test")
|
||||
if sys.platform == "win32":
|
||||
raise unittest.SkipTest("NCCL doesn't support Windows, skipping test")
|
||||
if torch.cuda.device_count() < 2:
|
||||
raise unittest.SkipTest("distributed tests require 2+ GPUs, skipping")
|
||||
|
||||
def test_broadcast_object_python(self):
|
||||
spawn_and_init(
|
||||
functools.partial(
|
||||
TestDistributedUtils._test_broadcast_object,
|
||||
"hello world",
|
||||
),
|
||||
world_size=2,
|
||||
)
|
||||
|
||||
def test_broadcast_object_tensor(self):
|
||||
spawn_and_init(
|
||||
functools.partial(
|
||||
TestDistributedUtils._test_broadcast_object,
|
||||
torch.rand(5),
|
||||
),
|
||||
world_size=2,
|
||||
)
|
||||
|
||||
def test_broadcast_object_complex(self):
|
||||
spawn_and_init(
|
||||
functools.partial(
|
||||
TestDistributedUtils._test_broadcast_object,
|
||||
{
|
||||
"a": "1",
|
||||
"b": [2, torch.rand(2, 3), 3],
|
||||
"c": (torch.rand(2, 3), 4),
|
||||
"d": {5, torch.rand(5)},
|
||||
"e": torch.rand(5),
|
||||
"f": torch.rand(5).int().cuda(),
|
||||
},
|
||||
),
|
||||
world_size=2,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _test_broadcast_object(ref_obj, rank, group):
|
||||
obj = dist_utils.broadcast_object(
|
||||
ref_obj if rank == 0 else None, src_rank=0, group=group
|
||||
)
|
||||
assert objects_are_equal(ref_obj, obj)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,61 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
import functools
|
||||
import tempfile
|
||||
|
||||
import torch
|
||||
|
||||
|
||||
def spawn_and_init(fn, world_size, args=None):
|
||||
if args is None:
|
||||
args = ()
|
||||
with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
|
||||
torch.multiprocessing.spawn(
|
||||
fn=functools.partial(init_and_run, fn, args),
|
||||
args=(world_size, tmp_file.name,),
|
||||
nprocs=world_size,
|
||||
)
|
||||
|
||||
|
||||
def distributed_init(rank, world_size, tmp_file):
|
||||
torch.distributed.init_process_group(
|
||||
backend="nccl",
|
||||
init_method="file://{}".format(tmp_file),
|
||||
world_size=world_size,
|
||||
rank=rank,
|
||||
)
|
||||
torch.cuda.set_device(rank)
|
||||
|
||||
|
||||
def init_and_run(fn, args, rank, world_size, tmp_file):
|
||||
distributed_init(rank, world_size, tmp_file)
|
||||
group = torch.distributed.new_group()
|
||||
fn(rank, group, *args)
|
||||
|
||||
|
||||
def objects_are_equal(a, b) -> bool:
|
||||
if type(a) is not type(b):
|
||||
return False
|
||||
if isinstance(a, dict):
|
||||
if set(a.keys()) != set(b.keys()):
|
||||
return False
|
||||
for k in a.keys():
|
||||
if not objects_are_equal(a[k], b[k]):
|
||||
return False
|
||||
return True
|
||||
elif isinstance(a, (list, tuple, set)):
|
||||
if len(a) != len(b):
|
||||
return False
|
||||
return all(objects_are_equal(x, y) for x, y in zip(a, b))
|
||||
elif torch.is_tensor(a):
|
||||
return (
|
||||
a.size() == b.size()
|
||||
and a.dtype == b.dtype
|
||||
and a.device == b.device
|
||||
and torch.all(a == b)
|
||||
)
|
||||
else:
|
||||
return a == b
|
||||
Reference in New Issue
Block a user