From e1baa2e871b10eed78114dca581a2499b2f11645 Mon Sep 17 00:00:00 2001 From: Vasilis Vryniotis Date: Wed, 3 Nov 2021 13:24:14 +0000 Subject: [PATCH 1/6] Reordering the builders to use proper typing. --- torchvision/models/quantization/googlenet.py | 125 +++++++++--------- torchvision/models/quantization/inception.py | 131 +++++++++---------- 2 files changed, 127 insertions(+), 129 deletions(-) diff --git a/torchvision/models/quantization/googlenet.py b/torchvision/models/quantization/googlenet.py index d25bf6f3e4d..fac2a738cba 100644 --- a/torchvision/models/quantization/googlenet.py +++ b/torchvision/models/quantization/googlenet.py @@ -19,69 +19,6 @@ } -def googlenet( - pretrained: bool = False, - progress: bool = True, - quantize: bool = False, - **kwargs: Any, -) -> "QuantizableGoogLeNet": - - r"""GoogLeNet (Inception v1) model architecture from - `"Going Deeper with Convolutions" `_. - - Note that quantize = True returns a quantized model with 8 bit - weights. Quantized models only support inference and run on CPUs. - GPU inference is not yet supported - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - quantize (bool): If True, return a quantized version of the model - aux_logits (bool): If True, adds two auxiliary branches that can improve training. - Default: *False* when pretrained is True otherwise *True* - transform_input (bool): If True, preprocesses the input according to the method with which it - was trained on ImageNet. Default: *False* - """ - if pretrained: - if "transform_input" not in kwargs: - kwargs["transform_input"] = True - if "aux_logits" not in kwargs: - kwargs["aux_logits"] = False - if kwargs["aux_logits"]: - warnings.warn( - "auxiliary heads in the pretrained googlenet model are NOT pretrained, so make sure to train them" - ) - original_aux_logits = kwargs["aux_logits"] - kwargs["aux_logits"] = True - kwargs["init_weights"] = False - - model = QuantizableGoogLeNet(**kwargs) - _replace_relu(model) - - if quantize: - # TODO use pretrained as a string to specify the backend - backend = "fbgemm" - quantize_model(model, backend) - else: - assert pretrained in [True, False] - - if pretrained: - if quantize: - model_url = quant_model_urls["googlenet_" + backend] - else: - model_url = model_urls["googlenet"] - - state_dict = load_state_dict_from_url(model_url, progress=progress) - - model.load_state_dict(state_dict) - - if not original_aux_logits: - model.aux_logits = False - model.aux1 = None # type: ignore[assignment] - model.aux2 = None # type: ignore[assignment] - return model - - class QuantizableBasicConv2d(BasicConv2d): def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -164,3 +101,65 @@ def fuse_model(self) -> None: for m in self.modules(): if type(m) is QuantizableBasicConv2d: m.fuse_model() + + +def googlenet( + pretrained: bool = False, + progress: bool = True, + quantize: bool = False, + **kwargs: Any, +) -> QuantizableGoogLeNet: + r"""GoogLeNet (Inception v1) model architecture from + `"Going Deeper with Convolutions" `_. + + Note that quantize = True returns a quantized model with 8 bit + weights. Quantized models only support inference and run on CPUs. + GPU inference is not yet supported + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + quantize (bool): If True, return a quantized version of the model + aux_logits (bool): If True, adds two auxiliary branches that can improve training. + Default: *False* when pretrained is True otherwise *True* + transform_input (bool): If True, preprocesses the input according to the method with which it + was trained on ImageNet. Default: *False* + """ + if pretrained: + if "transform_input" not in kwargs: + kwargs["transform_input"] = True + if "aux_logits" not in kwargs: + kwargs["aux_logits"] = False + if kwargs["aux_logits"]: + warnings.warn( + "auxiliary heads in the pretrained googlenet model are NOT pretrained, so make sure to train them" + ) + original_aux_logits = kwargs["aux_logits"] + kwargs["aux_logits"] = True + kwargs["init_weights"] = False + + model = QuantizableGoogLeNet(**kwargs) + _replace_relu(model) + + if quantize: + # TODO use pretrained as a string to specify the backend + backend = "fbgemm" + quantize_model(model, backend) + else: + assert pretrained in [True, False] + + if pretrained: + if quantize: + model_url = quant_model_urls["googlenet_" + backend] + else: + model_url = model_urls["googlenet"] + + state_dict = load_state_dict_from_url(model_url, progress=progress) + + model.load_state_dict(state_dict) + + if not original_aux_logits: + model.aux_logits = False + model.aux1 = None # type: ignore[assignment] + model.aux2 = None # type: ignore[assignment] + return model diff --git a/torchvision/models/quantization/inception.py b/torchvision/models/quantization/inception.py index f9c2f351af1..8b41bd00bb0 100644 --- a/torchvision/models/quantization/inception.py +++ b/torchvision/models/quantization/inception.py @@ -24,72 +24,6 @@ } -def inception_v3( - pretrained: bool = False, - progress: bool = True, - quantize: bool = False, - **kwargs: Any, -) -> "QuantizableInception3": - - r"""Inception v3 model architecture from - `"Rethinking the Inception Architecture for Computer Vision" `_. - - .. note:: - **Important**: In contrast to the other models the inception_v3 expects tensors with a size of - N x 3 x 299 x 299, so ensure your images are sized accordingly. - - Note that quantize = True returns a quantized model with 8 bit - weights. Quantized models only support inference and run on CPUs. - GPU inference is not yet supported - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - quantize (bool): If True, return a quantized version of the model - aux_logits (bool): If True, add an auxiliary branch that can improve training. - Default: *True* - transform_input (bool): If True, preprocesses the input according to the method with which it - was trained on ImageNet. Default: *False* - """ - if pretrained: - if "transform_input" not in kwargs: - kwargs["transform_input"] = True - if "aux_logits" in kwargs: - original_aux_logits = kwargs["aux_logits"] - kwargs["aux_logits"] = True - else: - original_aux_logits = False - - model = QuantizableInception3(**kwargs) - _replace_relu(model) - - if quantize: - # TODO use pretrained as a string to specify the backend - backend = "fbgemm" - quantize_model(model, backend) - else: - assert pretrained in [True, False] - - if pretrained: - if quantize: - if not original_aux_logits: - model.aux_logits = False - model.AuxLogits = None - model_url = quant_model_urls["inception_v3_google_" + backend] - else: - model_url = inception_module.model_urls["inception_v3_google"] - - state_dict = load_state_dict_from_url(model_url, progress=progress) - - model.load_state_dict(state_dict) - - if not quantize: - if not original_aux_logits: - model.aux_logits = False - model.AuxLogits = None - return model - - class QuantizableBasicConv2d(inception_module.BasicConv2d): def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -237,3 +171,68 @@ def fuse_model(self) -> None: for m in self.modules(): if type(m) is QuantizableBasicConv2d: m.fuse_model() + + +def inception_v3( + pretrained: bool = False, + progress: bool = True, + quantize: bool = False, + **kwargs: Any, +) -> QuantizableInception3: + r"""Inception v3 model architecture from + `"Rethinking the Inception Architecture for Computer Vision" `_. + + .. note:: + **Important**: In contrast to the other models the inception_v3 expects tensors with a size of + N x 3 x 299 x 299, so ensure your images are sized accordingly. + + Note that quantize = True returns a quantized model with 8 bit + weights. Quantized models only support inference and run on CPUs. + GPU inference is not yet supported + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + quantize (bool): If True, return a quantized version of the model + aux_logits (bool): If True, add an auxiliary branch that can improve training. + Default: *True* + transform_input (bool): If True, preprocesses the input according to the method with which it + was trained on ImageNet. Default: *False* + """ + if pretrained: + if "transform_input" not in kwargs: + kwargs["transform_input"] = True + if "aux_logits" in kwargs: + original_aux_logits = kwargs["aux_logits"] + kwargs["aux_logits"] = True + else: + original_aux_logits = False + + model = QuantizableInception3(**kwargs) + _replace_relu(model) + + if quantize: + # TODO use pretrained as a string to specify the backend + backend = "fbgemm" + quantize_model(model, backend) + else: + assert pretrained in [True, False] + + if pretrained: + if quantize: + if not original_aux_logits: + model.aux_logits = False + model.AuxLogits = None + model_url = quant_model_urls["inception_v3_google_" + backend] + else: + model_url = inception_module.model_urls["inception_v3_google"] + + state_dict = load_state_dict_from_url(model_url, progress=progress) + + model.load_state_dict(state_dict) + + if not quantize: + if not original_aux_logits: + model.aux_logits = False + model.AuxLogits = None + return model From cd01389838c92195fc5fff48e4ed2ae331f17dfd Mon Sep 17 00:00:00 2001 From: Vasilis Vryniotis Date: Wed, 3 Nov 2021 14:05:31 +0000 Subject: [PATCH 2/6] Adding additional meta-data on existing quantized models. --- torchvision/prototype/models/quantization/resnet.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/torchvision/prototype/models/quantization/resnet.py b/torchvision/prototype/models/quantization/resnet.py index 15a583f3f00..361bf3dc385 100644 --- a/torchvision/prototype/models/quantization/resnet.py +++ b/torchvision/prototype/models/quantization/resnet.py @@ -2,6 +2,8 @@ from functools import partial from typing import Any, List, Optional, Type, Union +from torchvision.transforms.functional import InterpolationMode + from ....models.quantization.resnet import ( QuantizableBasicBlock, QuantizableBottleneck, @@ -54,7 +56,9 @@ def _resnet( _common_meta = { "size": (224, 224), "categories": _IMAGENET_CATEGORIES, + "interpolation": InterpolationMode.BILINEAR, "backend": "fbgemm", + "quantization": "ptq", "recipe": "https://github.com/pytorch/vision/tree/main/references/classification#post-training-quantized-models", } @@ -65,6 +69,7 @@ class QuantizedResNet18Weights(Weights): transforms=partial(ImageNetEval, crop_size=224), meta={ **_common_meta, + "unquantized": ResNet18Weights.ImageNet1K_RefV1, "acc@1": 69.494, "acc@5": 88.882, }, @@ -77,6 +82,7 @@ class QuantizedResNet50Weights(Weights): transforms=partial(ImageNetEval, crop_size=224), meta={ **_common_meta, + "unquantized": ResNet50Weights.ImageNet1K_RefV1, "acc@1": 75.920, "acc@5": 92.814, }, @@ -89,6 +95,7 @@ class QuantizedResNeXt101_32x8dWeights(Weights): transforms=partial(ImageNetEval, crop_size=224), meta={ **_common_meta, + "unquantized": ResNeXt101_32x8dWeights.ImageNet1K_RefV1, "acc@1": 78.986, "acc@5": 94.480, }, From 0e6d7d015171554fcd6eab4248fa4e7e6cb247b5 Mon Sep 17 00:00:00 2001 From: Vasilis Vryniotis Date: Wed, 3 Nov 2021 14:45:15 +0000 Subject: [PATCH 3/6] Fixing meta on unquantized model. --- torchvision/prototype/models/googlenet.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/torchvision/prototype/models/googlenet.py b/torchvision/prototype/models/googlenet.py index 9b28ea8450a..59237b6198f 100644 --- a/torchvision/prototype/models/googlenet.py +++ b/torchvision/prototype/models/googlenet.py @@ -14,14 +14,13 @@ class GoogLeNetWeights(Weights): - ImageNet1K_Community = WeightEntry( + ImageNet1K_TFV1 = WeightEntry( url="https://download.pytorch.org/models/googlenet-1378be20.pth", transforms=partial(ImageNetEval, crop_size=224), meta={ "size": (224, 224), "categories": _IMAGENET_CATEGORIES, "interpolation": InterpolationMode.BILINEAR, - "recipe": "https://github.com/TheCodez/examples/blob/inception/imagenet/README.md#googlenet", "acc@1": 69.778, "acc@5": 89.530, }, @@ -31,7 +30,7 @@ class GoogLeNetWeights(Weights): def googlenet(weights: Optional[GoogLeNetWeights] = None, progress: bool = True, **kwargs: Any) -> GoogLeNet: if "pretrained" in kwargs: warnings.warn("The argument pretrained is deprecated, please use weights instead.") - weights = GoogLeNetWeights.ImageNet1K_Community if kwargs.pop("pretrained") else None + weights = GoogLeNetWeights.ImageNet1K_TFV1 if kwargs.pop("pretrained") else None weights = GoogLeNetWeights.verify(weights) original_aux_logits = kwargs.get("aux_logits", False) From 851ddcb4c6d957a0f071e0ce9fd77d066f5a1fd1 Mon Sep 17 00:00:00 2001 From: Vasilis Vryniotis Date: Wed, 3 Nov 2021 14:46:45 +0000 Subject: [PATCH 4/6] Adding quantized googlenet builder. --- test/test_prototype_models.py | 1 + .../prototype/models/quantization/__init__.py | 1 + .../models/quantization/googlenet.py | 88 +++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 torchvision/prototype/models/quantization/googlenet.py diff --git a/test/test_prototype_models.py b/test/test_prototype_models.py index 7a39b1c9a7f..82c5f2f811c 100644 --- a/test/test_prototype_models.py +++ b/test/test_prototype_models.py @@ -84,6 +84,7 @@ def test_old_vs_new_factory(model_fn, module_name, dev): }, "quantization": { "input_shape": (1, 3, 224, 224), + "quantize": True, }, "segmentation": { "input_shape": (1, 3, 520, 520), diff --git a/torchvision/prototype/models/quantization/__init__.py b/torchvision/prototype/models/quantization/__init__.py index b792ca6ecf7..e82fed54a9c 100644 --- a/torchvision/prototype/models/quantization/__init__.py +++ b/torchvision/prototype/models/quantization/__init__.py @@ -1 +1,2 @@ +from .googlenet import * from .resnet import * diff --git a/torchvision/prototype/models/quantization/googlenet.py b/torchvision/prototype/models/quantization/googlenet.py new file mode 100644 index 00000000000..2cf6527cccf --- /dev/null +++ b/torchvision/prototype/models/quantization/googlenet.py @@ -0,0 +1,88 @@ +import warnings +from functools import partial +from typing import Any, Optional, Union + +from torchvision.transforms.functional import InterpolationMode + +from ....models.quantization.googlenet import ( + QuantizableGoogLeNet, + _replace_relu, + quantize_model, +) +from ...transforms.presets import ImageNetEval +from .._api import Weights, WeightEntry +from .._meta import _IMAGENET_CATEGORIES +from ..googlenet import GoogLeNetWeights + + +__all__ = [ + "QuantizableGoogLeNet", + "QuantizedGoogLeNetWeights", + "googlenet", +] + + +class QuantizedGoogLeNetWeights(Weights): + ImageNet1K_FBGEMM_TFV1 = WeightEntry( + url="https://download.pytorch.org/models/quantized/googlenet_fbgemm-c00238cf.pth", + transforms=partial(ImageNetEval, crop_size=224), + meta={ + "size": (224, 224), + "categories": _IMAGENET_CATEGORIES, + "interpolation": InterpolationMode.BILINEAR, + "backend": "fbgemm", + "quantization": "ptq", + "recipe": "https://github.com/pytorch/vision/tree/main/references/classification#post-training-quantized-models", + "unquantized": GoogLeNetWeights.ImageNet1K_TFV1, + "acc@1": 69.826, + "acc@5": 89.404, + }, + ) + + +def googlenet( + weights: Optional[Union[QuantizedGoogLeNetWeights, GoogLeNetWeights]] = None, + progress: bool = True, + quantize: bool = False, + **kwargs: Any, +) -> QuantizableGoogLeNet: + if "pretrained" in kwargs: + warnings.warn("The argument pretrained is deprecated, please use weights instead.") + if kwargs.pop("pretrained"): + weights = QuantizedGoogLeNetWeights.ImageNet1K_FBGEMM_TFV1 if quantize else GoogLeNetWeights.ImageNet1K_TFV1 + else: + weights = None + + if quantize: + weights = QuantizedGoogLeNetWeights.verify(weights) + else: + weights = GoogLeNetWeights.verify(weights) + + original_aux_logits = kwargs.get("aux_logits", False) + if weights is not None: + if "transform_input" not in kwargs: + kwargs["transform_input"] = True + if original_aux_logits: + warnings.warn( + "auxiliary heads in the pretrained googlenet model are NOT pretrained, so make sure to train them" + ) + kwargs["aux_logits"] = True + kwargs["init_weights"] = False + kwargs["num_classes"] = len(weights.meta["categories"]) + if "backend" in weights.meta: + kwargs["backend"] = weights.meta["backend"] + backend = kwargs.pop("backend", "fbgemm") + + model = QuantizableGoogLeNet(**kwargs) + _replace_relu(model) + if quantize: + quantize_model(model, backend) + + if weights is not None: + model.load_state_dict(weights.state_dict(progress=progress)) + if not original_aux_logits: + model.aux_logits = False + model.aux1 = None # type: ignore[assignment] + model.aux2 = None # type: ignore[assignment] + + return model From efa445dc31f2e6ca9a008570a4fc31508b7fd6c5 Mon Sep 17 00:00:00 2001 From: Vasilis Vryniotis Date: Wed, 3 Nov 2021 14:50:17 +0000 Subject: [PATCH 5/6] undo inception move. --- torchvision/models/quantization/inception.py | 131 ++++++++++--------- 1 file changed, 66 insertions(+), 65 deletions(-) diff --git a/torchvision/models/quantization/inception.py b/torchvision/models/quantization/inception.py index 8b41bd00bb0..f9c2f351af1 100644 --- a/torchvision/models/quantization/inception.py +++ b/torchvision/models/quantization/inception.py @@ -24,6 +24,72 @@ } +def inception_v3( + pretrained: bool = False, + progress: bool = True, + quantize: bool = False, + **kwargs: Any, +) -> "QuantizableInception3": + + r"""Inception v3 model architecture from + `"Rethinking the Inception Architecture for Computer Vision" `_. + + .. note:: + **Important**: In contrast to the other models the inception_v3 expects tensors with a size of + N x 3 x 299 x 299, so ensure your images are sized accordingly. + + Note that quantize = True returns a quantized model with 8 bit + weights. Quantized models only support inference and run on CPUs. + GPU inference is not yet supported + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + quantize (bool): If True, return a quantized version of the model + aux_logits (bool): If True, add an auxiliary branch that can improve training. + Default: *True* + transform_input (bool): If True, preprocesses the input according to the method with which it + was trained on ImageNet. Default: *False* + """ + if pretrained: + if "transform_input" not in kwargs: + kwargs["transform_input"] = True + if "aux_logits" in kwargs: + original_aux_logits = kwargs["aux_logits"] + kwargs["aux_logits"] = True + else: + original_aux_logits = False + + model = QuantizableInception3(**kwargs) + _replace_relu(model) + + if quantize: + # TODO use pretrained as a string to specify the backend + backend = "fbgemm" + quantize_model(model, backend) + else: + assert pretrained in [True, False] + + if pretrained: + if quantize: + if not original_aux_logits: + model.aux_logits = False + model.AuxLogits = None + model_url = quant_model_urls["inception_v3_google_" + backend] + else: + model_url = inception_module.model_urls["inception_v3_google"] + + state_dict = load_state_dict_from_url(model_url, progress=progress) + + model.load_state_dict(state_dict) + + if not quantize: + if not original_aux_logits: + model.aux_logits = False + model.AuxLogits = None + return model + + class QuantizableBasicConv2d(inception_module.BasicConv2d): def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -171,68 +237,3 @@ def fuse_model(self) -> None: for m in self.modules(): if type(m) is QuantizableBasicConv2d: m.fuse_model() - - -def inception_v3( - pretrained: bool = False, - progress: bool = True, - quantize: bool = False, - **kwargs: Any, -) -> QuantizableInception3: - r"""Inception v3 model architecture from - `"Rethinking the Inception Architecture for Computer Vision" `_. - - .. note:: - **Important**: In contrast to the other models the inception_v3 expects tensors with a size of - N x 3 x 299 x 299, so ensure your images are sized accordingly. - - Note that quantize = True returns a quantized model with 8 bit - weights. Quantized models only support inference and run on CPUs. - GPU inference is not yet supported - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - quantize (bool): If True, return a quantized version of the model - aux_logits (bool): If True, add an auxiliary branch that can improve training. - Default: *True* - transform_input (bool): If True, preprocesses the input according to the method with which it - was trained on ImageNet. Default: *False* - """ - if pretrained: - if "transform_input" not in kwargs: - kwargs["transform_input"] = True - if "aux_logits" in kwargs: - original_aux_logits = kwargs["aux_logits"] - kwargs["aux_logits"] = True - else: - original_aux_logits = False - - model = QuantizableInception3(**kwargs) - _replace_relu(model) - - if quantize: - # TODO use pretrained as a string to specify the backend - backend = "fbgemm" - quantize_model(model, backend) - else: - assert pretrained in [True, False] - - if pretrained: - if quantize: - if not original_aux_logits: - model.aux_logits = False - model.AuxLogits = None - model_url = quant_model_urls["inception_v3_google_" + backend] - else: - model_url = inception_module.model_urls["inception_v3_google"] - - state_dict = load_state_dict_from_url(model_url, progress=progress) - - model.load_state_dict(state_dict) - - if not quantize: - if not original_aux_logits: - model.aux_logits = False - model.AuxLogits = None - return model From 1a150d95dee4042088b126c144e0c1fda729ffdb Mon Sep 17 00:00:00 2001 From: Vasilis Vryniotis Date: Wed, 3 Nov 2021 16:00:48 +0000 Subject: [PATCH 6/6] Adding recipe information. --- references/classification/README.md | 4 ++++ torchvision/prototype/models/googlenet.py | 1 + 2 files changed, 5 insertions(+) diff --git a/references/classification/README.md b/references/classification/README.md index 71692b61386..302e9d57562 100644 --- a/references/classification/README.md +++ b/references/classification/README.md @@ -31,6 +31,10 @@ Here `$MODEL` is one of `alexnet`, `vgg11`, `vgg13`, `vgg16` or `vgg19`. Note that `vgg11_bn`, `vgg13_bn`, `vgg16_bn`, and `vgg19_bn` include batch normalization and thus are trained with the default parameters. +### GoogLeNet + +The weights of the GoogLeNet model are ported from the original paper rather than trained from scratch. + ### Inception V3 The weights of the Inception V3 model are ported from the original paper rather than trained from scratch. diff --git a/torchvision/prototype/models/googlenet.py b/torchvision/prototype/models/googlenet.py index 59237b6198f..0fb45e103e3 100644 --- a/torchvision/prototype/models/googlenet.py +++ b/torchvision/prototype/models/googlenet.py @@ -21,6 +21,7 @@ class GoogLeNetWeights(Weights): "size": (224, 224), "categories": _IMAGENET_CATEGORIES, "interpolation": InterpolationMode.BILINEAR, + "recipe": "https://github.com/pytorch/vision/tree/main/references/classification#googlenet", "acc@1": 69.778, "acc@5": 89.530, },