Fix redundant outputs via Logging in DDP training (#500)
* Change print to logging * Clean function set_logging * Add line spacing * Change leftover prints to log * Fix scanning labels output * Fix rank naming * Change leftover print to logging * Reorganized DDP variables * Fix type error * Make quotes consistent * Fix spelling * Clean function call * Add line spacing * Update datasets.py * Update train.py Co-authored-by: Glenn Jocher <glenn.jocher@ultralytics.com>
This commit is contained in:
1 parent
542833c997
commit
4949401a94
5 files changed
+56
-39
No files matched your search
+13
-9
@@ -47,9 +47,9 @@ def exif_size(img):
|
||||
|
||||
|
||||
def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=False, cache=False, pad=0.0, rect=False,
|
||||
local_rank=-1, world_size=1):
|
||||
rank=-1, world_size=1):
|
||||
# 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(local_rank):
|
||||
with torch_distributed_zero_first(rank):
|
||||
dataset = LoadImagesAndLabels(path, imgsz, batch_size,
|
||||
augment=augment, # augment images
|
||||
hyp=hyp, # augmentation hyperparameters
|
||||
@@ -57,11 +57,12 @@ def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=Fa
|
||||
cache_images=cache,
|
||||
single_cls=opt.single_cls,
|
||||
stride=int(stride),
|
||||
pad=pad)
|
||||
pad=pad,
|
||||
rank=rank)
|
||||
|
||||
batch_size = min(batch_size, len(dataset))
|
||||
nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, 8]) # number of workers
|
||||
train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) if local_rank != -1 else None
|
||||
train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) if rank != -1 else None
|
||||
dataloader = torch.utils.data.DataLoader(dataset,
|
||||
batch_size=batch_size,
|
||||
num_workers=nw,
|
||||
@@ -292,7 +293,7 @@ class LoadStreams: # multiple IP or RTSP cameras
|
||||
|
||||
class LoadImagesAndLabels(Dataset): # for training/testing
|
||||
def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False,
|
||||
cache_images=False, single_cls=False, stride=32, pad=0.0):
|
||||
cache_images=False, single_cls=False, stride=32, pad=0.0, rank=-1):
|
||||
try:
|
||||
f = [] # image files
|
||||
for p in path if isinstance(path, list) else [path]:
|
||||
@@ -372,8 +373,10 @@ class LoadImagesAndLabels(Dataset): # for training/testing
|
||||
# Cache labels
|
||||
create_datasubset, extract_bounding_boxes, labels_loaded = False, False, False
|
||||
nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate
|
||||
pbar = tqdm(self.label_files)
|
||||
for i, file in enumerate(pbar):
|
||||
pbar = enumerate(self.label_files)
|
||||
if rank in [-1, 0]:
|
||||
pbar = tqdm(pbar)
|
||||
for i, file in pbar:
|
||||
l = self.labels[i] # label
|
||||
if l is not None and l.shape[0]:
|
||||
assert l.shape[1] == 5, '> 5 label columns: %s' % file
|
||||
@@ -420,8 +423,9 @@ class LoadImagesAndLabels(Dataset): # for training/testing
|
||||
ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty
|
||||
# os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove
|
||||
|
||||
pbar.desc = 'Scanning labels %s (%g found, %g missing, %g empty, %g duplicate, for %g images)' % (
|
||||
cache_path, nf, nm, ne, nd, n)
|
||||
if rank in [-1,0]:
|
||||
pbar.desc = 'Scanning labels %s (%g found, %g missing, %g empty, %g duplicate, for %g images)' % (
|
||||
cache_path, nf, nm, ne, nd, n)
|
||||
if nf == 0:
|
||||
s = 'WARNING: No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url)
|
||||
print(s)
|
||||
|
||||
@@ -5,6 +5,7 @@ import random
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
import logging
|
||||
from contextlib import contextmanager
|
||||
from copy import copy
|
||||
from pathlib import Path
|
||||
@@ -45,6 +46,12 @@ def torch_distributed_zero_first(local_rank: int):
|
||||
torch.distributed.barrier()
|
||||
|
||||
|
||||
def set_logging(rank=-1):
|
||||
logging.basicConfig(
|
||||
format="%(message)s",
|
||||
level=logging.INFO if rank in [-1, 0] else logging.WARN)
|
||||
|
||||
|
||||
def init_seeds(seed=0):
|
||||
random.seed(seed)
|
||||
np.random.seed(seed)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import math
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
from copy import deepcopy
|
||||
|
||||
import torch
|
||||
@@ -9,6 +10,7 @@ import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
import torchvision.models as models
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def init_seeds(seed=0):
|
||||
torch.manual_seed(seed)
|
||||
@@ -40,12 +42,12 @@ def select_device(device='', batch_size=None):
|
||||
for i in range(0, ng):
|
||||
if i == 1:
|
||||
s = ' ' * len(s)
|
||||
print("%sdevice%g _CudaDeviceProperties(name='%s', total_memory=%dMB)" %
|
||||
logger.info("%sdevice%g _CudaDeviceProperties(name='%s', total_memory=%dMB)" %
|
||||
(s, i, x[i].name, x[i].total_memory / c))
|
||||
else:
|
||||
print('Using CPU')
|
||||
logger.info('Using CPU')
|
||||
|
||||
print('') # skip a line
|
||||
logger.info('') # skip a line
|
||||
return torch.device('cuda:0' if cuda else 'cpu')
|
||||
|
||||
|
||||
@@ -142,7 +144,7 @@ def model_info(model, verbose=False):
|
||||
except:
|
||||
fs = ''
|
||||
|
||||
print('Model Summary: %g layers, %g parameters, %g gradients%s' % (len(list(model.parameters())), n_p, n_g, fs))
|
||||
logger.info('Model Summary: %g layers, %g parameters, %g gradients%s' % (len(list(model.parameters())), n_p, n_g, fs))
|
||||
|
||||
|
||||
def load_classifier(name='resnet101', n=2):
|
||||
|
||||
Reference in new issue
Block a user