From cf1646cb4a97bc5555e5100308aef435382ec657 Mon Sep 17 00:00:00 2001 From: heimish-kyma Date: Tue, 2 Aug 2022 23:58:32 +0900 Subject: [PATCH 01/19] remove under_review decorators --- pl_bolts/models/detection/yolo/yolo_config.py | 13 +++---------- pl_bolts/models/detection/yolo/yolo_layers.py | 10 ---------- pl_bolts/models/detection/yolo/yolo_module.py | 4 ---- 3 files changed, 3 insertions(+), 24 deletions(-) diff --git a/pl_bolts/models/detection/yolo/yolo_config.py b/pl_bolts/models/detection/yolo/yolo_config.py index fea807b1c0..254ee1523b 100644 --- a/pl_bolts/models/detection/yolo/yolo_config.py +++ b/pl_bolts/models/detection/yolo/yolo_config.py @@ -6,10 +6,8 @@ from pytorch_lightning.utilities.exceptions import MisconfigurationException from pl_bolts.models.detection.yolo import yolo_layers -from pl_bolts.utils.stability import under_review -@under_review() class YOLOConfiguration: """This class can be used to parse the configuration files of the Darknet YOLOv4 implementation. @@ -149,7 +147,6 @@ def convert(key, value): return sections -@under_review() def _create_layer(config: dict, num_inputs: List[int]) -> Tuple[nn.Module, int]: """Calls one of the ``_create_(config, num_inputs)`` functions to create a PyTorch module from the layer config. @@ -173,7 +170,6 @@ def _create_layer(config: dict, num_inputs: List[int]) -> Tuple[nn.Module, int]: return create_func[config["type"]](config, num_inputs) -@under_review() def _create_convolutional(config, num_inputs): module = nn.Sequential() @@ -210,14 +206,12 @@ def _create_convolutional(config, num_inputs): return module, config["filters"] -@under_review() def _create_maxpool(config, num_inputs): padding = (config["size"] - 1) // 2 module = nn.MaxPool2d(config["size"], config["stride"], padding) return module, num_inputs[-1] -@under_review() def _create_route(config, num_inputs): num_chunks = config.get("groups", 1) chunk_idx = config.get("group_id", 0) @@ -234,19 +228,16 @@ def _create_route(config, num_inputs): return module, num_outputs -@under_review() def _create_shortcut(config, num_inputs): module = yolo_layers.ShortcutLayer(config["from"]) return module, num_inputs[-1] -@under_review() def _create_upsample(config, num_inputs): module = nn.Upsample(scale_factor=config["stride"], mode="nearest") return module, num_inputs[-1] -@under_review() def _create_yolo(config, num_inputs): # The "anchors" list alternates width and height. anchor_dims = config["anchors"] @@ -264,8 +255,10 @@ def _create_yolo(config, num_inputs): overlap_loss_func = yolo_layers.SELoss() elif overlap_loss_name == "giou": overlap_loss_func = yolo_layers.GIoULoss() - else: + elif overlap_loss_name == "iou": overlap_loss_func = yolo_layers.IoULoss() + else: + assert False, "Unknown overlap loss: " + overlap_loss_name module = yolo_layers.DetectionLayer( num_classes=config["classes"], diff --git a/pl_bolts/models/detection/yolo/yolo_layers.py b/pl_bolts/models/detection/yolo/yolo_layers.py index 9e2d9f7475..9b1ee891df 100644 --- a/pl_bolts/models/detection/yolo/yolo_layers.py +++ b/pl_bolts/models/detection/yolo/yolo_layers.py @@ -5,7 +5,6 @@ from torch import Tensor, nn from pl_bolts.utils import _TORCHVISION_AVAILABLE -from pl_bolts.utils.stability import under_review from pl_bolts.utils.warnings import warn_missing_pkg if _TORCHVISION_AVAILABLE: @@ -21,7 +20,6 @@ warn_missing_pkg("torchvision") -@under_review() def _corner_coordinates(xy: Tensor, wh: Tensor) -> Tensor: """Converts box center points and sizes to corner coordinates. @@ -38,7 +36,6 @@ def _corner_coordinates(xy: Tensor, wh: Tensor) -> Tensor: return torch.cat((top_left, bottom_right), -1) -@under_review() def _aligned_iou(dims1: Tensor, dims2: Tensor) -> Tensor: """Calculates a matrix of intersections over union from box dimensions, assuming that the boxes are located at the same coordinates. @@ -61,7 +58,6 @@ def _aligned_iou(dims1: Tensor, dims2: Tensor) -> Tensor: return inter / union -@under_review() class SELoss(nn.MSELoss): def __init__(self): super().__init__(reduction="none") @@ -70,13 +66,11 @@ def forward(self, inputs: Tensor, target: Tensor) -> Tensor: return super().forward(inputs, target).sum(1) -@under_review() class IoULoss(nn.Module): def forward(self, inputs: Tensor, target: Tensor) -> Tensor: return 1.0 - box_iou(inputs, target).diagonal() -@under_review() class GIoULoss(nn.Module): def __init__(self) -> None: super().__init__() @@ -89,7 +83,6 @@ def forward(self, inputs: Tensor, target: Tensor) -> Tensor: return 1.0 - generalized_box_iou(inputs, target).diagonal() -@under_review() class DetectionLayer(nn.Module): """A YOLO detection layer. @@ -468,7 +461,6 @@ def _calculate_losses( return losses, hits -@under_review() class Mish(nn.Module): """Mish activation.""" @@ -476,7 +468,6 @@ def forward(self, x): return x * torch.tanh(nn.functional.softplus(x)) -@under_review() class RouteLayer(nn.Module): """Route layer concatenates the output (or part of it) from given layers.""" @@ -497,7 +488,6 @@ def forward(self, x, outputs): return torch.cat(chunks, dim=1) -@under_review() class ShortcutLayer(nn.Module): """Shortcut layer adds a residual connection from the source layer.""" diff --git a/pl_bolts/models/detection/yolo/yolo_module.py b/pl_bolts/models/detection/yolo/yolo_module.py index 6a012f1db9..ebb494f5ef 100644 --- a/pl_bolts/models/detection/yolo/yolo_module.py +++ b/pl_bolts/models/detection/yolo/yolo_module.py @@ -11,7 +11,6 @@ from pl_bolts.models.detection.yolo.yolo_layers import DetectionLayer, RouteLayer, ShortcutLayer from pl_bolts.optimizers.lr_scheduler import LinearWarmupCosineAnnealingLR from pl_bolts.utils import _TORCHVISION_AVAILABLE -from pl_bolts.utils.stability import under_review from pl_bolts.utils.warnings import warn_missing_pkg if _TORCHVISION_AVAILABLE: @@ -23,7 +22,6 @@ log = logging.getLogger(__name__) -@under_review() class YOLO(LightningModule): """PyTorch Lightning implementation of YOLOv3 and YOLOv4. @@ -455,7 +453,6 @@ def _filter_detections(self, detections: Dict[str, Tensor]) -> Dict[str, List[Te return {"boxes": out_boxes, "scores": out_scores, "classprobs": out_classprobs, "labels": out_labels} -@under_review() class Resize: """Rescales the image and target to given dimensions. @@ -486,7 +483,6 @@ def __call__(self, image: Tensor, target: Dict[str, Any]): return image, target -@under_review() def run_cli(): from argparse import ArgumentParser From fecf88cb512fcc812f8039a5ddc026e32a1c10e0 Mon Sep 17 00:00:00 2001 From: heimish-kyma Date: Wed, 3 Aug 2022 00:00:02 +0900 Subject: [PATCH 02/19] add yolo cfg with giou & update related test function --- tests/data/yolo_giou.cfg | 81 ++++++++++++++++++++++++++++++++++ tests/models/test_detection.py | 11 ++++- 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 tests/data/yolo_giou.cfg diff --git a/tests/data/yolo_giou.cfg b/tests/data/yolo_giou.cfg new file mode 100644 index 0000000000..16a96f918d --- /dev/null +++ b/tests/data/yolo_giou.cfg @@ -0,0 +1,81 @@ +[net] +width=256 +height=256 +channels=3 + +[convolutional] +batch_normalize=1 +filters=8 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers=-1 +groups=2 +group_id=1 + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=2 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=4 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +size=1 +stride=1 +pad=1 +filters=14 +activation=linear + +[yolo] +mask=2,3 +anchors=1,2, 3,4, 5,6, 9,10 +classes=2 +iou_loss=giou +scale_x_y=1.05 +cls_normalizer=1.0 +iou_normalizer=0.07 +ignore_thresh=0.7 + +[route] +layers = -4 + +[upsample] +stride=2 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=14 +activation=linear + +[yolo] +mask=0,1 +anchors=1,2, 3,4, 5,6, 9,10 +classes=2 +iou_loss=giou +scale_x_y=1.05 +cls_normalizer=1.0 +iou_normalizer=0.07 +ignore_thresh=0.7 diff --git a/tests/models/test_detection.py b/tests/models/test_detection.py index 31ac35377f..2630182317 100644 --- a/tests/models/test_detection.py +++ b/tests/models/test_detection.py @@ -88,8 +88,15 @@ def test_yolo(tmpdir): model(image) -def test_yolo_train(tmpdir): - config_path = Path(TEST_ROOT) / "data" / "yolo.cfg" +@pytest.mark.parametrize( + "cfg_name", + [ + ("yolo"), + ("yolo_giou"), + ], +) +def test_yolo_train(tmpdir, cfg_name): + config_path = Path(TEST_ROOT) / "data" / f"{cfg_name}.cfg" config = YOLOConfiguration(config_path) model = YOLO(config.get_network()) From b5abc8fded4a0f409ad6363cf43f5ce0a796faed Mon Sep 17 00:00:00 2001 From: heimish-kyma Date: Wed, 3 Aug 2022 00:01:15 +0900 Subject: [PATCH 03/19] add serveral yolo config & layers function test --- tests/models/yolo/__init__.py | 0 tests/models/yolo/unit/__init__.py | 0 tests/models/yolo/unit/test_yolo_config.py | 104 +++++++++++++++++++++ tests/models/yolo/unit/test_yolo_layers.py | 36 +++++++ 4 files changed, 140 insertions(+) create mode 100644 tests/models/yolo/__init__.py create mode 100644 tests/models/yolo/unit/__init__.py create mode 100644 tests/models/yolo/unit/test_yolo_config.py create mode 100644 tests/models/yolo/unit/test_yolo_layers.py diff --git a/tests/models/yolo/__init__.py b/tests/models/yolo/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/models/yolo/unit/__init__.py b/tests/models/yolo/unit/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/models/yolo/unit/test_yolo_config.py b/tests/models/yolo/unit/test_yolo_config.py new file mode 100644 index 0000000000..aab4c2f5a2 --- /dev/null +++ b/tests/models/yolo/unit/test_yolo_config.py @@ -0,0 +1,104 @@ +from pathlib import Path + +import pytest + +from pl_bolts.models.detection.yolo.yolo_config import ( + YOLOConfiguration, + _create_convolutional, + _create_maxpool, + _create_shortcut, + _create_upsample, + _create_yolo, +) +from tests import TEST_ROOT + + +@pytest.mark.parametrize( + "config", + [ + ({"batch_normalize": 1, "filters": 8, "size": 3, "stride": 1, "pad": 1, "activation": "leaky"}), + ({"batch_normalize": 0, "filters": 2, "size": 1, "stride": 1, "pad": 1, "activation": "mish"}), + ({"batch_normalize": 1, "filters": 6, "size": 3, "stride": 2, "pad": 1, "activation": "logistic"}), + ({"batch_normalize": 0, "filters": 4, "size": 3, "stride": 2, "pad": 0, "activation": "linear"}), + ], +) +def test_create_convolutional(config): + conv = _create_convolutional(config, [3])[0] + + assert conv.conv.out_channels == config["filters"] + assert conv.conv.kernel_size == (config["size"], config["size"]) + assert conv.conv.stride == (config["stride"], config["stride"]) + + activation = config["activation"] + pad_size = (config["size"] - 1) // 2 if config["pad"] else 0 + + if config["pad"]: + assert conv.conv.padding == (pad_size, pad_size) + + if config["batch_normalize"]: + assert len(conv) == 3 + + if activation != "linear": + if activation != "logistic": + assert activation == conv[-1].__class__.__name__.lower()[: len(activation)] + elif activation == "logistic": + assert "sigmoid" == conv[-1].__class__.__name__.lower() + + +@pytest.mark.parametrize( + "config", + [ + ( + { + "size": 2, + "stride": 2, + } + ), + ( + { + "size": 6, + "stride": 3, + } + ), + ], +) +def test_create_maxpool(config): + pad_size = (config["size"] - 1) // 2 + maxpool = _create_maxpool(config, [3])[0] + + assert maxpool.kernel_size == config["size"] + assert maxpool.stride == config["stride"] + assert maxpool.padding == pad_size + + +@pytest.mark.parametrize( + "config", + [ + ({"from": 1, "activation": "linear"}), + ({"from": 3, "activation": "linear"}), + ], +) +def test_create_shortcut(config): + shortcut = _create_shortcut(config, [3])[0] + + assert shortcut.source_layer == config["from"] + + +@pytest.mark.parametrize( + "config", + [ + ({"stride": 2}), + ({"stride": 4}), + ], +) +def test_create_upsample(config): + upsample = _create_upsample(config, [3])[0] + + assert upsample.scale_factor == float(config["stride"]) + + +@pytest.mark.parametrize("config", [("yolo"), ("yolo_giou")]) +def test_yolo_config(config): + config_path = Path(TEST_ROOT) / "data" / f"{config}.cfg" + config = YOLOConfiguration(config_path) + model = config.get_network() diff --git a/tests/models/yolo/unit/test_yolo_layers.py b/tests/models/yolo/unit/test_yolo_layers.py new file mode 100644 index 0000000000..5b3013f6f8 --- /dev/null +++ b/tests/models/yolo/unit/test_yolo_layers.py @@ -0,0 +1,36 @@ +import pytest +import torch + +from pl_bolts.models.detection.yolo.yolo_layers import GIoULoss, IoULoss, SELoss, _corner_coordinates + + +@pytest.mark.parametrize( + "xy, wh, expected", + [ + ([0.0, 0.0], [1.0, 1.0], [-0.5, -0.5, 0.5, 0.5]), + ([5.0, 5.0], [2.0, 2.0], [4.0, 4.0, 6.0, 6.0]), + ], +) +def test_corner_coordinates(xy, wh, expected): + xy = torch.tensor(xy) + wh = torch.tensor(wh) + corners = _corner_coordinates(xy, wh) + assert torch.allclose(corners, torch.tensor(expected)) + + +@pytest.mark.parametrize( + "loss_func, bbox1, bbox2, expected", + [ + (GIoULoss, [[0.0, 0.0, 120.0, 200.0]], [[189.0, 93.0, 242.0, 215.0]], 1.4144532680511475), + (IoULoss, [[0.0, 0.0, 120.0, 200.0]], [[189.0, 93.0, 242.0, 215.0]], 1.0), + (SELoss, [[0.0, 0.0, 120.0, 200.0]], [[189.0, 93.0, 242.0, 215.0]], 59479.0), + ], +) +def test_loss_functions(loss_func, bbox1, bbox2, expected): + loss_func = loss_func() + tensor1 = torch.tensor(bbox1, dtype=torch.float32) + tensor2 = torch.tensor(bbox2, dtype=torch.float32) + + loss = loss_func(tensor1, tensor2) + assert loss.item() > 0.0 + assert loss.item() == expected From 08f17f73a6c05982352754274cc3ba4133f45a55 Mon Sep 17 00:00:00 2001 From: Hongyeob Kim <41847456+heimish-kyma@users.noreply.github.com> Date: Wed, 3 Aug 2022 22:10:46 +0900 Subject: [PATCH 04/19] remove unused import & variable --- tests/models/yolo/unit/test_yolo_config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/models/yolo/unit/test_yolo_config.py b/tests/models/yolo/unit/test_yolo_config.py index aab4c2f5a2..58ac900d7e 100644 --- a/tests/models/yolo/unit/test_yolo_config.py +++ b/tests/models/yolo/unit/test_yolo_config.py @@ -8,7 +8,6 @@ _create_maxpool, _create_shortcut, _create_upsample, - _create_yolo, ) from tests import TEST_ROOT @@ -101,4 +100,4 @@ def test_create_upsample(config): def test_yolo_config(config): config_path = Path(TEST_ROOT) / "data" / f"{config}.cfg" config = YOLOConfiguration(config_path) - model = config.get_network() + config.get_network() From db2601a4f9f1c17d0bbb32f9361db6d3ee3f2fcc Mon Sep 17 00:00:00 2001 From: heimish-kyma Date: Wed, 10 Aug 2022 01:22:08 +0900 Subject: [PATCH 05/19] add type hints --- pl_bolts/models/detection/yolo/yolo_config.py | 12 ++++++------ pl_bolts/models/detection/yolo/yolo_layers.py | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pl_bolts/models/detection/yolo/yolo_config.py b/pl_bolts/models/detection/yolo/yolo_config.py index 254ee1523b..1bbb7eee86 100644 --- a/pl_bolts/models/detection/yolo/yolo_config.py +++ b/pl_bolts/models/detection/yolo/yolo_config.py @@ -170,7 +170,7 @@ def _create_layer(config: dict, num_inputs: List[int]) -> Tuple[nn.Module, int]: return create_func[config["type"]](config, num_inputs) -def _create_convolutional(config, num_inputs): +def _create_convolutional(config: dict, num_inputs: int) -> Tuple[nn.Module, int]: module = nn.Sequential() batch_normalize = config.get("batch_normalize", False) @@ -206,13 +206,13 @@ def _create_convolutional(config, num_inputs): return module, config["filters"] -def _create_maxpool(config, num_inputs): +def _create_maxpool(config: dict, num_inputs: int) -> Tuple[nn.Module, int]: padding = (config["size"] - 1) // 2 module = nn.MaxPool2d(config["size"], config["stride"], padding) return module, num_inputs[-1] -def _create_route(config, num_inputs): +def _create_route(config: dict, num_inputs: int) -> Tuple[nn.Module, int]: num_chunks = config.get("groups", 1) chunk_idx = config.get("group_id", 0) @@ -228,17 +228,17 @@ def _create_route(config, num_inputs): return module, num_outputs -def _create_shortcut(config, num_inputs): +def _create_shortcut(config: dict, num_inputs: int) -> Tuple[nn.Module, int]: module = yolo_layers.ShortcutLayer(config["from"]) return module, num_inputs[-1] -def _create_upsample(config, num_inputs): +def _create_upsample(config: dict, num_inputs: int) -> Tuple[nn.Module, int]: module = nn.Upsample(scale_factor=config["stride"], mode="nearest") return module, num_inputs[-1] -def _create_yolo(config, num_inputs): +def _create_yolo(config: dict, num_inputs: int) -> Tuple[nn.Module, int]: # The "anchors" list alternates width and height. anchor_dims = config["anchors"] anchor_dims = [(anchor_dims[i], anchor_dims[i + 1]) for i in range(0, len(anchor_dims), 2)] diff --git a/pl_bolts/models/detection/yolo/yolo_layers.py b/pl_bolts/models/detection/yolo/yolo_layers.py index 9b1ee891df..011895c5bc 100644 --- a/pl_bolts/models/detection/yolo/yolo_layers.py +++ b/pl_bolts/models/detection/yolo/yolo_layers.py @@ -1,4 +1,4 @@ -from typing import Callable, Dict, List, Optional, Tuple +from typing import Callable, Dict, List, Optional, Tuple, Union import torch from pytorch_lightning.utilities.exceptions import MisconfigurationException @@ -464,7 +464,7 @@ def _calculate_losses( class Mish(nn.Module): """Mish activation.""" - def forward(self, x): + def forward(self, x: Tensor) -> Tensor: return x * torch.tanh(nn.functional.softplus(x)) @@ -483,7 +483,7 @@ def __init__(self, source_layers: List[int], num_chunks: int, chunk_idx: int) -> self.num_chunks = num_chunks self.chunk_idx = chunk_idx - def forward(self, x, outputs): + def forward(self, x, outputs: List[Union[Tensor, None]]) -> Tensor: chunks = [torch.chunk(outputs[layer], self.num_chunks, dim=1)[self.chunk_idx] for layer in self.source_layers] return torch.cat(chunks, dim=1) @@ -500,5 +500,5 @@ def __init__(self, source_layer: int) -> None: super().__init__() self.source_layer = source_layer - def forward(self, x, outputs): + def forward(self, x, outputs: List[Union[Tensor, None]]) -> Tensor: return outputs[-1] + outputs[self.source_layer] From fe38bb760b1c90539b3b1756b7524adf12358bf2 Mon Sep 17 00:00:00 2001 From: heimish-kyma Date: Wed, 10 Aug 2022 01:24:34 +0900 Subject: [PATCH 06/19] remove and merge duplicated test --- tests/models/test_detection.py | 5 +++-- tests/models/yolo/unit/test_yolo_config.py | 14 +------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/tests/models/test_detection.py b/tests/models/test_detection.py index 2630182317..64b202b0ea 100644 --- a/tests/models/test_detection.py +++ b/tests/models/test_detection.py @@ -79,8 +79,9 @@ def test_fasterrcnn_pyt_module_bbone_train(tmpdir): trainer.fit(model, train_dl, valid_dl) -def test_yolo(tmpdir): - config_path = Path(TEST_ROOT) / "data" / "yolo.cfg" +@pytest.mark.parametrize("config", [("yolo"), ("yolo_giou")]) +def test_yolo(config): + config_path = Path(TEST_ROOT) / "data" / f"{config}.cfg" config = YOLOConfiguration(config_path) model = YOLO(config.get_network()) diff --git a/tests/models/yolo/unit/test_yolo_config.py b/tests/models/yolo/unit/test_yolo_config.py index aab4c2f5a2..2b2ec7833f 100644 --- a/tests/models/yolo/unit/test_yolo_config.py +++ b/tests/models/yolo/unit/test_yolo_config.py @@ -1,16 +1,11 @@ -from pathlib import Path - import pytest from pl_bolts.models.detection.yolo.yolo_config import ( - YOLOConfiguration, _create_convolutional, _create_maxpool, _create_shortcut, _create_upsample, - _create_yolo, ) -from tests import TEST_ROOT @pytest.mark.parametrize( @@ -92,13 +87,6 @@ def test_create_shortcut(config): ], ) def test_create_upsample(config): - upsample = _create_upsample(config, [3])[0] + upsample, _ = _create_upsample(config, [3]) assert upsample.scale_factor == float(config["stride"]) - - -@pytest.mark.parametrize("config", [("yolo"), ("yolo_giou")]) -def test_yolo_config(config): - config_path = Path(TEST_ROOT) / "data" / f"{config}.cfg" - config = YOLOConfiguration(config_path) - model = config.get_network() From 7da9d4a4dabd5e596026b76f58e0ac6eb5617520 Mon Sep 17 00:00:00 2001 From: heimish-kyma Date: Wed, 10 Aug 2022 01:25:29 +0900 Subject: [PATCH 07/19] improve readability --- tests/models/yolo/unit/test_yolo_config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/models/yolo/unit/test_yolo_config.py b/tests/models/yolo/unit/test_yolo_config.py index 2b2ec7833f..e3a33e5a70 100644 --- a/tests/models/yolo/unit/test_yolo_config.py +++ b/tests/models/yolo/unit/test_yolo_config.py @@ -18,7 +18,7 @@ ], ) def test_create_convolutional(config): - conv = _create_convolutional(config, [3])[0] + conv, _ = _create_convolutional(config, [3]) assert conv.conv.out_channels == config["filters"] assert conv.conv.kernel_size == (config["size"], config["size"]) @@ -59,7 +59,7 @@ def test_create_convolutional(config): ) def test_create_maxpool(config): pad_size = (config["size"] - 1) // 2 - maxpool = _create_maxpool(config, [3])[0] + maxpool, _ = _create_maxpool(config, [3]) assert maxpool.kernel_size == config["size"] assert maxpool.stride == config["stride"] @@ -74,7 +74,7 @@ def test_create_maxpool(config): ], ) def test_create_shortcut(config): - shortcut = _create_shortcut(config, [3])[0] + shortcut, _ = _create_shortcut(config, [3]) assert shortcut.source_layer == config["from"] From 17fab640fad166960178a77df661a2112dd7ba78 Mon Sep 17 00:00:00 2001 From: "Hongyeob.Kim" Date: Mon, 19 Sep 2022 14:26:02 +0900 Subject: [PATCH 08/19] add catch_warning fixture --- tests/models/test_detection.py | 21 +++++++++++-- tests/models/yolo/unit/test_yolo_config.py | 35 +++++++++++++++++++--- tests/models/yolo/unit/test_yolo_layers.py | 18 +++++++++-- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/tests/models/test_detection.py b/tests/models/test_detection.py index 64b202b0ea..e4a996a014 100644 --- a/tests/models/test_detection.py +++ b/tests/models/test_detection.py @@ -2,8 +2,11 @@ import pytest import torch -from pytorch_lightning import Trainer +import warnings + from torch.utils.data import DataLoader +from pytorch_lightning import Trainer +from pytorch_lightning.utilities.warnings import PossibleUserWarning from pl_bolts.datasets import DummyDetectionDataset from pl_bolts.models.detection import YOLO, FasterRCNN, RetinaNet, YOLOConfiguration @@ -96,7 +99,13 @@ def test_yolo(config): ("yolo_giou"), ], ) -def test_yolo_train(tmpdir, cfg_name): +def test_yolo_train(tmpdir, cfg_name, catch_warnings): + warnings.filterwarnings( + "ignore", + message=".*does not have many workers which may be a bottleneck.*", + category=PossibleUserWarning, + ) + config_path = Path(TEST_ROOT) / "data" / f"{cfg_name}.cfg" config = YOLOConfiguration(config_path) model = YOLO(config.get_network()) @@ -118,5 +127,11 @@ def test_yolo_train(tmpdir, cfg_name): ) ], ) -def test_aligned_iou(dims1, dims2, expected_ious): +def test_aligned_iou(dims1, dims2, expected_ious, catch_warnings): + warnings.filterwarnings( + "ignore", + message=".*does not have many workers which may be a bottleneck.*", + category=PossibleUserWarning, + ) + torch.testing.assert_allclose(_aligned_iou(dims1, dims2), expected_ious) diff --git a/tests/models/yolo/unit/test_yolo_config.py b/tests/models/yolo/unit/test_yolo_config.py index e3a33e5a70..6e8b004e4c 100644 --- a/tests/models/yolo/unit/test_yolo_config.py +++ b/tests/models/yolo/unit/test_yolo_config.py @@ -1,4 +1,7 @@ import pytest +import warnings + +from pytorch_lightning.utilities.warnings import PossibleUserWarning from pl_bolts.models.detection.yolo.yolo_config import ( _create_convolutional, @@ -17,7 +20,13 @@ ({"batch_normalize": 0, "filters": 4, "size": 3, "stride": 2, "pad": 0, "activation": "linear"}), ], ) -def test_create_convolutional(config): +def test_create_convolutional(config, catch_warnings): + warnings.filterwarnings( + "ignore", + message=".*does not have many workers which may be a bottleneck.*", + category=PossibleUserWarning, + ) + conv, _ = _create_convolutional(config, [3]) assert conv.conv.out_channels == config["filters"] @@ -57,7 +66,13 @@ def test_create_convolutional(config): ), ], ) -def test_create_maxpool(config): +def test_create_maxpool(config, catch_warnings): + warnings.filterwarnings( + "ignore", + message=".*does not have many workers which may be a bottleneck.*", + category=PossibleUserWarning, + ) + pad_size = (config["size"] - 1) // 2 maxpool, _ = _create_maxpool(config, [3]) @@ -73,7 +88,13 @@ def test_create_maxpool(config): ({"from": 3, "activation": "linear"}), ], ) -def test_create_shortcut(config): +def test_create_shortcut(config, catch_warnings): + warnings.filterwarnings( + "ignore", + message=".*does not have many workers which may be a bottleneck.*", + category=PossibleUserWarning, + ) + shortcut, _ = _create_shortcut(config, [3]) assert shortcut.source_layer == config["from"] @@ -86,7 +107,13 @@ def test_create_shortcut(config): ({"stride": 4}), ], ) -def test_create_upsample(config): +def test_create_upsample(config, catch_warnings): + warnings.filterwarnings( + "ignore", + message=".*does not have many workers which may be a bottleneck.*", + category=PossibleUserWarning, + ) + upsample, _ = _create_upsample(config, [3]) assert upsample.scale_factor == float(config["stride"]) diff --git a/tests/models/yolo/unit/test_yolo_layers.py b/tests/models/yolo/unit/test_yolo_layers.py index 5b3013f6f8..6ebf320494 100644 --- a/tests/models/yolo/unit/test_yolo_layers.py +++ b/tests/models/yolo/unit/test_yolo_layers.py @@ -1,7 +1,9 @@ import pytest import torch +import warnings from pl_bolts.models.detection.yolo.yolo_layers import GIoULoss, IoULoss, SELoss, _corner_coordinates +from pytorch_lightning.utilities.warnings import PossibleUserWarning @pytest.mark.parametrize( @@ -11,7 +13,13 @@ ([5.0, 5.0], [2.0, 2.0], [4.0, 4.0, 6.0, 6.0]), ], ) -def test_corner_coordinates(xy, wh, expected): +def test_corner_coordinates(xy, wh, expected, catch_warnings): + warnings.filterwarnings( + "ignore", + message=".*does not have many workers which may be a bottleneck.*", + category=PossibleUserWarning, + ) + xy = torch.tensor(xy) wh = torch.tensor(wh) corners = _corner_coordinates(xy, wh) @@ -26,7 +34,13 @@ def test_corner_coordinates(xy, wh, expected): (SELoss, [[0.0, 0.0, 120.0, 200.0]], [[189.0, 93.0, 242.0, 215.0]], 59479.0), ], ) -def test_loss_functions(loss_func, bbox1, bbox2, expected): +def test_loss_functions(loss_func, bbox1, bbox2, expected, catch_warnings): + warnings.filterwarnings( + "ignore", + message=".*does not have many workers which may be a bottleneck.*", + category=PossibleUserWarning, + ) + loss_func = loss_func() tensor1 = torch.tensor(bbox1, dtype=torch.float32) tensor2 = torch.tensor(bbox2, dtype=torch.float32) From 353f1199a79cd923a720c1bd3fe476ce6d47cd05 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 Sep 2022 05:47:59 +0000 Subject: [PATCH 09/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/models/test_detection.py | 5 ++--- tests/models/yolo/unit/test_yolo_config.py | 2 +- tests/models/yolo/unit/test_yolo_layers.py | 5 +++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/models/test_detection.py b/tests/models/test_detection.py index e4a996a014..14be7b7803 100644 --- a/tests/models/test_detection.py +++ b/tests/models/test_detection.py @@ -1,12 +1,11 @@ +import warnings from pathlib import Path import pytest import torch -import warnings - -from torch.utils.data import DataLoader from pytorch_lightning import Trainer from pytorch_lightning.utilities.warnings import PossibleUserWarning +from torch.utils.data import DataLoader from pl_bolts.datasets import DummyDetectionDataset from pl_bolts.models.detection import YOLO, FasterRCNN, RetinaNet, YOLOConfiguration diff --git a/tests/models/yolo/unit/test_yolo_config.py b/tests/models/yolo/unit/test_yolo_config.py index 6e8b004e4c..807e2a84db 100644 --- a/tests/models/yolo/unit/test_yolo_config.py +++ b/tests/models/yolo/unit/test_yolo_config.py @@ -1,6 +1,6 @@ -import pytest import warnings +import pytest from pytorch_lightning.utilities.warnings import PossibleUserWarning from pl_bolts.models.detection.yolo.yolo_config import ( diff --git a/tests/models/yolo/unit/test_yolo_layers.py b/tests/models/yolo/unit/test_yolo_layers.py index 6ebf320494..02e209d400 100644 --- a/tests/models/yolo/unit/test_yolo_layers.py +++ b/tests/models/yolo/unit/test_yolo_layers.py @@ -1,9 +1,10 @@ +import warnings + import pytest import torch -import warnings +from pytorch_lightning.utilities.warnings import PossibleUserWarning from pl_bolts.models.detection.yolo.yolo_layers import GIoULoss, IoULoss, SELoss, _corner_coordinates -from pytorch_lightning.utilities.warnings import PossibleUserWarning @pytest.mark.parametrize( From a3445acb2494ac8e9d07823242e80008d58db2b7 Mon Sep 17 00:00:00 2001 From: heimish-kyma Date: Mon, 19 Sep 2022 16:38:33 +0900 Subject: [PATCH 10/19] fix pytest error; indexing argument will be required to pass in upcoming release for torch.meshgrid. --- pl_bolts/models/detection/yolo/yolo_layers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pl_bolts/models/detection/yolo/yolo_layers.py b/pl_bolts/models/detection/yolo/yolo_layers.py index 011895c5bc..dda5ca2a59 100644 --- a/pl_bolts/models/detection/yolo/yolo_layers.py +++ b/pl_bolts/models/detection/yolo/yolo_layers.py @@ -256,7 +256,7 @@ def _global_xy(self, xy: Tensor, image_size: Tensor) -> Tensor: x_range = torch.arange(width, device=xy.device) y_range = torch.arange(height, device=xy.device) - grid_y, grid_x = torch.meshgrid(y_range, x_range) + grid_y, grid_x = torch.meshgrid(y_range, x_range, indexing='ij') offset = torch.stack((grid_x, grid_y), -1) # [height, width, 2] offset = offset.unsqueeze(2) # [height, width, 1, 2] From 189346cd508a4adaa996e3e553b11e40ce2a783c Mon Sep 17 00:00:00 2001 From: heimish-kyma Date: Mon, 19 Sep 2022 16:51:49 +0900 Subject: [PATCH 11/19] fix pytest catch_warnings; MisconfigurationException error batch_size should be provided for def training_step(self, dataloader_iter) --- pl_bolts/models/detection/yolo/yolo_module.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pl_bolts/models/detection/yolo/yolo_module.py b/pl_bolts/models/detection/yolo/yolo_module.py index ebb494f5ef..650765421d 100644 --- a/pl_bolts/models/detection/yolo/yolo_module.py +++ b/pl_bolts/models/detection/yolo/yolo_module.py @@ -177,7 +177,7 @@ def forward( ) for layer_idx, layer_hits in enumerate(hits): hit_rate = torch.true_divide(layer_hits, total_hits) if total_hits > 0 else 1.0 - self.log(f"layer_{layer_idx}_hit_rate", hit_rate, sync_dist=False) + self.log(f"layer_{layer_idx}_hit_rate", hit_rate, sync_dist=False, batch_size=images.size(0)) def total_loss(loss_name): """Returns the sum of the loss over detection layers.""" @@ -231,8 +231,8 @@ def validation_step(self, batch: Tuple[List[Tensor], List[Dict[str, Tensor]]], b total_loss = torch.stack(tuple(losses.values())).sum() for name, value in losses.items(): - self.log(f"val/{name}_loss", value, sync_dist=True) - self.log("val/total_loss", total_loss, sync_dist=True) + self.log(f"val/{name}_loss", value, sync_dist=True, batch_size=images.size(0)) + self.log("val/total_loss", total_loss, sync_dist=True, batch_size=images.size(0)) def test_step(self, batch: Tuple[List[Tensor], List[Dict[str, Tensor]]], batch_idx: int): """Evaluates a batch of data from the test set. From a1d97b672538911626eb33b1a04d7c35489911af Mon Sep 17 00:00:00 2001 From: heimish-kyma Date: Mon, 19 Sep 2022 16:54:15 +0900 Subject: [PATCH 12/19] fix pytest error with fast_dev_run=True, it will set 1 for batch(es) of train, however log_every_n_steps is set 50 as default this cause an error catching. --- tests/models/test_detection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/models/test_detection.py b/tests/models/test_detection.py index e4a996a014..e620882183 100644 --- a/tests/models/test_detection.py +++ b/tests/models/test_detection.py @@ -113,7 +113,7 @@ def test_yolo_train(tmpdir, cfg_name, catch_warnings): train_dl = DataLoader(DummyDetectionDataset(), collate_fn=_collate_fn) valid_dl = DataLoader(DummyDetectionDataset(), collate_fn=_collate_fn) - trainer = Trainer(fast_dev_run=True, default_root_dir=tmpdir) + trainer = Trainer(fast_dev_run=True, default_root_dir=tmpdir, logger=False) trainer.fit(model, train_dataloaders=train_dl, val_dataloaders=valid_dl) From 0b4eca495f4d1135aec12b01425e1995f8470905 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 Sep 2022 07:56:22 +0000 Subject: [PATCH 13/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pl_bolts/models/detection/yolo/yolo_layers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pl_bolts/models/detection/yolo/yolo_layers.py b/pl_bolts/models/detection/yolo/yolo_layers.py index dda5ca2a59..f71473308a 100644 --- a/pl_bolts/models/detection/yolo/yolo_layers.py +++ b/pl_bolts/models/detection/yolo/yolo_layers.py @@ -256,7 +256,7 @@ def _global_xy(self, xy: Tensor, image_size: Tensor) -> Tensor: x_range = torch.arange(width, device=xy.device) y_range = torch.arange(height, device=xy.device) - grid_y, grid_x = torch.meshgrid(y_range, x_range, indexing='ij') + grid_y, grid_x = torch.meshgrid(y_range, x_range, indexing="ij") offset = torch.stack((grid_x, grid_y), -1) # [height, width, 2] offset = offset.unsqueeze(2) # [height, width, 1, 2] From eb9930ec8c36bf766ce6bc25649a46f785f1101f Mon Sep 17 00:00:00 2001 From: otaj Date: Mon, 19 Sep 2022 13:33:36 +0200 Subject: [PATCH 14/19] Fix most obvious CI failings --- pl_bolts/models/detection/yolo/yolo_layers.py | 7 +++++-- pl_bolts/utils/__init__.py | 1 + tests/models/test_detection.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pl_bolts/models/detection/yolo/yolo_layers.py b/pl_bolts/models/detection/yolo/yolo_layers.py index f71473308a..d2259520e5 100644 --- a/pl_bolts/models/detection/yolo/yolo_layers.py +++ b/pl_bolts/models/detection/yolo/yolo_layers.py @@ -4,7 +4,7 @@ from pytorch_lightning.utilities.exceptions import MisconfigurationException from torch import Tensor, nn -from pl_bolts.utils import _TORCHVISION_AVAILABLE +from pl_bolts.utils import _TORCH_MESHGRID_REQUIRES_INDEXING, _TORCHVISION_AVAILABLE from pl_bolts.utils.warnings import warn_missing_pkg if _TORCHVISION_AVAILABLE: @@ -256,7 +256,10 @@ def _global_xy(self, xy: Tensor, image_size: Tensor) -> Tensor: x_range = torch.arange(width, device=xy.device) y_range = torch.arange(height, device=xy.device) - grid_y, grid_x = torch.meshgrid(y_range, x_range, indexing="ij") + if _TORCH_MESHGRID_REQUIRES_INDEXING: + grid_y, grid_x = torch.meshgrid(y_range, x_range, indexing="ij") + else: + grid_y, grid_x = torch.meshgrid(y_range, x_range) offset = torch.stack((grid_x, grid_y), -1) # [height, width, 2] offset = offset.unsqueeze(2) # [height, width, 1, 2] diff --git a/pl_bolts/utils/__init__.py b/pl_bolts/utils/__init__.py index 67907890a6..67746dc3dc 100644 --- a/pl_bolts/utils/__init__.py +++ b/pl_bolts/utils/__init__.py @@ -44,6 +44,7 @@ def _compare_version(package: str, op: Callable, version: str) -> bool: _PL_GREATER_EQUAL_1_4_5 = _compare_version("pytorch_lightning", operator.ge, "1.4.5") _TORCH_ORT_AVAILABLE = _module_available("torch_ort") _TORCH_MAX_VERSION_SPARSEML = _compare_version("torch", operator.lt, "1.11.0") +_TORCH_MESHGRID_REQUIRES_INDEXING = _compare_version("torch", operator.ge, "1.10.0") _SPARSEML_AVAILABLE = _module_available("sparseml") and _PL_GREATER_EQUAL_1_4_5 and _TORCH_MAX_VERSION_SPARSEML __all__ = ["BatchGradientVerification"] diff --git a/tests/models/test_detection.py b/tests/models/test_detection.py index f4861fa2f2..de0ba23696 100644 --- a/tests/models/test_detection.py +++ b/tests/models/test_detection.py @@ -133,4 +133,4 @@ def test_aligned_iou(dims1, dims2, expected_ious, catch_warnings): category=PossibleUserWarning, ) - torch.testing.assert_allclose(_aligned_iou(dims1, dims2), expected_ious) + torch.testing.assert_close(_aligned_iou(dims1, dims2), expected_ious) From fdf38fbecfe5e0b1db0d7a085aa71d37f4dd9568 Mon Sep 17 00:00:00 2001 From: otaj Date: Mon, 19 Sep 2022 14:01:46 +0200 Subject: [PATCH 15/19] fix test with a missing warning --- tests/models/test_detection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/models/test_detection.py b/tests/models/test_detection.py index de0ba23696..1c3e2f0b14 100644 --- a/tests/models/test_detection.py +++ b/tests/models/test_detection.py @@ -113,7 +113,7 @@ def test_yolo_train(tmpdir, cfg_name, catch_warnings): valid_dl = DataLoader(DummyDetectionDataset(), collate_fn=_collate_fn) trainer = Trainer(fast_dev_run=True, default_root_dir=tmpdir, logger=False) - trainer.fit(model, train_dataloaders=train_dl, val_dataloaders=valid_dl) + trainer.fit(model, train_dataloaders=train_dl, val_dataloaders=valid_dl, max_expochs=10) @pytest.mark.parametrize( From a42cdec9120a1f5b874f771196cc4369c65b07a8 Mon Sep 17 00:00:00 2001 From: otaj Date: Wed, 21 Sep 2022 17:20:39 +0200 Subject: [PATCH 16/19] resolve accidentally introduced errors --- tests/models/test_detection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/models/test_detection.py b/tests/models/test_detection.py index 1c3e2f0b14..899ec5c393 100644 --- a/tests/models/test_detection.py +++ b/tests/models/test_detection.py @@ -112,8 +112,8 @@ def test_yolo_train(tmpdir, cfg_name, catch_warnings): train_dl = DataLoader(DummyDetectionDataset(), collate_fn=_collate_fn) valid_dl = DataLoader(DummyDetectionDataset(), collate_fn=_collate_fn) - trainer = Trainer(fast_dev_run=True, default_root_dir=tmpdir, logger=False) - trainer.fit(model, train_dataloaders=train_dl, val_dataloaders=valid_dl, max_expochs=10) + trainer = Trainer(fast_dev_run=True, default_root_dir=tmpdir, logger=False, max_epochs=10, accelerator="auto") + trainer.fit(model, train_dataloaders=train_dl, val_dataloaders=valid_dl) @pytest.mark.parametrize( From d534cfaa942cd8f296191cb184c41576aa39a3f6 Mon Sep 17 00:00:00 2001 From: otaj Date: Tue, 11 Oct 2022 11:14:03 +0200 Subject: [PATCH 17/19] add catch_warnings --- tests/models/test_detection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/models/test_detection.py b/tests/models/test_detection.py index 899ec5c393..b451ddfde7 100644 --- a/tests/models/test_detection.py +++ b/tests/models/test_detection.py @@ -82,7 +82,7 @@ def test_fasterrcnn_pyt_module_bbone_train(tmpdir): @pytest.mark.parametrize("config", [("yolo"), ("yolo_giou")]) -def test_yolo(config): +def test_yolo(config, catch_warnings): config_path = Path(TEST_ROOT) / "data" / f"{config}.cfg" config = YOLOConfiguration(config_path) model = YOLO(config.get_network()) From bf5b3608883d49b37a807bcdfdd8cb106b50857e Mon Sep 17 00:00:00 2001 From: Jirka Borovec <6035284+Borda@users.noreply.github.com> Date: Tue, 28 Mar 2023 20:35:20 +0200 Subject: [PATCH 18/19] Apply suggestions from code review --- pl_bolts/models/detection/yolo/yolo_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pl_bolts/models/detection/yolo/yolo_config.py b/pl_bolts/models/detection/yolo/yolo_config.py index 1bbb7eee86..293a33e3a6 100644 --- a/pl_bolts/models/detection/yolo/yolo_config.py +++ b/pl_bolts/models/detection/yolo/yolo_config.py @@ -258,7 +258,7 @@ def _create_yolo(config: dict, num_inputs: int) -> Tuple[nn.Module, int]: elif overlap_loss_name == "iou": overlap_loss_func = yolo_layers.IoULoss() else: - assert False, "Unknown overlap loss: " + overlap_loss_name + raise ValueError("Unknown overlap loss: " + overlap_loss_name) module = yolo_layers.DetectionLayer( num_classes=config["classes"], From bd23c27f3adc7712a268c22e19edf05b78f7b117 Mon Sep 17 00:00:00 2001 From: Jirka B Date: Fri, 19 May 2023 10:17:31 -0400 Subject: [PATCH 19/19] update mergify team --- .github/mergify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/mergify.yml b/.github/mergify.yml index dc431ff4c5..314ae28dca 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -79,4 +79,4 @@ pull_request_rules: actions: request_reviews: teams: - - "@PyTorchLightning/core-bolts" + - "@Lightning-Universe/core-Bolts"