From 1bcd9e339cdab5419067d45508438b5041d3d88e Mon Sep 17 00:00:00 2001 From: Aditya Oke Date: Wed, 13 Oct 2021 01:06:21 +0530 Subject: [PATCH 1/8] Start adding types --- mypy.ini | 4 ---- torchvision/models/detection/backbone_utils.py | 16 +++++++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mypy.ini b/mypy.ini index 0c46a09610b..e0d71caac2f 100644 --- a/mypy.ini +++ b/mypy.ini @@ -21,10 +21,6 @@ ignore_errors=True ignore_errors = True -[mypy-torchvision.models.detection.backbone_utils] - -ignore_errors = True - [mypy-torchvision.models.detection.image_list] ignore_errors = True diff --git a/torchvision/models/detection/backbone_utils.py b/torchvision/models/detection/backbone_utils.py index 70a7b40bd50..d4a67760410 100644 --- a/torchvision/models/detection/backbone_utils.py +++ b/torchvision/models/detection/backbone_utils.py @@ -1,6 +1,7 @@ import warnings +from typing import Callable -from torch import nn +from torch import nn, Tensor from torchvision.ops import misc as misc_nn_ops from torchvision.ops.feature_pyramid_network import FeaturePyramidNetwork, LastLevelMaxPool @@ -42,7 +43,7 @@ def __init__(self, backbone, return_layers, in_channels_list, out_channels, extr ) self.out_channels = out_channels - def forward(self, x): + def forward(self, x: Tensor) -> Tensor: x = self.body(x) x = self.fpn(x) return x @@ -51,11 +52,11 @@ def forward(self, x): def resnet_fpn_backbone( backbone_name, pretrained, - norm_layer=misc_nn_ops.FrozenBatchNorm2d, + norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, trainable_layers=3, returned_layers=None, extra_blocks=None, -): +) -> BackboneWithFPN: """ Constructs a specified ResNet backbone with FPN on top. Freezes the specified number of layers in the backbone. @@ -137,12 +138,13 @@ def _validate_trainable_layers(pretrained, trainable_backbone_layers, max_value, def mobilenet_backbone( backbone_name, pretrained, - fpn, - norm_layer=misc_nn_ops.FrozenBatchNorm2d, + fpn: bool, + norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, trainable_layers=2, returned_layers=None, extra_blocks=None, -): +) -> nn.Module: + backbone = mobilenet.__dict__[backbone_name](pretrained=pretrained, norm_layer=norm_layer).features # Gather the indices of blocks which are strided. These are the locations of C1, ..., Cn-1 blocks. From f64f80d75fcdd407ebf0bb56a91c2483512da24a Mon Sep 17 00:00:00 2001 From: Khushi Agrawal Date: Mon, 18 Oct 2021 13:01:49 +0530 Subject: [PATCH 2/8] add typing --- .../models/detection/backbone_utils.py | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/torchvision/models/detection/backbone_utils.py b/torchvision/models/detection/backbone_utils.py index d4a67760410..23242a161b2 100644 --- a/torchvision/models/detection/backbone_utils.py +++ b/torchvision/models/detection/backbone_utils.py @@ -1,9 +1,9 @@ import warnings -from typing import Callable +from typing import Callable, Dict, Optional, List, Union from torch import nn, Tensor from torchvision.ops import misc as misc_nn_ops -from torchvision.ops.feature_pyramid_network import FeaturePyramidNetwork, LastLevelMaxPool +from torchvision.ops.feature_pyramid_network import FeaturePyramidNetwork, LastLevelMaxPool, ExtraFPNBlock from .. import mobilenet from .. import resnet @@ -29,7 +29,7 @@ class BackboneWithFPN(nn.Module): out_channels (int): the number of channels in the FPN """ - def __init__(self, backbone, return_layers, in_channels_list, out_channels, extra_blocks=None): + def __init__(self, backbone: nn.Module, return_layers: Dict[str, str], in_channels_list: List[int], out_channels: int, extra_blocks: Optional[ExtraFPNBlock] = None) -> None: super(BackboneWithFPN, self).__init__() if extra_blocks is None: @@ -50,13 +50,13 @@ def forward(self, x: Tensor) -> Tensor: def resnet_fpn_backbone( - backbone_name, - pretrained, - norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, - trainable_layers=3, - returned_layers=None, - extra_blocks=None, -) -> BackboneWithFPN: + backbone_name: str, + pretrained: bool, + norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, + trainable_layers: int = 3, + returned_layers: List[int] = None, + extra_blocks: Optional[ExtraFPNBlock] = None, +) -> Optional[BackboneWithFPN]: """ Constructs a specified ResNet backbone with FPN on top. Freezes the specified number of layers in the backbone. @@ -117,7 +117,7 @@ def resnet_fpn_backbone( return BackboneWithFPN(backbone, return_layers, in_channels_list, out_channels, extra_blocks=extra_blocks) -def _validate_trainable_layers(pretrained, trainable_backbone_layers, max_value, default_value): +def _validate_trainable_layers(pretrained: bool, trainable_backbone_layers: int, max_value: int, default_value: int) -> int: # dont freeze any layers if pretrained model or backbone is not used if not pretrained: if trainable_backbone_layers is not None: @@ -136,13 +136,13 @@ def _validate_trainable_layers(pretrained, trainable_backbone_layers, max_value, def mobilenet_backbone( - backbone_name, - pretrained, - fpn: bool, - norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, - trainable_layers=2, - returned_layers=None, - extra_blocks=None, + backbone_name: str, + pretrained: bool, + fpn: bool, + norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, + trainable_layers: int = 2, + returned_layers: List[int] = None, + extra_blocks: Optional[ExtraFPNBlock] = None, ) -> nn.Module: backbone = mobilenet.__dict__[backbone_name](pretrained=pretrained, norm_layer=norm_layer).features From 0d7aec50ccdb38d76949963add98780f08bf1caa Mon Sep 17 00:00:00 2001 From: Aditya Oke Date: Mon, 18 Oct 2021 19:00:08 +0530 Subject: [PATCH 3/8] Type prototype models --- .../models/detection/backbone_utils.py | 15 +++++++------- .../models/detection/backbone_utils.py | 20 ++++++++++++------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/torchvision/models/detection/backbone_utils.py b/torchvision/models/detection/backbone_utils.py index 16452c06d1e..2e088f12f82 100644 --- a/torchvision/models/detection/backbone_utils.py +++ b/torchvision/models/detection/backbone_utils.py @@ -50,7 +50,7 @@ def __init__( ) self.out_channels = out_channels - def forward(self, x: Tensor) -> Tensor: + def forward(self, x: Tensor) -> Dict[str, Tensor]: x = self.body(x) x = self.fpn(x) return x @@ -61,9 +61,9 @@ def resnet_fpn_backbone( pretrained: bool, norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, trainable_layers: int = 3, - returned_layers: List[int] = None, + returned_layers: Optional[List[int]] = None, extra_blocks: Optional[ExtraFPNBlock] = None, -) -> Optional[BackboneWithFPN]: +) -> BackboneWithFPN: """ Constructs a specified ResNet backbone with FPN on top. Freezes the specified number of layers in the backbone. @@ -106,9 +106,10 @@ def resnet_fpn_backbone( def _resnet_backbone_config( backbone: resnet.ResNet, trainable_layers: int, - returned_layers: Optional[List[int]], - extra_blocks: Optional[ExtraFPNBlock], -): + returned_layers: Optional[List[int]] = None, + extra_blocks: Optional[ExtraFPNBlock] = None, +) -> BackboneWithFPN: + # select layers that wont be frozen assert 0 <= trainable_layers <= 5 layers_to_train = ["layer4", "layer3", "layer2", "layer1", "conv1"][:trainable_layers] @@ -195,5 +196,5 @@ def mobilenet_backbone( # depthwise linear combination of channels to reduce their size nn.Conv2d(backbone[-1].out_channels, out_channels, 1), ) - m.out_channels = out_channels + m.out_channels = out_channels # type: ignore[assignment] return m diff --git a/torchvision/prototype/models/detection/backbone_utils.py b/torchvision/prototype/models/detection/backbone_utils.py index 9893ebf8e5d..d90d6962231 100644 --- a/torchvision/prototype/models/detection/backbone_utils.py +++ b/torchvision/prototype/models/detection/backbone_utils.py @@ -1,14 +1,20 @@ -from ....models.detection.backbone_utils import misc_nn_ops, _resnet_backbone_config +from typing import Callable, Optional, List + +from torch import nn + +from ....models.detection.backbone_utils import misc_nn_ops, _resnet_backbone_config, BackboneWithFPN +from ....ops.feature_pyramid_network import ExtraFPNBlock from .. import resnet def resnet_fpn_backbone( - backbone_name, + backbone_name: str, weights, - norm_layer=misc_nn_ops.FrozenBatchNorm2d, - trainable_layers=3, - returned_layers=None, - extra_blocks=None, -): + norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, + trainable_layers: int = 3, + returned_layers: Optional[List[int]] = None, + extra_blocks: Optional[ExtraFPNBlock] = None, +) -> BackboneWithFPN: + backbone = resnet.__dict__[backbone_name](weights=weights, norm_layer=norm_layer) return _resnet_backbone_config(backbone, trainable_layers, returned_layers, extra_blocks) From 947228386aa03369dff07e5098df22f09fefbb8a Mon Sep 17 00:00:00 2001 From: Aditya Oke Date: Mon, 18 Oct 2021 19:05:31 +0530 Subject: [PATCH 4/8] fix optional type bug --- torchvision/models/detection/backbone_utils.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/torchvision/models/detection/backbone_utils.py b/torchvision/models/detection/backbone_utils.py index 2e088f12f82..d2805154cfc 100644 --- a/torchvision/models/detection/backbone_utils.py +++ b/torchvision/models/detection/backbone_utils.py @@ -87,7 +87,7 @@ def resnet_fpn_backbone( backbone_name (string): resnet architecture. Possible values are 'ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152', 'resnext50_32x4d', 'resnext101_32x8d', 'wide_resnet50_2', 'wide_resnet101_2' pretrained (bool): If True, returns a model with backbone pre-trained on Imagenet - norm_layer (torchvision.ops): it is recommended to use the default value. For details visit: + norm_layer (callable nn.Module): it is recommended to use the default value. For details visit: (https://github.com/facebookresearch/maskrcnn-benchmark/issues/267) trainable_layers (int): number of trainable (not frozen) resnet layers starting from final block. Valid values are between 0 and 5, with 5 meaning all backbone layers are trainable. @@ -134,9 +134,12 @@ def _resnet_backbone_config( def _validate_trainable_layers( - pretrained: bool, trainable_backbone_layers: int, max_value: int, default_value: int + pretrained: bool, + trainable_backbone_layers: Optional[int], + max_value: int, + default_value: int, ) -> int: - # dont freeze any layers if pretrained model or backbone is not used + # don't freeze any layers if pretrained model or backbone is not used if not pretrained: if trainable_backbone_layers is not None: warnings.warn( From 96962ecd3e15b6f4abf542a348491bd68a04dc02 Mon Sep 17 00:00:00 2001 From: Aditya Oke Date: Mon, 18 Oct 2021 19:38:03 +0530 Subject: [PATCH 5/8] transient import --- torchvision/prototype/models/detection/backbone_utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/torchvision/prototype/models/detection/backbone_utils.py b/torchvision/prototype/models/detection/backbone_utils.py index d90d6962231..70907522ace 100644 --- a/torchvision/prototype/models/detection/backbone_utils.py +++ b/torchvision/prototype/models/detection/backbone_utils.py @@ -2,8 +2,7 @@ from torch import nn -from ....models.detection.backbone_utils import misc_nn_ops, _resnet_backbone_config, BackboneWithFPN -from ....ops.feature_pyramid_network import ExtraFPNBlock +from ....models.detection.backbone_utils import misc_nn_ops, _resnet_backbone_config, BackboneWithFPN, ExtraFPNBlock from .. import resnet From 9b05464bb07689de418e182d9540aff381fb2cdd Mon Sep 17 00:00:00 2001 From: Aditya Oke <47158509+oke-aditya@users.noreply.github.com> Date: Mon, 18 Oct 2021 21:01:57 +0530 Subject: [PATCH 6/8] Fix weights type --- torchvision/prototype/models/detection/backbone_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/torchvision/prototype/models/detection/backbone_utils.py b/torchvision/prototype/models/detection/backbone_utils.py index 70907522ace..1f70f7a6d72 100644 --- a/torchvision/prototype/models/detection/backbone_utils.py +++ b/torchvision/prototype/models/detection/backbone_utils.py @@ -8,7 +8,7 @@ def resnet_fpn_backbone( backbone_name: str, - weights, + weights: Optional[Weights], norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, trainable_layers: int = 3, returned_layers: Optional[List[int]] = None, From 9df1de0dec49fc0bbbb7750b516716dd85f5df99 Mon Sep 17 00:00:00 2001 From: Aditya Oke Date: Mon, 18 Oct 2021 21:03:41 +0530 Subject: [PATCH 7/8] fix import --- torchvision/prototype/models/detection/backbone_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/torchvision/prototype/models/detection/backbone_utils.py b/torchvision/prototype/models/detection/backbone_utils.py index 1f70f7a6d72..d95b1ab52f0 100644 --- a/torchvision/prototype/models/detection/backbone_utils.py +++ b/torchvision/prototype/models/detection/backbone_utils.py @@ -4,6 +4,7 @@ from ....models.detection.backbone_utils import misc_nn_ops, _resnet_backbone_config, BackboneWithFPN, ExtraFPNBlock from .. import resnet +from .._api import Weights def resnet_fpn_backbone( From 06bb8755f4bbf15cf2489db3694b70cd05712cb2 Mon Sep 17 00:00:00 2001 From: Aditya Oke <47158509+oke-aditya@users.noreply.github.com> Date: Mon, 18 Oct 2021 22:12:08 +0530 Subject: [PATCH 8/8] Apply suggestions from code review Address nits Co-authored-by: Vasilis Vryniotis --- torchvision/models/detection/backbone_utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/torchvision/models/detection/backbone_utils.py b/torchvision/models/detection/backbone_utils.py index d2805154cfc..e697e06929a 100644 --- a/torchvision/models/detection/backbone_utils.py +++ b/torchvision/models/detection/backbone_utils.py @@ -87,7 +87,7 @@ def resnet_fpn_backbone( backbone_name (string): resnet architecture. Possible values are 'ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152', 'resnext50_32x4d', 'resnext101_32x8d', 'wide_resnet50_2', 'wide_resnet101_2' pretrained (bool): If True, returns a model with backbone pre-trained on Imagenet - norm_layer (callable nn.Module): it is recommended to use the default value. For details visit: + norm_layer (callable): it is recommended to use the default value. For details visit: (https://github.com/facebookresearch/maskrcnn-benchmark/issues/267) trainable_layers (int): number of trainable (not frozen) resnet layers starting from final block. Valid values are between 0 and 5, with 5 meaning all backbone layers are trainable. @@ -106,8 +106,8 @@ def resnet_fpn_backbone( def _resnet_backbone_config( backbone: resnet.ResNet, trainable_layers: int, - returned_layers: Optional[List[int]] = None, - extra_blocks: Optional[ExtraFPNBlock] = None, + returned_layers: Optional[List[int]], + extra_blocks: Optional[ExtraFPNBlock], ) -> BackboneWithFPN: # select layers that wont be frozen @@ -162,7 +162,7 @@ def mobilenet_backbone( fpn: bool, norm_layer: Callable[..., nn.Module] = misc_nn_ops.FrozenBatchNorm2d, trainable_layers: int = 2, - returned_layers: List[int] = None, + returned_layers: Optional[List[int]] = None, extra_blocks: Optional[ExtraFPNBlock] = None, ) -> nn.Module: