From 007902ee68564203af339e652fe3c10c394600c6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 12:04:55 +0200 Subject: [PATCH 01/33] Update DDP for `torch.distributed.run` --- train.py | 69 +++++++++++++++++++++++------------------------ utils/datasets.py | 4 +-- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/train.py b/train.py index 3eb866345d47..5b1a304463ee 100644 --- a/train.py +++ b/train.py @@ -37,15 +37,16 @@ from utils.wandb_logging.wandb_utils import WandbLogger, check_wandb_resume logger = logging.getLogger(__name__) +WORLD_SIZE = int(getattr(os.environ, 'WORLD_SIZE', 1)) +RANK = int(getattr(os.environ, 'RANK', -1)) def train(hyp, # path/to/hyp.yaml or hyp dictionary opt, device, ): - save_dir, epochs, batch_size, total_batch_size, weights, rank, single_cls = \ - Path(opt.save_dir), opt.epochs, opt.batch_size, opt.total_batch_size, opt.weights, opt.global_rank, \ - opt.single_cls + save_dir, epochs, batch_size, total_batch_size, weights, single_cls = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.total_batch_size, opt.weights, opt.single_cls # Directories wdir = save_dir / 'weights' @@ -69,13 +70,13 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # Configure plots = not opt.evolve # create plots cuda = device.type != 'cpu' - init_seeds(2 + rank) + init_seeds(2 + RANK) with open(opt.data) as f: data_dict = yaml.safe_load(f) # data dict # Loggers loggers = {'wandb': None, 'tb': None} # loggers dict - if rank in [-1, 0]: + if RANK in [-1, 0]: # TensorBoard if not opt.evolve: prefix = colorstr('tensorboard: ') @@ -99,7 +100,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # Model pretrained = weights.endswith('.pt') if pretrained: - with torch_distributed_zero_first(rank): + with torch_distributed_zero_first(RANK): weights = attempt_download(weights) # download if not found locally ckpt = torch.load(weights, map_location=device) # load checkpoint model = Model(opt.cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create @@ -110,7 +111,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary logger.info('Transferred %g/%g items from %s' % (len(state_dict), len(model.state_dict()), weights)) # report else: model = Model(opt.cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create - with torch_distributed_zero_first(rank): + with torch_distributed_zero_first(RANK): check_dataset(data_dict) # check train_path = data_dict['train'] test_path = data_dict['val'] @@ -158,7 +159,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # plot_lr_scheduler(optimizer, scheduler, epochs) # EMA - ema = ModelEMA(model) if rank in [-1, 0] else None + ema = ModelEMA(model) if RANK in [-1, 0] else None # Resume start_epoch, best_fitness = 0, 0.0 @@ -194,28 +195,28 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary imgsz, imgsz_test = [check_img_size(x, gs) for x in opt.img_size] # verify imgsz are gs-multiples # DP mode - if cuda and rank == -1 and torch.cuda.device_count() > 1: + if cuda and RANK == -1 and torch.cuda.device_count() > 1: model = torch.nn.DataParallel(model) # SyncBatchNorm - if opt.sync_bn and cuda and rank != -1: + if opt.sync_bn and cuda and RANK != -1: model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) logger.info('Using SyncBatchNorm()') # Trainloader dataloader, dataset = create_dataloader(train_path, imgsz, batch_size, gs, single_cls, - hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, rank=rank, - world_size=opt.world_size, workers=opt.workers, + hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, rank=RANK, + workers=opt.workers // WORLD_SIZE, image_weights=opt.image_weights, quad=opt.quad, prefix=colorstr('train: ')) mlc = np.concatenate(dataset.labels, 0)[:, 0].max() # max label class nb = len(dataloader) # number of batches assert mlc < nc, 'Label class %g exceeds nc=%g in %s. Possible class labels are 0-%g' % (mlc, nc, opt.data, nc - 1) # Process 0 - if rank in [-1, 0]: + if RANK in [-1, 0]: testloader = create_dataloader(test_path, imgsz_test, batch_size * 2, gs, single_cls, hyp=hyp, cache=opt.cache_images and not opt.notest, rect=True, rank=-1, - world_size=opt.world_size, workers=opt.workers, + workers=opt.workers, pad=0.5, prefix=colorstr('val: '))[0] if not opt.resume: @@ -234,7 +235,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary model.half().float() # pre-reduce anchor precision # DDP mode - if cuda and rank != -1: + if cuda and RANK != -1: model = DDP(model, device_ids=[opt.local_rank], output_device=opt.local_rank, # nn.MultiheadAttention incompatibility with DDP https://github.com/pytorch/pytorch/issues/26698 find_unused_parameters=any(isinstance(layer, nn.MultiheadAttention) for layer in model.modules())) @@ -269,15 +270,15 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # Update image weights (optional) if opt.image_weights: # Generate indices - if rank in [-1, 0]: + if RANK in [-1, 0]: cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx # Broadcast if DDP - if rank != -1: - indices = (torch.tensor(dataset.indices) if rank == 0 else torch.zeros(dataset.n)).int() + if RANK != -1: + indices = (torch.tensor(dataset.indices) if RANK == 0 else torch.zeros(dataset.n)).int() dist.broadcast(indices, 0) - if rank != 0: + if RANK != 0: dataset.indices = indices.cpu().numpy() # Update mosaic border @@ -285,11 +286,11 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # dataset.mosaic_border = [b - imgsz, -b] # height, width borders mloss = torch.zeros(4, device=device) # mean losses - if rank != -1: + if RANK != -1: dataloader.sampler.set_epoch(epoch) pbar = enumerate(dataloader) logger.info(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'total', 'labels', 'img_size')) - if rank in [-1, 0]: + if RANK in [-1, 0]: pbar = tqdm(pbar, total=nb) # progress bar optimizer.zero_grad() for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- @@ -319,8 +320,8 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary with amp.autocast(enabled=cuda): pred = model(imgs) # forward loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size - if rank != -1: - loss *= opt.world_size # gradient averaged between devices in DDP mode + if RANK != -1: + loss *= WORLD_SIZE # gradient averaged between devices in DDP mode if opt.quad: loss *= 4. @@ -336,7 +337,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary ema.update(model) # Print - if rank in [-1, 0]: + if RANK in [-1, 0]: mloss = (mloss * i + loss_items) / (i + 1) # update mean losses mem = '%.3gG' % (torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0) # (GB) s = ('%10s' * 2 + '%10.4g' * 6) % ( @@ -362,7 +363,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary scheduler.step() # DDP process 0 or single-GPU - if rank in [-1, 0]: + if RANK in [-1, 0]: # mAP ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'gr', 'names', 'stride', 'class_weights']) final_epoch = epoch + 1 == epochs @@ -424,7 +425,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # end epoch ---------------------------------------------------------------------------------------------------- # end training ----------------------------------------------------------------------------------------------------- - if rank in [-1, 0]: + if RANK in [-1, 0]: logger.info(f'{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.\n') if plots: plot_results(save_dir=save_dir) # save as results.png @@ -502,10 +503,8 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary opt = parser.parse_args() # Set DDP variables - opt.world_size = int(getattr(os.environ, 'WORLD_SIZE', 1)) - opt.global_rank = int(getattr(os.environ, 'RANK', -1)) - set_logging(opt.global_rank) - if opt.global_rank in [-1, 0]: + set_logging(RANK) + if RANK in [-1, 0]: check_git_status() check_requirements(exclude=['thop']) @@ -514,11 +513,11 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary if opt.resume and not wandb_run: # resume an interrupted run ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run() # specified or most recent path assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' - apriori = opt.global_rank, opt.local_rank + apriori_local_rank = opt.local_rank with open(Path(ckpt).parent.parent / 'opt.yaml') as f: opt = argparse.Namespace(**yaml.safe_load(f)) # replace - opt.cfg, opt.weights, opt.resume, opt.batch_size, opt.global_rank, opt.local_rank = \ - '', ckpt, True, opt.total_batch_size, *apriori # reinstate + opt.cfg, opt.weights, opt.resume, opt.batch_size, opt.local_rank = \ + '', ckpt, True, opt.total_batch_size, apriori_local_rank # reinstate logger.info('Resuming training from %s' % ckpt) else: # opt.hyp = opt.hyp or ('hyp.finetune.yaml' if opt.weights else 'hyp.scratch.yaml') @@ -536,9 +535,9 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary torch.cuda.set_device(opt.local_rank) device = torch.device('cuda', opt.local_rank) dist.init_process_group(backend='nccl', init_method='env://') # distributed backend - assert opt.batch_size % opt.world_size == 0, '--batch-size must be multiple of CUDA device count' + assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' - opt.batch_size = opt.total_batch_size // opt.world_size + opt.batch_size = opt.total_batch_size // WORLD_SIZE # Train logger.info(opt) diff --git a/utils/datasets.py b/utils/datasets.py index f927abb20f5a..b842c056e263 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -64,7 +64,7 @@ def exif_size(img): def create_dataloader(path, imgsz, batch_size, stride, single_cls=False, hyp=None, augment=False, cache=False, pad=0.0, - rect=False, rank=-1, world_size=1, workers=8, image_weights=False, quad=False, prefix=''): + rect=False, rank=-1, workers=8, image_weights=False, quad=False, prefix=''): # Make sure only the first process in DDP process the dataset first, and the following others can use the cache with torch_distributed_zero_first(rank): dataset = LoadImagesAndLabels(path, imgsz, batch_size, @@ -79,7 +79,7 @@ def create_dataloader(path, imgsz, batch_size, stride, single_cls=False, hyp=Non prefix=prefix) batch_size = min(batch_size, len(dataset)) - nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, workers]) # number of workers + nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, workers]) # number of workers sampler = torch.utils.data.distributed.DistributedSampler(dataset) if rank != -1 else None loader = torch.utils.data.DataLoader if image_weights else InfiniteDataLoader # Use torch.utils.data.DataLoader() if dataset.properties will update during training else InfiniteDataLoader() From 9bcb4ad16527fa5d68eee5662ff5fa018b4d6784 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 12:19:03 +0200 Subject: [PATCH 02/33] Add LOCAL_RANK --- train.py | 19 +++++++++---------- utils/wandb_logging/wandb_utils.py | 6 ++++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/train.py b/train.py index 5b1a304463ee..d4d93c6ed687 100644 --- a/train.py +++ b/train.py @@ -37,8 +37,9 @@ from utils.wandb_logging.wandb_utils import WandbLogger, check_wandb_resume logger = logging.getLogger(__name__) -WORLD_SIZE = int(getattr(os.environ, 'WORLD_SIZE', 1)) +LOCAL_RANK = int(getattr(os.environ, 'LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html RANK = int(getattr(os.environ, 'RANK', -1)) +WORLD_SIZE = int(getattr(os.environ, 'WORLD_SIZE', 1)) def train(hyp, # path/to/hyp.yaml or hyp dictionary @@ -236,7 +237,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # DDP mode if cuda and RANK != -1: - model = DDP(model, device_ids=[opt.local_rank], output_device=opt.local_rank, + model = DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK, # nn.MultiheadAttention incompatibility with DDP https://github.com/pytorch/pytorch/issues/26698 find_unused_parameters=any(isinstance(layer, nn.MultiheadAttention) for layer in model.modules())) @@ -513,11 +514,9 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary if opt.resume and not wandb_run: # resume an interrupted run ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run() # specified or most recent path assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' - apriori_local_rank = opt.local_rank with open(Path(ckpt).parent.parent / 'opt.yaml') as f: opt = argparse.Namespace(**yaml.safe_load(f)) # replace - opt.cfg, opt.weights, opt.resume, opt.batch_size, opt.local_rank = \ - '', ckpt, True, opt.total_batch_size, apriori_local_rank # reinstate + opt.cfg, opt.weights, opt.resume, opt.batch_size = '', ckpt, True, opt.total_batch_size # reinstate logger.info('Resuming training from %s' % ckpt) else: # opt.hyp = opt.hyp or ('hyp.finetune.yaml' if opt.weights else 'hyp.scratch.yaml') @@ -530,10 +529,10 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # DDP mode opt.total_batch_size = opt.batch_size device = select_device(opt.device, batch_size=opt.batch_size) - if opt.local_rank != -1: - assert torch.cuda.device_count() > opt.local_rank - torch.cuda.set_device(opt.local_rank) - device = torch.device('cuda', opt.local_rank) + if LOCAL_RANK != -1: + assert torch.cuda.device_count() > LOCAL_RANK + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) dist.init_process_group(backend='nccl', init_method='env://') # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' @@ -578,7 +577,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary with open(opt.hyp) as f: hyp = yaml.safe_load(f) # load hyps dict - assert opt.local_rank == -1, 'DDP mode not implemented for --evolve' + assert LOCAL_RANK == -1, 'DDP mode not implemented for --evolve' opt.notest, opt.nosave = True, True # only test/save final epoch # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices yaml_file = Path(opt.save_dir) / 'hyp_evolved.yaml' # save best result here diff --git a/utils/wandb_logging/wandb_utils.py b/utils/wandb_logging/wandb_utils.py index 7652f964f2c0..59213929c47d 100644 --- a/utils/wandb_logging/wandb_utils.py +++ b/utils/wandb_logging/wandb_utils.py @@ -1,5 +1,6 @@ """Utilities and tools for tracking runs with Weights & Biases.""" import logging +import os import sys from contextlib import contextmanager from pathlib import Path @@ -18,6 +19,7 @@ except ImportError: wandb = None +RANK = int(getattr(os.environ, 'RANK', -1)) WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' @@ -42,10 +44,10 @@ def get_run_info(run_path): def check_wandb_resume(opt): - process_wandb_config_ddp_mode(opt) if opt.global_rank not in [-1, 0] else None + process_wandb_config_ddp_mode(opt) if RANK not in [-1, 0] else None if isinstance(opt.resume, str): if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): - if opt.global_rank not in [-1, 0]: # For resuming DDP runs + if RANK not in [-1, 0]: # For resuming DDP runs entity, project, run_id, model_artifact_name = get_run_info(opt.resume) api = wandb.Api() artifact = api.artifact(entity + '/' + project + '/' + model_artifact_name + ':latest') From b32bae0631318a0d1f36b1e703e96f8f7fefc317 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 12:26:58 +0200 Subject: [PATCH 03/33] remove opt.local_rank --- train.py | 1 - 1 file changed, 1 deletion(-) diff --git a/train.py b/train.py index d4d93c6ed687..cf14e0997771 100644 --- a/train.py +++ b/train.py @@ -488,7 +488,6 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') - parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers') parser.add_argument('--project', default='runs/train', help='save to project/name') parser.add_argument('--entity', default=None, help='W&B entity') From b467501fe41c71d85ee02ba7028623dd7764b68e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 12:45:46 +0200 Subject: [PATCH 04/33] backend="gloo|nccl" --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index cf14e0997771..fcb38f128c5b 100644 --- a/train.py +++ b/train.py @@ -532,7 +532,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary assert torch.cuda.device_count() > LOCAL_RANK torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend='nccl', init_method='env://') # distributed backend + dist.init_process_group(backend="gloo|nccl") # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From c886538f9d5c54d114506031d87ff57132dcdf59 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 13:16:09 +0200 Subject: [PATCH 05/33] print --- train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/train.py b/train.py index fcb38f128c5b..748ccea4bae0 100644 --- a/train.py +++ b/train.py @@ -531,6 +531,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary if LOCAL_RANK != -1: assert torch.cuda.device_count() > LOCAL_RANK torch.cuda.set_device(LOCAL_RANK) + print({'RANK': RANK, 'LOCAL_RANK': LOCAL_RANK, 'WORLD_SIZE': WORLD_SIZE}) device = torch.device('cuda', LOCAL_RANK) dist.init_process_group(backend="gloo|nccl") # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' From 5d847dc143485c907909f0c16aa7f6fb3fc5a657 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 13:17:42 +0200 Subject: [PATCH 06/33] print --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 748ccea4bae0..6aaf41eb32cc 100644 --- a/train.py +++ b/train.py @@ -528,10 +528,10 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # DDP mode opt.total_batch_size = opt.batch_size device = select_device(opt.device, batch_size=opt.batch_size) + print({'RANK': RANK, 'LOCAL_RANK': LOCAL_RANK, 'WORLD_SIZE': WORLD_SIZE}) if LOCAL_RANK != -1: assert torch.cuda.device_count() > LOCAL_RANK torch.cuda.set_device(LOCAL_RANK) - print({'RANK': RANK, 'LOCAL_RANK': LOCAL_RANK, 'WORLD_SIZE': WORLD_SIZE}) device = torch.device('cuda', LOCAL_RANK) dist.init_process_group(backend="gloo|nccl") # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' From 26d0ecf185f42d2741aa2a896d3259783536169f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 13:21:00 +0200 Subject: [PATCH 07/33] debug --- train.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/train.py b/train.py index 6aaf41eb32cc..348f7f24f59f 100644 --- a/train.py +++ b/train.py @@ -502,6 +502,10 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used') opt = parser.parse_args() + LOCAL_RANK = int(getattr(os.environ, 'LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html + RANK = int(getattr(os.environ, 'RANK', -1)) + WORLD_SIZE = int(getattr(os.environ, 'WORLD_SIZE', 1)) + # Set DDP variables set_logging(RANK) if RANK in [-1, 0]: From 832ba4c8c69391b6a601ed422fbc0d4a9e476351 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 13:26:23 +0200 Subject: [PATCH 08/33] debug --- train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/train.py b/train.py index 348f7f24f59f..5ab25a7b093a 100644 --- a/train.py +++ b/train.py @@ -484,6 +484,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') From 9a1bb01e576635b04d2c4215a234d81bd85bd04b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 13:34:56 +0200 Subject: [PATCH 09/33] os.getenv --- train.py | 6 +++--- utils/wandb_logging/wandb_utils.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index 5ab25a7b093a..41edffa6bcce 100644 --- a/train.py +++ b/train.py @@ -503,9 +503,9 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used') opt = parser.parse_args() - LOCAL_RANK = int(getattr(os.environ, 'LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html - RANK = int(getattr(os.environ, 'RANK', -1)) - WORLD_SIZE = int(getattr(os.environ, 'WORLD_SIZE', 1)) + LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html + RANK = int(os.getenv('RANK', -1)) + WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) # Set DDP variables set_logging(RANK) diff --git a/utils/wandb_logging/wandb_utils.py b/utils/wandb_logging/wandb_utils.py index 59213929c47d..43b4c3d04e8e 100644 --- a/utils/wandb_logging/wandb_utils.py +++ b/utils/wandb_logging/wandb_utils.py @@ -19,7 +19,7 @@ except ImportError: wandb = None -RANK = int(getattr(os.environ, 'RANK', -1)) +RANK = int(os.getenv('RANK', -1)) WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' From 0e912df75eca4f2f67031808b18435ce3bbb6010 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 13:36:06 +0200 Subject: [PATCH 10/33] gloo --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 41edffa6bcce..6729e82f1b42 100644 --- a/train.py +++ b/train.py @@ -538,7 +538,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary assert torch.cuda.device_count() > LOCAL_RANK torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="gloo|nccl") # distributed backend + dist.init_process_group(backend="gloo") # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From 5f5e4289e1cc72f8ae43b565a6e901f77d27342b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 13:37:11 +0200 Subject: [PATCH 11/33] gloo --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 6729e82f1b42..c21f214a723e 100644 --- a/train.py +++ b/train.py @@ -538,7 +538,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary assert torch.cuda.device_count() > LOCAL_RANK torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="gloo") # distributed backend + dist.init_process_group(backend="nccl") # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From e8493c6065c27b6dd36a521aa372a9e9d115fd0b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 13:41:43 +0200 Subject: [PATCH 12/33] gloo --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index c21f214a723e..6729e82f1b42 100644 --- a/train.py +++ b/train.py @@ -538,7 +538,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary assert torch.cuda.device_count() > LOCAL_RANK torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="nccl") # distributed backend + dist.init_process_group(backend="gloo") # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From fb342fc8fc84cdfdbb090749faeb7ee2e3e992e6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 13:49:19 +0200 Subject: [PATCH 13/33] cleanup --- train.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/train.py b/train.py index 6729e82f1b42..ee1295ca3a59 100644 --- a/train.py +++ b/train.py @@ -484,7 +484,6 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') @@ -503,11 +502,6 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used') opt = parser.parse_args() - LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html - RANK = int(os.getenv('RANK', -1)) - WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) - - # Set DDP variables set_logging(RANK) if RANK in [-1, 0]: check_git_status() @@ -535,7 +529,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary device = select_device(opt.device, batch_size=opt.batch_size) print({'RANK': RANK, 'LOCAL_RANK': LOCAL_RANK, 'WORLD_SIZE': WORLD_SIZE}) if LOCAL_RANK != -1: - assert torch.cuda.device_count() > LOCAL_RANK + assert torch.cuda.device_count() > LOCAL_RANK, 'too few GPUS for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) dist.init_process_group(backend="gloo") # distributed backend From 382ce4ffdd7ca7e575e8102f8e2949f479a80dfd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 14:04:51 +0200 Subject: [PATCH 14/33] fix getenv --- train.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index ee1295ca3a59..e31c0dbd3e69 100644 --- a/train.py +++ b/train.py @@ -37,9 +37,9 @@ from utils.wandb_logging.wandb_utils import WandbLogger, check_wandb_resume logger = logging.getLogger(__name__) -LOCAL_RANK = int(getattr(os.environ, 'LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html -RANK = int(getattr(os.environ, 'RANK', -1)) -WORLD_SIZE = int(getattr(os.environ, 'WORLD_SIZE', 1)) +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) def train(hyp, # path/to/hyp.yaml or hyp dictionary From b09b415139d6a15f9fc8677f5d6096eb81b6bbaa Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 14:27:28 +0200 Subject: [PATCH 15/33] cleanup --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index e31c0dbd3e69..79d1b882c38a 100644 --- a/train.py +++ b/train.py @@ -207,7 +207,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # Trainloader dataloader, dataset = create_dataloader(train_path, imgsz, batch_size, gs, single_cls, hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, rank=RANK, - workers=opt.workers // WORLD_SIZE, + workers=opt.workers, image_weights=opt.image_weights, quad=opt.quad, prefix=colorstr('train: ')) mlc = np.concatenate(dataset.labels, 0)[:, 0].max() # max label class nb = len(dataloader) # number of batches From 9c4ac0530e036fb863216677982bc324a98815e0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 16:11:49 +0200 Subject: [PATCH 16/33] cleanup destroy --- train.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/train.py b/train.py index 79d1b882c38a..ae70e237a250 100644 --- a/train.py +++ b/train.py @@ -459,7 +459,8 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary name='run_' + wandb_logger.wandb_run.id + '_model', aliases=['latest', 'best', 'stripped']) wandb_logger.finish_run() - else: + + if WORLD_SIZE > 1: dist.destroy_process_group() torch.cuda.empty_cache() return results From 8ae9ea1fac7e442403e83c719867decfad385b36 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Jun 2021 16:13:13 +0200 Subject: [PATCH 17/33] try nccl --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index ae70e237a250..e4838e61b503 100644 --- a/train.py +++ b/train.py @@ -533,7 +533,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary assert torch.cuda.device_count() > LOCAL_RANK, 'too few GPUS for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="gloo") # distributed backend + dist.init_process_group(backend="nccl") # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From 24357757feeac846cff663667751e9cf42d55cc6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 14:30:53 +0200 Subject: [PATCH 18/33] return opt --- train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/train.py b/train.py index 17d7a33f37b1..9d998bb55aea 100644 --- a/train.py +++ b/train.py @@ -502,6 +502,7 @@ def parse_opt(): parser.add_argument('--save_period', type=int, default=-1, help='Log model after every "save_period" epoch') parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used') opt = parser.parse_args() + return opt def main(opt): From 56a4ab4cb799a6929ddcdbff08acd03813c92c62 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 14:32:56 +0200 Subject: [PATCH 19/33] add --local_rank --- train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/train.py b/train.py index 9d998bb55aea..baa1e24538cb 100644 --- a/train.py +++ b/train.py @@ -501,6 +501,7 @@ def parse_opt(): parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval for W&B') parser.add_argument('--save_period', type=int, default=-1, help='Log model after every "save_period" epoch') parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used') + parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') opt = parser.parse_args() return opt From c4d839b99e25d2af260939aaf0dc0e6a35fc9747 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:04:59 +0200 Subject: [PATCH 20/33] add timeout --- train.py | 3 ++- utils/torch_utils.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index baa1e24538cb..012b0555e36f 100644 --- a/train.py +++ b/train.py @@ -535,10 +535,11 @@ def main(opt): device = select_device(opt.device, batch_size=opt.batch_size) print({'RANK': RANK, 'LOCAL_RANK': LOCAL_RANK, 'WORLD_SIZE': WORLD_SIZE}) if LOCAL_RANK != -1: + from datetime import timedelta assert torch.cuda.device_count() > LOCAL_RANK, 'too few GPUS for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="nccl") # distributed backend + dist.init_process_group(backend="gloo", timeout=timedelta(seconds=10)) # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE diff --git a/utils/torch_utils.py b/utils/torch_utils.py index b690dbe96700..2d5382471e3c 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -13,6 +13,7 @@ import torch import torch.backends.cudnn as cudnn +import torch.distributed as dist import torch.nn as nn import torch.nn.functional as F import torchvision @@ -30,10 +31,10 @@ def torch_distributed_zero_first(local_rank: int): Decorator to make all processes in distributed training wait for each local_master to do something. """ if local_rank not in [-1, 0]: - torch.distributed.barrier() + dist.barrier() yield if local_rank == 0: - torch.distributed.barrier() + dist.barrier() def init_torch_seeds(seed=0): From 0584e7e7416a835ea68f201473a7d9867ff4dea4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:10:05 +0200 Subject: [PATCH 21/33] add init_method --- train.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/train.py b/train.py index 012b0555e36f..030f6d910340 100644 --- a/train.py +++ b/train.py @@ -539,7 +539,8 @@ def main(opt): assert torch.cuda.device_count() > LOCAL_RANK, 'too few GPUS for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="gloo", timeout=timedelta(seconds=10)) # distributed backend + # dist.init_process_group(backend="gloo", timeout=timedelta(seconds=10)) # distributed backend + dist.init_process_group(backend="nccl", init_method='env://') # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From d91734163271233aefb6cd9192b69b143f3c3de2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:25:14 +0200 Subject: [PATCH 22/33] gloo --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 030f6d910340..cbfe9fb99cd2 100644 --- a/train.py +++ b/train.py @@ -539,8 +539,8 @@ def main(opt): assert torch.cuda.device_count() > LOCAL_RANK, 'too few GPUS for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - # dist.init_process_group(backend="gloo", timeout=timedelta(seconds=10)) # distributed backend - dist.init_process_group(backend="nccl", init_method='env://') # distributed backend + dist.init_process_group(backend="gloo", timeout=timedelta(seconds=10)) # distributed backend + # dist.init_process_group(backend="nccl", init_method='env://') # distributed backend assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From 6a1cc64e0767d41555f9dc40e627493abde9e85c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:26:23 +0200 Subject: [PATCH 23/33] move destroy --- train.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index cbfe9fb99cd2..5e5e0b1332a8 100644 --- a/train.py +++ b/train.py @@ -460,8 +460,6 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary aliases=['latest', 'best', 'stripped']) wandb_logger.finish_run() - if WORLD_SIZE > 1: - dist.destroy_process_group() torch.cuda.empty_cache() return results @@ -549,6 +547,10 @@ def main(opt): logger.info(opt) if not opt.evolve: train(opt.hyp, opt, device) + if WORLD_SIZE > 1: + print('WORLD_SIZE > 1, destroying...') + dist.destroy_process_group() + print('WORLD_SIZE > 1, done destroying.') # Evolve hyperparameters (optional) else: From 3581c76797738beea3a241fee5ad713be190cb92 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:29:46 +0200 Subject: [PATCH 24/33] move destroy --- train.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/train.py b/train.py index 5e5e0b1332a8..b4d6d8e320f4 100644 --- a/train.py +++ b/train.py @@ -548,9 +548,7 @@ def main(opt): if not opt.evolve: train(opt.hyp, opt, device) if WORLD_SIZE > 1: - print('WORLD_SIZE > 1, destroying...') - dist.destroy_process_group() - print('WORLD_SIZE > 1, done destroying.') + _ = [print('Destroying process group... ', end=''), dist.destroy_process_group(), print('Done.')] # Evolve hyperparameters (optional) else: From 5f5d122a7e99bb7e0d43075d5fa27c7ef38e7368 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:30:39 +0200 Subject: [PATCH 25/33] move print(opt) under if RANK --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index b4d6d8e320f4..782c8a946021 100644 --- a/train.py +++ b/train.py @@ -505,9 +505,9 @@ def parse_opt(): def main(opt): - print(opt) set_logging(RANK) if RANK in [-1, 0]: + print(opt) check_git_status() check_requirements(exclude=['thop']) From 5451fc2493ece7133d26532f008b968c7b4279b0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:31:25 +0200 Subject: [PATCH 26/33] destroy only RANK 0 --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 782c8a946021..3eb9974c3f78 100644 --- a/train.py +++ b/train.py @@ -547,7 +547,7 @@ def main(opt): logger.info(opt) if not opt.evolve: train(opt.hyp, opt, device) - if WORLD_SIZE > 1: + if WORLD_SIZE > 1 and RANK == 0: _ = [print('Destroying process group... ', end=''), dist.destroy_process_group(), print('Done.')] # Evolve hyperparameters (optional) From 9aa229e8050c5726b275591511876be2f809a891 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:34:10 +0200 Subject: [PATCH 27/33] move destroy inside train() --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 3eb9974c3f78..03fbb0167cd8 100644 --- a/train.py +++ b/train.py @@ -461,6 +461,8 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary wandb_logger.finish_run() torch.cuda.empty_cache() + if WORLD_SIZE > 1 and RANK == 0: + _ = [print('Destroying process group... ', end=''), dist.destroy_process_group(), print('Done.')] return results @@ -547,8 +549,6 @@ def main(opt): logger.info(opt) if not opt.evolve: train(opt.hyp, opt, device) - if WORLD_SIZE > 1 and RANK == 0: - _ = [print('Destroying process group... ', end=''), dist.destroy_process_group(), print('Done.')] # Evolve hyperparameters (optional) else: From 94363ce3d88f94aee476f0c134dd3b4464e41ff4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:35:46 +0200 Subject: [PATCH 28/33] restore destroy outside train() --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 03fbb0167cd8..3eb9974c3f78 100644 --- a/train.py +++ b/train.py @@ -461,8 +461,6 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary wandb_logger.finish_run() torch.cuda.empty_cache() - if WORLD_SIZE > 1 and RANK == 0: - _ = [print('Destroying process group... ', end=''), dist.destroy_process_group(), print('Done.')] return results @@ -549,6 +547,8 @@ def main(opt): logger.info(opt) if not opt.evolve: train(opt.hyp, opt, device) + if WORLD_SIZE > 1 and RANK == 0: + _ = [print('Destroying process group... ', end=''), dist.destroy_process_group(), print('Done.')] # Evolve hyperparameters (optional) else: From 9647379473e2bfb9049b6a299385610d368dac4d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:43:06 +0200 Subject: [PATCH 29/33] update print(opt) --- train.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/train.py b/train.py index 3eb9974c3f78..81f612533bc1 100644 --- a/train.py +++ b/train.py @@ -507,7 +507,7 @@ def parse_opt(): def main(opt): set_logging(RANK) if RANK in [-1, 0]: - print(opt) + print(colorstr('train: ') + ', '.join(f'{k}={v}' for k, v in vars(opt).items())) check_git_status() check_requirements(exclude=['thop']) @@ -544,7 +544,6 @@ def main(opt): opt.batch_size = opt.total_batch_size // WORLD_SIZE # Train - logger.info(opt) if not opt.evolve: train(opt.hyp, opt, device) if WORLD_SIZE > 1 and RANK == 0: From 96686fd9c245514de476af2a3937f0aa065791de Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:49:47 +0200 Subject: [PATCH 30/33] cleanup --- train.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/train.py b/train.py index 81f612533bc1..0b3677af672f 100644 --- a/train.py +++ b/train.py @@ -531,14 +531,12 @@ def main(opt): # DDP mode opt.total_batch_size = opt.batch_size device = select_device(opt.device, batch_size=opt.batch_size) - print({'RANK': RANK, 'LOCAL_RANK': LOCAL_RANK, 'WORLD_SIZE': WORLD_SIZE}) if LOCAL_RANK != -1: from datetime import timedelta assert torch.cuda.device_count() > LOCAL_RANK, 'too few GPUS for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="gloo", timeout=timedelta(seconds=10)) # distributed backend - # dist.init_process_group(backend="nccl", init_method='env://') # distributed backend + dist.init_process_group(backend="gloo", timeout=timedelta(seconds=10)) assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From 446c610ef6c903d83962e198edd6ebae9525d45c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:50:10 +0200 Subject: [PATCH 31/33] nccl --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 0b3677af672f..659f8aa92afd 100644 --- a/train.py +++ b/train.py @@ -536,7 +536,7 @@ def main(opt): assert torch.cuda.device_count() > LOCAL_RANK, 'too few GPUS for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="gloo", timeout=timedelta(seconds=10)) + dist.init_process_group(backend="nccl", timeout=timedelta(seconds=10)) assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From 49bb0b78e96ed566f2b679292e8d30155bec172d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 15:53:04 +0200 Subject: [PATCH 32/33] gloo with 60 second timeout --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 659f8aa92afd..8f206a9401c5 100644 --- a/train.py +++ b/train.py @@ -536,7 +536,7 @@ def main(opt): assert torch.cuda.device_count() > LOCAL_RANK, 'too few GPUS for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="nccl", timeout=timedelta(seconds=10)) + dist.init_process_group(backend="gloo", timeout=timedelta(seconds=60)) assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // WORLD_SIZE From b5decdebf7d1b4f54238b15043122731541c0779 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Jun 2021 16:01:41 +0200 Subject: [PATCH 33/33] update namespace printing --- detect.py | 6 +++--- models/export.py | 2 +- test.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/detect.py b/detect.py index c51c6fa4e0c1..fb2d2702234d 100644 --- a/detect.py +++ b/detect.py @@ -8,8 +8,8 @@ from models.experimental import attempt_load from utils.datasets import LoadStreams, LoadImages -from utils.general import check_img_size, check_requirements, check_imshow, non_max_suppression, apply_classifier, \ - scale_coords, xyxy2xywh, strip_optimizer, set_logging, increment_path, save_one_box +from utils.general import check_img_size, check_requirements, check_imshow, colorstr, non_max_suppression, \ + apply_classifier, scale_coords, xyxy2xywh, strip_optimizer, set_logging, increment_path, save_one_box from utils.plots import colors, plot_one_box from utils.torch_utils import select_device, load_classifier, time_synchronized @@ -202,7 +202,7 @@ def parse_opt(): def main(opt): - print(opt) + print(colorstr('detect: ') + ', '.join(f'{k}={v}' for k, v in vars(opt).items())) check_requirements(exclude=('tensorboard', 'thop')) detect(**vars(opt)) diff --git a/models/export.py b/models/export.py index 8c491dabddc0..15d6a87ecea6 100644 --- a/models/export.py +++ b/models/export.py @@ -163,8 +163,8 @@ def parse_opt(): def main(opt): - print(opt) set_logging() + print(colorstr('export: ') + ', '.join(f'{k}={v}' for k, v in vars(opt).items())) export(**vars(opt)) diff --git a/test.py b/test.py index 5ebfb36509ea..1e82fd2d1611 100644 --- a/test.py +++ b/test.py @@ -51,7 +51,6 @@ def test(data, device = next(model.parameters()).device # get model device else: # called directly - set_logging() device = select_device(device, batch_size=batch_size) # Directories @@ -323,7 +322,8 @@ def parse_opt(): def main(opt): - print(opt) + set_logging() + print(colorstr('test: ') + ', '.join(f'{k}={v}' for k, v in vars(opt).items())) check_requirements(exclude=('tensorboard', 'thop')) if opt.task in ('train', 'val', 'test'): # run normally