COMM_SCRIPT = r'''
import contextlib, json, os, time, torch
from torch import nn
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
from d2l import torch as d2l
rank = int(os.environ["LOCAL_RANK"])
torch.cuda.set_device(rank)
dist.init_process_group("nccl", device_id=torch.device("cuda", rank))
torch.set_float32_matmul_precision("high"); torch.backends.cudnn.benchmark = True
model = d2l.resnet18(10, 1).to(rank)
model(torch.zeros(1, 1, 64, 64, device=rank))
model = DDP(model, device_ids=[rank])
loss = nn.CrossEntropyLoss()
X = torch.randn(256, 1, 64, 64, device=rank)
y = torch.randint(0, 10, (256,), device=rank)
def fwd_bwd():
model.zero_grad(set_to_none=True)
loss(model(X), y).backward()
def step_time(sync_grads, steps=30):
ctx = contextlib.nullcontext if sync_grads else model.no_sync
for _ in range(10): # warmup
with ctx(): fwd_bwd()
torch.cuda.synchronize(); dist.barrier(); t0 = time.time()
for _ in range(steps):
with ctx(): fwd_bwd()
torch.cuda.synchronize()
return (time.time() - t0) / steps
synced, silent = step_time(True), step_time(False)
if rank == 0:
here = os.path.dirname(os.path.abspath(__file__))
with open(os.path.join(here, "comm.json"), "w") as f:
json.dump({"synced_ms": 1e3 * synced, "no_sync_ms": 1e3 * silent}, f)
dist.destroy_process_group()
'''
_ = (DDP_DIR / 'comm_probe.py').write_text(COMM_SCRIPT)
net = resnet18(10, 1) # the gradient bytes, N
net(torch.zeros(1, 1, 64, 64)) # materialize Lazy params
n_bytes = 4 * sum(p.numel() for p in net.parameters())
beta = 4.5e9 # NCCL allreduce, effective bytes/device/s on this box (13.5)
if d2l.num_gpus() >= 2:
torchrun = str(pathlib.Path(sys.executable).parent / 'torchrun')
subprocess.run([torchrun, '--standalone', '--nproc-per-node=2',
str(DDP_DIR / 'comm_probe.py')], check=True)
with open(DDP_DIR / 'comm.json') as f:
comm = json.load(f)
print(f"k=2: predicted comm 2N/beta = {2 * n_bytes / beta * 1e3:.0f} "
f"ms/step; measured {comm['synced_ms'] - comm['no_sync_ms']:.0f} ms "
f"(synced {comm['synced_ms']:.0f}, no_sync {comm['no_sync_ms']:.0f})")