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

Lazy Config #82

Open
wants to merge 45 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
d4f742a
intial commit
abhi-glitchhg Mar 16, 2022
0edb1fa
LazyCall implementation
abhi-glitchhg Mar 31, 2022
422e68e
test added
abhi-glitchhg Mar 31, 2022
bd63e31
minor change
abhi-glitchhg Mar 31, 2022
3eb6c78
pre-commit
abhi-glitchhg Mar 31, 2022
e288838
Delete vanilla.yaml
abhi-glitchhg Mar 31, 2022
370e6f5
pre-commit
abhi-glitchhg Mar 31, 2022
0f1942b
hopefully last
abhi-glitchhg Mar 31, 2022
b1907cb
pre-commit
abhi-glitchhg Mar 31, 2022
9a0f6b5
pre-commit
abhi-glitchhg Mar 31, 2022
fd9f3df
pre-commit
abhi-glitchhg Mar 31, 2022
b15323a
changing click version from 8.0.1 to 8.0.4
abhi-glitchhg Mar 31, 2022
84987e5
this commit contains only minor changes due to diffetent black hook; …
abhi-glitchhg Mar 31, 2022
137ec6c
Update lazy.py
abhi-glitchhg Mar 31, 2022
368662d
Merge branch 'main' into config
abhi-glitchhg Mar 31, 2022
aa6aac6
fixes black hook issue
abhi-glitchhg Mar 31, 2022
9a19923
Merge branch 'main' into config
abhi-glitchhg Apr 2, 2022
8688a51
lazyconfig
abhi-glitchhg Apr 8, 2022
220d1d8
lazyconfig added
abhi-glitchhg Apr 11, 2022
bb1c126
lil bit of formatting
abhi-glitchhg Apr 11, 2022
4fa6098
added relative loading method in test
abhi-glitchhg Apr 11, 2022
bf155b0
added packages to requirements.txt
abhi-glitchhg Apr 11, 2022
18e9ed9
WIP
abhi-glitchhg Apr 12, 2022
1bfa3ff
WIP
abhi-glitchhg Apr 13, 2022
1bed82f
[WIP]
abhi-glitchhg Apr 13, 2022
f1ed4dc
trying to increase coverge
abhi-glitchhg Apr 13, 2022
d7fdf8a
Merge branch 'main' into config
abhi-glitchhg Apr 15, 2022
473de0d
Update requirements.txt
abhi-glitchhg Apr 15, 2022
1ffab02
adding hydra.utils._locate for dynamically locating objects.
abhi-glitchhg Apr 17, 2022
1f3a8cd
Merge branch 'config' of https://github.com/abhi-glitchhg/vformer int…
abhi-glitchhg Apr 17, 2022
1c5f7be
test coverage
abhi-glitchhg Apr 17, 2022
e30502a
minor nits
abhi-glitchhg Apr 19, 2022
21581e6
added config file for swin transformer.
abhi-glitchhg Apr 19, 2022
bcb3a29
change variable name in config file
abhi-glitchhg Apr 19, 2022
befa87e
Merge branch 'SforAiDl:main' into config
abhi-glitchhg Apr 25, 2022
a1ade82
rename the config file
abhi-glitchhg May 26, 2022
517aeb8
removed md files
abhi-glitchhg May 29, 2022
4eeb3c1
formatting
abhi-glitchhg May 29, 2022
bd50892
code formatting - lint issue resolved
abhi-glitchhg May 29, 2022
1b1f816
hopefully final
abhi-glitchhg May 31, 2022
a51faae
final
abhi-glitchhg May 31, 2022
9e1ea6f
link config files with setup.py
abhi-glitchhg Jun 5, 2022
d9f9623
checking coverage
abhi-glitchhg Jun 5, 2022
083bf2e
rollback
abhi-glitchhg Jun 5, 2022
3ebf701
minor change
abhi-glitchhg Jun 9, 2022
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 .isort.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[settings]
known_third_party = cv2,einops,numpy,setuptools,timm,torch,torchvision
known_third_party = cv2,einops,numpy,omegaconf,setuptools,timm,torch,torchvision
multi_line_output=3
include_trailing_comma=True
force_grid_wrap=0
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ repos:
- id: isort

- repo: https://github.com/python/black
rev: 20.8b1
rev: 22.3.0
abhi-glitchhg marked this conversation as resolved.
Show resolved Hide resolved
hooks:
- id: black
language_version: python3.8

# - repo: https://gitlab.com/pycqa/flake8
# rev: 3.8.3
# hooks:
# - id: flake8
# - id: flake8
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jinja2-time==0.2.0
MarkupSafe==2.0.1
nodeenv==1.6.0
olefile
omegaconf
packaging==21.0
Pillow
platformdirs==2.3.0
Expand All @@ -41,4 +42,4 @@ timm==0.4.12
typing-extensions
urllib3==1.26.6
virtualenv==20.7.2
opencv-python==4.5.3.56
opencv-python==4.5.3.56
48 changes: 48 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import torch

from vformer.config import LazyCall, instantiate
from vformer.models import PVTSegmentation, SwinTransformer, VanillaViT, ViViTModel2


def test_lazy():
# classification models
vanilla_config = LazyCall(VanillaViT)(img_size=224, patch_size=7, n_classes=10)
swin_config = LazyCall(SwinTransformer)(
img_size=224,
patch_size=4,
in_channels=3,
n_classes=10,
embedding_dim=96,
depths=[2, 2, 6, 2],
num_heads=[3, 6, 12, 24],
window_size=7,
p_dropout=0.2,
)
vivit_config = LazyCall(ViViTModel2)(
img_size=224,
in_channels=3,
patch_size=16,
embedding_dim=192,
depth=4,
num_heads=3,
head_dim=64,
num_frames=1,
n_classes=10,
)

# dense models
pvt_config = LazyCall(PVTSegmentation)()
pvt_config["img_size"] = 224
rand_img_tensor = torch.randn(4, 3, 224, 224)
rand_vdo_tensor = torch.randn([32, 16, 3, 224, 224])

vanilla_vit = instantiate(vanilla_config)
swin_vit = instantiate(swin_config)
vivit = instantiate(vivit_config)

pvt = instantiate(pvt_config)

assert vanilla_vit(rand_img_tensor).shape == (4, 10)
assert swin_vit(rand_img_tensor).shape == (4, 10)
assert pvt(rand_img_tensor).shape == (4, 1, 224, 224)
assert vivit(rand_vdo_tensor).shape == (32, 10)
2 changes: 1 addition & 1 deletion vformer/attention/convvt.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def __init__(
self.with_cls_token = with_cls_token
self.dim = dim_out
self.num_heads = num_heads
self.scale = dim_out ** -0.5
self.scale = dim_out**-0.5
self.h, self.w = img_size, img_size
self.conv_proj_q = self._build_projection(
dim_in, kernel_size, padding_q, stride_q, method
Expand Down
2 changes: 1 addition & 1 deletion vformer/attention/cross.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def __init__(self, cls_dim, patch_dim, num_heads=8, head_dim=64):

inner_dim = num_heads * head_dim
self.num_heads = num_heads
self.scale = head_dim ** -0.5
self.scale = head_dim**-0.5
self.fl = _Projection(cls_dim, patch_dim)
self.gl = _Projection(patch_dim, cls_dim)
self.to_k = nn.Linear(patch_dim, inner_dim)
Expand Down
4 changes: 2 additions & 2 deletions vformer/attention/gated_positional.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ def __init__(self, dim, num_heads=8, head_dim=64, p_dropout=0):

def rel_embedding(self, n):

l = int(n ** 0.5)
l = int(n**0.5)
rel_indices_x = torch.arange(l).reshape(1, -1)
rel_indices_y = torch.arange(l).reshape(-1, 1)
indices = rel_indices_x - rel_indices_y
rel_indices_x = indices.repeat(l, l)
rel_indices_y = indices.repeat_interleave(l, dim=0).repeat_interleave(l, dim=1)
rel_indices_d = (rel_indices_x ** 2 + rel_indices_y ** 2) ** 0.5
rel_indices_d = (rel_indices_x**2 + rel_indices_y**2) ** 0.5
self.rel_indices = torch.stack(
[rel_indices_x, rel_indices_y, rel_indices_d], dim=-1
)
Expand Down
2 changes: 1 addition & 1 deletion vformer/attention/vanilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(self, dim, num_heads=8, head_dim=64, p_dropout=0.0):
project_out = not (num_heads == 1 and head_dim == dim)

self.num_heads = num_heads
self.scale = head_dim ** -0.5
self.scale = head_dim**-0.5

self.attend = nn.Softmax(dim=-1)
self.to_qkv = nn.Linear(dim, inner_dim * 3, bias=False)
Expand Down
2 changes: 1 addition & 1 deletion vformer/attention/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __init__(
self.window_size = pair(window_size)
self.num_heads = num_heads
self.head_dim = dim // num_heads
self.scale = qk_scale or self.head_dim ** -0.5
self.scale = qk_scale or self.head_dim**-0.5
self.qkv_bias = True
self.relative_position_bias_table = nn.Parameter(
torch.zeros(
Expand Down
2 changes: 2 additions & 0 deletions vformer/config/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .config_utils import instantiate
from .lazy import LazyCall
67 changes: 67 additions & 0 deletions vformer/config/config_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import logging
import pydoc
from collections import abc
from typing import Any


def _convert_target_to_string(t: Any) -> str:

module, qualname = t.__module__, t.__qualname__

module_parts = module.split(".")
for k in range(1, len(module_parts)):
prefix = ".".join(module_parts[:k])
candidate = f"{prefix}.{qualname}"
try:
if locate(candidate) is t:
return candidate
except ImportError:
pass
return f"{module}.{qualname}"


def locate(name: str) -> Any:

obj = pydoc.locate(name)

# Some cases (e.g. torch.optim.sgd.SGD) not handled correctly
# by pydoc.locate. Try a private function from hydra.
if obj is None:
raise TypeError(f"can't locate object {obj} !")


def instantiate(cfg):

from omegaconf import ListConfig

if isinstance(cfg, ListConfig):
lst = [instantiate(x) for x in cfg]
return ListConfig(lst, flags={"allow_objects": True})
if isinstance(cfg, list):
return [instantiate(x) for x in cfg]

if isinstance(cfg, abc.Mapping) and "_target_" in cfg:
# conceptually equivalent to hydra.utils.instantiate(cfg) with _convert_=all,
# but faster: https://github.com/facebookresearch/hydra/issues/1200
cfg = {k: instantiate(v) for k, v in cfg.items()}
cls = cfg.pop("_target_")
cls = instantiate(cls)

if isinstance(cls, str):
cls_name = cls
cls = locate(cls_name)
assert cls is not None, cls_name
else:
try:
cls_name = cls.__module__ + "." + cls.__qualname__
except Exception:
# target could be anything, so the above could fail
cls_name = str(cls)
assert callable(cls), f"_target_ {cls} does not define a callable object"
try:
return cls(**cfg)
except TypeError:
logger = logging.getLogger(__name__)
logger.error(f"Error when instantiating {cls_name}!")
raise
return cfg # return as-is if don't know what to do
59 changes: 59 additions & 0 deletions vformer/config/lazy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from collections import abc
from dataclasses import is_dataclass

from omegaconf import DictConfig

from .config_utils import _convert_target_to_string

# copied from detectron 2


class LazyCall:
"""
Wrap a callable so that when it's called, the call will not be executed,
but returns a dict that describes the call.
LazyCall object has to be called with only keyword arguments. Positional
arguments are not yet supported.
Examples:
::
from detectron2.config import instantiate, LazyCall
layer_cfg = LazyCall(nn.Conv2d)(in_channels=32, out_channels=32)
layer_cfg.out_channels = 64 # can edit it afterwards
layer = instantiate(layer_cfg)
"""

def __init__(self, target):
if not (callable(target) or isinstance(target, (str, abc.Mapping))):
raise TypeError(
f"target of LazyCall must be a callable or defines a callable! Got {target}"
)
self._target = target

def __call__(self, **kwargs):
if is_dataclass(self._target):
# omegaconf object cannot hold dataclass type
# https://github.com/omry/omegaconf/issues/784
target = _convert_target_to_string(self._target)
else:
target = self._target
kwargs["_target_"] = target

return DictConfig(content=kwargs, flags={"allow_objects": True})


if __name__ == "__main__":
import vformer.models

print("ok lets check :)")
model_config = LazyCall(vformer.models.VanillaViT)(
img_size=224, patch_size=7, n_classes=4
)
print(model_config)
# change kwargs
model_config["img_size"], model_config["patch_size"] = 256, 8
print(model_config)

from config_utils import instantiate

model = instantiate(model_config)
print(model)
2 changes: 1 addition & 1 deletion vformer/encoder/vivit.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@ENCODER_REGISTRY.register()
class ViViTEncoderBlock(nn.Module):
"""For model 3 only """
"""For model 3 only"""

def __init__(
self, dim, num_heads, head_dim, p_dropout, out_dim=None, hidden_dim=None
Expand Down
2 changes: 1 addition & 1 deletion vformer/models/classification/convvt.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def __init__(
for i in range(self.num_stages):
stage = ConvVTStage(
in_channels=in_channels,
img_size=img_size // (4 * 2 ** i),
img_size=img_size // (4 * 2**i),
with_cls_token=False if i < self.num_stages - 1 else True,
patch_size=patch_size[i],
patch_stride=patch_stride[i],
Expand Down
6 changes: 3 additions & 3 deletions vformer/models/classification/swin.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ def __init__(

for i_layer in range(len(depths)):
layer = SwinEncoder(
dim=int(embedding_dim * (2 ** i_layer)),
dim=int(embedding_dim * (2**i_layer)),
input_resolution=(
(self.patch_resolution[0] // (2 ** i_layer)),
self.patch_resolution[1] // (2 ** i_layer),
(self.patch_resolution[0] // (2**i_layer)),
self.patch_resolution[1] // (2**i_layer),
),
depth=depths[i_layer],
num_heads=num_heads[i_layer],
Expand Down
2 changes: 1 addition & 1 deletion vformer/models/classification/vivit.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __init__(
pool=pool,
)

patch_dim = in_channels * patch_size ** 2
patch_dim = in_channels * patch_size**2
self.patch_embedding = LinearVideoEmbedding(
embedding_dim=embedding_dim,
patch_height=patch_size,
Expand Down