Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tests/ to work in a mm-free environment #3632

Merged
merged 8 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ dependencies = [
"datumaro==1.6.1",
"omegaconf==2.3.0",
"rich==13.7.1",
"jsonargparse==4.27.7",
"jsonargparse==4.30.0",
"psutil==5.9.8", # Mem cache needs system checks
"ftfy==6.2.0",
"regex==2024.5.10",
Expand Down
12 changes: 8 additions & 4 deletions src/otx/cli/utils/installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,15 +523,18 @@ def patch_mmaction2() -> None:

if not file_mmaction2_patch.exists():
msg = f"Cannot find `mmaction2.patch` file from {dir_patches}"
raise RuntimeError(msg)
warn(msg, stacklevel=1)
return

if (spec := find_spec("mmaction")) is None:
msg = "Cannot find mmaction spec"
raise RuntimeError(msg)
warn(msg, stacklevel=1)
return

if (spec_origin := spec.origin) is None:
msg = "Cannot find mmaction spec origin"
raise RuntimeError(msg)
warn(msg, stacklevel=1)
return

dir_mmaction_parent = Path(spec_origin).parent.parent

Expand All @@ -546,6 +549,7 @@ def patch_mmaction2() -> None:

if proc.returncode > 1:
msg = f"Cannot patch. Error code: {proc.returncode}, stdout: {stdout.decode()} and stderr: {stderr.decode()}"
raise RuntimeError(msg)
warn(msg, stacklevel=1)
return
if proc.returncode == 1:
warn("MMAction2 is already patched. Skip patching it.", stacklevel=1)
16 changes: 6 additions & 10 deletions src/otx/core/data/transform_libs/torchvision.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import itertools
import math
from inspect import isclass
from pathlib import Path
from typing import TYPE_CHECKING, Any, ClassVar, Iterable, Sequence

import cv2
Expand Down Expand Up @@ -2716,19 +2717,14 @@ def __repr__(self) -> str:
class DecordInit(tvt_v2.Transform):
"""Using decord to initialize the video_reader."""

def __init__(self, io_backend: str = "disk", num_threads: int = 1, **kwargs) -> None:
self.io_backend = io_backend
def __init__(self, num_threads: int = 1, **kwargs) -> None:
self.num_threads = num_threads
self.kwargs = kwargs
self.file_client = None

def _get_video_reader(self, filename: str) -> decord.VideoReader:
if self.file_client is None:
# TODO(wonjulee): Remove mmengine imports
from mmengine.fileio import FileClient

self.file_client = FileClient(self.io_backend, **self.kwargs)
file_obj = io.BytesIO(self.file_client.get(filename))
with Path(filename).open("rb") as f:
file_byte = f.read()
file_obj = io.BytesIO(file_byte)
return decord.VideoReader(file_obj, num_threads=self.num_threads)

def __call__(self, *_inputs: T_OTXDataEntity) -> T_OTXDataEntity | None:
Expand All @@ -2743,7 +2739,7 @@ def __call__(self, *_inputs: T_OTXDataEntity) -> T_OTXDataEntity | None:
return inputs

def __repr__(self) -> str:
return f"{self.__class__.__name__}(io_backend={self.io_backend}, num_threads={self.num_threads})"
return f"{self.__class__.__name__}(num_threads={self.num_threads})"


class SampleFrames(tvt_v2.Transform):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import pytest
import torch
from mmengine.runner import save_checkpoint
from otx.algo.classification.backbones import VisionTransformer
from otx.algo.utils.mmengine_utils import load_checkpoint_to_model
from torch.nn import functional
Expand Down Expand Up @@ -115,7 +114,8 @@ def test_init_weights(self, tmp_path, config):
# test load checkpoint
pretrain_pos_embed = model.pos_embed.clone().detach()
checkpoint = tmp_path / "test.pth"
save_checkpoint(model.state_dict(), str(checkpoint))
torch.save(model.state_dict(), str(checkpoint))

cfg = deepcopy(config)
model = VisionTransformer(**cfg)
state_dict = torch.load(str(checkpoint), None)
Expand Down
10 changes: 0 additions & 10 deletions tests/unit/algo/classification/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import pytest
import torch
from mmpretrain.structures import DataSample
from omegaconf import DictConfig
from otx.core.data.dataset.classification import MulticlassClsBatchDataEntity
from otx.core.data.entity.base import ImageInfo
Expand All @@ -16,15 +15,6 @@
from torchvision import tv_tensors


@pytest.fixture()
def fxt_data_sample() -> DataSample:
data_sample = DataSample(
img_shape=(24, 24, 3),
gt_label=torch.zeros(6, dtype=torch.long),
)
return [data_sample, data_sample]


@pytest.fixture()
def fxt_hlabel_data() -> HLabelInfo:
return HLabelInfo(
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/algo/detection/heads/test_yolox_head.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"""

import torch
from mmengine.config import Config
from omegaconf import DictConfig
from otx.algo.detection.heads.sim_ota_assigner import SimOTAAssigner
from otx.algo.detection.heads.yolox_head import YOLOXHead
from otx.algo.modules.conv_module import ConvModule
Expand All @@ -24,7 +24,7 @@ def test_predict_by_feat(self):
"scale_factor": (1.0, 1.0),
},
]
test_cfg = Config({"score_thr": 0.01, "nms": {"type": "nms", "iou_threshold": 0.65}})
test_cfg = DictConfig({"score_thr": 0.01, "nms": {"type": "nms", "iou_threshold": 0.65}})
head = YOLOXHead(num_classes=4, in_channels=1, stacked_convs=1, use_depthwise=False, test_cfg=test_cfg)
feat = [torch.rand(1, 1, s // feat_size, s // feat_size) for feat_size in [4, 8, 16]]
cls_scores, bbox_preds, objectnesses = head.forward(feat)
Expand Down
7 changes: 7 additions & 0 deletions tests/unit/cli/utils/test_installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
from pkg_resources import Requirement
from pytest_mock import MockerFixture

SKIP_MMLAB_TEST = False
try:
import mim # noqa: F401
except ImportError:
SKIP_MMLAB_TEST = True


@pytest.fixture()
def requirements_file() -> Path:
Expand Down Expand Up @@ -225,6 +231,7 @@ def test_get_mmcv_install_args(mocker: MockerFixture) -> None:
get_mmcv_install_args(torch_requirement=torch_requirement, mmcv_requirements=["mmengine==2.0.0"])


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
def test_mim_installation(mocker: MockerFixture) -> None:
mocker.patch("otx.cli.utils.installation.find_spec", return_value=True)
# https://github.com/Madoshakalaka/pipenv-setup/issues/101
Expand Down
27 changes: 18 additions & 9 deletions tests/unit/core/data/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,38 @@
from otx.core.data.dataset.segmentation import OTXSegmentationDataset
from otx.core.data.dataset.visual_prompting import OTXVisualPromptingDataset, OTXZeroShotVisualPromptingDataset
from otx.core.data.factory import OTXDatasetFactory, TransformLibFactory
from otx.core.data.transform_libs.mmaction import MMActionTransformLib
from otx.core.data.transform_libs.mmcv import MMCVTransformLib
from otx.core.data.transform_libs.mmdet import MMDetTransformLib
from otx.core.data.transform_libs.mmpretrain import MMPretrainTransformLib
from otx.core.data.transform_libs.mmseg import MMSegTransformLib
from otx.core.data.transform_libs.torchvision import TorchVisionTransformLib
from otx.core.types.image import ImageColorChannel
from otx.core.types.task import OTXTaskType
from otx.core.types.transformer_libs import TransformLibType

lib_type_parameters = [(TransformLibType.TORCHVISION, TorchVisionTransformLib)]
SKIP_MMLAB_TEST = False
try:
from otx.core.data.transform_libs.mmaction import MMActionTransformLib
from otx.core.data.transform_libs.mmcv import MMCVTransformLib
from otx.core.data.transform_libs.mmdet import MMDetTransformLib
from otx.core.data.transform_libs.mmpretrain import MMPretrainTransformLib
from otx.core.data.transform_libs.mmseg import MMSegTransformLib

class TestTransformLibFactory:
@pytest.mark.parametrize(
("lib_type", "lib"),
lib_type_parameters.extend(
[
(TransformLibType.TORCHVISION, TorchVisionTransformLib),
(TransformLibType.MMCV, MMCVTransformLib),
(TransformLibType.MMPRETRAIN, MMPretrainTransformLib),
(TransformLibType.MMDET, MMDetTransformLib),
(TransformLibType.MMSEG, MMSegTransformLib),
(TransformLibType.MMACTION, MMActionTransformLib),
],
)
except ImportError:
SKIP_MMLAB_TEST = True


class TestTransformLibFactory:
@pytest.mark.parametrize(
("lib_type", "lib"),
lib_type_parameters,
)
def test_generate(self, lib_type, lib, mocker) -> None:
mock_generate = mocker.patch.object(lib, "generate")
config = mocker.MagicMock(spec=SubsetConfig)
Expand Down
19 changes: 13 additions & 6 deletions tests/unit/core/data/transform_libs/test_mmaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,28 @@
import numpy as np
import pytest
import torch
from mmaction.registry import TRANSFORMS
from otx.core.config.data import SubsetConfig
from otx.core.data.entity.action_classification import ActionClsDataEntity
from otx.core.data.entity.base import ImageInfo, VideoInfo
from otx.core.data.transform_libs.mmaction import (
LoadVideoForClassification,
MMActionTransformLib,
PackActionInputs,
)
from otx.core.types.transformer_libs import TransformLibType

SKIP_MMLAB_TEST = False
try:
from mmaction.registry import TRANSFORMS
from otx.core.data.transform_libs.mmaction import (
LoadVideoForClassification,
MMActionTransformLib,
PackActionInputs,
)
except ImportError:
SKIP_MMLAB_TEST = True


class MockVideo:
path: str = "video_path"


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestActionClsPipeline:
@pytest.fixture()
def fxt_action_cls_data(self) -> dict:
Expand Down Expand Up @@ -52,6 +58,7 @@ def test_pack_action_inputs(self, fxt_action_cls_data):
assert isinstance(transform(fxt_action_cls_data), ActionClsDataEntity)


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestMMActionTransformLib:
def test_get_builder(self) -> None:
assert MMActionTransformLib.get_builder() == TRANSFORMS
Expand Down
11 changes: 9 additions & 2 deletions tests/unit/core/data/transform_libs/test_mmcv.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@

import numpy as np
import pytest
from mmcv.transforms.builder import TRANSFORMS
from otx.core.config.data import SubsetConfig
from otx.core.data.entity.base import ImageInfo, OTXDataEntity
from otx.core.data.transform_libs.mmcv import LoadImageFromFile, MMCVTransformLib
from otx.core.types.transformer_libs import TransformLibType

SKIP_MMLAB_TEST = False
try:
from mmcv.transforms.builder import TRANSFORMS
from otx.core.data.transform_libs.mmcv import LoadImageFromFile, MMCVTransformLib
except ImportError:
SKIP_MMLAB_TEST = True


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestLoadImageFromFile:
def test_transform(self) -> None:
transform = LoadImageFromFile()
Expand All @@ -23,6 +29,7 @@ def test_transform(self) -> None:
assert out["ori_shape"] == (224, 224)


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestMMCVTransformLib:
def test_get_builder(self) -> None:
assert MMCVTransformLib.get_builder() == TRANSFORMS
Expand Down
20 changes: 17 additions & 3 deletions tests/unit/core/data/transform_libs/test_mmdet.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,30 @@
import pytest
import torch
from datumaro import Polygon
from mmdet.structures.mask import PolygonMasks
from otx.core.config.data import SubsetConfig
from otx.core.data.entity.base import ImageInfo
from otx.core.data.entity.detection import DetDataEntity
from otx.core.data.entity.instance_segmentation import InstanceSegDataEntity
from otx.core.data.entity.visual_prompting import VisualPromptingDataEntity
from otx.core.data.transform_libs.mmcv import LoadImageFromFile
from otx.core.data.transform_libs.mmdet import LoadAnnotations, MMDetTransformLib, PackDetInputs, PerturbBoundingBoxes
from otx.core.types.transformer_libs import TransformLibType
from torch import LongTensor
from torchvision import tv_tensors

SKIP_MMLAB_TEST = False
try:
from mmdet.structures.mask import PolygonMasks
from otx.core.data.transform_libs.mmcv import LoadImageFromFile
from otx.core.data.transform_libs.mmdet import (
LoadAnnotations,
MMDetTransformLib,
PackDetInputs,
PerturbBoundingBoxes,
)
except ImportError:
SKIP_MMLAB_TEST = True


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestLoadAnnotations:
def test_det_transform(self) -> None:
data_entity = DetDataEntity(
Expand Down Expand Up @@ -60,6 +71,7 @@ def test_vp_transform(self) -> None:
assert results["gt_ignore_flags"] == np.array([False])


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestPackDetInputs:
@pytest.mark.parametrize(
("data_entity", "with_point", "expected"),
Expand Down Expand Up @@ -129,6 +141,7 @@ def test_transform(
assert results.image.shape == expected


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestPerturbBoundingBoxes:
def test_transform(self) -> None:
transform = PerturbBoundingBoxes(offset=20)
Expand All @@ -153,6 +166,7 @@ def test_transform(self) -> None:
assert np.all(results["gt_bboxes"][3][2:] == inputs["gt_bboxes"][3][2:])


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestMMDetTransformLib:
def test_generate(self, mocker) -> None:
def mock_convert_func(cfg: dict) -> dict:
Expand Down
15 changes: 10 additions & 5 deletions tests/unit/core/data/transform_libs/test_mmpretrain.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#


import numpy as np
import pytest
import torch
from mmpretrain.registry import TRANSFORMS
from otx.core.config.data import SubsetConfig
from otx.core.data.entity.base import ImageInfo
from otx.core.data.entity.classification import HlabelClsDataEntity, MulticlassClsDataEntity, MultilabelClsDataEntity
from otx.core.data.transform_libs.mmcv import LoadImageFromFile
from otx.core.data.transform_libs.mmpretrain import MMPretrainTransformLib, PackInputs
from otx.core.types.transformer_libs import TransformLibType

SKIP_MMLAB_TEST = False
try:
from mmpretrain.registry import TRANSFORMS
from otx.core.data.transform_libs.mmcv import LoadImageFromFile
from otx.core.data.transform_libs.mmpretrain import MMPretrainTransformLib, PackInputs
except ImportError:
SKIP_MMLAB_TEST = True


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestPackInputs:
@pytest.mark.parametrize(
"entity",
Expand Down Expand Up @@ -52,6 +56,7 @@ def test_transform(self, entity):
assert isinstance(PackInputs()(LoadImageFromFile()(entity)), type(entity))


@pytest.mark.skipif(SKIP_MMLAB_TEST, reason="MMLab is not installed")
class TestMMPretrainTransformLib:
def test_get_builder(self) -> None:
assert MMPretrainTransformLib.get_builder() == TRANSFORMS
Expand Down
Loading
Loading