From 11cb2ed931bcd464162edb08cdd845abc6175d22 Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Tue, 30 Apr 2024 08:59:30 +0100 Subject: [PATCH 01/13] modified ptq_evaluate.py to allow switching between timm and torchvision models --- .../ptq/ptq_evaluate.py | 20 +++++++++++-------- .../imagenet_classification/ptq/utils.py | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py index 1f7c06a2b..74d5d38d7 100644 --- a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py +++ b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py @@ -8,6 +8,7 @@ import warnings import numpy as np +import timm import torch import torch.backends.cudnn as cudnn import torch.nn.parallel @@ -47,10 +48,6 @@ def parse_type(v, default_type): return default_type(v) -model_names = sorted( - name for name in torchvision.models.__dict__ if name.islower() and not name.startswith("__") and - callable(torchvision.models.__dict__[name]) and not name.startswith("get_")) - parser = argparse.ArgumentParser(description='PyTorch ImageNet PTQ Validation') parser.add_argument( '--calibration-dir', @@ -75,12 +72,16 @@ def parse_type(v, default_type): parser.add_argument('--gpu', default=None, type=int, help='GPU id to use (default: None)') parser.add_argument( '--calibration-samples', default=1000, type=int, help='Calibration size (default: 1000)') +parser.add_argument( + '--dataset', + default='torchvision', + choices=['torchvision', 'timm'], + help='Source of models (default: torchvision)') parser.add_argument( '--model-name', default='resnet18', metavar='ARCH', - choices=model_names, - help='model architecture: ' + ' | '.join(model_names) + ' (default: resnet18)') + help='model architecture: (default: resnet18)') parser.add_argument( '--dtype', default='float', choices=['float', 'bfloat16'], help='Data type to use') parser.add_argument( @@ -351,8 +352,11 @@ def main(): center_crop_shape, inception_preprocessing=inception_preprocessing) - # Get the model from torchvision - model = get_torchvision_model(args.model_name) + # Get the model from torchvision or timm + if args.dataset == 'torchvision': + model = get_torchvision_model(args.model_name) + else: + model = timm.create_model(args.model_name, pretrained=True) model = model.to(dtype) # Preprocess the model for quantization diff --git a/src/brevitas_examples/imagenet_classification/ptq/utils.py b/src/brevitas_examples/imagenet_classification/ptq/utils.py index bb622d93a..3d523f994 100644 --- a/src/brevitas_examples/imagenet_classification/ptq/utils.py +++ b/src/brevitas_examples/imagenet_classification/ptq/utils.py @@ -15,7 +15,7 @@ def get_model_config(model_name): config = dict() # Set-up config parameters - if model_name == 'inception_v3' or model_name == 'googlenet': + if 'inception_v3' in model_name or 'googlenet' in model_name: config['inception_preprocessing'] = True else: config['inception_preprocessing'] = False From 863a4e502fa7b09f52951f30e3dbcdd9e07eda21 Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:16:21 +0100 Subject: [PATCH 02/13] updated node.kwargs to return false if not present so ptq_evaluate works with more timm models --- src/brevitas/graph/standardize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/brevitas/graph/standardize.py b/src/brevitas/graph/standardize.py index 7bbbb201d..93e99eac9 100644 --- a/src/brevitas/graph/standardize.py +++ b/src/brevitas/graph/standardize.py @@ -59,7 +59,7 @@ def match_node(self, node: Node) -> bool: is_adaptive_2d_mean = ((2, 3) in node.args or [2, 3] in node.args or 'dim' in node.kwargs and (node.kwargs['dim'] == (2, 3) or node.kwargs['dim'] == [2, 3])) - is_adaptive_2d_mean = is_adaptive_2d_mean and not node.kwargs['keepdim'] + is_adaptive_2d_mean = is_adaptive_2d_mean and not node.kwargs.get('keepdim', False) return spr and is_adaptive_2d_mean def move_node_args_to_kwargs(self, node: Node): From c6b5cd50bcacde11de4eacbd5faa647caab5fe1d Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Tue, 30 Apr 2024 15:53:53 +0100 Subject: [PATCH 03/13] implemented mean in int_quant_tensor --- src/brevitas/quant_tensor/int_quant_tensor.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/brevitas/quant_tensor/int_quant_tensor.py b/src/brevitas/quant_tensor/int_quant_tensor.py index 62c501250..99c22586f 100644 --- a/src/brevitas/quant_tensor/int_quant_tensor.py +++ b/src/brevitas/quant_tensor/int_quant_tensor.py @@ -222,6 +222,9 @@ def ndim(self): def dim(self): return self.value.dim() + def mean(self): + return self.value.mean() + @property def shape(self): return self.value.shape From 5469a2448f3f3f85f6853076977fc684930d5662 Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:02:42 +0100 Subject: [PATCH 04/13] added variable number of arguments to mean implementation --- src/brevitas/quant_tensor/int_quant_tensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/brevitas/quant_tensor/int_quant_tensor.py b/src/brevitas/quant_tensor/int_quant_tensor.py index 99c22586f..497f5d53a 100644 --- a/src/brevitas/quant_tensor/int_quant_tensor.py +++ b/src/brevitas/quant_tensor/int_quant_tensor.py @@ -222,8 +222,8 @@ def ndim(self): def dim(self): return self.value.dim() - def mean(self): - return self.value.mean() + def mean(self, *args): + return self.value.mean(args) @property def shape(self): From 5596ca409be7597559c89dddf532539361da52f1 Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:06:30 +0100 Subject: [PATCH 05/13] args and kwargs added to mean --- src/brevitas/quant_tensor/int_quant_tensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/brevitas/quant_tensor/int_quant_tensor.py b/src/brevitas/quant_tensor/int_quant_tensor.py index 497f5d53a..7391a9ba8 100644 --- a/src/brevitas/quant_tensor/int_quant_tensor.py +++ b/src/brevitas/quant_tensor/int_quant_tensor.py @@ -222,8 +222,8 @@ def ndim(self): def dim(self): return self.value.dim() - def mean(self, *args): - return self.value.mean(args) + def mean(self, *args, **kwargs): + return self.value.mean(*args, **kwargs) @property def shape(self): From e29ef29e952df5e6bba13e8ff79040e89370d89d Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Wed, 1 May 2024 08:58:41 +0100 Subject: [PATCH 06/13] using timm model config info to load data and renamed the dataset parameter to repository --- .../ptq/ptq_evaluate.py | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py index 74d5d38d7..b14c93995 100644 --- a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py +++ b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py @@ -73,7 +73,7 @@ def parse_type(v, default_type): parser.add_argument( '--calibration-samples', default=1000, type=int, help='Calibration size (default: 1000)') parser.add_argument( - '--dataset', + '--repository', default='torchvision', choices=['torchvision', 'timm'], help='Source of models (default: torchvision)') @@ -182,6 +182,11 @@ def parse_type(v, default_type): 'weight-narrow-range', default=False, help='Narrow range for weight quantization (default: disabled)') +add_bool_arg( + parser, + 'validate-before-quantize', + default=False, + help='Run validation on the model before it is quantized') parser.add_argument('--gpfq-p', default=1.0, type=float, help='P parameter for GPFQ (default: 1.0)') parser.add_argument( '--quant-format', @@ -332,10 +337,22 @@ def main(): # Get model-specific configurations about input shapes and normalization model_config = get_model_config(args.model_name) + # Get the model from torchvision or timm + if args.repository == 'torchvision': + model = get_torchvision_model(args.model_name) + else: + model = timm.create_model(args.model_name, pretrained=True) + data_cfg = timm.data.resolve_data_config(model.pretrained_cfg) + transform = timm.data.create_transform(**data_cfg) + model_config['resize_shape'] = transform.transforms[0].size + model_config['center_crop_shape'] = transform.transforms[1].size[0] + model = model.to(dtype) + # Generate calibration and validation dataloaders resize_shape = model_config['resize_shape'] center_crop_shape = model_config['center_crop_shape'] inception_preprocessing = model_config['inception_preprocessing'] + calib_loader = generate_dataloader( args.calibration_dir, args.batch_size_calibration, @@ -352,13 +369,6 @@ def main(): center_crop_shape, inception_preprocessing=inception_preprocessing) - # Get the model from torchvision or timm - if args.dataset == 'torchvision': - model = get_torchvision_model(args.model_name) - else: - model = timm.create_model(args.model_name, pretrained=True) - model = model.to(dtype) - # Preprocess the model for quantization if args.target_backend == 'flexml': # flexml requires static shapes, pass a representative input in @@ -459,6 +469,10 @@ def main(): print("Starting validation:") validate(val_loader, quant_model, stable=dtype != torch.bfloat16) + if args.validate_before_quantize == True: + print("Starting validation of unquantized model") + validate(val_loader, model, stable=dtype != torch.bfloat16) + if args.export_onnx_qcdq or args.export_torch_qcdq: # Generate reference input tensor to drive the export process model_config = get_model_config(args.model_name) From f5d5e8ee9a80d7b8d93b66eec883827e57f9ec04 Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Wed, 1 May 2024 10:58:46 +0100 Subject: [PATCH 07/13] modified dataloader code to use timm data_config --- .../ptq/ptq_evaluate.py | 49 ++++++++++++------- .../imagenet_classification/utils.py | 21 ++++++++ 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py index b14c93995..9422e129a 100644 --- a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py +++ b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py @@ -34,6 +34,7 @@ from brevitas_examples.imagenet_classification.ptq.utils import get_model_config from brevitas_examples.imagenet_classification.ptq.utils import get_torchvision_model from brevitas_examples.imagenet_classification.utils import generate_dataloader +from brevitas_examples.imagenet_classification.utils import generate_dataloader_with_transform from brevitas_examples.imagenet_classification.utils import SEED from brevitas_examples.imagenet_classification.utils import validate @@ -349,25 +350,35 @@ def main(): model = model.to(dtype) # Generate calibration and validation dataloaders - resize_shape = model_config['resize_shape'] - center_crop_shape = model_config['center_crop_shape'] - inception_preprocessing = model_config['inception_preprocessing'] - - calib_loader = generate_dataloader( - args.calibration_dir, - args.batch_size_calibration, - args.workers, - resize_shape, - center_crop_shape, - args.calibration_samples, - inception_preprocessing) - val_loader = generate_dataloader( - args.validation_dir, - args.batch_size_validation, - args.workers, - resize_shape, - center_crop_shape, - inception_preprocessing=inception_preprocessing) + if args.repostory == 'torchvision': + resize_shape = model_config['resize_shape'] + center_crop_shape = model_config['center_crop_shape'] + inception_preprocessing = model_config['inception_preprocessing'] + + calib_loader = generate_dataloader( + args.calibration_dir, + args.batch_size_calibration, + args.workers, + resize_shape, + center_crop_shape, + args.calibration_samples, + inception_preprocessing) + val_loader = generate_dataloader( + args.validation_dir, + args.batch_size_validation, + args.workers, + resize_shape, + center_crop_shape, + inception_preprocessing=inception_preprocessing) + else: + calib_loader = generate_dataloader_with_transform( + args.calibration_dir, + args.batch_size_calibration, + args.workers, + transform, + args.calibration_samples) + val_loader = generate_dataloader_with_transform( + args.validation_dir, args.batch_size_validation, args.workers, transform) # Preprocess the model for quantization if args.target_backend == 'flexml': diff --git a/src/brevitas_examples/imagenet_classification/utils.py b/src/brevitas_examples/imagenet_classification/utils.py index d506b8a61..8823b9a62 100644 --- a/src/brevitas_examples/imagenet_classification/utils.py +++ b/src/brevitas_examples/imagenet_classification/utils.py @@ -109,6 +109,11 @@ def generate_dataset(dir, resize_shape=256, center_crop_shape=224, inception_pre return dataset +def generate_dataset_with_transform(dir, transform): + dataset = datasets.ImageFolder(dir, transform) + return dataset + + def generate_dataloader( dir, batch_size, @@ -128,3 +133,19 @@ def generate_dataloader( dataset, batch_size=batch_size, num_workers=num_workers, pin_memory=True) return loader + + +def generate_dataloader_with_transform( + dir, + batch_size, + num_workers, + transform, + subset_size=None, +): + dataset = generate_dataset_with_transform(dir, transform) + if subset_size is not None: + dataset = torch.utils.data.Subset(dataset, list(range(subset_size))) + loader = torch.utils.data.DataLoader( + dataset, batch_size=batch_size, num_workers=num_workers, pin_memory=True) + + return loader From c0f596b7e2d815c64f7c090b5fbef43ee5c7153b Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Wed, 1 May 2024 11:01:09 +0100 Subject: [PATCH 08/13] fix typo --- .../imagenet_classification/ptq/ptq_evaluate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py index 9422e129a..87a687cf3 100644 --- a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py +++ b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py @@ -350,7 +350,7 @@ def main(): model = model.to(dtype) # Generate calibration and validation dataloaders - if args.repostory == 'torchvision': + if args.repository == 'torchvision': resize_shape = model_config['resize_shape'] center_crop_shape = model_config['center_crop_shape'] inception_preprocessing = model_config['inception_preprocessing'] From 28e8868c43fddd969c516b5a65fdbba8b17a6854 Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Wed, 1 May 2024 11:15:02 +0100 Subject: [PATCH 09/13] moved pre quantize validate step to earlier in the script --- .../imagenet_classification/ptq/ptq_evaluate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py index 87a687cf3..3d35a49dc 100644 --- a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py +++ b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py @@ -380,6 +380,10 @@ def main(): val_loader = generate_dataloader_with_transform( args.validation_dir, args.batch_size_validation, args.workers, transform) + if args.validate_before_quantize is True: + print("Starting validation of unquantized model") + validate(val_loader, model, stable=dtype != torch.bfloat16) + # Preprocess the model for quantization if args.target_backend == 'flexml': # flexml requires static shapes, pass a representative input in @@ -480,10 +484,6 @@ def main(): print("Starting validation:") validate(val_loader, quant_model, stable=dtype != torch.bfloat16) - if args.validate_before_quantize == True: - print("Starting validation of unquantized model") - validate(val_loader, model, stable=dtype != torch.bfloat16) - if args.export_onnx_qcdq or args.export_torch_qcdq: # Generate reference input tensor to drive the export process model_config = get_model_config(args.model_name) From 5ae57199c5580620c60c668764fc5f59ff2244e4 Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Wed, 1 May 2024 14:22:06 +0100 Subject: [PATCH 10/13] moved offloading model to gpu to earlier --- .../imagenet_classification/ptq/ptq_evaluate.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py index 3d35a49dc..69da2ab8e 100644 --- a/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py +++ b/src/brevitas_examples/imagenet_classification/ptq/ptq_evaluate.py @@ -349,6 +349,12 @@ def main(): model_config['center_crop_shape'] = transform.transforms[1].size[0] model = model.to(dtype) + # If available, use the selected GPU + if args.gpu is not None: + torch.cuda.set_device(args.gpu) + model = model.cuda(args.gpu) + cudnn.benchmark = False + # Generate calibration and validation dataloaders if args.repository == 'torchvision': resize_shape = model_config['resize_shape'] @@ -405,12 +411,6 @@ def main(): else: raise RuntimeError(f"{args.target_backend} backend not supported.") - # If available, use the selected GPU - if args.gpu is not None: - torch.cuda.set_device(args.gpu) - model = model.cuda(args.gpu) - cudnn.benchmark = False - if args.act_equalization is not None: print("Applying activation equalization:") apply_act_equalization(model, calib_loader, layerwise=args.act_equalization == 'layerwise') From 8283979002a9c3c70ad5b0e11897ebbd7e9a3541 Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Wed, 1 May 2024 16:02:59 +0100 Subject: [PATCH 11/13] implement squeeze in int_quant_tensor --- src/brevitas/quant_tensor/int_quant_tensor.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/brevitas/quant_tensor/int_quant_tensor.py b/src/brevitas/quant_tensor/int_quant_tensor.py index 7391a9ba8..25685e7c3 100644 --- a/src/brevitas/quant_tensor/int_quant_tensor.py +++ b/src/brevitas/quant_tensor/int_quant_tensor.py @@ -235,6 +235,9 @@ def dim(self): def add(self, other): return self + other + def unsqueeze(self, *args, **kwargs): + return self.value.unsqueeze(*args, **kwargs) + @staticmethod def cat(tensors, dim, out=None): if out is not None: From 639041627afab6cfd5e6df2c6f592b96e7bf0752 Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Fri, 3 May 2024 09:50:19 +0100 Subject: [PATCH 12/13] added sigmoid function to QuantTensor --- src/brevitas/quant_tensor/int_quant_tensor.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/brevitas/quant_tensor/int_quant_tensor.py b/src/brevitas/quant_tensor/int_quant_tensor.py index 25685e7c3..1522221cd 100644 --- a/src/brevitas/quant_tensor/int_quant_tensor.py +++ b/src/brevitas/quant_tensor/int_quant_tensor.py @@ -238,6 +238,9 @@ def add(self, other): def unsqueeze(self, *args, **kwargs): return self.value.unsqueeze(*args, **kwargs) + def sigmoid(self): + return self.value.sigmoid() + @staticmethod def cat(tensors, dim, out=None): if out is not None: From 2ca8133143a9595e11c1075babbc0fd79709013e Mon Sep 17 00:00:00 2001 From: costigt-dev <156176839+costigt-dev@users.noreply.github.com> Date: Thu, 9 May 2024 09:40:27 +0100 Subject: [PATCH 13/13] added sum function to int_quant_tensor --- src/brevitas/quant_tensor/int_quant_tensor.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/brevitas/quant_tensor/int_quant_tensor.py b/src/brevitas/quant_tensor/int_quant_tensor.py index 1522221cd..0abde1f48 100644 --- a/src/brevitas/quant_tensor/int_quant_tensor.py +++ b/src/brevitas/quant_tensor/int_quant_tensor.py @@ -235,6 +235,9 @@ def dim(self): def add(self, other): return self + other + def sum(self, *args, **kwargs): + return self.value.sum(*args, **kwargs) + def unsqueeze(self, *args, **kwargs): return self.value.unsqueeze(*args, **kwargs)