Skip to content

Commit 5594c69

Browse files
authored
Update imagenet example (#860)
1 parent 55b6156 commit 5594c69

1 file changed

Lines changed: 38 additions & 28 deletions

File tree

examples/imagenet_classification.py

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323
--split val
2424
"""
2525

26-
# pyre-ignore-all-errors
26+
# pyre-strict
2727

28+
import argparse
2829
import contextlib
2930
import logging
3031
import time
32+
from argparse import Namespace
3133
from collections.abc import Awaitable, Callable, Iterator
3234
from pathlib import Path
3335

@@ -39,7 +41,7 @@
3941
from torch import Tensor
4042
from torch.profiler import profile
4143

42-
_LG = logging.getLogger(__name__)
44+
_LG: logging.Logger = logging.getLogger(__name__)
4345

4446

4547
__all__ = [
@@ -54,9 +56,7 @@
5456
]
5557

5658

57-
def _parse_args(args):
58-
import argparse
59-
59+
def _parse_args(args: list[str] | None) -> Namespace:
6060
parser = argparse.ArgumentParser(
6161
description=__doc__,
6262
formatter_class=argparse.RawDescriptionHelpFormatter,
@@ -72,10 +72,10 @@ def _parse_args(args):
7272
parser.add_argument("--no-compile", action="store_false", dest="compile")
7373
parser.add_argument("--no-bf16", action="store_false", dest="use_bf16")
7474
parser.add_argument("--use-nvjpeg", action="store_true")
75-
args = parser.parse_args(args)
76-
if args.trace:
77-
args.max_batches = 60
78-
return args
75+
ns = parser.parse_args(args)
76+
if ns.trace:
77+
ns.max_batches = 60
78+
return ns
7979

8080

8181
# Handroll the transforms so as to support `torch.compile`
@@ -132,7 +132,13 @@ class ModelBundle(torch.nn.Module):
132132
Bundle the transform, model backbone, and classification head into a single module
133133
for a simple handling."""
134134

135-
def __init__(self, model, preprocessing, classification, use_bf16):
135+
def __init__(
136+
self,
137+
model: torch.nn.Module,
138+
preprocessing: Preprocessing,
139+
classification: Classification,
140+
use_bf16: bool,
141+
) -> None:
136142
super().__init__()
137143
self.model = model
138144
self.preprocessing = preprocessing
@@ -160,7 +166,7 @@ def forward(self, images: Tensor, labels: Tensor) -> tuple[Tensor, Tensor]:
160166
return self.classification(output, labels)
161167

162168

163-
def _expand(vals, batch_size, res):
169+
def _expand(vals: list[float], batch_size: int, res: int) -> Tensor:
164170
return torch.tensor(vals).view(1, 3, 1, 1).expand(batch_size, 3, res, res).clone()
165171

166172

@@ -206,7 +212,7 @@ def get_model(
206212
model = torch.compile(model, mode=mode)
207213
preprocessing = torch.compile(preprocessing, mode=mode)
208214

209-
return ModelBundle(model, preprocessing, classification, use_bf16)
215+
return ModelBundle(model, preprocessing, classification, use_bf16) # pyre-ignore[6]
210216

211217

212218
def get_decode_func(
@@ -225,17 +231,17 @@ def get_decode_func(
225231
Async function to decode images in to batch tensor of NCHW format
226232
and labels of shape ``(batch_size, 1)``.
227233
"""
228-
device = torch.device(f"cuda:{device_index}")
234+
device: torch.device = torch.device(f"cuda:{device_index}")
229235

230-
filter_desc = spdl.io.get_video_filter_desc(
236+
filter_desc: str | None = spdl.io.get_video_filter_desc(
231237
scale_width=256,
232238
scale_height=256,
233239
crop_width=width,
234240
crop_height=height,
235241
pix_fmt="rgb24",
236242
)
237243

238-
async def decode_images(items: list[tuple[str, int]]):
244+
async def decode_images(items: list[tuple[str, int]]) -> tuple[Tensor, Tensor]:
239245
paths = [item for item, _ in items]
240246
labels = [[item] for _, item in items]
241247
labels = torch.tensor(labels, dtype=torch.int64).to(device)
@@ -265,17 +271,19 @@ def _get_experimental_nvjpeg_decode_function(
265271
device_index: int,
266272
width: int = 224,
267273
height: int = 224,
268-
):
269-
device = torch.device(f"cuda:{device_index}")
270-
device_config = spdl.io.cuda_config(
274+
) -> Callable[[list[tuple[str, int]]], Awaitable[tuple[Tensor, Tensor]]]:
275+
device: torch.device = torch.device(f"cuda:{device_index}")
276+
device_config: spdl.io.CUDAConfig = spdl.io.cuda_config(
271277
device_index=device_index,
272278
allocator=(
273279
torch.cuda.caching_allocator_alloc,
274280
torch.cuda.caching_allocator_delete,
275281
),
276282
)
277283

278-
async def decode_images_nvjpeg(items: list[tuple[str, int]]):
284+
async def decode_images_nvjpeg(
285+
items: list[tuple[str, int]],
286+
) -> tuple[Tensor, Tensor]:
279287
paths = [item for item, _ in items]
280288
labels = [[item] for _, item in items]
281289
labels = torch.tensor(labels, dtype=torch.int64).to(device)
@@ -299,7 +307,7 @@ def get_dataloader(
299307
decode_func: Callable[[list[tuple[str, int]]], Awaitable[tuple[Tensor, Tensor]]],
300308
buffer_size: int,
301309
num_threads: int,
302-
) -> DataLoader:
310+
) -> Iterator[tuple[Tensor, Tensor]]:
303311
"""Build the dataloader for the ImageNet classification task.
304312
305313
The dataloader uses the ``decode_func`` for decoding images concurrently and
@@ -313,7 +321,7 @@ def get_dataloader(
313321
num_threads: The number of worker threads.
314322
315323
"""
316-
return DataLoader(
324+
return DataLoader( # pyre-ignore[7]
317325
src,
318326
batch_size=batch_size,
319327
drop_last=True,
@@ -327,7 +335,7 @@ def get_dataloader(
327335
def benchmark(
328336
dataloader: Iterator[tuple[Tensor, Tensor]],
329337
model: ModelBundle,
330-
max_batches: int = float("nan"),
338+
max_batches: float = float("nan"),
331339
) -> None:
332340
"""The main loop that measures the performance of dataloading and model inference.
333341
@@ -361,7 +369,7 @@ def benchmark(
361369
finally:
362370
elapsed = time.monotonic() - t0
363371
if num_frames != 0:
364-
num_correct_top1 = num_correct_top1.item()
372+
num_correct_top1 = num_correct_top1.item() # pyre-ignore[16]
365373
num_correct_top5 = num_correct_top5.item()
366374
fps = num_frames / elapsed
367375
_LG.info(f"FPS={fps:.2f} ({num_frames}/{elapsed:.2f})")
@@ -371,7 +379,9 @@ def benchmark(
371379
_LG.info(f"Accuracy (top5)={acc5:.2%} ({num_correct_top5}/{num_frames})")
372380

373381

374-
def _get_dataloader(args, device_index) -> DataLoader:
382+
def _get_dataloader(
383+
args: Namespace, device_index: int
384+
) -> Iterator[tuple[Tensor, Tensor]]:
375385
src = ImageNet(args.root_dir, split=args.split)
376386

377387
if args.use_nvjpeg:
@@ -380,18 +390,18 @@ def _get_dataloader(args, device_index) -> DataLoader:
380390
decode_func = get_decode_func(device_index)
381391

382392
return get_dataloader(
383-
src,
393+
src, # pyre-ignore[6]
384394
args.batch_size,
385395
decode_func,
386396
args.buffer_size,
387397
args.num_threads,
388398
)
389399

390400

391-
def entrypoint(args: list[int] | None = None):
401+
def entrypoint(args_: list[str] | None = None) -> None:
392402
"""CLI entrypoint. Run pipeline, transform and model and measure its performance."""
393403

394-
args = _parse_args(args)
404+
args = _parse_args(args_)
395405
_init_logging(args.debug)
396406
_LG.info(args)
397407

@@ -414,7 +424,7 @@ def entrypoint(args: list[int] | None = None):
414424
prof.export_chrome_trace(f"{trace_path}.json")
415425

416426

417-
def _init_logging(debug=False):
427+
def _init_logging(debug: bool = False) -> None:
418428
fmt = "%(asctime)s [%(filename)s:%(lineno)d] [%(levelname)s] %(message)s"
419429
level = logging.DEBUG if debug else logging.INFO
420430
logging.basicConfig(format=fmt, level=level)

0 commit comments

Comments
 (0)