Skip to content

Commit 9844fee

Browse files
committed
Use torch.accelerator API in Imagenet example
1 parent 35c0da0 commit 9844fee

3 files changed

Lines changed: 67 additions & 63 deletions

File tree

imagenet/README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ python main.py -a resnet18 --dummy
3333

3434
## Multi-processing Distributed Data Parallel Training
3535

36-
If running on CUDA, you should always use the NCCL backend for multi-processing distributed training since it currently provides the best distributed training performance.
37-
38-
For XPU multiprocessing is not supported as of PyTorch 2.6.
36+
You should always use the NCCL backend for multi-processing distributed training since it currently provides the best distributed training performance.
3937

4038
### Single node, multiple GPUs:
4139

@@ -61,7 +59,7 @@ python main.py -a resnet50 --dist-url 'tcp://IP_OF_NODE0:FREEPORT' --dist-backen
6159

6260
```bash
6361
usage: main.py [-h] [-a ARCH] [-j N] [--epochs N] [--start-epoch N] [-b N] [--lr LR] [--momentum M] [--wd W] [-p N] [--resume PATH] [-e] [--pretrained] [--world-size WORLD_SIZE] [--rank RANK]
64-
[--dist-url DIST_URL] [--dist-backend DIST_BACKEND] [--seed SEED] [--gpu GPU] [--multiprocessing-distributed] [--dummy]
62+
[--dist-url DIST_URL] [--dist-backend DIST_BACKEND] [--seed SEED] [--gpu GPU] [--no-accel][--multiprocessing-distributed] [--dummy]
6563
[DIR]
6664

6765
PyTorch ImageNet Training
@@ -98,6 +96,7 @@ optional arguments:
9896
distributed backend
9997
--seed SEED seed for initializing training.
10098
--gpu GPU GPU id to use.
99+
--no-accel disables accelerator
101100
--multiprocessing-distributed
102101
Use multi-processing distributed training to launch N processes per node, which has N GPUs. This is the fastest way to use PyTorch for either single node or multi node data parallel
103102
training

imagenet/main.py

Lines changed: 63 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
help='seed for initializing training. ')
7272
parser.add_argument('--gpu', default=None, type=int,
7373
help='GPU id to use.')
74+
parser.add_argument('--no-accel', action='store_true',
75+
help='disables accelerator')
7476
parser.add_argument('--multiprocessing-distributed', action='store_true',
7577
help='Use multi-processing distributed training to launch '
7678
'N processes per node, which has N GPUs. This is the '
@@ -104,8 +106,17 @@ def main():
104106

105107
args.distributed = args.world_size > 1 or args.multiprocessing_distributed
106108

107-
if torch.cuda.is_available():
108-
ngpus_per_node = torch.cuda.device_count()
109+
use_accel = not args.no_accel and torch.accelerator.is_available()
110+
111+
if use_accel:
112+
device = torch.accelerator.current_accelerator()
113+
else:
114+
device = torch.device("cpu")
115+
116+
print(f"Using device: {device}")
117+
118+
if device.type =='cuda':
119+
ngpus_per_node = torch.accelerator.device_count()
109120
if ngpus_per_node == 1 and args.dist_backend == "nccl":
110121
warnings.warn("nccl backend >=2.5 requires GPU count>1, see https://github.com/NVIDIA/nccl/issues/103 perhaps use 'gloo'")
111122
else:
@@ -127,6 +138,13 @@ def main_worker(gpu, ngpus_per_node, args):
127138
global best_acc1
128139
args.gpu = gpu
129140

141+
use_accel = not args.no_accel and torch.accelerator.is_available()
142+
143+
if use_accel:
144+
device = torch.accelerator.current_accelerator()
145+
else:
146+
device = torch.device("cpu")
147+
130148
if args.gpu is not None:
131149
print("Use GPU: {} for training".format(args.gpu))
132150

@@ -147,16 +165,16 @@ def main_worker(gpu, ngpus_per_node, args):
147165
print("=> creating model '{}'".format(args.arch))
148166
model = models.__dict__[args.arch]()
149167

150-
if not torch.cuda.is_available() and not torch.backends.mps.is_available() and not torch.xpu.is_available():
168+
if not use_accel:
151169
print('using CPU, this will be slow')
152170
elif args.distributed:
153171
# For multiprocessing distributed, DistributedDataParallel constructor
154172
# should always set the single device scope, otherwise,
155173
# DistributedDataParallel will use all available devices.
156-
if torch.cuda.is_available():
174+
if device.type == 'cuda':
157175
if args.gpu is not None:
158-
torch.cuda.set_device(args.gpu)
159-
model.cuda(args.gpu)
176+
torch.accelerator.set_device_index(args.gpu)
177+
model.to(device)
160178
# When using a single GPU per process and per
161179
# DistributedDataParallel, we need to divide the batch size
162180
# ourselves based on the total number of GPUs of the current node.
@@ -168,15 +186,12 @@ def main_worker(gpu, ngpus_per_node, args):
168186
# DistributedDataParallel will divide and allocate batch_size to all
169187
# available GPUs if device_ids are not set
170188
model = torch.nn.parallel.DistributedDataParallel(model)
171-
elif args.gpu is not None and torch.cuda.is_available():
172-
torch.cuda.set_device(args.gpu)
173-
model = model.cuda(args.gpu)
174-
elif torch.xpu.is_available():
175-
device = torch.device("xpu")
176-
model = model.to(device)
177-
elif torch.backends.mps.is_available():
178-
device = torch.device("mps")
179-
model = model.to(device)
189+
190+
elif args.gpu is not None and device.type=='cuda':
191+
torch.accelerator.set_device_index(args.gpu)
192+
model.to(device)
193+
elif device.type != 'cuda':
194+
model.to(device)
180195
else:
181196
# DataParallel will divide and allocate batch_size to all available GPUs
182197
if args.arch.startswith('alexnet') or args.arch.startswith('vgg'):
@@ -185,20 +200,6 @@ def main_worker(gpu, ngpus_per_node, args):
185200
else:
186201
model = torch.nn.DataParallel(model).cuda()
187202

188-
if torch.cuda.is_available():
189-
if args.gpu:
190-
device = torch.device('cuda:{}'.format(args.gpu))
191-
else:
192-
device = torch.device("cuda")
193-
elif torch.xpu.is_available():
194-
device = torch.device("xpu")
195-
elif torch.backends.mps.is_available():
196-
device = torch.device("mps")
197-
else:
198-
device = torch.device("cpu")
199-
200-
print (f"Device to use: ", {device.type})
201-
202203
# define loss function (criterion), optimizer, and learning rate scheduler
203204
criterion = nn.CrossEntropyLoss().to(device)
204205

@@ -215,7 +216,7 @@ def main_worker(gpu, ngpus_per_node, args):
215216
print("=> loading checkpoint '{}'".format(args.resume))
216217
if args.gpu is None:
217218
checkpoint = torch.load(args.resume)
218-
elif torch.cuda.is_available():
219+
elif device.type=='cuda':
219220
# Map model to be loaded to specified single gpu.
220221
loc = 'cuda:{}'.format(args.gpu)
221222
checkpoint = torch.load(args.resume, map_location=loc)
@@ -310,11 +311,14 @@ def main_worker(gpu, ngpus_per_node, args):
310311

311312

312313
def train(train_loader, model, criterion, optimizer, epoch, device, args):
313-
batch_time = AverageMeter('Time', ':6.3f')
314-
data_time = AverageMeter('Data', ':6.3f')
315-
losses = AverageMeter('Loss', ':.4e')
316-
top1 = AverageMeter('Acc@1', ':6.2f')
317-
top5 = AverageMeter('Acc@5', ':6.2f')
314+
315+
use_accel = not args.no_accel and torch.accelerator.is_available()
316+
317+
batch_time = AverageMeter('Time', use_accel, ':6.3f', Summary.NONE)
318+
data_time = AverageMeter('Data', use_accel, ':6.3f', Summary.NONE)
319+
losses = AverageMeter('Loss', use_accel, ':.4e', Summary.NONE)
320+
top1 = AverageMeter('Acc@1', use_accel, ':6.2f', Summary.NONE)
321+
top5 = AverageMeter('Acc@5', use_accel, ':6.2f', Summary.NONE)
318322
progress = ProgressMeter(
319323
len(train_loader),
320324
[batch_time, data_time, losses, top1, top5],
@@ -357,23 +361,27 @@ def train(train_loader, model, criterion, optimizer, epoch, device, args):
357361

358362
def validate(val_loader, model, criterion, args):
359363

364+
use_accel = not args.no_accel and torch.accelerator.is_available()
365+
360366
def run_validate(loader, base_progress=0):
367+
368+
if use_accel:
369+
device = torch.accelerator.current_accelerator()
370+
else:
371+
device = torch.device("cpu")
372+
361373
with torch.no_grad():
362374
end = time.time()
363375
for i, (images, target) in enumerate(loader):
364376
i = base_progress + i
365-
366-
if torch.cuda.is_available():
367-
if args.gpu is not None:
377+
if use_accel:
378+
if args.gpu is not None and device.type=='cuda':
379+
torch.accelerator.set_device_index(argps.gpu)
368380
images = images.cuda(args.gpu, non_blocking=True)
369-
target = target.cuda(args.gpu, non_blocking=True)
370-
371-
elif torch.xpu.is_available():
372-
images = images.to("xpu")
373-
target = target.to("xpu")
374-
elif torch.backends.mps.is_available():
375-
images = images.to('mps')
376-
target = target.to('mps')
381+
target = target.cuda(args.gpu, non_blocking=True)
382+
else:
383+
images = images.to(device)
384+
target = target.to(device)
377385

378386
# compute output
379387
output = model(images)
@@ -392,10 +400,10 @@ def run_validate(loader, base_progress=0):
392400
if i % args.print_freq == 0:
393401
progress.display(i + 1)
394402

395-
batch_time = AverageMeter('Time', ':6.3f', Summary.NONE)
396-
losses = AverageMeter('Loss', ':.4e', Summary.NONE)
397-
top1 = AverageMeter('Acc@1', ':6.2f', Summary.AVERAGE)
398-
top5 = AverageMeter('Acc@5', ':6.2f', Summary.AVERAGE)
403+
batch_time = AverageMeter('Time', use_accel, ':6.3f', Summary.NONE)
404+
losses = AverageMeter('Loss', use_accel, ':.4e', Summary.NONE)
405+
top1 = AverageMeter('Acc@1', use_accel, ':6.2f', Summary.AVERAGE)
406+
top5 = AverageMeter('Acc@5', use_accel, ':6.2f', Summary.AVERAGE)
399407
progress = ProgressMeter(
400408
len(val_loader) + (args.distributed and (len(val_loader.sampler) * args.world_size < len(val_loader.dataset))),
401409
[batch_time, losses, top1, top5],
@@ -435,8 +443,9 @@ class Summary(Enum):
435443

436444
class AverageMeter(object):
437445
"""Computes and stores the average and current value"""
438-
def __init__(self, name, fmt=':f', summary_type=Summary.AVERAGE):
446+
def __init__(self, name, use_accel, fmt=':f', summary_type=Summary.AVERAGE):
439447
self.name = name
448+
self.use_accel = use_accel
440449
self.fmt = fmt
441450
self.summary_type = summary_type
442451
self.reset()
@@ -453,13 +462,9 @@ def update(self, val, n=1):
453462
self.count += n
454463
self.avg = self.sum / self.count
455464

456-
def all_reduce(self):
457-
if torch.cuda.is_available():
458-
device = torch.device("cuda")
459-
elif torch.xpu.is_available():
460-
device = torch.device("xpu")
461-
elif torch.backends.mps.is_available():
462-
device = torch.device("mps")
465+
def all_reduce(self):
466+
if use_accel:
467+
device = torch.accelerator.current_accelerator()
463468
else:
464469
device = torch.device("cpu")
465470
total = torch.tensor([self.sum, self.count], dtype=torch.float32, device=device)

imagenet/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
torch
2-
torchvision==0.20.0
2+
torchvision

0 commit comments

Comments
 (0)