From 10dfa73a0910ebd3781709bb92960c925d2abc6b Mon Sep 17 00:00:00 2001 From: Pierre Chapuis Date: Sat, 10 Aug 2024 15:17:36 +0200 Subject: [PATCH] Add Multi-View Aggregation Network (MVANet) Co-authored-by: Pierre Colle --- docs/reference/SUMMARY.md | 2 +- docs/reference/foundationals/swin.md | 2 + pyproject.toml | 1 + requirements.lock | 11 + scripts/conversion/convert_mvanet.py | 40 ++ scripts/prepare_test_weights.py | 32 ++ src/refiners/foundationals/swin/__init__.py | 3 + .../foundationals/swin/mvanet/__init__.py | 3 + .../foundationals/swin/mvanet/converter.py | 138 +++++++ .../foundationals/swin/mvanet/mclm.py | 211 ++++++++++ .../foundationals/swin/mvanet/mcrm.py | 119 ++++++ .../foundationals/swin/mvanet/mvanet.py | 337 +++++++++++++++ .../foundationals/swin/mvanet/utils.py | 173 ++++++++ .../foundationals/swin/swin_transformer.py | 391 ++++++++++++++++++ tests/e2e/test_mvanet.py | 59 +++ tests/e2e/test_mvanet_ref/README.md | 3 + tests/e2e/test_mvanet_ref/cactus.png | Bin 0 -> 98012 bytes .../test_mvanet_ref/expected_cactus_mask.png | Bin 0 -> 7955 bytes typings/gdown/__init__.pyi | 1 + 19 files changed, 1525 insertions(+), 1 deletion(-) create mode 100644 docs/reference/foundationals/swin.md create mode 100644 scripts/conversion/convert_mvanet.py create mode 100644 src/refiners/foundationals/swin/__init__.py create mode 100644 src/refiners/foundationals/swin/mvanet/__init__.py create mode 100644 src/refiners/foundationals/swin/mvanet/converter.py create mode 100644 src/refiners/foundationals/swin/mvanet/mclm.py create mode 100644 src/refiners/foundationals/swin/mvanet/mcrm.py create mode 100644 src/refiners/foundationals/swin/mvanet/mvanet.py create mode 100644 src/refiners/foundationals/swin/mvanet/utils.py create mode 100644 src/refiners/foundationals/swin/swin_transformer.py create mode 100644 tests/e2e/test_mvanet.py create mode 100644 tests/e2e/test_mvanet_ref/README.md create mode 100644 tests/e2e/test_mvanet_ref/cactus.png create mode 100644 tests/e2e/test_mvanet_ref/expected_cactus_mask.png create mode 100644 typings/gdown/__init__.pyi diff --git a/docs/reference/SUMMARY.md b/docs/reference/SUMMARY.md index 8338a2450..76475d690 100644 --- a/docs/reference/SUMMARY.md +++ b/docs/reference/SUMMARY.md @@ -9,4 +9,4 @@ * [ DINOv2](foundationals/dinov2.md) * [ Latent Diffusion](foundationals/latent_diffusion.md) * [ Segment Anything](foundationals/segment_anything.md) - + * [ Swin Transformers](foundationals/swin.md) diff --git a/docs/reference/foundationals/swin.md b/docs/reference/foundationals/swin.md new file mode 100644 index 000000000..02c39b351 --- /dev/null +++ b/docs/reference/foundationals/swin.md @@ -0,0 +1,2 @@ +::: refiners.foundationals.swin.swin_transformer +::: refiners.foundationals.swin.mvanet diff --git a/pyproject.toml b/pyproject.toml index c3962e851..ee6909f4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ conversion = [ "segment-anything-py>=1.0", "requests>=2.26.0", "tqdm>=4.62.3", + "gdown>=5.2.0", ] doc = [ # required by mkdocs to format the signatures diff --git a/requirements.lock b/requirements.lock index a56a5a5e3..f9ec26074 100644 --- a/requirements.lock +++ b/requirements.lock @@ -31,6 +31,8 @@ babel==2.15.0 # via mkdocs-material backports-strenum==1.3.1 # via griffe +beautifulsoup4==4.12.3 + # via gdown bitsandbytes==0.43.3 # via refiners black==24.4.2 @@ -70,6 +72,7 @@ docker-pycreds==0.4.0 filelock==3.15.4 # via datasets # via diffusers + # via gdown # via huggingface-hub # via torch # via transformers @@ -85,6 +88,8 @@ fsspec==2024.5.0 # via torch future==1.0.0 # via neptune +gdown==5.2.0 + # via refiners ghp-import==2.1.0 # via mkdocs gitdb==4.0.11 @@ -274,6 +279,8 @@ pyjwt==2.9.0 pymdown-extensions==10.9 # via mkdocs-material # via mkdocstrings +pysocks==1.7.1 + # via requests python-dateutil==2.9.0.post0 # via arrow # via botocore @@ -311,6 +318,7 @@ requests==2.32.3 # via bravado-core # via datasets # via diffusers + # via gdown # via huggingface-hub # via mkdocs-material # via neptune @@ -356,6 +364,8 @@ six==1.16.0 # via rfc3339-validator smmap==5.0.1 # via gitdb +soupsieve==2.6 + # via beautifulsoup4 swagger-spec-validator==3.0.4 # via bravado-core # via neptune @@ -383,6 +393,7 @@ torchvision==0.19.0 # via timm tqdm==4.66.4 # via datasets + # via gdown # via huggingface-hub # via refiners # via transformers diff --git a/scripts/conversion/convert_mvanet.py b/scripts/conversion/convert_mvanet.py new file mode 100644 index 000000000..e5b30e754 --- /dev/null +++ b/scripts/conversion/convert_mvanet.py @@ -0,0 +1,40 @@ +import argparse +from pathlib import Path + +from refiners.fluxion.utils import load_tensors, save_to_safetensors +from refiners.foundationals.swin.mvanet.converter import convert_weights + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument( + "--from", + type=str, + required=True, + dest="source_path", + help="A MVANet checkpoint. One can be found at https://github.com/qianyu-dlut/MVANet", + ) + parser.add_argument( + "--to", + type=str, + dest="output_path", + default=None, + help=( + "Path to save the converted model. If not specified, the output path will be the source path with the" + " extension changed to .safetensors." + ), + ) + parser.add_argument("--half", action="store_true", dest="half") + args = parser.parse_args() + + src_weights = load_tensors(args.source_path) + weights = convert_weights(src_weights) + if args.half: + weights = {key: value.half() for key, value in weights.items()} + if args.output_path is None: + args.output_path = f"{Path(args.source_path).stem}.safetensors" + save_to_safetensors(path=args.output_path, tensors=weights) + + +if __name__ == "__main__": + main() diff --git a/scripts/prepare_test_weights.py b/scripts/prepare_test_weights.py index c20447cc8..6f27a67b1 100644 --- a/scripts/prepare_test_weights.py +++ b/scripts/prepare_test_weights.py @@ -11,6 +11,7 @@ import sys from urllib.parse import urlparse +import gdown import requests from tqdm import tqdm @@ -446,6 +447,25 @@ def download_ic_light(): ) +def download_mvanet(): + fn = "Model_80.pth" + dest_folder = os.path.join(test_weights_dir, "mvanet") + dest_filename = os.path.join(dest_folder, fn) + + if os.environ.get("DRY_RUN") == "1": + return + + if os.path.exists(dest_filename): + print(f"✖️ ️ Skipping previously downloaded mvanet/{fn}") + else: + os.makedirs(dest_folder, exist_ok=True) + print(f"🔽 Downloading mvanet/{fn} => '{rel(dest_filename)}'", end="\n") + gdown.download(id="1_gabQXOF03MfXnf3EWDK1d_8wKiOemOv", output=dest_filename, quiet=True) + print(f"{previous_line}✅ Downloaded mvanet/{fn} => '{rel(dest_filename)}' ") + + check_hash(dest_filename, "b915d492") + + def printg(msg: str): """print in green color""" print("\033[92m" + msg + "\033[0m") @@ -808,6 +828,16 @@ def convert_ic_light(): ) +def convert_mvanet(): + run_conversion_script( + "convert_mvanet.py", + "tests/weights/mvanet/Model_80.pth", + "tests/weights/mvanet/mvanet.safetensors", + half=True, + expected_hash="bf9ae4cb", + ) + + def download_all(): print(f"\nAll weights will be downloaded to {test_weights_dir}\n") download_sd15("runwayml/stable-diffusion-v1-5") @@ -830,6 +860,7 @@ def download_all(): download_sdxl_lightning_base() download_sdxl_lightning_lora() download_ic_light() + download_mvanet() def convert_all(): @@ -850,6 +881,7 @@ def convert_all(): convert_lcm_base() convert_sdxl_lightning_base() convert_ic_light() + convert_mvanet() def main(): diff --git a/src/refiners/foundationals/swin/__init__.py b/src/refiners/foundationals/swin/__init__.py new file mode 100644 index 000000000..51cfb2284 --- /dev/null +++ b/src/refiners/foundationals/swin/__init__.py @@ -0,0 +1,3 @@ +from .swin_transformer import SwinTransformer + +__all__ = ["SwinTransformer"] diff --git a/src/refiners/foundationals/swin/mvanet/__init__.py b/src/refiners/foundationals/swin/mvanet/__init__.py new file mode 100644 index 000000000..5c54590a8 --- /dev/null +++ b/src/refiners/foundationals/swin/mvanet/__init__.py @@ -0,0 +1,3 @@ +from .mvanet import MVANet + +__all__ = ["MVANet"] diff --git a/src/refiners/foundationals/swin/mvanet/converter.py b/src/refiners/foundationals/swin/mvanet/converter.py new file mode 100644 index 000000000..daacd69a9 --- /dev/null +++ b/src/refiners/foundationals/swin/mvanet/converter.py @@ -0,0 +1,138 @@ +import re + +from torch import Tensor + + +def convert_weights(official_state_dict: dict[str, Tensor]) -> dict[str, Tensor]: + rm_list = [ + # Official weights contains useless keys + # See https://github.com/qianyu-dlut/MVANet/issues/3#issuecomment-2105650425 + r"multifieldcrossatt.linear[56]", + r"multifieldcrossatt.attention.5", + r"dec_blk\d+\.linear[12]", + r"dec_blk[1234]\.attention\.[4567]", + # We don't need the sideout weights + r"sideout\d+", + ] + state_dict = {k: v for k, v in official_state_dict.items() if not any(re.match(rm, k) for rm in rm_list)} + + keys_map: dict[str, str] = {} + for k in state_dict.keys(): + v: str = k + + def rpfx(s: str, src: str, dst: str) -> str: + if not s.startswith(src): + return s + return s.replace(src, dst, 1) + + # Swin Transformer backbone + + v = rpfx(v, "backbone.patch_embed.proj.", "SwinTransformer.PatchEmbedding.Conv2d.") + v = rpfx(v, "backbone.patch_embed.norm.", "SwinTransformer.PatchEmbedding.LayerNorm.") + + if m := re.match(r"backbone\.layers\.(\d+)\.downsample\.(.*)", v): + s = m.group(2).replace("reduction.", "Linear.").replace("norm.", "LayerNorm.") + v = f"SwinTransformer.Chain_{int(m.group(1)) + 1}.PatchMerging.{s}" + + if m := re.match(r"backbone\.layers\.(\d+)\.blocks\.(\d+)\.(.*)", v): + s = m.group(3) + s = s.replace("norm1.", "Residual_1.LayerNorm.") + s = s.replace("norm2.", "Residual_2.LayerNorm.") + + s = s.replace("attn.qkv.", "Residual_1.WindowAttention.Linear_1.") + s = s.replace("attn.proj.", "Residual_1.WindowAttention.Linear_2.") + s = s.replace("attn.relative_position", "Residual_1.WindowAttention.WindowSDPA.rpb.relative_position") + + s = s.replace("mlp.fc", "Residual_2.Linear_") + v = ".".join( + [ + f"SwinTransformer.Chain_{int(m.group(1)) + 1}", + f"BasicLayer.SwinTransformerBlock_{int(m.group(2)) + 1}", + s, + ] + ) + + if m := re.match(r"backbone\.norm(\d+)\.(.*)", v): + v = f"SwinTransformer.Chain_{int(m.group(1)) + 1}.Passthrough.LayerNorm.{m.group(2)}" + + # MVANet + + def mclm(s: str, pfx_src: str, pfx_dst: str) -> str: + pca = f"{pfx_dst}Residual.PatchwiseCrossAttention" + s = rpfx(s, f"{pfx_src}linear1.", f"{pfx_dst}FeedForward_1.Linear_1.") + s = rpfx(s, f"{pfx_src}linear2.", f"{pfx_dst}FeedForward_1.Linear_2.") + s = rpfx(s, f"{pfx_src}linear3.", f"{pfx_dst}FeedForward_2.Linear_1.") + s = rpfx(s, f"{pfx_src}linear4.", f"{pfx_dst}FeedForward_2.Linear_2.") + s = rpfx(s, f"{pfx_src}norm1.", f"{pfx_dst}LayerNorm_1.") + s = rpfx(s, f"{pfx_src}norm2.", f"{pfx_dst}LayerNorm_2.") + s = rpfx(s, f"{pfx_src}attention.0.", f"{pfx_dst}GlobalAttention.Sum.Chain.MultiheadAttention.") + s = rpfx(s, f"{pfx_src}attention.1.", f"{pca}.Concatenate.Chain_1.MultiheadAttention.") + s = rpfx(s, f"{pfx_src}attention.2.", f"{pca}.Concatenate.Chain_2.MultiheadAttention.") + s = rpfx(s, f"{pfx_src}attention.3.", f"{pca}.Concatenate.Chain_3.MultiheadAttention.") + s = rpfx(s, f"{pfx_src}attention.4.", f"{pca}.Concatenate.Chain_4.MultiheadAttention.") + return s + + def mcrm(s: str, pfx_src: str, pfx_dst: str) -> str: + # Note: there are no linear{1,2}, see https://github.com/qianyu-dlut/MVANet/issues/3#issuecomment-2105650425 + tca = f"{pfx_dst}Parallel_3.TiledCrossAttention" + pca = f"{tca}.Sum.Chain_2.PatchwiseCrossAttention" + s = rpfx(s, f"{pfx_src}linear3.", f"{tca}.FeedForward.Linear_1.") + s = rpfx(s, f"{pfx_src}linear4.", f"{tca}.FeedForward.Linear_2.") + s = rpfx(s, f"{pfx_src}norm1.", f"{tca}.LayerNorm_1.") + s = rpfx(s, f"{pfx_src}norm2.", f"{tca}.LayerNorm_2.") + s = rpfx(s, f"{pfx_src}attention.0.", f"{pca}.Concatenate.Chain_1.MultiheadAttention.") + s = rpfx(s, f"{pfx_src}attention.1.", f"{pca}.Concatenate.Chain_2.MultiheadAttention.") + s = rpfx(s, f"{pfx_src}attention.2.", f"{pca}.Concatenate.Chain_3.MultiheadAttention.") + s = rpfx(s, f"{pfx_src}attention.3.", f"{pca}.Concatenate.Chain_4.MultiheadAttention.") + s = rpfx(s, f"{pfx_src}sal_conv.", f"{pfx_dst}Parallel_2.Multiply.Chain.Conv2d.") + return s + + def cbr(s: str, pfx_src: str, pfx_dst: str, shift: int = 0) -> str: + s = rpfx(s, f"{pfx_src}{shift}.", f"{pfx_dst}Conv2d.") + s = rpfx(s, f"{pfx_src}{shift + 1}.", f"{pfx_dst}BatchNorm2d.") + s = rpfx(s, f"{pfx_src}{shift + 2}.", f"{pfx_dst}PReLU.") + return s + + def cbg(s: str, pfx_src: str, pfx_dst: str) -> str: + s = rpfx(s, f"{pfx_src}0.", f"{pfx_dst}Conv2d.") + s = rpfx(s, f"{pfx_src}1.", f"{pfx_dst}BatchNorm2d.") + return s + + v = rpfx(v, "shallow.0.", "ComputeShallow.Conv2d.") + + v = cbr(v, "output1.", "Pyramid.Sum.Chain.CBR.") + v = cbr(v, "output2.", "Pyramid.Sum.PyramidL2.Sum.Chain.CBR.") + v = cbr(v, "output3.", "Pyramid.Sum.PyramidL2.Sum.PyramidL3.Sum.Chain.CBR.") + v = cbr(v, "output4.", "Pyramid.Sum.PyramidL2.Sum.PyramidL3.Sum.PyramidL4.Sum.Chain.CBR.") + v = cbr(v, "output5.", "Pyramid.Sum.PyramidL2.Sum.PyramidL3.Sum.PyramidL4.Sum.PyramidL5.CBR.") + + v = cbr(v, "conv1.", "Pyramid.CBR.") + v = cbr(v, "conv2.", "Pyramid.Sum.PyramidL2.CBR.") + v = cbr(v, "conv3.", "Pyramid.Sum.PyramidL2.Sum.PyramidL3.CBR.") + v = cbr(v, "conv4.", "Pyramid.Sum.PyramidL2.Sum.PyramidL3.Sum.PyramidL4.CBR.") + + v = mclm(v, "multifieldcrossatt.", "Pyramid.Sum.PyramidL2.Sum.PyramidL3.Sum.PyramidL4.Sum.PyramidL5.MCLM.") + + v = mcrm(v, "dec_blk1.", "Pyramid.MCRM.") + v = mcrm(v, "dec_blk2.", "Pyramid.Sum.PyramidL2.MCRM.") + v = mcrm(v, "dec_blk3.", "Pyramid.Sum.PyramidL2.Sum.PyramidL3.MCRM.") + v = mcrm(v, "dec_blk4.", "Pyramid.Sum.PyramidL2.Sum.PyramidL3.Sum.PyramidL4.MCRM.") + + v = cbr(v, "insmask_head.", "RearrangeMultiView.Chain.CBR_1.") + v = cbr(v, "insmask_head.", "RearrangeMultiView.Chain.CBR_2.", shift=3) + + v = rpfx(v, "insmask_head.6.", "RearrangeMultiView.Chain.Conv2d.") + + v = cbg(v, "upsample1.", "ShallowUpscaler.Sum_2.Chain_1.CBG.") + v = cbg(v, "upsample2.", "ShallowUpscaler.CBG.") + + v = rpfx(v, "output.0.", "Conv2d.") + + if v != k: + keys_map[k] = v + + for key, new_key in keys_map.items(): + state_dict[new_key] = state_dict[key] + state_dict.pop(key) + + return state_dict diff --git a/src/refiners/foundationals/swin/mvanet/mclm.py b/src/refiners/foundationals/swin/mvanet/mclm.py new file mode 100644 index 000000000..041308afc --- /dev/null +++ b/src/refiners/foundationals/swin/mvanet/mclm.py @@ -0,0 +1,211 @@ +# Multi-View Complementary Localization + +import math + +import torch +from torch import Tensor, device as Device + +import refiners.fluxion.layers as fl +from refiners.fluxion.context import Contexts + +from .utils import FeedForward, MultiheadAttention, MultiPool, PatchMerge, PatchwiseCrossAttention, Unflatten + + +class PerPixel(fl.Chain): + """(B, C, H, W) -> H*W, B, C""" + + def __init__(self): + super().__init__( + fl.Permute(2, 3, 0, 1), + fl.Flatten(0, 1), + ) + + +class PositionEmbeddingSine(fl.Module): + """ + Non-trainable position embedding, originally from https://github.com/facebookresearch/detr + """ + + def __init__(self, num_pos_feats: int, device: Device | None = None): + super().__init__() + self.device = device + temperature = 10000 + self.dim_t = torch.arange(0, num_pos_feats, dtype=torch.float32, device=self.device) + self.dim_t = temperature ** (2 * (self.dim_t // 2) / num_pos_feats) + + def __call__(self, h: int, w: int) -> Tensor: + mask = torch.ones([1, h, w, 1], dtype=torch.bool, device=self.device) + y_embed = mask.cumsum(dim=1, dtype=torch.float32) + x_embed = mask.cumsum(dim=2, dtype=torch.float32) + + eps, scale = 1e-6, 2 * math.pi + y_embed = (y_embed - 0.5) / (y_embed[:, -1:, :] + eps) * scale + x_embed = (x_embed - 0.5) / (x_embed[:, :, -1:] + eps) * scale + + pos_x = x_embed / self.dim_t + pos_y = y_embed / self.dim_t + + pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3) + pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3) + return torch.cat((pos_y, pos_x), dim=3).permute(1, 2, 0, 3).flatten(0, 1) + + +class MultiPoolPos(fl.Module): + def __init__(self, pool_ratios: list[int], positional_embedding: PositionEmbeddingSine): + super().__init__() + self.pool_ratios = pool_ratios + self.positional_embedding = positional_embedding + + def forward(self, *args: int) -> Tensor: + h, w = args + return torch.cat([self.positional_embedding(h // ratio, w // ratio) for ratio in self.pool_ratios]) + + +class Repeat(fl.Module): + def __init__(self, dim: int = 0): + self.dim = dim + super().__init__() + + def forward(self, x: Tensor, n: int) -> Tensor: + return torch.repeat_interleave(x, n, dim=self.dim) + + +class _MHA_Arg(fl.Sum): + def __init__(self, offset: int): + self.offset = offset + super().__init__( + fl.GetArg(offset), # value + fl.Chain( + fl.Parallel( + fl.GetArg(self.offset + 1), # position embedding + fl.Lambda(self._batch_size), + ), + Repeat(1), + ), + ) + + def _batch_size(self, *args: Tensor) -> int: + return args[self.offset].size(1) + + +class GlobalAttention(fl.Chain): + # Input must be a 4-tuple: (global, global pos. emb, pools, pools pos. emb.) + def __init__( + self, + emb_dim: int, + num_heads: int = 1, + device: Device | None = None, + ): + super().__init__( + fl.Sum( + fl.GetArg(0), # global + fl.Chain( + fl.Parallel( + _MHA_Arg(0), # Q: global + pos. emb + _MHA_Arg(2), # K: pools + pos. emb + fl.GetArg(2), # V: pools + ), + MultiheadAttention(emb_dim, num_heads, device=device), + ), + ), + ) + + +class MCLM(fl.Chain): + """Multi-View Complementary Localization Module + Inputs: + tensor: (b, 5, e, h, h) + Outputs: + tensor: (b, 5, e, h, h) + """ + + def __init__( + self, + emb_dim: int, + num_heads: int = 1, + pool_ratios: list[int] | None = None, + device: Device | None = None, + ): + if pool_ratios is None: + pool_ratios = [2, 8, 16] + + positional_embedding = PositionEmbeddingSine(num_pos_feats=emb_dim // 2, device=device) + + # LayerNorms in MCLM share their weights. + + ln1 = fl.LayerNorm(emb_dim, device=device) + ln2 = fl.LayerNorm(emb_dim, device=device) + + def proxy(m: fl.Module) -> fl.Module: + def f(x: Tensor) -> Tensor: + return m(x) + + return fl.Lambda(f) + + super().__init__( + fl.Parallel( + fl.Chain( # global + fl.Slicing(dim=1, start=4), + fl.Squeeze(1), + fl.Parallel( + PerPixel(), # glb + fl.Chain( # g_pos + fl.Lambda(lambda x: x.shape[-2:]), # type: ignore + positional_embedding, + ), + ), + ), + fl.Chain( # local + fl.Slicing(dim=1, end=4), + fl.SetContext("mclm", "local"), + PatchMerge(), + fl.Parallel( + fl.Chain( # pool + MultiPool(pool_ratios), + fl.Squeeze(0), + ), + fl.Chain( # pool_pos + fl.Lambda(lambda x: x.shape[-2:]), # type: ignore + MultiPoolPos(pool_ratios, positional_embedding), + ), + ), + ), + ), + fl.Lambda(lambda t1, t2: (*t1, *t2)), # type: ignore + GlobalAttention(emb_dim, num_heads, device=device), + ln1, + FeedForward(emb_dim, device=device), + ln2, + fl.SetContext("mclm", "global"), + fl.UseContext("mclm", "local"), + fl.Flatten(-2, -1), + fl.Permute(1, 3, 0, 2), + fl.Residual( + fl.Parallel( + fl.Identity(), + fl.Chain( + fl.UseContext("mclm", "global"), + Unflatten(0, (2, 8, 2, 8)), # 2, h/2, 2, h/2 + fl.Permute(0, 2, 1, 3, 4, 5), + fl.Flatten(0, 1), + fl.Flatten(1, 2), + ), + ), + PatchwiseCrossAttention(emb_dim, num_heads, device=device), + ), + proxy(ln1), + FeedForward(emb_dim, device=device), + proxy(ln2), + fl.Concatenate( + fl.Identity(), + fl.Chain( + fl.UseContext("mclm", "global"), + fl.Unsqueeze(0), + ), + ), + Unflatten(1, (16, 16)), # h, h + fl.Permute(3, 0, 4, 1, 2), + ) + + def init_context(self) -> Contexts: + return {"mclm": {"global": None, "local": None}} diff --git a/src/refiners/foundationals/swin/mvanet/mcrm.py b/src/refiners/foundationals/swin/mvanet/mcrm.py new file mode 100644 index 000000000..01311da1a --- /dev/null +++ b/src/refiners/foundationals/swin/mvanet/mcrm.py @@ -0,0 +1,119 @@ +# Multi-View Complementary Refinement + +import torch +from torch import Tensor, device as Device + +import refiners.fluxion.layers as fl + +from .utils import FeedForward, Interpolate, MultiPool, PatchMerge, PatchSplit, PatchwiseCrossAttention, Unflatten + + +class Multiply(fl.Chain): + def __init__(self, o1: fl.Module, o2: fl.Module) -> None: + super().__init__(o1, o2) + + def forward(self, *args: Tensor) -> Tensor: + return torch.mul(self[0](*args), self[1](*args)) + + +class TiledCrossAttention(fl.Chain): + def __init__( + self, + emb_dim: int, + dim: int, + num_heads: int = 1, + pool_ratios: list[int] | None = None, + device: Device | None = None, + ): + # Input must be a 4-tuple: (local, global) + + if pool_ratios is None: + pool_ratios = [1, 2, 4] + + super().__init__( + fl.Distribute( + fl.Chain( # local + fl.Flatten(-2, -1), + fl.Permute(1, 3, 0, 2), + ), + fl.Chain( # global + PatchSplit(), + fl.Squeeze(0), + MultiPool(pool_ratios), + ), + ), + fl.Sum( + fl.Chain( + fl.GetArg(0), + fl.Permute(2, 1, 0, 3), + ), + fl.Chain( + PatchwiseCrossAttention(emb_dim, num_heads, device=device), + fl.Permute(2, 1, 0, 3), + ), + ), + fl.LayerNorm(emb_dim, device=device), + FeedForward(emb_dim, device=device), + fl.LayerNorm(emb_dim, device=device), + fl.Permute(0, 2, 3, 1), + Unflatten(-1, (dim, dim)), + ) + + +class MCRM(fl.Chain): + """Multi-View Complementary Refinement""" + + def __init__( + self, + emb_dim: int, + size: int, + num_heads: int = 1, + pool_ratios: list[int] | None = None, + device: Device | None = None, + ): + if pool_ratios is None: + pool_ratios = [1, 2, 4] + + super().__init__( + fl.Parallel( + fl.Chain( # local + fl.Slicing(dim=1, end=4), + ), + fl.Chain( # global + fl.Slicing(dim=1, start=4), + fl.Squeeze(1), + ), + ), + fl.Parallel( + Multiply( + fl.GetArg(0), + fl.Chain( + fl.GetArg(1), + fl.Conv2d(emb_dim, 1, 1, device=device), + fl.Sigmoid(), + Interpolate((size * 2, size * 2), "nearest"), + PatchSplit(), + ), + ), + fl.GetArg(1), + ), + fl.Parallel( + TiledCrossAttention(emb_dim, size, num_heads, pool_ratios, device=device), + fl.GetArg(1), + ), + fl.Concatenate( + fl.GetArg(0), + fl.Chain( + fl.Sum( + fl.GetArg(1), + fl.Chain( + fl.GetArg(0), + PatchMerge(), + Interpolate((size, size), "nearest"), + ), + ), + fl.Unsqueeze(1), + ), + dim=1, + ), + ) diff --git a/src/refiners/foundationals/swin/mvanet/mvanet.py b/src/refiners/foundationals/swin/mvanet/mvanet.py new file mode 100644 index 000000000..4410eb65b --- /dev/null +++ b/src/refiners/foundationals/swin/mvanet/mvanet.py @@ -0,0 +1,337 @@ +# Multi-View Aggregation Network (arXiv:2404.07445) + +from torch import device as Device + +import refiners.fluxion.layers as fl +from refiners.fluxion.context import Contexts +from refiners.foundationals.swin.swin_transformer import SwinTransformer + +from .mclm import MCLM # Multi-View Complementary Localization +from .mcrm import MCRM # Multi-View Complementary Refinement +from .utils import BatchNorm2d, Interpolate, PatchMerge, PatchSplit, PReLU, Rescale, Unflatten + + +class CBG(fl.Chain): + """(C)onvolution + (B)atchNorm + (G)eLU""" + + def __init__( + self, + in_dim: int, + out_dim: int | None = None, + device: Device | None = None, + ): + out_dim = out_dim or in_dim + super().__init__( + fl.Conv2d(in_dim, out_dim, kernel_size=3, padding=1, device=device), + BatchNorm2d(out_dim, device=device), + fl.GeLU(), + ) + + +class CBR(fl.Chain): + """(C)onvolution + (B)atchNorm + Parametric (R)eLU""" + + def __init__( + self, + in_dim: int, + out_dim: int | None = None, + device: Device | None = None, + ): + out_dim = out_dim or in_dim + super().__init__( + fl.Conv2d(in_dim, out_dim, kernel_size=3, padding=1, device=device), + BatchNorm2d(out_dim, device=device), + PReLU(device=device), + ) + + +class SplitMultiView(fl.Chain): + """ + Split a hd tensor into 5 ld views, (5 = 1 global + 4 tiles) + See also the reverse Module [`RearrangeMultiView`][refiners.foundationals.swin.mvanet.RearrangeMultiView] + + Inputs: + single_view (b, c, H, W) + + Outputs: + multi_view (b, 5, c, H/2, W/2) + """ + + def __init__(self): + super().__init__( + fl.Concatenate( + PatchSplit(), # global features + fl.Chain( # local features + Rescale(scale_factor=0.5, mode="bilinear"), + fl.Unsqueeze(1), + ), + dim=1, + ) + ) + + +class ShallowUpscaler(fl.Chain): + """4x Upscaler reusing the image as input to upscale the feature + See [[arXiv:2108.10257] SwinIR: Image Restoration Using Swin Transformer](https://arxiv.org/abs/2108.10257) + + Args: + embedding_dim (int): the embedding dimension + + Inputs: + feature (b, E, image_size/4, image_size/4) + + Output: + upscaled tensor (b, E, image_size, image_size) + """ + + def __init__( + self, + embedding_dim: int = 128, + device: Device | None = None, + ): + super().__init__( + fl.Sum( + fl.Identity(), + fl.Chain( + fl.UseContext("mvanet", "shallow"), + Interpolate((256, 256)), + ), + ), + fl.Sum( + fl.Chain( + Rescale(2), + CBG(embedding_dim, device=device), + ), + fl.Chain( + fl.UseContext("mvanet", "shallow"), + Interpolate((512, 512)), + ), + ), + Rescale(2), + CBG(embedding_dim, device=device), + ) + + +class PyramidL5(fl.Chain): + def __init__( + self, + embedding_dim: int = 128, + device: Device | None = None, + ): + super().__init__( + fl.GetArg(0), # output5 + fl.Flatten(0, 1), + CBR(1024, embedding_dim, device=device), + Unflatten(0, (-1, 5)), + MCLM(embedding_dim, device=device), + fl.Flatten(0, 1), + Interpolate((32, 32)), + ) + + +class PyramidL4(fl.Chain): + def __init__( + self, + embedding_dim: int = 128, + device: Device | None = None, + ): + super().__init__( + fl.Sum( + PyramidL5(embedding_dim=embedding_dim, device=device), + fl.Chain( + fl.GetArg(1), + fl.Flatten(0, 1), + CBR(512, embedding_dim, device=device), # output4 + Unflatten(0, (-1, 5)), + ), + ), + MCRM(embedding_dim, 32, device=device), # dec_blk4 + fl.Flatten(0, 1), + CBR(embedding_dim, device=device), # conv4 + Interpolate((64, 64)), + ) + + +class PyramidL3(fl.Chain): + def __init__( + self, + embedding_dim: int = 128, + device: Device | None = None, + ): + super().__init__( + fl.Sum( + PyramidL4(embedding_dim=embedding_dim, device=device), + fl.Chain( + fl.GetArg(2), + fl.Flatten(0, 1), + CBR(256, embedding_dim, device=device), # output3 + Unflatten(0, (-1, 5)), + ), + ), + MCRM(embedding_dim, 64, device=device), # dec_blk3 + fl.Flatten(0, 1), + CBR(embedding_dim, device=device), # conv3 + Interpolate((128, 128)), + ) + + +class PyramidL2(fl.Chain): + def __init__( + self, + embedding_dim: int = 128, + device: Device | None = None, + ): + embedding_dim = 128 + super().__init__( + fl.Sum( + PyramidL3(embedding_dim=embedding_dim, device=device), + fl.Chain( + fl.GetArg(3), + fl.Flatten(0, 1), + CBR(128, embedding_dim, device=device), # output2 + Unflatten(0, (-1, 5)), + ), + ), + MCRM(embedding_dim, 128, device=device), # dec_blk2 + fl.Flatten(0, 1), + CBR(embedding_dim, device=device), # conv2 + Interpolate((128, 128)), + ) + + +class Pyramid(fl.Chain): + """ + Recursive Pyramidal Network calling MCLM and MCRM blocks + + It acts as a FPN (Feature Pyramid Network) Neck for MVANet + see [[arXiv:1612.03144] Feature Pyramid Networks for Object Detection](https://arxiv.org/abs/1612.03144) + + Inputs: + features: a pyramid of N = 5 tensors + shapes are (b, 5, E_{0}, S_{0}, S_{0}), ..., (b, 5, E_{1}, S_{i}, S_{i}), ..., (b, 5, E_{N-1}, S_{N-1}, S_{N-1}) + with S_{i} = S_{i-1} or S_{i} = 2*S_{i-1} for 0 < i < N + + Outputs: + output (b, 5, E, S_{N-1}, S_{N-1}) + """ + + def __init__( + self, + embedding_dim: int = 128, + device: Device | None = None, + ): + super().__init__( + fl.Sum( + PyramidL2(embedding_dim=embedding_dim, device=device), + fl.Chain( + fl.GetArg(4), + fl.Flatten(0, 1), + CBR(128, embedding_dim, device=device), # output1 + Unflatten(0, (-1, 5)), + ), + ), + MCRM(embedding_dim, 128, device=device), # dec_blk1 + fl.Flatten(0, 1), + CBR(embedding_dim, device=device), # conv1 + Unflatten(0, (-1, 5)), + ) + + +class RearrangeMultiView(fl.Chain): + """ + Inputs: + multi_view (b, 5, E, H, W) + + Outputs: + single_view (b, E, H*2, W*2) + + Fusion a multi view tensor into a single view tensor, using convolutions + See also the reverse Module [`SplitMultiView`][refiners.foundationals.swin.mvanet.SplitMultiView] + """ + + def __init__( + self, + embedding_dim: int = 128, + device: Device | None = None, + ): + super().__init__( + fl.Sum( + fl.Chain( # local features + fl.Slicing(dim=1, end=4), + PatchMerge(), + ), + fl.Chain( # global feature + fl.Slicing(dim=1, start=4), + fl.Squeeze(1), + Interpolate((256, 256)), + ), + ), + fl.Chain( # conv head + CBR(embedding_dim, 384, device=device), + CBR(384, device=device), + fl.Conv2d(384, embedding_dim, kernel_size=3, padding=1, device=device), + ), + ) + + +class ComputeShallow(fl.Passthrough): + def __init__( + self, + embedding_dim: int = 128, + device: Device | None = None, + ): + super().__init__( + fl.Conv2d(3, embedding_dim, kernel_size=3, padding=1, device=device), + fl.SetContext("mvanet", "shallow"), + ) + + +class MVANet(fl.Chain): + """Multi-view Aggregation Network for Dichotomous Image Segmentation + + See [[arXiv:2404.07445] Multi-view Aggregation Network for Dichotomous Image Segmentation](https://arxiv.org/abs/2404.07445) for more details. + + Args: + embedding_dim (int): embedding dimension + n_logits (int): the number of output logits (default to 1) + 1 logit is used for alpha matting/foreground-background segmentation/sod segmentation + depths (list[int]): see [`SwinTransformer`][refiners.foundationals.swin.swin_transformer.SwinTransformer] + num_heads (list[int]): see [`SwinTransformer`][refiners.foundationals.swin.swin_transformer.SwinTransformer] + window_size (int): default to 12, see [`SwinTransformer`][refiners.foundationals.swin.swin_transformer.SwinTransformer] + device (Device | None): the device to use + """ + + def __init__( + self, + embedding_dim: int = 128, + n_logits: int = 1, + depths: list[int] | None = None, + num_heads: list[int] | None = None, + window_size: int = 12, + device: Device | None = None, + ): + if depths is None: + depths = [2, 2, 18, 2] + if num_heads is None: + num_heads = [4, 8, 16, 32] + + super().__init__( + ComputeShallow(embedding_dim=embedding_dim, device=device), + SplitMultiView(), + fl.Flatten(0, 1), + SwinTransformer( + embedding_dim=embedding_dim, + depths=depths, + num_heads=num_heads, + window_size=window_size, + device=device, + ), + fl.Distribute(*(Unflatten(0, (-1, 5)) for _ in range(5))), + Pyramid(embedding_dim=embedding_dim, device=device), + RearrangeMultiView(embedding_dim=embedding_dim, device=device), + ShallowUpscaler(embedding_dim, device=device), + fl.Conv2d(embedding_dim, n_logits, kernel_size=3, padding=1, device=device), + ) + + def init_context(self) -> Contexts: + return {"mvanet": {"shallow": None}} diff --git a/src/refiners/foundationals/swin/mvanet/utils.py b/src/refiners/foundationals/swin/mvanet/utils.py new file mode 100644 index 000000000..363b55a84 --- /dev/null +++ b/src/refiners/foundationals/swin/mvanet/utils.py @@ -0,0 +1,173 @@ +import torch +from torch import Size, Tensor +from torch.nn.functional import ( + adaptive_avg_pool2d, + interpolate, # type: ignore +) + +import refiners.fluxion.layers as fl + + +class Unflatten(fl.Module): + def __init__(self, dim: int, sizes: tuple[int, ...]) -> None: + super().__init__() + self.dim = dim + self.sizes = Size(sizes) + + def forward(self, x: Tensor) -> Tensor: + return torch.unflatten(input=x, dim=self.dim, sizes=self.sizes) + + +class Interpolate(fl.Module): + def __init__(self, size: tuple[int, ...], mode: str = "bilinear"): + super().__init__() + self.size = Size(size) + self.mode = mode + + def forward(self, x: Tensor) -> Tensor: + return interpolate(x, size=self.size, mode=self.mode) # type: ignore + + +class Rescale(fl.Module): + def __init__(self, scale_factor: float, mode: str = "nearest"): + super().__init__() + self.scale_factor = scale_factor + self.mode = mode + + def forward(self, x: Tensor) -> Tensor: + return interpolate(x, scale_factor=self.scale_factor, mode=self.mode) # type: ignore + + +class BatchNorm2d(torch.nn.BatchNorm2d, fl.WeightedModule): + def __init__(self, num_features: int, device: torch.device | None = None): + super().__init__(num_features=num_features, device=device) # type: ignore + + +class PReLU(torch.nn.PReLU, fl.WeightedModule, fl.Activation): + def __init__(self, device: torch.device | None = None): + super().__init__(device=device) # type: ignore + + +class PatchSplit(fl.Chain): + """(B, N, H, W) -> B, 4, N, H/2, W/2""" + + def __init__(self): + super().__init__( + Unflatten(-2, (2, -1)), + Unflatten(-1, (2, -1)), + fl.Permute(0, 2, 4, 1, 3, 5), + fl.Flatten(1, 2), + ) + + +class PatchMerge(fl.Chain): + """B, 4, N, H, W -> (B, N, 2*H, 2*W)""" + + def __init__(self): + super().__init__( + Unflatten(1, (2, 2)), + fl.Permute(0, 3, 1, 4, 2, 5), + fl.Flatten(-2, -1), + fl.Flatten(-3, -2), + ) + + +class FeedForward(fl.Residual): + def __init__(self, emb_dim: int, device: torch.device | None = None) -> None: + super().__init__( + fl.Linear(in_features=emb_dim, out_features=2 * emb_dim, device=device), + fl.ReLU(), + fl.Linear(in_features=2 * emb_dim, out_features=emb_dim, device=device), + ) + + +class _GetArgs(fl.Parallel): + def __init__(self, n: int): + super().__init__( + fl.Chain( + fl.GetArg(0), + fl.Slicing(dim=0, start=n, end=n + 1), + fl.Squeeze(0), + ), + fl.Chain( + fl.GetArg(1), + fl.Slicing(dim=0, start=n, end=n + 1), + fl.Squeeze(0), + ), + fl.Chain( + fl.GetArg(1), + fl.Slicing(dim=0, start=n, end=n + 1), + fl.Squeeze(0), + ), + ) + + +class MultiheadAttention(torch.nn.MultiheadAttention, fl.WeightedModule): + def __init__(self, embedding_dim: int, num_heads: int, device: torch.device | None = None): + super().__init__(embed_dim=embedding_dim, num_heads=num_heads, device=device) # type: ignore + + @property + def weight(self) -> Tensor: # type: ignore + return self.in_proj_weight + + def forward(self, q: Tensor, k: Tensor, v: Tensor) -> Tensor: # type: ignore + return super().forward(q, k, v)[0] + + +class PatchwiseCrossAttention(fl.Chain): + # Input is 2 tensors of sizes (4, HW, B, C) and (4, HW', B, C), + # output is size (4, HW, B, C). + def __init__( + self, + d_model: int, + num_heads: int, + device: torch.device | None = None, + ): + super().__init__( + fl.Concatenate( + fl.Chain( + _GetArgs(0), + MultiheadAttention(d_model, num_heads, device=device), + ), + fl.Chain( + _GetArgs(1), + MultiheadAttention(d_model, num_heads, device=device), + ), + fl.Chain( + _GetArgs(2), + MultiheadAttention(d_model, num_heads, device=device), + ), + fl.Chain( + _GetArgs(3), + MultiheadAttention(d_model, num_heads, device=device), + ), + ), + Unflatten(0, (4, -1)), + ) + + +class Pool(fl.Module): + def __init__(self, ratio: int) -> None: + super().__init__() + self.ratio = ratio + + def forward(self, x: Tensor) -> Tensor: + b, _, h, w = x.shape + assert h % self.ratio == 0 and w % self.ratio == 0 + r = adaptive_avg_pool2d(x, (h // self.ratio, w // self.ratio)) + return torch.unflatten(r, 0, (b, -1)) + + +class MultiPool(fl.Concatenate): + def __init__(self, pool_ratios: list[int]) -> None: + super().__init__( + *( + fl.Chain( + Pool(pool_ratio), + fl.Flatten(-2, -1), + fl.Permute(0, 3, 1, 2), + ) + for pool_ratio in pool_ratios + ), + dim=1, + ) diff --git a/src/refiners/foundationals/swin/swin_transformer.py b/src/refiners/foundationals/swin/swin_transformer.py new file mode 100644 index 000000000..f1291fead --- /dev/null +++ b/src/refiners/foundationals/swin/swin_transformer.py @@ -0,0 +1,391 @@ +# Swin Transformer (arXiv:2103.14030) +# +# Specific to MVANet, only supports square inputs. +# Originally adapted from the version in MVANet and InSPyReNet (https://github.com/plemeri/InSPyReNet) +# Original implementation by Microsoft at https://github.com/microsoft/Swin-Transformer + +import functools +from math import isqrt + +import torch +from torch import Tensor, device as Device + +import refiners.fluxion.layers as fl +from refiners.fluxion.context import Contexts + + +def to_windows(x: Tensor, window_size: int) -> Tensor: + B, H, W, C = x.shape + assert W == H and H % window_size == 0 + x = x.reshape(B, H // window_size, window_size, W // window_size, window_size, C) + return x.permute(0, 1, 3, 2, 4, 5).reshape(B, -1, window_size * window_size, C) + + +class ToWindows(fl.Module): + def __init__(self, window_size: int): + super().__init__() + self.window_size = window_size + + def forward(self, x: Tensor) -> Tensor: + return to_windows(x, self.window_size) + + +class FromWindows(fl.Module): + def forward(self, x: Tensor) -> Tensor: + B, num_windows, window_size_2, C = x.shape + window_size = isqrt(window_size_2) + H = isqrt(num_windows * window_size_2) + x = x.reshape(B, H // window_size, H // window_size, window_size, window_size, C) + return x.permute(0, 1, 3, 2, 4, 5).reshape(B, H, H, C) + + +@functools.cache +def get_attn_mask(H: int, window_size: int, device: Device | None = None) -> Tensor: + assert H % window_size == 0 + shift_size = window_size // 2 + img_mask = torch.zeros((1, H, H, 1), device=device) + h_slices = ( + slice(0, -window_size), + slice(-window_size, -shift_size), + slice(-shift_size, None), + ) + w_slices = ( + slice(0, -window_size), + slice(-window_size, -shift_size), + slice(-shift_size, None), + ) + cnt = 0 + for h in h_slices: + for w in w_slices: + img_mask[:, h, w, :] = cnt + cnt += 1 + + mask_windows = to_windows(img_mask, window_size).squeeze() # B, nW, window_size * window_size, [1] + attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2) + attn_mask.masked_fill_(attn_mask != 0, -100.0).masked_fill_(attn_mask == 0, 0.0) + return attn_mask + + +class Pad(fl.Module): + def __init__(self, step: int): + super().__init__() + self.step = step + + def forward(self, x: Tensor) -> Tensor: + B, H, W, C = x.shape + assert W == H + if H % self.step == 0: + return x + p = self.step * ((H + self.step - 1) // self.step) + padded = torch.zeros(B, p, p, C, device=x.device, dtype=x.dtype) + padded[:, :H, :H, :] = x + return padded + + +class StatefulPad(fl.Chain): + def __init__(self, context: str, key: str, step: int) -> None: + super().__init__( + fl.SetContext(context=context, key=key, callback=self._push), + Pad(step=step), + ) + + def _push(self, sizes: list[int], x: Tensor) -> None: + sizes.append(x.size(1)) + + +class StatefulUnpad(fl.Chain): + def __init__(self, context: str, key: str) -> None: + super().__init__( + fl.Parallel( + fl.Identity(), + fl.UseContext(context=context, key=key).compose(lambda x: x.pop()), + ), + fl.Lambda(self._unpad), + ) + + @staticmethod + def _unpad(x: Tensor, size: int) -> Tensor: + return x[:, :size, :size, :] + + +class SquareUnflatten(fl.Module): + # ..., L^2, ... -> ..., L, L, ... + + def __init__(self, dim: int = 0) -> None: + super().__init__() + self.dim = dim + + def forward(self, x: Tensor) -> Tensor: + d = isqrt(x.shape[self.dim]) + return torch.unflatten(x, self.dim, (d, d)) + + +class WindowUnflatten(fl.Module): + # ..., H, ... -> ..., H // ws, ws, ... + + def __init__(self, window_size: int, dim: int = 0) -> None: + super().__init__() + self.window_size = window_size + self.dim = dim + + def forward(self, x: Tensor) -> Tensor: + assert x.shape[self.dim] % self.window_size == 0 + H = x.shape[self.dim] + return torch.unflatten(x, self.dim, (H // self.window_size, self.window_size)) + + +class Roll(fl.Module): + def __init__(self, *shifts: tuple[int, int]): + super().__init__() + self.shifts = shifts + self._dims = tuple(s[0] for s in shifts) + self._shifts = tuple(s[1] for s in shifts) + + def forward(self, x: Tensor) -> Tensor: + return torch.roll(x, self._shifts, self._dims) + + +class RelativePositionBias(fl.Module): + relative_position_index: Tensor + + def __init__(self, window_size: int, num_heads: int, device: Device | None = None): + super().__init__() + self.relative_position_bias_table = torch.nn.Parameter( + torch.empty( + (2 * window_size - 1) * (2 * window_size - 1), + num_heads, + device=device, + ) + ) + relative_position_index = torch.empty( + window_size**2, + window_size**2, + device=device, + dtype=torch.int64, + ) + self.register_buffer("relative_position_index", relative_position_index) + + def forward(self) -> Tensor: + # Yes, this is a (trainable) constant. + return self.relative_position_bias_table[self.relative_position_index].permute(2, 0, 1).unsqueeze(0) + + +class WindowSDPA(fl.Module): + def __init__( + self, + dim: int, + window_size: int, + num_heads: int, + shift: bool = False, + device: Device | None = None, + ): + super().__init__() + self.window_size = window_size + self.num_heads = num_heads + self.shift = shift + self.rpb = RelativePositionBias(window_size, num_heads, device=device) + + def forward(self, x: Tensor): + B, num_windows, N, _C = x.shape + assert _C % (3 * self.num_heads) == 0 + C = _C // 3 + x = torch.reshape(x, (B * num_windows, N, 3, self.num_heads, C // self.num_heads)) + q, k, v = x.permute(2, 0, 3, 1, 4) + + attn_mask = self.rpb() + if self.shift: + mask = get_attn_mask(isqrt(num_windows * (self.window_size**2)), self.window_size, x.device) + mask = mask.reshape(1, num_windows, 1, N, N) + mask = mask.expand(B, -1, self.num_heads, -1, -1) + attn_mask = attn_mask + mask.reshape(-1, self.num_heads, N, N) + + x = torch.nn.functional.scaled_dot_product_attention(q, k, v, attn_mask) + x = x.transpose(1, 2).reshape(B, num_windows, N, C) + return x + + +class WindowAttention(fl.Chain): + """ + Window-based Multi-head Self-Attenion (W-MSA), optionally shifted (SW-MSA). + + It has a trainable relative position bias (RelativePositionBias). + + The input projection is stored as a single Linear for q, k and v. + """ + + def __init__( + self, + dim: int, + window_size: int, + num_heads: int, + shift: bool = False, + device: Device | None = None, + ): + super().__init__( + fl.Linear(dim, dim * 3, bias=True, device=device), + WindowSDPA(dim, window_size, num_heads, shift, device=device), + fl.Linear(dim, dim, device=device), + ) + + +class SwinTransformerBlock(fl.Chain): + def __init__( + self, + dim: int, + num_heads: int, + window_size: int = 7, + shift_size: int = 0, + mlp_ratio: float = 4.0, + device: Device | None = None, + ): + assert 0 <= shift_size < window_size, "shift_size must in [0, window_size[" + + super().__init__( + fl.Residual( + fl.LayerNorm(dim, device=device), + SquareUnflatten(1), + StatefulPad(context="padding", key="sizes", step=window_size), + Roll((1, -shift_size), (2, -shift_size)), + ToWindows(window_size), + WindowAttention( + dim, + window_size=window_size, + num_heads=num_heads, + shift=shift_size > 0, + device=device, + ), + FromWindows(), + Roll((1, shift_size), (2, shift_size)), + StatefulUnpad(context="padding", key="sizes"), + fl.Flatten(1, 2), + ), + fl.Residual( + fl.LayerNorm(dim, device=device), + fl.Linear(dim, int(dim * mlp_ratio), device=device), + fl.GeLU(), + fl.Linear(int(dim * mlp_ratio), dim, device=device), + ), + ) + + def init_context(self) -> Contexts: + return {"padding": {"sizes": []}} + + +class PatchMerging(fl.Chain): + def __init__(self, dim: int, device: Device | None = None): + super().__init__( + SquareUnflatten(1), + Pad(2), + WindowUnflatten(2, 2), + WindowUnflatten(2, 1), + fl.Permute(0, 1, 3, 4, 2, 5), + fl.Flatten(3), + fl.Flatten(1, 2), + fl.LayerNorm(4 * dim, device=device), + fl.Linear(4 * dim, 2 * dim, bias=False, device=device), + ) + + +class BasicLayer(fl.Chain): + def __init__( + self, + dim: int, + depth: int, + num_heads: int, + window_size: int = 7, + mlp_ratio: float = 4.0, + device: Device | None = None, + ): + super().__init__( + SwinTransformerBlock( + dim=dim, + num_heads=num_heads, + window_size=window_size, + shift_size=0 if (i % 2 == 0) else window_size // 2, + mlp_ratio=mlp_ratio, + device=device, + ) + for i in range(depth) + ) + + +class PatchEmbedding(fl.Chain): + def __init__( + self, + patch_size: tuple[int, int] = (4, 4), + in_chans: int = 3, + embedding_dim: int = 96, + device: Device | None = None, + ): + super().__init__( + fl.Conv2d(in_chans, embedding_dim, kernel_size=patch_size, stride=patch_size, device=device), + fl.Flatten(2), + fl.Transpose(1, 2), + fl.LayerNorm(embedding_dim, device=device), + ) + + +class SwinTransformer(fl.Chain): + """Swin Transformer (arXiv:2103.14030) + + Currently specific to MVANet, only supports square inputs. + """ + + def __init__( + self, + patch_size: tuple[int, int] = (4, 4), + in_chans: int = 3, + embedding_dim: int = 96, + depths: list[int] | None = None, + num_heads: list[int] | None = None, + window_size: int = 7, # image size is 32 * this + mlp_ratio: float = 4.0, + device: Device | None = None, + ): + if depths is None: + depths = [2, 2, 6, 2] + + if num_heads is None: + num_heads = [3, 6, 12, 24] + + self.num_layers = len(depths) + assert len(num_heads) == self.num_layers + + super().__init__( + PatchEmbedding( + patch_size=patch_size, + in_chans=in_chans, + embedding_dim=embedding_dim, + device=device, + ), + fl.Passthrough( + fl.Transpose(1, 2), + SquareUnflatten(2), + fl.SetContext("swin", "outputs", callback=lambda t, x: t.append(x)), + ), + *( + fl.Chain( + BasicLayer( + dim=int(embedding_dim * 2**i), + depth=depths[i], + num_heads=num_heads[i], + window_size=window_size, + mlp_ratio=mlp_ratio, + device=device, + ), + fl.Passthrough( + fl.LayerNorm(int(embedding_dim * 2**i), device=device), + fl.Transpose(1, 2), + SquareUnflatten(2), + fl.SetContext("swin", "outputs", callback=lambda t, x: t.insert(0, x)), + ), + PatchMerging(dim=int(embedding_dim * 2**i), device=device) + if i < self.num_layers - 1 + else fl.UseContext("swin", "outputs").compose(lambda t: tuple(t)), + ) + for i in range(self.num_layers) + ), + ) + + def init_context(self) -> Contexts: + return {"swin": {"outputs": []}} diff --git a/tests/e2e/test_mvanet.py b/tests/e2e/test_mvanet.py new file mode 100644 index 000000000..08a47ad02 --- /dev/null +++ b/tests/e2e/test_mvanet.py @@ -0,0 +1,59 @@ +from pathlib import Path +from warnings import warn + +import pytest +import torch +from PIL import Image +from tests.utils import ensure_similar_images + +from refiners.fluxion.utils import image_to_tensor, no_grad, normalize, tensor_to_image +from refiners.foundationals.swin.mvanet import MVANet + + +def _img_open(path: Path) -> Image.Image: + return Image.open(path) # type: ignore + + +@pytest.fixture(scope="module") +def ref_path(test_e2e_path: Path) -> Path: + return test_e2e_path / "test_mvanet_ref" + + +@pytest.fixture(scope="module") +def ref_cactus(ref_path: Path) -> Image.Image: + return _img_open(ref_path / "cactus.png").convert("RGB") + + +@pytest.fixture +def expected_cactus_mask(ref_path: Path) -> Image.Image: + return _img_open(ref_path / "expected_cactus_mask.png") + + +@pytest.fixture(scope="module") +def mvanet_weights(test_weights_path: Path) -> Path: + weights = test_weights_path / "mvanet" / "mvanet.safetensors" + if not weights.is_file(): + warn(f"could not find weights at {test_weights_path}, skipping") + pytest.skip(allow_module_level=True) + return weights + + +@pytest.fixture +def mvanet_model(mvanet_weights: Path, test_device: torch.device) -> MVANet: + model = MVANet(device=test_device).eval() # .eval() is important! + model.load_from_safetensors(mvanet_weights) + return model + + +@no_grad() +def test_mvanet( + mvanet_model: MVANet, + ref_cactus: Image.Image, + expected_cactus_mask: Image.Image, + test_device: torch.device, +): + in_t = image_to_tensor(ref_cactus.resize((1024, 1024), Image.Resampling.BILINEAR)).squeeze() + in_t = normalize(in_t, [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]).unsqueeze(0) + prediction: torch.Tensor = mvanet_model(in_t.to(test_device)).sigmoid() + cactus_mask = tensor_to_image(prediction).resize(ref_cactus.size, Image.Resampling.BILINEAR) + ensure_similar_images(cactus_mask.convert("RGB"), expected_cactus_mask.convert("RGB")) diff --git a/tests/e2e/test_mvanet_ref/README.md b/tests/e2e/test_mvanet_ref/README.md new file mode 100644 index 000000000..687f9f8f0 --- /dev/null +++ b/tests/e2e/test_mvanet_ref/README.md @@ -0,0 +1,3 @@ +`cactus.png` is cropped from this image: https://www.freepik.com/free-photo/laptop-notebook-pen-coffee-cup-plants-wooden-desk_269339828.htm + +`expected_cactus_mask.png` has been generated using the [official MVANet codebase](https://github.com/qianyu-dlut/MVANet) and weights. diff --git a/tests/e2e/test_mvanet_ref/cactus.png b/tests/e2e/test_mvanet_ref/cactus.png new file mode 100644 index 0000000000000000000000000000000000000000..b917acb7d1aab66e996f94a49da8e152f72d5270 GIT binary patch literal 98012 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�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
J>|pR(AvtJZF*yB>-qe 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 str: ...