From 4a9dfa43541d6ca93d609de35125be1522d0d84f Mon Sep 17 00:00:00 2001 From: rangoliu Date: Mon, 6 Mar 2023 17:28:40 +0800 Subject: [PATCH 01/39] [Fix] Fix disco inference (#1673) fix inference bug --- configs/disco_diffusion/README.md | 2 +- configs/disco_diffusion/metafile.yml | 7 +++---- demo/mmediting_inference_tutorial.ipynb | 22 +++++++++++++------- mmedit/apis/inferencers/mmedit_inferencer.py | 4 +++- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/configs/disco_diffusion/README.md b/configs/disco_diffusion/README.md index 1a1cbf1ebc..dcd9ff98aa 100644 --- a/configs/disco_diffusion/README.md +++ b/configs/disco_diffusion/README.md @@ -2,7 +2,7 @@ > [Disco Diffusion](https://github.com/alembics/disco-diffusion) -> **Task**: Text2Image, Image2Image, diffusion +> **Task**: Text2Image, Image2Image diff --git a/configs/disco_diffusion/metafile.yml b/configs/disco_diffusion/metafile.yml index 96f2b8d47a..e3fb1f0fc8 100644 --- a/configs/disco_diffusion/metafile.yml +++ b/configs/disco_diffusion/metafile.yml @@ -7,7 +7,6 @@ Collections: Task: - text2image - image2image - - diffusion Year: 2022 Models: - Config: configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py @@ -16,7 +15,7 @@ Models: Results: - Dataset: ImageNet Metrics: {} - Task: Text2Image, Image2Image, diffusion + Task: Text2Image, Image2Image Weights: https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u_finetuned_imagenet-512x512-ab471d70.pth - Config: configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-256x256.py In Collection: Disco Diffusion @@ -24,7 +23,7 @@ Models: Results: - Dataset: ImageNet Metrics: {} - Task: Text2Image, Image2Image, diffusion + Task: Text2Image, Image2Image Weights: <> - Config: configs/disco_diffusion/disco-diffusion_portrait-generator-v001.py In Collection: Disco Diffusion @@ -32,5 +31,5 @@ Models: Results: - Dataset: unknown Metrics: {} - Task: Text2Image, Image2Image, diffusion + Task: Text2Image, Image2Image Weights: https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u-cvt-rgb_portrait-v001-f4a3f3bc.pth diff --git a/demo/mmediting_inference_tutorial.ipynb b/demo/mmediting_inference_tutorial.ipynb index 96c2fdfee4..72595185fc 100644 --- a/demo/mmediting_inference_tutorial.ipynb +++ b/demo/mmediting_inference_tutorial.ipynb @@ -1162,18 +1162,27 @@ "name": "stdout", "output_type": "stream", "text": [ + "02/28 11:34:29 - mmengine - INFO - Creating ViT-B/32 by OpenAI\n", + "02/28 11:34:32 - mmengine - INFO - Creating ViT-B/16 by OpenAI\n", + "02/28 11:34:35 - mmengine - INFO - Creating RN50 by OpenAI\n", "Setting up [LPIPS] perceptual loss: trunk [vgg], v[0.1], spatial [off]\n", - "Loading model from: /nvme/liuwenran/miniconda3/envs/mmedit/lib/python3.8/site-packages/lpips/weights/v0.1/vgg.pth\n", + "Loading model from: /nvme/liuwenran/miniconda3/envs/dev-sd/lib/python3.8/site-packages/lpips/weights/v0.1/vgg.pth\n", "Loads checkpoint by http backend from path: https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u_finetuned_imagenet-512x512-ab471d70.pth\n", "Load pretrained unet from https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u_finetuned_imagenet-512x512-ab471d70.pth\n", "Loads checkpoint by http backend from path: https://download.openmmlab.com/mmediting/synthesizers/disco/secondary_model_imagenet_2.pth\n", "Load pretrained secondary_model from https://download.openmmlab.com/mmediting/synthesizers/disco/secondary_model_imagenet_2.pth\n", - "Convert unet modules to floatpoint16\n" + "Convert unet modules to floatpoint16\n", + "Loads checkpoint by http backend from path: https://download.openmmlab.com/mmediting/synthesizers/disco/adm-u_finetuned_imagenet-512x512-ab471d70.pth\n", + "The model and loaded state dict do not match exactly\n", + "\n", + "missing keys in source state_dict: guider.lpips_model.scaling_layer.shift, guider.lpips_model.scaling_layer.scale, guider.lpips_model.net.slice1.0.weight, guider.lpips_model.net.slice1.0.bias, guider.lpips_model.net.slice1.2.weight, guider.lpips_model.net.slice1.2.bias, guider.lpips_model.net.slice2.5.weight, guider.lpips_model.net.slice2.5.bias, guider.lpips_model.net.slice2.7.weight, guider.lpips_model.net.slice2.7.bias, guider.lpips_model.net.slice3.10.weight, guider.lpips_model.net.slice3.10.bias, guider.lpips_model.net.slice3.12.weight, guider.lpips_model.net.slice3.12.bias, guider.lpips_model.net.slice3.14.weight, guider.lpips_model.net.slice3.14.bias, guider.lpips_model.net.slice4.17.weight, guider.lpips_model.net.slice4.17.bias, guider.lpips_model.net.slice4.19.weight, guider.lpips_model.net.slice4.19.bias, guider.lpips_model.net.slice4.21.weight, guider.lpips_model.net.slice4.21.bias, guider.lpips_model.net.slice5.24.weight, guider.lpips_model.net.slice5.24.bias, guider.lpips_model.net.slice5.26.weight, guider.lpips_model.net.slice5.26.bias, guider.lpips_model.net.slice5.28.weight, guider.lpips_model.net.slice5.28.bias, guider.lpips_model.lin0.model.1.weight, guider.lpips_model.lin1.model.1.weight, guider.lpips_model.lin2.model.1.weight, guider.lpips_model.lin3.model.1.weight, guider.lpips_model.lin4.model.1.weight, guider.lpips_model.lins.0.model.1.weight, guider.lpips_model.lins.1.model.1.weight, guider.lpips_model.lins.2.model.1.weight, guider.lpips_model.lins.3.model.1.weight, guider.lpips_model.lins.4.model.1.weight, secondary_model.timestep_embed.weight, secondary_model.net.0.0.weight, secondary_model.net.0.0.bias, secondary_model.net.1.0.weight, secondary_model.net.1.0.bias, secondary_model.net.2.main.1.0.weight, secondary_model.net.2.main.1.0.bias, secondary_model.net.2.main.2.0.weight, secondary_model.net.2.main.2.0.bias, secondary_model.net.2.main.3.main.1.0.weight, secondary_model.net.2.main.3.main.1.0.bias, secondary_model.net.2.main.3.main.2.0.weight, secondary_model.net.2.main.3.main.2.0.bias, secondary_model.net.2.main.3.main.3.main.1.0.weight, secondary_model.net.2.main.3.main.3.main.1.0.bias, secondary_model.net.2.main.3.main.3.main.2.0.weight, secondary_model.net.2.main.3.main.3.main.2.0.bias, secondary_model.net.2.main.3.main.3.main.3.main.1.0.weight, secondary_model.net.2.main.3.main.3.main.3.main.1.0.bias, secondary_model.net.2.main.3.main.3.main.3.main.2.0.weight, secondary_model.net.2.main.3.main.3.main.3.main.2.0.bias, secondary_model.net.2.main.3.main.3.main.3.main.3.main.1.0.weight, secondary_model.net.2.main.3.main.3.main.3.main.3.main.1.0.bias, secondary_model.net.2.main.3.main.3.main.3.main.3.main.2.0.weight, secondary_model.net.2.main.3.main.3.main.3.main.3.main.2.0.bias, secondary_model.net.2.main.3.main.3.main.3.main.3.main.3.0.weight, secondary_model.net.2.main.3.main.3.main.3.main.3.main.3.0.bias, secondary_model.net.2.main.3.main.3.main.3.main.3.main.4.0.weight, secondary_model.net.2.main.3.main.3.main.3.main.3.main.4.0.bias, secondary_model.net.2.main.3.main.3.main.3.main.4.0.weight, secondary_model.net.2.main.3.main.3.main.3.main.4.0.bias, secondary_model.net.2.main.3.main.3.main.3.main.5.0.weight, secondary_model.net.2.main.3.main.3.main.3.main.5.0.bias, secondary_model.net.2.main.3.main.3.main.4.0.weight, secondary_model.net.2.main.3.main.3.main.4.0.bias, secondary_model.net.2.main.3.main.3.main.5.0.weight, secondary_model.net.2.main.3.main.3.main.5.0.bias, secondary_model.net.2.main.3.main.4.0.weight, secondary_model.net.2.main.3.main.4.0.bias, secondary_model.net.2.main.3.main.5.0.weight, secondary_model.net.2.main.3.main.5.0.bias, secondary_model.net.2.main.4.0.weight, secondary_model.net.2.main.4.0.bias, secondary_model.net.2.main.5.0.weight, secondary_model.net.2.main.5.0.bias, secondary_model.net.3.0.weight, secondary_model.net.3.0.bias, secondary_model.net.4.weight, secondary_model.net.4.bias\n", + "\n", + "02/28 11:34:41 - mmengine - WARNING - Failed to search registry with scope \"mmedit\" in the \"Collate Functions\" registry tree. As a workaround, the current \"Collate Functions\" registry in \"mmengine\" is used to build instance. This may cause unexpected failure when running the built modules. Please check whether \"mmedit\" is a correct scope, or whether the registry is initialized.\n" ] }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -1186,10 +1195,9 @@ "import mmcv\n", "import matplotlib.pyplot as plt \n", "from mmedit.edit import MMEdit\n", - "from mmengine import mkdir_or_exist\n", "\n", "# Create a MMEdit instance and infer\n", - "editor = MMEdit(model_name='disco')\n", + "editor = MMEdit(model_name='disco_diffusion')\n", "text_prompts = {\n", " 0: [\n", " 'clouds surround the mountains and Chinese palaces,sunshine,lake,overlook,overlook,unreal engine,light effect,Dream,Greg Rutkowski,James Gurney,artstation'\n", @@ -1207,7 +1215,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3.8.15 ('mmedit')", + "display_name": "dev-sd", "language": "python", "name": "python3" }, @@ -1226,7 +1234,7 @@ "orig_nbformat": 4, "vscode": { "interpreter": { - "hash": "47c665e53b75451c1dff53c40a25ed4e9f485a1a46eacd0e608af5fccd511a1c" + "hash": "d7e6c97a1f3313226c2da85dd83e85417c7b1e4ab07fe1dc506eecff36b257e7" } } }, diff --git a/mmedit/apis/inferencers/mmedit_inferencer.py b/mmedit/apis/inferencers/mmedit_inferencer.py index 0da98016aa..a05de7095c 100644 --- a/mmedit/apis/inferencers/mmedit_inferencer.py +++ b/mmedit/apis/inferencers/mmedit_inferencer.py @@ -64,7 +64,9 @@ def __init__(self, elif self.task in ['video_interpolation', 'Video Interpolation']: self.inferencer = VideoInterpolationInferencer( config, ckpt, device, extra_parameters) - elif self.task in ['text2image', 'Text2Image']: + elif self.task in [ + 'text2image', 'Text2Image', 'Text2Image, Image2Image' + ]: self.inferencer = Text2ImageInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['3D_aware_generation', '3D-aware Generation']: From 50b73fb42f35f6c8221e8e8c0d22c9bd97e5c738 Mon Sep 17 00:00:00 2001 From: Yanhong Zeng Date: Thu, 9 Mar 2023 17:47:01 +0800 Subject: [PATCH 02/39] [Feature] register models and scheduelrs from diffusers (#1692) * register models and schedulers from diffusers * remove extension * rename registered models and scheduelrs to modulename * use try-import to register diffusers modules * fix ut * - * fix ut * update docstring per review --- ...fusion_adm-u-finetuned_imagenet-256x256.py | 2 +- ...fusion_adm-u-finetuned_imagenet-512x512.py | 2 +- .../stable-diffusion_ddim_denoisingunet.py | 2 +- mmedit/models/base_archs/__init__.py | 36 +++++++++++++ .../models/diffusion_schedulers/__init__.py | 48 ++++++++++++++++++ .../ddim_scheduler.py | 6 +-- .../ddpm_scheduler.py | 4 +- mmedit/models/editors/__init__.py | 8 ++- mmedit/models/editors/ddim/__init__.py | 4 -- mmedit/models/editors/ddpm/__init__.py | 3 +- mmedit/registry.py | 2 +- requirements/runtime.txt | 1 + tests/data/video_interpolation_result.mp4 | Bin 0 -> 14050 bytes .../test_text2image_inferencers.py | 5 +- .../test_ddim_scheduler.py | 14 ++--- .../test_ddpm/test_ddpm_scheduler.py | 12 ++--- .../test_disco_diffusion.py | 5 +- .../test_guided_diffusion/test_adm.py | 4 +- .../test_stable_diffusion.py | 2 +- 19 files changed, 120 insertions(+), 40 deletions(-) create mode 100644 mmedit/models/diffusion_schedulers/__init__.py rename mmedit/models/{editors/ddim => diffusion_schedulers}/ddim_scheduler.py (98%) rename mmedit/models/{editors/ddpm => diffusion_schedulers}/ddpm_scheduler.py (98%) delete mode 100644 mmedit/models/editors/ddim/__init__.py create mode 100644 tests/data/video_interpolation_result.mp4 rename tests/test_models/{test_editors/test_ddim => test_diffusion_schedulers}/test_ddim_scheduler.py (78%) diff --git a/configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-256x256.py b/configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-256x256.py index b92c3c6be3..84c88cfd9b 100644 --- a/configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-256x256.py +++ b/configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-256x256.py @@ -26,7 +26,7 @@ secondary_model = dict(type='SecondaryDiffusionImageNet2') diffusion_scheduler = dict( - type='DDIMScheduler', + type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='linear', clip_sample=False) diff --git a/configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py b/configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py index f839a5a7b6..b63b26c616 100644 --- a/configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py +++ b/configs/disco_diffusion/disco-diffusion_adm-u-finetuned_imagenet-512x512.py @@ -26,7 +26,7 @@ secondary_model = dict(type='SecondaryDiffusionImageNet2') diffusion_scheduler = dict( - type='DDIMScheduler', + type='EditDDIMScheduler', variance_type='learned_range', beta_schedule='linear', clip_sample=False) diff --git a/configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py b/configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py index e83921f4d7..489ff00a57 100644 --- a/configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py +++ b/configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py @@ -38,7 +38,7 @@ ]) diffusion_scheduler = dict( - type='DDIMScheduler', + type='EditDDIMScheduler', variance_type='learned_range', beta_end=0.012, beta_schedule='scaled_linear', diff --git a/mmedit/models/base_archs/__init__.py b/mmedit/models/base_archs/__init__.py index 30b0ec3002..22585ee445 100644 --- a/mmedit/models/base_archs/__init__.py +++ b/mmedit/models/base_archs/__init__.py @@ -1,5 +1,9 @@ # Copyright (c) OpenMMLab. All rights reserved. # To register Deconv +import warnings +from typing import List + +from mmedit.utils import try_import from .all_gather_layer import AllGatherLayer from .aspp import ASPP from .conv import * # noqa: F401, F403 @@ -19,6 +23,38 @@ from .upsample import PixelShufflePack from .vgg import VGG16 + +def register_diffusers_models() -> List[str]: + """Register models in ``diffusers.models`` to the ``MODELS`` registry. + Specifically, the registered models from diffusers only defines the network + forward without training. See more details about diffusers in: + https://huggingface.co/docs/diffusers/api/models. + + Returns: + List[str]: A list of registered DIFFUSION_MODELS' name. + """ + import inspect + + from mmedit.registry import MODELS + + diffusers = try_import('diffusers') + if diffusers is None: + warnings.warn('Diffusion Models are not registered as expect. ' + 'If you want to use diffusion models, ' + 'please install diffusers>=0.12.0.') + return None + + DIFFUSERS_MODELS = [] + for module_name in dir(diffusers.models): + module = getattr(diffusers.models, module_name) + if inspect.isclass(module): + MODELS.register_module(name=module_name, module=module) + DIFFUSERS_MODELS.append(module_name) + return DIFFUSERS_MODELS + + +REGISTERED_DIFFUSERS_MODELS = register_diffusers_models() + __all__ = [ 'ASPP', 'DepthwiseSeparableConvModule', 'SimpleGatedConvModule', 'LinearModule', 'conv2d', 'conv_transpose2d', 'pixel_unshuffle', diff --git a/mmedit/models/diffusion_schedulers/__init__.py b/mmedit/models/diffusion_schedulers/__init__.py new file mode 100644 index 0000000000..8e81e1a670 --- /dev/null +++ b/mmedit/models/diffusion_schedulers/__init__.py @@ -0,0 +1,48 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import warnings +from typing import List + +from mmedit.utils import try_import +from .ddim_scheduler import EditDDIMScheduler +from .ddpm_scheduler import EditDDPMScheduler + + +def register_diffusers_schedulers() -> List[str]: + """Register schedulers in ``diffusers.schedulers`` to the + ``DIFFUSION_SCHEDULERS`` registry. Specifically, the registered schedulers + from diffusers define the methodology for iteratively adding noise to an + image or for updating a sample based on model outputs. See more details + about schedulers in diffusers here: + https://huggingface.co/docs/diffusers/api/schedulers/overview. + + Returns: + List[str]: A list of registered DIFFUSION_SCHEDULERS' name. + """ + + import inspect + + from mmedit.registry import DIFFUSION_SCHEDULERS + + diffusers = try_import('diffusers') + if diffusers is None: + warnings.warn('Diffusion Schedulers are not registered as expect. ' + 'If you want to use diffusion models, ' + 'please install diffusers>=0.12.0.') + return None + + DIFFUSERS_SCHEDULERS = [] + for module_name in dir(diffusers.schedulers): + if module_name.startswith('Flax'): + continue + elif module_name.endswith('Scheduler'): + _scheduler = getattr(diffusers.schedulers, module_name) + if inspect.isclass(_scheduler): + DIFFUSION_SCHEDULERS.register_module( + name=module_name, module=_scheduler) + DIFFUSERS_SCHEDULERS.append(module_name) + return DIFFUSERS_SCHEDULERS + + +REGISTERED_DIFFUSERS_SCHEDULERS = register_diffusers_schedulers() + +__all__ = ['EditDDIMScheduler', 'EditDDPMScheduler'] diff --git a/mmedit/models/editors/ddim/ddim_scheduler.py b/mmedit/models/diffusion_schedulers/ddim_scheduler.py similarity index 98% rename from mmedit/models/editors/ddim/ddim_scheduler.py rename to mmedit/models/diffusion_schedulers/ddim_scheduler.py index 13dd9506d2..a4948267b9 100644 --- a/mmedit/models/editors/ddim/ddim_scheduler.py +++ b/mmedit/models/diffusion_schedulers/ddim_scheduler.py @@ -9,9 +9,9 @@ @DIFFUSION_SCHEDULERS.register_module() -class DDIMScheduler: - """```DDIMScheduler``` support the diffusion and reverse process formulated - in https://arxiv.org/abs/2010.02502. +class EditDDIMScheduler: + """```EditDDIMScheduler``` support the diffusion and reverse process + formulated in https://arxiv.org/abs/2010.02502. The code is heavily influenced by https://github.com/huggingface/diffusers/blob/main/src/diffusers/schedulers/scheduling_ddim.py. # noqa The difference is that we ensemble gradient-guided sampling in step function. diff --git a/mmedit/models/editors/ddpm/ddpm_scheduler.py b/mmedit/models/diffusion_schedulers/ddpm_scheduler.py similarity index 98% rename from mmedit/models/editors/ddpm/ddpm_scheduler.py rename to mmedit/models/diffusion_schedulers/ddpm_scheduler.py index b1f52da8cd..0047020c2d 100644 --- a/mmedit/models/editors/ddpm/ddpm_scheduler.py +++ b/mmedit/models/diffusion_schedulers/ddpm_scheduler.py @@ -9,7 +9,7 @@ @DIFFUSION_SCHEDULERS.register_module() -class DDPMScheduler: +class EditDDPMScheduler: def __init__(self, num_train_timesteps: int = 1000, @@ -19,7 +19,7 @@ def __init__(self, trained_betas: Optional[Union[np.array, list]] = None, variance_type='fixed_small', clip_sample=True): - """```DDPMScheduler``` support the diffusion and reverse process + """```EditDDPMScheduler``` support the diffusion and reverse process formulated in https://arxiv.org/abs/2006.11239. The code is heavily influenced by https://github.com/huggingface/diffusers/blob/main/src/diffusers/schedulers/scheduling_ddpm.py. # noqa diff --git a/mmedit/models/editors/__init__.py b/mmedit/models/editors/__init__.py index b1add6f756..fdb6702b8e 100644 --- a/mmedit/models/editors/__init__.py +++ b/mmedit/models/editors/__init__.py @@ -7,8 +7,7 @@ from .cain import CAIN, CAINNet from .cyclegan import CycleGAN from .dcgan import DCGAN -from .ddim import DDIMScheduler -from .ddpm import DDPMScheduler, DenoisingUnet +from .ddpm import DenoisingUnet from .deepfillv1 import (ContextualAttentionModule, ContextualAttentionNeck, DeepFillDecoder, DeepFillEncoder, DeepFillRefiner, DeepFillv1Discriminators, DeepFillv1Inpaintor) @@ -85,7 +84,6 @@ 'ProgressiveGrowingGAN', 'SinGAN', 'AblatedDiffusionModel', 'DiscoDiffusion', 'IDLossModel', 'PESinGAN', 'MSPIEStyleGAN2', 'StyleGAN3Generator', 'InstColorization', 'NAFBaseline', - 'NAFBaselineLocal', 'NAFNet', 'NAFNetLocal', 'DDIMScheduler', - 'DDPMScheduler', 'DenoisingUnet', 'ClipWrapper', 'EG3D', 'Restormer', - 'SwinIRNet', 'StableDiffusion' + 'NAFBaselineLocal', 'NAFNet', 'NAFNetLocal', 'DenoisingUnet', + 'ClipWrapper', 'EG3D', 'Restormer', 'SwinIRNet', 'StableDiffusion' ] diff --git a/mmedit/models/editors/ddim/__init__.py b/mmedit/models/editors/ddim/__init__.py deleted file mode 100644 index 4b14e89b77..0000000000 --- a/mmedit/models/editors/ddim/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from .ddim_scheduler import DDIMScheduler - -__all__ = ['DDIMScheduler'] diff --git a/mmedit/models/editors/ddpm/__init__.py b/mmedit/models/editors/ddpm/__init__.py index 2b94f11031..a8c27b30ce 100644 --- a/mmedit/models/editors/ddpm/__init__.py +++ b/mmedit/models/editors/ddpm/__init__.py @@ -1,5 +1,4 @@ # Copyright (c) OpenMMLab. All rights reserved. -from .ddpm_scheduler import DDPMScheduler from .denoising_unet import DenoisingUnet -__all__ = ['DDPMScheduler', 'DenoisingUnet'] +__all__ = ['DenoisingUnet'] diff --git a/mmedit/registry.py b/mmedit/registry.py index 8c505c469c..38c3dace11 100644 --- a/mmedit/registry.py +++ b/mmedit/registry.py @@ -155,7 +155,7 @@ # modules for diffusion models that support adding noise and denoising DIFFUSION_SCHEDULERS = Registry( 'diffusion scheduler', - locations=['mmedit.models'], + locations=['mmedit.models.diffusion_schedulers'], ) ####################################################################### diff --git a/requirements/runtime.txt b/requirements/runtime.txt index d98b318732..46b6bede70 100644 --- a/requirements/runtime.txt +++ b/requirements/runtime.txt @@ -1,5 +1,6 @@ av av==8.0.3; python_version < '3.7' +diffusers>=0.12.0 einops face-alignment facexlib diff --git a/tests/data/video_interpolation_result.mp4 b/tests/data/video_interpolation_result.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..8770abcb2303d85c4f8cfe149587a06bed1d23ca GIT binary patch literal 14050 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 Date: Thu, 9 Mar 2023 17:56:49 +0800 Subject: [PATCH 03/39] [Fix] Fix ValSampler error when use EditValLoop (#1691) * fix ValSampler error when use EditValLoop * revise unit test of GenVisHook --- mmedit/utils/sampler.py | 15 ++++-- .../test_hooks/test_visualization_hook.py | 3 +- tests/test_utils/test_sampler.py | 49 ++++++++++++++++++- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/mmedit/utils/sampler.py b/mmedit/utils/sampler.py index 436963f2de..8cb8ab566d 100644 --- a/mmedit/utils/sampler.py +++ b/mmedit/utils/sampler.py @@ -4,7 +4,7 @@ from mmengine.dataset import pseudo_collate from mmengine.runner import Runner -from torch.utils.data.dataloader import DataLoader +from torch.utils.data import ConcatDataset, DataLoader def _check_keys(sample_kwargs: dict, key: str) -> None: @@ -124,7 +124,7 @@ def __next__(self): class ValDataSampler: - """Sampler loop the train_dataloader.""" + """Sampler loop the val_dataloader.""" def __init__(self, sample_kwargs: dict, runner: Runner) -> None: _check_keys(sample_kwargs, 'max_times') @@ -134,8 +134,15 @@ def __init__(self, sample_kwargs: dict, runner: Runner) -> None: # build a new vanilla dataloader, because we should not reset the one # used in the training process. - dataset = runner.val_dataloader.dataset - batch_size = runner.val_dataloader.batch_size + if hasattr(runner.val_loop, 'dataloader'): + dataset = runner.val_loop.dataloader.dataset + batch_size = runner.val_loop.dataloader.batch_size + else: + # EditValLoop use `dataloaders` instead `dataloader` + loaders = runner.val_loop.dataloaders + dataset = ConcatDataset([loader.dataset for loader in loaders]) + batch_size = loaders[0].batch_size + self._dataloader = DataLoader( dataset, batch_size=batch_size, collate_fn=pseudo_collate) self._iterator = iter(self._dataloader) diff --git a/tests/test_engine/test_hooks/test_visualization_hook.py b/tests/test_engine/test_hooks/test_visualization_hook.py index b839ca1329..1d5bde0035 100644 --- a/tests/test_engine/test_hooks/test_visualization_hook.py +++ b/tests/test_engine/test_hooks/test_visualization_hook.py @@ -208,7 +208,8 @@ def __getitem__(self, index): runner = MagicMock() runner.model = model runner.train_dataloader = train_dataloader - runner.val_dataloader = val_dataloader + runner.val_loop = MagicMock() + runner.val_loop.dataloader = val_dataloader hook = GenVisualizationHook( interval=10, diff --git a/tests/test_utils/test_sampler.py b/tests/test_utils/test_sampler.py index e72cb3d5cf..8173a8d7c3 100644 --- a/tests/test_utils/test_sampler.py +++ b/tests/test_utils/test_sampler.py @@ -1,5 +1,9 @@ # Copyright (c) OpenMMLab. All rights reserved. -from mmedit.utils.sampler import ArgumentsSampler +from unittest.mock import MagicMock + +from torch.utils.data import DataLoader + +from mmedit.utils.sampler import ArgumentsSampler, ValDataSampler def test_argument_sampler(): @@ -15,3 +19,46 @@ def test_argument_sampler(): for sample in sampler: assert 'inputs' in sample assert sample['inputs'] == dict(forward_mode='gen', num_batches=2) + + +class MockDataset(): + + def __init__(self, length): + self.length = length + + def __getitem__(self, idx): + return idx + + def __len__(self): + return self.length + + +class MockValLoop(): + + def __init__(self): + self.dataloaders = None + + +def test_val_data_sampler(): + runner = MagicMock() + val_loop = MockValLoop() + val_loop.dataloaders = [ + DataLoader(MockDataset(10), batch_size=4), + DataLoader(MockDataset(5), batch_size=4) + ] + # val_loop.dataloader = None + runner.val_loop = val_loop + + val_sampler = ValDataSampler( + sample_kwargs=dict(max_times=10), runner=runner) + assert len(val_sampler._dataloader.dataset) == 15 + tar_out = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 0, 1], [2, 3, 4]] + for idx, out in enumerate(val_sampler): + assert out == tar_out[idx] + + setattr(val_loop, 'dataloader', DataLoader(MockDataset(8), batch_size=4)) + val_sampler = ValDataSampler( + sample_kwargs=dict(max_times=10), runner=runner) + assert len(val_sampler._dataloader.dataset) == 8 + for idx, out in enumerate(val_sampler): + assert out == tar_out[idx] From c7bf4028b50d091c7626773748cb0d4b026ac7c4 Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Mon, 13 Mar 2023 16:06:58 +0800 Subject: [PATCH 04/39] [Enhancement] Simplify EditLogProcessor and corresponding unit test (#1694) simplify EditLogProcessor and corresponding unit test --- mmedit/engine/runner/log_processor.py | 170 +---------- .../test_runner/test_log_processor.py | 268 +----------------- 2 files changed, 20 insertions(+), 418 deletions(-) diff --git a/mmedit/engine/runner/log_processor.py b/mmedit/engine/runner/log_processor.py index f53947b9a8..f59894a94c 100644 --- a/mmedit/engine/runner/log_processor.py +++ b/mmedit/engine/runner/log_processor.py @@ -1,9 +1,4 @@ # Copyright (c) OpenMMLab. All rights reserved. -import copy -import datetime -from typing import Tuple - -import torch from mmengine.registry import LOG_PROCESSORS from mmengine.runner import LogProcessor @@ -14,164 +9,23 @@ class EditLogProcessor(LogProcessor): overwrites :meth:`self.get_log_after_iter`. This log processor should be used along with - :class:`mmedit.engine.runner.GenValLoop` and - :class:`mmedit.engine.runner.GenTestLoop`. + :class:`mmedit.engine.runner.EditValLoop` and + :class:`mmedit.engine.runner.EditTestLoop`. """ - def get_log_after_iter(self, runner, batch_idx: int, - mode: str) -> Tuple[dict, str]: - """Format log string after training, validation or testing epoch. - - If `mode` is in 'val' or 'test', we use `runner.val_loop.total_length` - and `runner.test_loop.total_length` as the total number of iterations - shown in log. If you want to know how `total_length` is calculated, - please refers to :meth:`mmedit.engine.runner.GenValLoop.run` and - :meth:`mmedit.engine.runner.GenTestLoop.run`. + def _get_dataloader_size(self, runner, mode) -> int: + """Get dataloader size of current loop. In `EditValLoop` and + `EditTestLoop`, we use `total_length` instead of `len(dataloader)` to + denote the total number of iterations. Args: - runner (Runner): The runner of training phase. - batch_idx (int): The index of the current batch in the current - loop. - mode (str): Current mode of runner, train, test or val. - Return: - Tuple(dict, str): Formatted log dict/string which will be - recorded by :obj:`runner.message_hub` and - :obj:`runner.visualizer`. - """ - assert mode in ['train', 'test', 'val'] - if mode == 'train': - return super().get_log_after_iter(runner, batch_idx, 'train') - - # use our own defined method in test and val mode - - current_loop = self._get_cur_loop(runner, mode) - cur_iter = self._get_iter(runner, batch_idx=batch_idx) - # Overwrite ``window_size`` defined in ``custom_cfg`` to int value. - custom_cfg_copy = self._parse_windows_size(runner, batch_idx) - # tag is used to write log information to different backends. - tag = self._collect_scalars(custom_cfg_copy, runner, mode) - # `log_tag` will pop 'lr' and loop other keys to `log_str`. - log_tag = copy.deepcopy(tag) - # Record learning rate. - lr_str_list = [] - for key, value in tag.items(): - if key.startswith('lr'): - log_tag.pop(key) - lr_str_list.append(f'{key}: {value:.{self.num_digits}e}') - lr_str = ' '.join(lr_str_list) - # Format log header. - # by_epoch == True - # train/val: Epoch [5][5/10] ... - # test: Epoch [5/10] - # by_epoch == False - # train: Epoch [5/10000] ... (divided by `max_iter`) - # val/test: Epoch [5/2000] ... (divided by `total_length`) - - total_length = current_loop.total_length - - if self.by_epoch: - if mode == 'val': - cur_epoch = self._get_epoch(runner, mode) - log_str = (f'Epoch({mode}) [{cur_epoch}]' - f'[{cur_iter}/{total_length}] ') - else: - log_str = (f'Epoch({mode}) ' f'[{cur_iter}/{total_length}] ') - else: - log_str = (f'Iter({mode}) [{batch_idx+1}/{total_length}] ') - # Concatenate lr, momentum string with log header. - log_str += f'{lr_str} ' - # If IterTimerHook used in runner, eta, time, and data_time should be - # recorded. - if (all(item in tag for item in ['time', 'data_time']) - and 'eta' in runner.message_hub.runtime_info): - eta = runner.message_hub.get_info('eta') - eta_str = str(datetime.timedelta(seconds=int(eta))) - log_str += f'eta: {eta_str} ' - log_str += (f'time: {tag["time"]:.{self.num_digits}f} ' - f'data_time: {tag["data_time"]:.{self.num_digits}f} ') - # Pop recorded keys - log_tag.pop('time') - log_tag.pop('data_time') - - # If cuda is available, the max memory occupied should be calculated. - if torch.cuda.is_available(): - log_str += f'memory: {self._get_max_memory(runner)} ' - # Loop left keys to fill `log_str`. - if mode in ('train', 'val'): - log_items = [] - for name, val in log_tag.items(): - if mode == 'val' and not name.startswith('val/loss'): - continue - if isinstance(val, float): - val = f'{val:.{self.num_digits}f}' - log_items.append(f'{name}: {val}') - log_str += ' '.join(log_items) - return tag, log_str - - def get_log_after_epoch(self, - runner, - batch_idx: int, - mode: str, - with_non_scalar: bool = False) -> Tuple[dict, str]: - """Format log string after validation or testing epoch. - - We use `runner.val_loop.total_length` and - `runner.test_loop.total_length` as the total number of iterations - shown in log. If you want to know how `total_length` is calculated, - please refers to :meth:`mmedit.engine.runner.EditValLoop.run` and - :meth:`mmedit.engine.runner.EditTestLoop.run`. - - Args: - runner (Runner): The runner of validation/testing phase. - batch_idx (int): The index of the current batch in the current - loop. + runner (Runner): The runner of the training/validation/testing mode (str): Current mode of runner. - with_non_scalar (bool): Whether to include non-scalar infos in the - returned tag. Defaults to False. - Return: - Tuple(dict, str): Formatted log dict/string which will be - recorded by :obj:`runner.message_hub` and :obj:`runner.visualizer`. + Returns: + int: The dataloader size of current loop. """ - assert mode in [ - 'test', 'val' - ], ('`_get_metric_log_str` only accept val or test mode, but got ' - f'{mode}') - cur_loop = self._get_cur_loop(runner, mode) - total_length = cur_loop.total_length - - custom_cfg_copy = self._parse_windows_size(runner, batch_idx) - # tag is used to write log information to different backends. - tag = self._collect_scalars(custom_cfg_copy, runner, mode) - non_scalar_tag = self._collect_non_scalars(runner, mode) - # By epoch: - # Epoch(val) [10][1000/1000] ... - # Epoch(test) [1000/1000] ... - # By iteration: - # Iteration(val) [1000/1000] ... - # Iteration(test) [1000/1000] ... - if self.by_epoch: - if mode == 'val': - cur_epoch = self._get_epoch(runner, mode) - log_str = (f'Epoch({mode}) [{cur_epoch}][{total_length}/' - f'{total_length}] ') - else: - log_str = (f'Epoch({mode}) [{total_length}/{total_length}] ') - + if hasattr(self._get_cur_loop(runner, mode), 'total_length'): + return self._get_cur_loop(runner, mode).total_length else: - log_str = (f'Iter({mode}) [{total_length}/{total_length}] ') - # `time` and `data_time` will not be recorded in after epoch log - # message. - log_items = [] - for name, val in tag.items(): - if name in ('time', 'data_time'): - continue - if isinstance(val, float): - val = f'{val:.{self.num_digits}f}' - log_items.append(f'{name}: {val}') - log_str += ' '.join(log_items) - - if with_non_scalar: - tag.update(non_scalar_tag) - - return tag, log_str + return super()._get_dataloader_size(runner, mode) diff --git a/tests/test_engine/test_runner/test_log_processor.py b/tests/test_engine/test_runner/test_log_processor.py index 98bd60f70c..257258afaa 100644 --- a/tests/test_engine/test_runner/test_log_processor.py +++ b/tests/test_engine/test_runner/test_log_processor.py @@ -1,260 +1,11 @@ # Copyright (c) OpenMMLab. All rights reserved. -import copy -from unittest.mock import MagicMock, patch - -import numpy as np -import pytest -import torch -from mmengine.logging import HistoryBuffer, MessageHub, MMLogger +from unittest.mock import MagicMock from mmedit.engine import EditLogProcessor as LogProcessor class TestLogProcessor: - def test_init(self): - log_processor = LogProcessor( - window_size=10, by_epoch=True, custom_cfg=None) - assert log_processor.by_epoch - assert log_processor.window_size == 10 - assert log_processor.custom_cfg == [] - - def test_check_custom_cfg(self): - # ``by_epoch==False`` and `window_size='epoch'` in log config will - # raise AssertionError. - custom_cfg = [dict(data_src='loss', window_size='epoch')] - with pytest.raises(AssertionError): - LogProcessor(by_epoch=False, custom_cfg=custom_cfg) - # Duplicate log_name will raise AssertionError. - custom_cfg = [ - dict(data_src='loss', log_name='loss_1'), - dict(data_src='loss', log_name='loss_1') - ] - with pytest.raises(AssertionError): - LogProcessor(custom_cfg=custom_cfg) - # Overwrite loss item twice will raise AssertionError. - custom_cfg = [dict(data_src='loss'), dict(data_src='loss')] - with pytest.raises(AssertionError): - LogProcessor(custom_cfg=custom_cfg) - - custom_cfg = [ - dict(data_src='loss_cls', window_size=100, method_name='min'), - dict(data_src='loss', log_name='loss_min', method_name='max'), - dict(data_src='loss', log_name='loss_max', method_name='max') - ] - LogProcessor(custom_cfg=custom_cfg) - - def test_parse_windows_size(self): - log_processor = LogProcessor() - # Test parse 'epoch' window_size. - log_processor.custom_cfg = [ - dict(data_src='loss_cls', window_size='epoch') - ] - custom_cfg = log_processor._parse_windows_size(self.runner, 1) - assert custom_cfg[0]['window_size'] == 2 - - # Test parse 'global' window_size. - log_processor.custom_cfg = [ - dict(data_src='loss_cls', window_size='global') - ] - custom_cfg = log_processor._parse_windows_size(self.runner, 1) - assert custom_cfg[0]['window_size'] == 11 - - # Test parse int window_size - log_processor.custom_cfg = [dict(data_src='loss_cls', window_size=100)] - custom_cfg = log_processor._parse_windows_size(self.runner, 1) - assert custom_cfg[0]['window_size'] == 100 - - # Invalid type window_size will raise TypeError. - log_processor.custom_cfg = [dict(data_src='loss_cls', window_size=[])] - with pytest.raises(TypeError): - log_processor._parse_windows_size(custom_cfg, self.runner) - - @pytest.mark.parametrize('by_epoch,mode', - ([True, 'train'], [False, 'train'], [True, 'val'], - [False, 'val'], [True, 'test'], [False, 'test'])) - def test_get_log_after_iter(self, by_epoch, mode): - # Prepare LoggerHook - log_processor = LogProcessor(by_epoch=by_epoch) - log_processor._get_max_memory = MagicMock(return_value='100') - eta = 40 - self.runner.message_hub.update_info('eta', eta) - # Prepare training information. - if mode == 'train': - train_logs = dict(lr=0.1, time=1.0, data_time=1.0, loss_cls=1.0) - else: - train_logs = dict(time=1.0, data_time=1.0, loss_cls=1.0) - log_processor._collect_scalars = MagicMock(return_value=train_logs) - tag, out = log_processor.get_log_after_iter(self.runner, 1, mode) - # Verify that the correct context have been logged. - cur_loop = log_processor._get_cur_loop(self.runner, mode) - if by_epoch: - if mode == 'train': - cur_epoch = log_processor._get_epoch(self.runner, mode) - log_str = (f'Epoch({mode}) [{cur_epoch}][ 2/' - f'{len(cur_loop.dataloader)}] ') - elif mode == 'val': - cur_epoch = log_processor._get_epoch(self.runner, mode) - log_str = (f'Epoch({mode}) [{cur_epoch}][2/' - f'{cur_loop.total_length}] ') - else: - log_str = (f'Epoch({mode}) [2/{cur_loop.total_length}] ') - - if mode == 'train': - log_str += f"lr: {train_logs['lr']:.4e} " - else: - log_str += ' ' - - log_str += (f'eta: 0:00:40 ' - f"time: {train_logs['time']:.4f} " - f"data_time: {train_logs['data_time']:.4f} ") - - if torch.cuda.is_available(): - log_str += 'memory: 100 ' - if mode == 'train': - log_str += f"loss_cls: {train_logs['loss_cls']:.4f}" - assert out == log_str - else: - if mode == 'train': - max_iters = self.runner.max_iters - log_str = f'Iter({mode}) [11/{max_iters}] ' - else: - max_iters = cur_loop.total_length - log_str = f'Iter({mode}) [2/{max_iters}] ' - - if mode == 'train': - log_str += f"lr: {train_logs['lr']:.4e} " - else: - log_str += ' ' - - log_str += (f'eta: 0:00:40 ' - f"time: {train_logs['time']:.4f} " - f"data_time: {train_logs['data_time']:.4f} ") - - if torch.cuda.is_available(): - log_str += 'memory: 100 ' - - if mode == 'train': - log_str += f"loss_cls: {train_logs['loss_cls']:.4f}" - assert out == log_str - - @pytest.mark.parametrize('by_epoch,mode', - ([True, 'val'], [False, 'val'], [True, 'test'], - [False, 'test'])) - def test_log_val(self, by_epoch, mode): - # Prepare LoggerHook - log_processor = LogProcessor(by_epoch=by_epoch) - # Prepare validation information. - val_logs = dict(accuracy=0.9, data_time=1.0) - log_processor._collect_scalars = MagicMock(return_value=val_logs) - _, out = log_processor.get_log_after_epoch(self.runner, 2, mode) - if by_epoch: - if mode == 'test': - assert out == 'Epoch(test) [5/5] accuracy: 0.9000' - else: - assert out == 'Epoch(val) [1][10/10] accuracy: 0.9000' - else: - if mode == 'test': - assert out == 'Iter(test) [5/5] accuracy: 0.9000' - else: - assert out == 'Iter(val) [10/10] accuracy: 0.9000' - - def test_non_scalar(self): - # test with non scalar - metric1 = np.random.rand(10) - metric2 = torch.tensor(10) - - log_processor = LogProcessor() - # Collect with prefix. - log_infos = {'test/metric1': metric1, 'test/metric2': metric2} - self.runner.message_hub._runtime_info = log_infos - tag = log_processor._collect_non_scalars(self.runner, mode='test') - # Test training key in tag. - assert list(tag.keys()) == ['metric1', 'metric2'] - # Test statistics lr with `current`, loss and time with 'mean' - assert tag['metric1'] is metric1 - assert tag['metric2'] is metric2 - - def test_collect_scalars(self): - history_count = np.ones(100) - time_scalars = np.random.randn(100) - loss_cls_scalars = np.random.randn(100) - lr_scalars = np.random.randn(100) - metric_scalars = np.random.randn(100) - - history_time_buffer = HistoryBuffer(time_scalars, history_count) - histroy_loss_cls = HistoryBuffer(loss_cls_scalars, history_count) - history_lr_buffer = HistoryBuffer(lr_scalars, history_count) - history_metric_buffer = HistoryBuffer(metric_scalars, history_count) - - custom_cfg = [ - dict(data_src='time', method_name='max', log_name='time_max') - ] - logger_hook = LogProcessor(custom_cfg=custom_cfg) - # Collect with prefix. - log_scalars = { - 'train/time': history_time_buffer, - 'lr': history_lr_buffer, - 'train/loss_cls': histroy_loss_cls, - 'val/metric': history_metric_buffer - } - self.runner.message_hub._log_scalars = log_scalars - tag = logger_hook._collect_scalars( - copy.deepcopy(custom_cfg), self.runner, mode='train') - # Test training key in tag. - assert list(tag.keys()) == ['time', 'loss_cls', 'time_max'] - # Test statistics lr with `current`, loss and time with 'mean' - assert tag['time'] == time_scalars[-10:].mean() - assert tag['time_max'] == time_scalars.max() - assert tag['loss_cls'] == loss_cls_scalars[-10:].mean() - - tag = logger_hook._collect_scalars( - copy.deepcopy(custom_cfg), self.runner, mode='val') - assert list(tag.keys()) == ['metric'] - assert tag['metric'] == metric_scalars[-1] - - @patch('torch.cuda.max_memory_allocated', MagicMock()) - @patch('torch.cuda.reset_peak_memory_stats', MagicMock()) - def test_get_max_memory(self): - logger_hook = LogProcessor() - runner = MagicMock() - runner.world_size = 1 - runner.model = torch.nn.Linear(1, 1) - logger_hook._get_max_memory(runner) - torch.cuda.max_memory_allocated.assert_called() - torch.cuda.reset_peak_memory_stats.assert_called() - - def test_get_iter(self): - log_processor = LogProcessor() - # Get global iter when `inner_iter=False` - iter = log_processor._get_iter(self.runner) - assert iter == 11 - # Get inner iter - iter = log_processor._get_iter(self.runner, 1) - assert iter == 2 - # Still get global iter when `logger_hook.by_epoch==False` - log_processor.by_epoch = False - iter = log_processor._get_iter(self.runner, 1) - assert iter == 11 - - def test_get_epoch(self): - log_processor = LogProcessor() - epoch = log_processor._get_epoch(self.runner, 'train') - assert epoch == 2 - epoch = log_processor._get_epoch(self.runner, 'val') - assert epoch == 1 - with pytest.raises(ValueError): - log_processor._get_epoch(self.runner, 'test') - - def test_get_cur_loop(self): - log_processor = LogProcessor() - loop = log_processor._get_cur_loop(self.runner, 'train') - assert len(loop.dataloader) == 20 - loop = log_processor._get_cur_loop(self.runner, 'val') - assert loop.total_length == 10 - loop = log_processor._get_cur_loop(self.runner, 'test') - assert loop.total_length == 5 - def setup(self): runner = MagicMock() runner.epoch = 1 @@ -265,16 +16,13 @@ def setup(self): runner.val_dataloader = [0] * 10 runner.test_dataloader = [0] * 5 runner.train_loop.dataloader = [0] * 20 - # runner.val_loop.dataloader = [0] * 10 - # runner.test_loop.dataloader = [0] * 5 runner.val_loop.total_length = 10 runner.test_loop.total_length = 5 - logger = MMLogger.get_instance('log_processor_test') - runner.logger = logger - message_hub = MessageHub.get_instance('log_processor_test') - for i in range(10): - message_hub.update_scalar('train/loss', 10 - i) - for i in range(10): - message_hub.update_scalar('val/acc', i * 0.1) - runner.message_hub = message_hub self.runner = runner + + def test_get_dataloader_size(self): + log_processor = LogProcessor(by_epoch=True) + del self.runner.train_loop.total_length + assert log_processor._get_dataloader_size(self.runner, 'train') == 20 + assert log_processor._get_dataloader_size(self.runner, 'val') == 10 + assert log_processor._get_dataloader_size(self.runner, 'test') == 5 From 0e821d350764e118f1b8ce702a43a2642a7ebc22 Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Mon, 13 Mar 2023 22:19:28 +0800 Subject: [PATCH 05/39] [Enhancement] Support diffuser wrapper (#1693) * support wrapper for diffusers models * add example for diffuser wrapper * mock SiLU function for torch <= 1.6.0 * revise the type of diffusers modules and revise the use case of DiffuserWrapper * revise the docstring of DiffusersWrapper * revise DiffusersWrapper as comment * revise block_out_channels in unit test --- mmedit/models/base_archs/__init__.py | 12 +- mmedit/models/base_archs/wrapper.py | 136 ++++++++++++++++++ .../configs/diffuser_wrapper_cfg/config.json | 32 +++++ .../test_base_archs/test_wrapper.py | 87 +++++++++++ 4 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 mmedit/models/base_archs/wrapper.py create mode 100644 tests/configs/diffuser_wrapper_cfg/config.json create mode 100644 tests/test_models/test_base_archs/test_wrapper.py diff --git a/mmedit/models/base_archs/__init__.py b/mmedit/models/base_archs/__init__.py index 22585ee445..7454266a31 100644 --- a/mmedit/models/base_archs/__init__.py +++ b/mmedit/models/base_archs/__init__.py @@ -22,6 +22,7 @@ from .sr_backbone import ResidualBlockNoBN from .upsample import PixelShufflePack from .vgg import VGG16 +from .wrapper import DiffusersWrapper def register_diffusers_models() -> List[str]: @@ -44,11 +45,20 @@ def register_diffusers_models() -> List[str]: 'please install diffusers>=0.12.0.') return None + def gen_wrapped_cls(module, module_name): + return type( + module_name, (DiffusersWrapper, ), + dict( + _module_cls=module, + _module_name=module_name, + __module__=__name__)) + DIFFUSERS_MODELS = [] for module_name in dir(diffusers.models): module = getattr(diffusers.models, module_name) if inspect.isclass(module): - MODELS.register_module(name=module_name, module=module) + wrapped_module = gen_wrapped_cls(module, module_name) + MODELS.register_module(name=module_name, module=wrapped_module) DIFFUSERS_MODELS.append(module_name) return DIFFUSERS_MODELS diff --git a/mmedit/models/base_archs/wrapper.py b/mmedit/models/base_archs/wrapper.py new file mode 100644 index 0000000000..6329ac50ed --- /dev/null +++ b/mmedit/models/base_archs/wrapper.py @@ -0,0 +1,136 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +from logging import WARNING +from typing import Any, List, Optional, Union + +from mmengine import print_log +from mmengine.model import BaseModule + + +class DiffusersWrapper(BaseModule): + """Wrapper for models from HuggingFace Diffusers. This wrapper will be set + a attribute called `_module_cls` by wrapping function and will be used to + initialize the model structure. + + Example: + >>> 1. Load pretrained model from HuggingFace Space. + >>> config = dict( + >>> type='ControlNetModel', # has been registered in `MODELS` + >>> from_pretrained='lllyasviel/sd-controlnet-canny', + >>> torch_dtype=torch.float16) + >>> controlnet = MODELS.build(config) + + >>> 2. Initialize model with pre-defined configs. + >>> config = dict( + >>> type='ControlNetModel', # has been registered in `MODELS` + >>> from_config='lllyasviel/sd-controlnet-canny', + >>> cache_dir='~/.cache/OpenMMLab') + >>> controlnet = MODELS.build(config) + + >>> 3. Initialize model with own defined arguments + >>> config = dict( + >>> type='ControlNetModel', # has been registered in `MODELS` + >>> in_channels=3, + >>> down_block_types=['DownBlock2D'], + >>> block_out_channels=(32, ), + >>> conditioning_embedding_out_channels=(16, )) + >>> controlnet = MODELS.build(config) + + Args: + from_pretrained (Union[str, os.PathLike], optional): The *model id* + of a pretrained model or a path to a *directory* containing + model weights and config. Please refers to + `diffusers.model.modeling_utils.ModelMixin.from_pretrained` + for more detail. Defaults to None. + from_config (Union[str, os.PathLike], optional): The *model id* + of a pretrained model or a path to a *directory* containing + model weights and config. Please refers to + `diffusers.configuration_utils.ConfigMixin.load_config` + for more detail. Defaults to None. + init_cfg (dict or List[dict], optional): Initialization config dict. + Noted that, in `DiffuserWrapper`, if you want to load pretrained + weight from HuggingFace space, please use `from_pretrained` + argument instead of using `init_cfg`. Defaults to None. + + *args, **kwargs: If `from_pretrained` is passed, *args and **kwargs + will be passed to `from_pretrained` function. If `from_config` + is passed, *args and **kwargs will be passed to `load_config` + function. Otherwise, *args and **kwargs will be used to + initialize the model by `self._module_cls(*args, **kwargs)`. + """ + + def __init__(self, + from_pretrained: Optional[Union[str, os.PathLike]] = None, + from_config: Optional[Union[str, os.PathLike]] = None, + init_cfg: Union[dict, List[dict], None] = None, + *args, + **kwargs): + super().__init__(init_cfg) + + module_cls = self._module_cls + assert not (from_pretrained and from_config), ( + '\'from_pretrained\' and \'from_config\' should not be passed ' + 'at the same time.') + + self._from_pretrained = from_pretrained + self._from_config = from_config + + if from_pretrained is not None: + self.model = module_cls.from_pretrained(from_pretrained, *args, + **kwargs) + # weight has been initialized from pretrained, therefore we + # `self._is_init` as True manually + self._is_init = True + elif from_config is not None: + _config = module_cls.load_config(from_config, *args, **kwargs) + self.model = module_cls(**_config) + else: + self.model = module_cls(*args, **kwargs) + + self.config = self.model.config + + def init_weights(self): + """Initialize the weights. + + If type is 'Pretrained' but the model has be loaded from `repo_id`, a + warning will be raised. + """ + if self.init_cfg and self.init_cfg['type'] == 'Pretrained': + if self._from_pretrained is not None: + print_log( + 'Has been loaded from pretrained model from ' + f'\'{self._from_pretrained}\'. Your behavior is ' + 'very dangerous.', 'current', WARNING) + super().init_weights() + + def __getattr__(self, name: str) -> Any: + """This function provide a way to access the attributes of the wrapped + model. + + Args: + name (str): The name of the attribute. + + Returns: + Any: The got attribute. + """ + try: + return super().__getattr__(name) + except AttributeError: + try: + return getattr(self.model, name) + except AttributeError: + raise AttributeError('\'name\' cannot be found in both ' + f'\'{self.__class__.__name__}\' and ' + f'\'{self.__class__.__name__}.model\'.') + + def __repr__(self): + """The representation of the wrapper.""" + s = super().__repr__() + prefix = f'Wrapped Module Class: {self._module_cls}\n' + prefix += f'Wrapped Module Name: {self._module_name}\n' + if self._from_pretrained: + prefix += f'From Pretrained: {self._from_pretrained}\n' + if self._from_config: + prefix += f'From Config: {self._from_config}\n' + s = prefix + s + return s diff --git a/tests/configs/diffuser_wrapper_cfg/config.json b/tests/configs/diffuser_wrapper_cfg/config.json new file mode 100644 index 0000000000..dc533598cc --- /dev/null +++ b/tests/configs/diffuser_wrapper_cfg/config.json @@ -0,0 +1,32 @@ +{ + "_class_name": "ControlNetModel", + "_diffusers_version": "0.14.0", + "act_fn": "silu", + "attention_head_dim": 8, + "block_out_channels": [ + 320 + ], + "class_embed_type": null, + "conditioning_embedding_out_channels": [ + 16 + ], + "controlnet_conditioning_channel_order": "rgb", + "cross_attention_dim": 32, + "down_block_types": [ + "CrossAttnDownBlock2D" + ], + "downsample_padding": 1, + "flip_sin_to_cos": true, + "freq_shift": 0, + "in_channels": 4, + "layers_per_block": 2, + "mid_block_scale_factor": 1, + "norm_eps": 1e-05, + "norm_num_groups": 32, + "num_class_embeds": null, + "only_cross_attention": false, + "projection_class_embeddings_input_dim": null, + "resnet_time_scale_shift": "default", + "upcast_attention": false, + "use_linear_projection": false +} diff --git a/tests/test_models/test_base_archs/test_wrapper.py b/tests/test_models/test_base_archs/test_wrapper.py new file mode 100644 index 0000000000..55c1e3ee85 --- /dev/null +++ b/tests/test_models/test_base_archs/test_wrapper.py @@ -0,0 +1,87 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +import shutil +from unittest import TestCase + +import torch +from mmengine.utils import digit_version +from mmengine.utils.dl_utils import TORCH_VERSION + +from mmedit.registry import MODELS + +test_dir = osp.join(osp.dirname(__file__), '../../..', 'tests') +config_path = osp.join(test_dir, 'configs', 'diffuser_wrapper_cfg') +model_path = osp.join(test_dir, 'configs', 'tmp_weight') +ckpt_path = osp.join(test_dir, 'configs', 'ckpt') + + +class TestWrapper(TestCase): + + def test_build(self): + # mock SiLU + if digit_version(TORCH_VERSION) <= digit_version('1.6.0'): + from mmedit.models.editors.ddpm.denoising_unet import SiLU + torch.nn.SiLU = SiLU + + # 1. test from config + model = MODELS.build( + dict(type='ControlNetModel', from_config=config_path)) + model.init_weights() # test init_weights without warning + model_str = repr(model) + self.assertIn( + 'Wrapped Module Class: ', model_str) + self.assertIn('Wrapped Module Name: ControlNetModel', model_str) + self.assertIn(f'From Config: {config_path}', model_str) + + # 2. test save as diffuser + model.save_pretrained(model_path) + + # 3. test from_pretrained + model = MODELS.build( + dict( + type='ControlNetModel', + from_pretrained=model_path, + torch_dtype=torch.float16)) + assert all([p.dtype == torch.float16 for p in model.parameters()]) + model_str = repr(model) + self.assertIn(f'From Pretrained: {model_path}', model_str) + + # save ckpt to test init_weights + os.makedirs(ckpt_path, exist_ok=True) + torch.save(model.state_dict(), osp.join(ckpt_path, 'model.pth')) + + # test raise warning when init_cfg is passed + model = MODELS.build( + dict( + type='ControlNetModel', + from_pretrained=model_path, + torch_dtype=torch.float16, + init_cfg=dict( + type='Pretrained', + checkpoint=osp.join(ckpt_path, 'model.pth')))) + model.init_weights() + + # delete saved model to save space + shutil.rmtree(model_path) + shutil.rmtree(ckpt_path) + + # 4. test loading without repo_id + model = MODELS.build( + dict( + type='ControlNetModel', + in_channels=3, + down_block_types=['DownBlock2D'], + block_out_channels=(32, ), + conditioning_embedding_out_channels=(16, )), ) + model_str = repr(model) + self.assertNotIn('From Config:', model_str) + self.assertNotIn('From Pretrained:', model_str) + + # 5. test attribute error for a unknown attribute + with self.assertRaises(AttributeError): + model.unkonwn_attr('what\'s this?') + + # 6. test init_weights + model.init_weights() From 2b9fda9178acb3d812a6bb372ed5629307df6cfe Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Wed, 15 Mar 2023 11:27:41 +0800 Subject: [PATCH 06/39] [Refactor] Refactor dataset_converters for restoration datasets (#1690) * fix df2k df2k_ost * add datasets * fix reds * fix vid4 * add SPMCS * fix dpdd * add hide * add ntire * add gopro * add sidd * fix glean * fix vimeo90k * fix udm10 * fix live1 --- tools/dataset_converters/classic5/README.md | 30 +++ .../classic5/README_zh-CN.md | 28 +++ tools/dataset_converters/denoising/README.md | 31 ++++ .../denoising/README_zh-CN.md | 31 ++++ tools/dataset_converters/deraining/README.md | 42 +++++ .../deraining/README_zh-CN.md | 42 +++++ tools/dataset_converters/df2k_ost/README.md | 18 +- .../df2k_ost/README_zh-CN.md | 18 +- .../df2k_ost/preprocess_df2k_ost_dataset.py | 31 +++- tools/dataset_converters/div2k/README.md | 19 +- .../dataset_converters/div2k/README_zh-CN.md | 19 +- .../div2k/preprocess_div2k_dataset.py | 36 ++++ tools/dataset_converters/dpdd/README.md | 29 +++ tools/dataset_converters/dpdd/README_zh-CN.md | 29 +++ tools/dataset_converters/glean/README.md | 171 ++++++++++++++++++ .../dataset_converters/glean/README_zh-CN.md | 171 ++++++++++++++++++ .../glean/preprocess_cat_test_dataset.py | 121 +++++++++++++ .../glean/preprocess_cat_train_dataset.py | 169 +++++++++++++++++ .../glean/preprocess_ffhq_celebahq_dataset.py | 104 +++++++++++ tools/dataset_converters/gopro/README.md | 31 ++++ .../dataset_converters/gopro/README_zh-CN.md | 31 ++++ tools/dataset_converters/hide/README.md | 27 +++ tools/dataset_converters/hide/README_zh-CN.md | 27 +++ tools/dataset_converters/live1/README.md | 28 +++ .../dataset_converters/live1/README_zh-CN.md | 28 +++ .../ntire21_decompression/README.md | 46 +++++ .../ntire21_decompression/README_zh-CN.md | 45 +++++ tools/dataset_converters/realblur/README.md | 31 ++++ .../realblur/README_zh-CN.md | 31 ++++ tools/dataset_converters/realsrset/README.md | 29 +++ .../realsrset/README_zh-CN.md | 29 +++ tools/dataset_converters/reds/README.md | 12 +- tools/dataset_converters/reds/README_zh-CN.md | 12 +- .../reds/crop_sub_images.py | 7 +- .../reds/preprocess_reds_dataset.py | 13 +- tools/dataset_converters/sidd/README.md | 40 ++++ tools/dataset_converters/sidd/README_zh-CN.md | 40 ++++ .../sidd/preprocess_sidd_test_dataset.py | 77 ++++++++ tools/dataset_converters/spmcs/README.md | 30 +++ .../dataset_converters/spmcs/README_zh-CN.md | 30 +++ tools/dataset_converters/udm10/README.md | 29 +++ .../dataset_converters/udm10/README_zh-CN.md | 29 +++ tools/dataset_converters/vid4/README.md | 35 ++++ tools/dataset_converters/vid4/README_zh-CN.md | 35 ++++ .../vid4/preprocess_vid4_dataset.py | 103 +++++++++++ tools/dataset_converters/videolq/README.md | 32 ++++ .../videolq/README_zh-CN.md | 32 ++++ tools/dataset_converters/vimeo90k/README.md | 43 +++-- .../vimeo90k/README_zh-CN.md | 43 +++-- .../vimeo90k/preprocess_vimeo90k_dataset.py | 167 ++++++++++++++++- 50 files changed, 2267 insertions(+), 64 deletions(-) create mode 100644 tools/dataset_converters/classic5/README.md create mode 100644 tools/dataset_converters/classic5/README_zh-CN.md create mode 100644 tools/dataset_converters/denoising/README.md create mode 100644 tools/dataset_converters/denoising/README_zh-CN.md create mode 100644 tools/dataset_converters/deraining/README.md create mode 100644 tools/dataset_converters/deraining/README_zh-CN.md create mode 100644 tools/dataset_converters/dpdd/README.md create mode 100644 tools/dataset_converters/dpdd/README_zh-CN.md create mode 100644 tools/dataset_converters/glean/README.md create mode 100644 tools/dataset_converters/glean/README_zh-CN.md create mode 100644 tools/dataset_converters/glean/preprocess_cat_test_dataset.py create mode 100644 tools/dataset_converters/glean/preprocess_cat_train_dataset.py create mode 100644 tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py create mode 100644 tools/dataset_converters/gopro/README.md create mode 100644 tools/dataset_converters/gopro/README_zh-CN.md create mode 100644 tools/dataset_converters/hide/README.md create mode 100644 tools/dataset_converters/hide/README_zh-CN.md create mode 100644 tools/dataset_converters/live1/README.md create mode 100644 tools/dataset_converters/live1/README_zh-CN.md create mode 100644 tools/dataset_converters/ntire21_decompression/README.md create mode 100644 tools/dataset_converters/ntire21_decompression/README_zh-CN.md create mode 100644 tools/dataset_converters/realblur/README.md create mode 100644 tools/dataset_converters/realblur/README_zh-CN.md create mode 100644 tools/dataset_converters/realsrset/README.md create mode 100644 tools/dataset_converters/realsrset/README_zh-CN.md create mode 100644 tools/dataset_converters/sidd/README.md create mode 100644 tools/dataset_converters/sidd/README_zh-CN.md create mode 100644 tools/dataset_converters/sidd/preprocess_sidd_test_dataset.py create mode 100644 tools/dataset_converters/spmcs/README.md create mode 100644 tools/dataset_converters/spmcs/README_zh-CN.md create mode 100644 tools/dataset_converters/udm10/README.md create mode 100644 tools/dataset_converters/udm10/README_zh-CN.md create mode 100644 tools/dataset_converters/vid4/preprocess_vid4_dataset.py create mode 100644 tools/dataset_converters/videolq/README.md create mode 100644 tools/dataset_converters/videolq/README_zh-CN.md diff --git a/tools/dataset_converters/classic5/README.md b/tools/dataset_converters/classic5/README.md new file mode 100644 index 0000000000..ccf33e47c3 --- /dev/null +++ b/tools/dataset_converters/classic5/README.md @@ -0,0 +1,30 @@ +# Preparing Classic5 Dataset + + + +```bibtex +@article{zhang2017beyond, + title={Beyond a {Gaussian} denoiser: Residual learning of deep {CNN} for image denoising}, + author={Zhang, Kai and Zuo, Wangmeng and Chen, Yunjin and Meng, Deyu and Zhang, Lei}, + journal={IEEE Transactions on Image Processing}, + year={2017}, + volume={26}, + number={7}, + pages={3142-3155}, +} +``` + +The test datasets can be download from [here](https://github.com/cszn/DnCNN/tree/master/testsets). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── Classic5 +|   |   ├── input +|   |   ├── target +``` diff --git a/tools/dataset_converters/classic5/README_zh-CN.md b/tools/dataset_converters/classic5/README_zh-CN.md new file mode 100644 index 0000000000..531fa9b772 --- /dev/null +++ b/tools/dataset_converters/classic5/README_zh-CN.md @@ -0,0 +1,28 @@ +# 准备 Classic5 数据集 + + + +```bibtex +@article{zhang2017beyond, + title={Beyond a {Gaussian} denoiser: Residual learning of deep {CNN} for image denoising}, + author={Zhang, Kai and Zuo, Wangmeng and Chen, Yunjin and Meng, Deyu and Zhang, Lei}, + journal={IEEE Transactions on Image Processing}, + year={2017}, + volume={26}, + number={7}, + pages={3142-3155}, +} +``` + +测试数据集可以从 [此处](https://github.com/cszn/DnCNN/tree/master/testsets) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── Classic5 +``` diff --git a/tools/dataset_converters/denoising/README.md b/tools/dataset_converters/denoising/README.md new file mode 100644 index 0000000000..0d9cd25fbb --- /dev/null +++ b/tools/dataset_converters/denoising/README.md @@ -0,0 +1,31 @@ +# Preparing Denoising Dataset + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +The test datasets (Set12, BSD68, CBSD68, Kodak, McMaster, Urban100) can be download from [here](https://drive.google.com/file/d/1mwMLt-niNqcQpfN_ZduG9j4k6P_ZkOl0/). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── denoising_gaussian_test +|   |   ├── Set12 +|   |   ├── BSD68 +|   |   ├── CBSD68 +|   |   ├── Kodak +|   |   ├── McMaster +|   |   ├── Urban100 +``` diff --git a/tools/dataset_converters/denoising/README_zh-CN.md b/tools/dataset_converters/denoising/README_zh-CN.md new file mode 100644 index 0000000000..62164d864a --- /dev/null +++ b/tools/dataset_converters/denoising/README_zh-CN.md @@ -0,0 +1,31 @@ +# 准备 Denoising 数据集 + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +测试数据集(Set12, BSD68, CBSD68, Kodak, McMaster, Urban100)可以从 [此处](https://drive.google.com/file/d/1P_-RAvltEoEhfT-9GrWRdpEi6NSswTs8/) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── denoising_gaussian_test +|   |   ├── Set12 +|   |   ├── BSD68 +|   |   ├── CBSD68 +|   |   ├── Kodak +|   |   ├── McMaster +|   |   ├── Urban100 +``` diff --git a/tools/dataset_converters/deraining/README.md b/tools/dataset_converters/deraining/README.md new file mode 100644 index 0000000000..9bb004b7bb --- /dev/null +++ b/tools/dataset_converters/deraining/README.md @@ -0,0 +1,42 @@ +# Preparing Deraining Dataset + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +The test datasets (Rain100H, Rain100L, Test100, Test1200, Test2800) can be download from [here](https://drive.google.com/file/d/1P_-RAvltEoEhfT-9GrWRdpEi6NSswTs8/). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── Rain100H +|   |   ├── input +|   |   ├── target +|   ├── Rain100L +|   |   ├── input +|   |   ├── target +|   ├── Test100 +|   |   ├── input +|   |   ├── target +|   ├── Test1200 +|   |   ├── input +|   |   ├── target +|   ├── Test2800 +|   |   ├── input +|   |   ├── target +|   ├── Test100 +|   |   ├── input +|   |   ├── target +``` diff --git a/tools/dataset_converters/deraining/README_zh-CN.md b/tools/dataset_converters/deraining/README_zh-CN.md new file mode 100644 index 0000000000..c5e9bf5f40 --- /dev/null +++ b/tools/dataset_converters/deraining/README_zh-CN.md @@ -0,0 +1,42 @@ +# 准备 Deraining 数据集 + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +测试数据集(Rain100H, Rain100L, Test100, Test1200, Test2800)可以从 [此处](https://drive.google.com/file/d/1P_-RAvltEoEhfT-9GrWRdpEi6NSswTs8/) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── Rain100H +|   |   ├── input +|   |   ├── target +|   ├── Rain100L +|   |   ├── input +|   |   ├── target +|   ├── Test100 +|   |   ├── input +|   |   ├── target +|   ├── Test1200 +|   |   ├── input +|   |   ├── target +|   ├── Test2800 +|   |   ├── input +|   |   ├── target +|   ├── Test100 +|   |   ├── input +|   |   ├── target +``` diff --git a/tools/dataset_converters/df2k_ost/README.md b/tools/dataset_converters/df2k_ost/README.md index 5aeaf52ce9..4371efe2dc 100644 --- a/tools/dataset_converters/df2k_ost/README.md +++ b/tools/dataset_converters/df2k_ost/README.md @@ -37,7 +37,7 @@ mmediting For faster IO, we recommend to crop the images to sub-images. We provide such a script: ```shell -python tools/dataset_converters/super-resolution/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost +python tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost ``` The generated data is stored under `df2k_ost` and the data structure is as follows, where `_sub` indicates the sub-images. @@ -51,9 +51,25 @@ mmediting │ ├── df2k_ost │ │ ├── GT │ │ ├── GT_sub +│ │ ├── meta_info_df2k_ost.txt ... ``` +## Prepare annotation list + +If you use the annotation mode for the dataset, you first need to prepare a specific `txt` file. + +Each line in the annotation file contains the image names and image shape (usually for the ground-truth images), separated by a white space. + +Example of an annotation file: + +```text +0001_s001.png (480,480,3) +0001_s002.png (480,480,3) +``` + +Note that `preprocess_df2k_ost_dataset.py` will generate default annotation files. + ## Prepare LMDB dataset for DF2K_OST If you want to use LMDB datasets for faster IO speed, you can make LMDB files by: diff --git a/tools/dataset_converters/df2k_ost/README_zh-CN.md b/tools/dataset_converters/df2k_ost/README_zh-CN.md index 1e00116138..efda1da681 100644 --- a/tools/dataset_converters/df2k_ost/README_zh-CN.md +++ b/tools/dataset_converters/df2k_ost/README_zh-CN.md @@ -37,7 +37,7 @@ mmediting 为了更快的 IO,我们建议将图像裁剪为子图像。 我们提供了这样一个脚本: ```shell -python tools/dataset_converters/super-resolution/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost +python tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost ``` 生成的数据存放在 `df2k_ost` 下,数据结构如下,其中 `_sub` 表示子图像。 @@ -51,9 +51,25 @@ mmediting │ ├── df2k_ost │ │ ├── GT │ │ ├── GT_sub +│ │ ├── meta_info_df2k_ost.txt ... ``` +## 准备标注列表文件 + +如果您想使用`标注模式`来处理数据集,需要先准备一个 `txt` 格式的标注文件。 + +标注文件中的每一行包含了图片名以及图片尺寸(这些通常是 ground-truth 图片),这两个字段用空格间隔开。 + +标注文件示例: + +```text +0001_s001.png (480,480,3) +0001_s002.png (480,480,3) +``` + +请注意,`preprocess_df2k_ost_dataset.py` 脚本默认生成一份标注文件。 + ## Prepare LMDB dataset for DF2K_OST 如果你想使用 LMDB 数据集来获得更快的 IO 速度,你可以通过以下方式制作 LMDB 文件: diff --git a/tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py b/tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py index e540ab6f24..208be7dd56 100644 --- a/tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py +++ b/tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py @@ -8,9 +8,23 @@ import cv2 import lmdb import mmcv +import mmengine import numpy as np +def generate_anno_file(args): + """Generate annotation file for DF2K_OST datasets from the ground-truth + folder.""" + + print('Generate annotation files ...') + txt_file = osp.join(args.data_root, args.anno_path) + mmengine.utils.mkdir_or_exist(osp.dirname(txt_file)) + img_list = sorted(os.listdir(osp.join(args.data_root, 'GT_sub'))) + with open(txt_file, 'w') as f: + for img in img_list: + f.write(f'{img} ({args.crop_size}, {args.crop_size}, 3)\n') + + def main_extract_subimages(args): """A multi-thread tool to crop large images to sub-images for faster IO. @@ -34,8 +48,8 @@ def main_extract_subimages(args): opt['compression_level'] = args.compression_level # HR images - opt['input_folder'] = osp.join(args.data_root, 'df2k_ost/GT') - opt['save_folder'] = osp.join(args.data_root, 'df2k_ost/GT_sub') + opt['input_folder'] = osp.join(args.data_root, 'GT') + opt['save_folder'] = osp.join(args.data_root, 'GT_sub') opt['crop_size'] = args.crop_size opt['step'] = args.step opt['thresh_size'] = args.thresh_size @@ -60,10 +74,10 @@ def extract_subimages(opt): print(f'Folder {save_folder} already exists. Exit.') sys.exit(1) - img_list = list(mmcv.scandir(input_folder, suffix='png')) + img_list = list(mmengine.scandir(input_folder, suffix='png')) img_list = [osp.join(input_folder, v) for v in img_list] - prog_bar = mmcv.ProgressBar(len(img_list)) + prog_bar = mmengine.ProgressBar(len(img_list)) pool = Pool(opt['n_thread']) for path in img_list: pool.apply_async( @@ -305,6 +319,12 @@ def parse_args(): description='Prepare DF2K_OST dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--data-root', help='dataset root') + parser.add_argument( + '--anno-path', + nargs='?', + default='meta_info_df2k_ost.txt', + type=str, + help='annotation file path') parser.add_argument( '--crop-size', type=int, @@ -349,6 +369,9 @@ def parse_args(): # extract subimages main_extract_subimages(args) + # generate annotation files + generate_anno_file(args) + # prepare lmdb files if necessary if args.make_lmdb: make_lmdb_for_df2k_ost(args.data_root) diff --git a/tools/dataset_converters/div2k/README.md b/tools/dataset_converters/div2k/README.md index 74c23d3ecc..dd51dcf5c7 100644 --- a/tools/dataset_converters/div2k/README.md +++ b/tools/dataset_converters/div2k/README.md @@ -13,7 +13,9 @@ ``` - Training dataset: [DIV2K dataset](https://data.vision.ee.ethz.ch/cvl/DIV2K/). -- Validation dataset: Set5 and Set14. +- Validation dataset: [Set5](https://drive.google.com/drive/folders/1B3DJGQKB6eNdwuQIhdskA64qUuVKLZ9u) and [Set14](https://drive.google.com/drive/folders/1B3DJGQKB6eNdwuQIhdskA64qUuVKLZ9u). + +Note that we merge the original val dataset (image names from 0801 to 0900) to the original train dataset (image names from 0001 to 0800). The folder structure should look like: ```text mmediting @@ -23,6 +25,13 @@ mmediting ├── data │ ├── DIV2K │ │ ├── DIV2K_train_HR +│ │ │ ├── 0001.png +│ │ │ ├── 0002.png +│ │ │ ├── ... +│ │ │ ├── 0800.png +│ │ │ ├── 0801.png +│ │ │ ├── ... +│ │ │ ├── 0900.png │ │ ├── DIV2K_train_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 @@ -49,7 +58,7 @@ mmediting For faster IO, we recommend to crop the DIV2K images to sub-images. We provide such a script: ```shell -python tools/dataset_converters/super-resolution/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K +python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K ``` The generated data is stored under `DIV2K` and the data structure is as follows, where `_sub` indicates the sub-images. @@ -72,6 +81,8 @@ mmediting │ │ │ ├── X4_sub │ │ ├── DIV2K_valid_HR │ │ ├── ... +│ │ ├── meta_info_DIV2K800sub_GT.txt +│ │ ├── meta_info_DIV2K100sub_GT.txt ... ``` @@ -88,10 +99,12 @@ Example of an annotation file: 0001_s002.png (480,480,3) ``` +Note that `preprocess_div2k_dataset` will generate default annotation files. + ## Prepare LMDB dataset for DIV2K If you want to use LMDB datasets for faster IO speed, you can make LMDB files by: ```shell -python tools/dataset_converters/super-resolution/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K --make-lmdb +python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K --make-lmdb ``` diff --git a/tools/dataset_converters/div2k/README_zh-CN.md b/tools/dataset_converters/div2k/README_zh-CN.md index e5318135a4..2f683e2979 100644 --- a/tools/dataset_converters/div2k/README_zh-CN.md +++ b/tools/dataset_converters/div2k/README_zh-CN.md @@ -13,7 +13,9 @@ ``` - 训练集: [DIV2K dataset](https://data.vision.ee.ethz.ch/cvl/DIV2K/). -- 验证集: Set5 and Set14. +- 验证集: [Set5](https://drive.google.com/drive/folders/1B3DJGQKB6eNdwuQIhdskA64qUuVKLZ9u) 和 [Set14](https://drive.google.com/drive/folders/1B3DJGQKB6eNdwuQIhdskA64qUuVKLZ9u). + +请注意,我们将原始的验证集(文件名 0801 到 0900)合并进了原始的训练集(文件名 0001 到 0800)。文件目录结构应如下所示: ```text mmediting @@ -23,6 +25,13 @@ mmediting ├── data │ ├── DIV2K │ │ ├── DIV2K_train_HR +│ │ │ ├── 0001.png +│ │ │ ├── 0002.png +│ │ │ ├── ... +│ │ │ ├── 0800.png +│ │ │ ├── 0801.png +│ │ │ ├── ... +│ │ │ ├── 0900.png │ │ ├── DIV2K_train_LR_bicubic │ │ │ ├── X2 │ │ │ ├── X3 @@ -49,7 +58,7 @@ mmediting 为了加快 IO,建议将 DIV2K 中的图片裁剪为一系列子图,为此,我们提供了一个脚本: ```shell -python tools/dataset_converters/super-resolution/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K +python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K ``` 生成的数据保存在 `DIV2K` 目录下,其文件结构如下所示,其中 `_sub` 表示子图: @@ -72,6 +81,8 @@ mmediting │ │ │ ├── X4_sub │ │ ├── DIV2K_valid_HR │ │ ├── ... +│ │ ├── meta_info_DIV2K800sub_GT.txt +│ │ ├── meta_info_DIV2K100sub_GT.txt ... ``` @@ -88,10 +99,12 @@ mmediting 0001_s002.png (480,480,3) ``` +请注意,`preprocess_div2k_dataset` 脚本默认生成一份标注文件。 + ## 准备 LMDB 格式的 DIV2K 数据集 如果您想使用 `LMDB` 以获得更快的 IO 速度,可以通过以下脚本来构建 LMDB 文件 ```shell -python tools/dataset_converters/super-resolution/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K --make-lmdb +python tools/dataset_converters/div2k/preprocess_div2k_dataset.py --data-root ./data/DIV2K --make-lmdb ``` diff --git a/tools/dataset_converters/div2k/preprocess_div2k_dataset.py b/tools/dataset_converters/div2k/preprocess_div2k_dataset.py index aed02a09c3..3ab4547f35 100644 --- a/tools/dataset_converters/div2k/preprocess_div2k_dataset.py +++ b/tools/dataset_converters/div2k/preprocess_div2k_dataset.py @@ -13,6 +13,25 @@ import numpy as np +def generate_anno_file(args): + """Generate annotation file for DIV2K datasets from the ground-truth + folder.""" + + print('Generate annotation files ...') + train_file = osp.join(args.data_root, args.anno_train_path) + test_file = osp.join(args.data_root, args.anno_test_path) + mmengine.utils.mkdir_or_exist(osp.dirname(train_file)) + mmengine.utils.mkdir_or_exist(osp.dirname(test_file)) + img_list = sorted( + os.listdir(osp.join(args.data_root, 'DIV2K_train_HR_sub'))) + with open(train_file, 'w') as f1, open(test_file, 'w') as f2: + for img in img_list: + if img[:4] < '0801': + f1.write(f'{img} ({args.crop_size}, {args.crop_size}, 3)\n') + else: + f2.write(f'{img} ({args.crop_size}, {args.crop_size}, 3)\n') + + def main_extract_subimages(args): """A multi-thread tool to crop large images to sub-images for faster IO. @@ -351,6 +370,18 @@ def parse_args(): description='Prepare DIV2K dataset', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--data-root', help='dataset root') + parser.add_argument( + '--anno-train-path', + nargs='?', + default='meta_info_DIV2K800sub_GT.txt', + type=str, + help='annotation file path of train dataset') + parser.add_argument( + '--anno-test-path', + nargs='?', + default='meta_info_DIV2K100sub_GT.txt', + type=str, + help='annotation file path of test dataset') parser.add_argument( '--scales', nargs='*', @@ -397,8 +428,13 @@ def parse_args(): if __name__ == '__main__': args = parse_args() + # extract subimages main_extract_subimages(args) + + # generate annotation files + generate_anno_file(args) + # prepare lmdb files if necessary if args.make_lmdb: make_lmdb_for_div2k(args.data_root) diff --git a/tools/dataset_converters/dpdd/README.md b/tools/dataset_converters/dpdd/README.md new file mode 100644 index 0000000000..9eee774cb5 --- /dev/null +++ b/tools/dataset_converters/dpdd/README.md @@ -0,0 +1,29 @@ +# Preparing DPDD Dataset + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +The test datasets can be download from [here](https://drive.google.com/file/d/1dDWUQ_D93XGtcywoUcZE1HOXCV4EuLyw/). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── DPDD +|   |   ├── inputL +|   |   ├── inputR +|   |   ├── inputC +|   |   ├── target +``` diff --git a/tools/dataset_converters/dpdd/README_zh-CN.md b/tools/dataset_converters/dpdd/README_zh-CN.md new file mode 100644 index 0000000000..38907c94c7 --- /dev/null +++ b/tools/dataset_converters/dpdd/README_zh-CN.md @@ -0,0 +1,29 @@ +# 准备 DPDD 数据集 + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +测试数据集可以从 [此处](https://drive.google.com/file/d/1dDWUQ_D93XGtcywoUcZE1HOXCV4EuLyw/) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── DPDD +|   |   ├── inputL +|   |   ├── inputR +|   |   ├── inputC +|   |   ├── target +``` diff --git a/tools/dataset_converters/glean/README.md b/tools/dataset_converters/glean/README.md new file mode 100644 index 0000000000..a0cbade8b4 --- /dev/null +++ b/tools/dataset_converters/glean/README.md @@ -0,0 +1,171 @@ +# Preparing GLEAN Dataset + + + +```bibtex +@InProceedings{chan2021glean, + author = {Chan, Kelvin CK and Wang, Xintao and Xu, Xiangyu and Gu, Jinwei and Loy, Chen Change}, + title = {GLEAN: Generative Latent Bank for Large-Factor Image Super-Resolution}, + booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, + year = {2021} +} +``` + +## Preparing cat_train dataset + +1. Download [cat dataset](http://dl.yf.io/lsun/objects/cat.zip) from [LSUN homepage](https://www.yf.io/p/lsun) + +2. Download [cat_train/meta_info_LSUNcat_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/cat_train/meta_info_LSUNcat_GT.txt) from [GLEAN homepage](https://github.com/ckkelvinchan/GLEAN) + +3. Export and downsample images + +Export images from lmdb file and resize the input images to the designated size. We provide such a script: + +```shell +python tools/dataset_converters/glean/preprocess_cat_train_dataset.py --lmdb-path .data/cat --meta-file-path ./data/cat_train/meta_info_LSUNcat_GT.txt --out-dir ./data/cat_train +``` + +The generated data is stored under `cat_train` and the folder structure is as follows. + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +│ ├── cat_train +│ │ ├── GT +│ │ ├── BIx8_down +│ │ ├── BIx16_down +│ │ ├── meta_info_LSUNcat_GT.txt +... +``` + +## Preparing cat_test dataset + +1. Download [CAT dataset](https://archive.org/download/CAT_DATASET/CAT_DATASET_02.zip) from [here](https://archive.org/details/CAT_DATASET). + +2. Download [cat_test/meta_info_Cat100_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/cat_test/meta_info_Cat100_GT.txt) from [GLEAN homepage](https://github.com/ckkelvinchan/GLEAN) + +3. Downsample images + +Resize the input images to the designated size. We provide such a script: + +```shell +python tools/dataset_converters/glean/preprocess_cat_test_dataset.py --data-path ./data/CAT_03 --meta-file-path ./data/cat_test/meta_info_Cat100_GT.txt --out-dir ./data/cat_test +``` + +The generated data is stored under `cat_test` and the folder structure is as follows. + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +│ ├── cat_test +│ │ ├── GT +│ │ ├── BIx8_down +│ │ ├── BIx16_down +│ │ ├── meta_info_Cat100_GT.txt +... +``` + +## Preparing FFHQ dataset + +1. Download [FFHQ dataset (images1024x1024)](https://drive.google.com/drive/folders/1tZUcXDBeOibC6jcMCtgRRz67pzrAHeHL) from it's [homepage](https://github.com/NVlabs/ffhq-dataset) + +Then you can refactor the folder structure looks like: + +```text +ffhq +├── images +|   ├── 00000.png +|   ├── 00001.png +|   ├── ... +|   ├── 69999.png +``` + +2. Download [ffhq/meta_info_FFHQ_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/FFHQ/meta_info_FFHQ_GT.txt) from [GLEAN homepage](https://github.com/ckkelvinchan/GLEAN) + +3. Downsample images + +Resize the input images to the designated size. We provide such a script: + +```shell +python tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py --data-root ./data/ffhq/images +``` + +The generated data is stored under `ffhq` and the folder structure is as follows. + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +| ├── ffhq +| | ├── images +│ │ ├── BIx8_down +| | ├── BIx16_down +| | ├── meta_info_FFHQ_GT.txt +... +``` + +## Preparing CelebA-HQ dataset + +1. Preparing datasets following it's [homepage](https://github.com/tkarras/progressive_growing_of_gans) + +Then you can refactor the folder structure looks like: + +```text +CelebA-HQ +├── GT +|   ├── 00000.png +|   ├── 00001.png +|   ├── ... +|   ├── 30000.png +``` + +2. Download [CelebA-HQ/meta_info_CelebAHQ_val100_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/CelebA-HQ/meta_info_CelebAHQ_val100_GT.txt) from [GLEAN homepage](https://github.com/ckkelvinchan/GLEAN) + +3. Downsample images + +Resize the input images to the designated size. We provide such a script: + +```shell +python tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py --data-root ./data/CelebA-HQ/GT +``` + +The generated data is stored under `CelebA-HQ` and the folder structure is as follows. + +```text +mmediting +├── mmedit +├── tools +├── configsdata +├── data +| ├── CelebA-HQ +| | ├── GT +│ │ ├── BIx8_down +| | ├── BIx16_down +| | ├── meta_info_CelebAHQ_val100_GT.txt +... +``` + +## Preparing FFHQ_CelebAHQ dataset + +We merge FFHQ(`ffhq/images`) and CelebA-HQ(`CelebA-HQ/GT`) to generate FFHQ_CelebAHQ dataset. + +The folder structure should looks like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +| ├── FFHQ_CelebAHQ +| | ├── GT +... +``` diff --git a/tools/dataset_converters/glean/README_zh-CN.md b/tools/dataset_converters/glean/README_zh-CN.md new file mode 100644 index 0000000000..4a88e7fdbc --- /dev/null +++ b/tools/dataset_converters/glean/README_zh-CN.md @@ -0,0 +1,171 @@ +# 准备 GLEAN 数据集 + + + +```bibtex +@InProceedings{chan2021glean, + author = {Chan, Kelvin CK and Wang, Xintao and Xu, Xiangyu and Gu, Jinwei and Loy, Chen Change}, + title = {GLEAN: Generative Latent Bank for Large-Factor Image Super-Resolution}, + booktitle = {Proceedings of the IEEE conference on computer vision and pattern recognition}, + year = {2021} +} +``` + +## 准备 cat_train 数据集 + +1. 从[LSUN 主页](https://www.yf.io/p/lsun)下载[cat 数据集](http://dl.yf.io/lsun/objects/cat.zip)。 + +2. 从[GLEAN 主页](https://github.com/ckkelvinchan/GLEAN)下载[cat_train/meta_info_LSUNcat_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/cat_train/meta_info_LSUNcat_GT.txt)。 + +3. 导出图像并下采样 + +从 lmdb 文件中导出图像,并下采样到所需尺寸。为此,我们提供了一个脚本: + +```shell +python tools/dataset_converters/glean/preprocess_cat_train_dataset.py --lmdb-path .data/cat --meta-file-path ./data/cat_train/meta_info_LSUNcat_GT.txt --out-dir ./data/cat_train +``` + +生成的数据存储在 `cat_train` 目录下,目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +│ ├── cat_train +│ │ ├── GT +│ │ ├── BIx8_down +│ │ ├── BIx16_down +│ │ ├── meta_info_LSUNcat_GT.txt +... +``` + +## 准备 cat_test 数据集 + +1. 从数据集[主页](https://archive.org/details/CAT_DATASET)下载[CAT 数据集](https://archive.org/download/CAT_DATASET/CAT_DATASET_02.zip)。 + +2. 从[GLEAN 主页](https://github.com/ckkelvinchan/GLEAN)下载[cat_test/meta_info_Cat100_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/cat_test/meta_info_Cat100_GT.txt)。 + +3. 下采样 + +将图像下采样到所需尺寸。为此,我们提供了一个脚本: + +```shell +python tools/dataset_converters/glean/preprocess_cat_test_dataset.py --data-path ./data/CAT_03 --meta-file-path ./data/cat_test/meta_info_Cat100_GT.txt --out-dir ./data/cat_test +``` + +生成的数据存储在 `cat_test` 目录下,目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +│ ├── cat_test +│ │ ├── GT +│ │ ├── BIx8_down +│ │ ├── BIx16_down +│ │ ├── meta_info_Cat100_GT.txt +... +``` + +## 准备 FFHQ 数据集 + +1. 从数据集[主页](https://github.com/NVlabs/ffhq-dataset)下载[FFHQ 数据集 (images1024x1024)](https://drive.google.com/drive/folders/1tZUcXDBeOibC6jcMCtgRRz67pzrAHeHL)。 + +将文件目录重构为如下所示: + +```text +ffhq +├── images +|   ├── 00000.png +|   ├── 00001.png +|   ├── ... +|   ├── 69999.png +``` + +2. 从[GLEAN 主页](https://github.com/ckkelvinchan/GLEAN)下载[ffhq/meta_info_FFHQ_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/FFHQ/meta_info_FFHQ_GT.txt)。 + +3. 下采样 + +将图像下采样到所需尺寸。为此,我们提供了一个脚本: + +```shell +python tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py --data-root ./data/ffhq/images +``` + +生成的数据存储在 `ffhq` 目录下,目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +| ├── ffhq +| | ├── images +│ │ ├── BIx8_down +| | ├── BIx16_down +| | ├── meta_info_FFHQ_GT.txt +... +``` + +## 准备 CelebA-HQ 数据集 + +1. 根据数据集[主页](https://github.com/tkarras/progressive_growing_of_gans)文档准备数据集。 + +将文件目录重构为如下所示: + +```text +CelebA-HQ +├── GT +|   ├── 00000.png +|   ├── 00001.png +|   ├── ... +|   ├── 30000.png +``` + +2. 从[GLEAN 主页](https://github.com/ckkelvinchan/GLEAN)下载[CelebA-HQ/meta_info_CelebAHQ_val100_GT.txt](https://github.com/ckkelvinchan/GLEAN/blob/main/data/CelebA-HQ/meta_info_CelebAHQ_val100_GT.txt)。 + +3. 下采样 + +将图像下采样到所需尺寸。为此,我们提供了一个脚本: + +```shell +python tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py --data-root ./data/CelebA-HQ/GT +``` + +生成的数据存储在 `CelebA-HQ` 目录下,目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configsdata +├── data +| ├── CelebA-HQ +| | ├── GT +│ │ ├── BIx8_down +| | ├── BIx16_down +| | ├── meta_info_CelebAHQ_val100_GT.txt +... +``` + +## 准备 FFHQ_CelebAHQ 数据集 + +将 FFHQ(`ffhq/images`) 和 CelebA-HQ(`CelebA-HQ/GT`) 合并,生成 FFHQ_CelebAHQ 数据集。 + +文件目录重构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +| ├── FFHQ_CelebAHQ +| | ├── GT +... +``` diff --git a/tools/dataset_converters/glean/preprocess_cat_test_dataset.py b/tools/dataset_converters/glean/preprocess_cat_test_dataset.py new file mode 100644 index 0000000000..06d1a16944 --- /dev/null +++ b/tools/dataset_converters/glean/preprocess_cat_test_dataset.py @@ -0,0 +1,121 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os +import os.path as osp +from multiprocessing import Pool + +import mmengine +import numpy as np +from skimage import img_as_float +from skimage.io import imread, imsave + +from mmedit.datasets.transforms import MATLABLikeResize + + +def imresize(img_path, output_path, scale=None, output_shape=None): + """Resize the image using MATLAB-like downsampling. + + Args: + img_path (str): Input image path. + output_path (str): Output image path. + scale (float | None, optional): The scale factor of the resize + operation. If None, it will be determined by output_shape. + Default: None. + output_shape (tuple(int) | None, optional): The size of the output + image. If None, it will be determined by scale. Note that if + scale is provided, output_shape will not be used. + Default: None. + """ + + matlab_resize = MATLABLikeResize( + keys=['data'], scale=scale, output_shape=output_shape) + img = imread(img_path) + img = img_as_float(img) + data = {'data': img} + output = matlab_resize(data)['data'] + output = np.clip(output, 0.0, 1.0) * 255 + output = np.around(output).astype(np.uint8) + imsave(output_path, output) + + +def worker(img_name, args): + """Worker for each process. + + Args: + img_name (str): Image filename. + + Returns: + process_info (str): Process information displayed in progress bar. + """ + + gt_dir = osp.join(args.out_dir, 'GT') + bix8_dir = osp.join(args.out_dir, 'BIx8_down') + bix16_dir = osp.join(args.out_dir, 'BIx16_down') + + new_img_name = img_name + '.png' + + imresize( + osp.join(args.data_path, img_name + '.jpg'), + osp.join(gt_dir, new_img_name), + output_shape=(256, 256)) + imresize( + osp.join(gt_dir, new_img_name), + osp.join(bix8_dir, new_img_name), + scale=1 / 8) + imresize( + osp.join(gt_dir, new_img_name), + osp.join(bix16_dir, new_img_name), + scale=1 / 16) + process_info = f'Processing {new_img_name} ...' + return process_info + + +def downsample_images(args): + """Downsample images for cat_test datasets from the ground-truth.""" + + meta_file = open(args.meta_file_path, 'r') + img_list = [_.split('.')[0] for _ in meta_file.readlines()] + prog_bar = mmengine.ProgressBar(len(img_list)) + pool = Pool(args.n_thread) + for path in img_list: + pool.apply_async( + worker, args=(path, args), callback=lambda arg: prog_bar.update()) + pool.close() + pool.join() + print('All processes done.') + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Prepare cat dataset', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('--data-path', help='dataset root') + parser.add_argument('--meta-file-path', help='meta file path') + parser.add_argument('--out-dir', help='output directory of dataset') + parser.add_argument( + '--n-thread', + nargs='?', + default=8, + type=int, + help='thread number when using multiprocessing') + args = parser.parse_args() + return args + + +if __name__ == '__main__': + args = parse_args() + + if not osp.exists(args.out_dir): + os.makedirs(args.out_dir) + gt_dir = osp.join(args.out_dir, 'GT') + bix8_dir = osp.join(args.out_dir, 'BIx8_down') + bix16_dir = osp.join(args.out_dir, 'BIx16_down') + if not osp.exists(gt_dir): + os.makedirs(gt_dir) + if not osp.exists(bix8_dir): + os.makedirs(bix8_dir) + if not osp.exists(bix16_dir): + os.makedirs(bix16_dir) + + # downsample images + downsample_images(args) diff --git a/tools/dataset_converters/glean/preprocess_cat_train_dataset.py b/tools/dataset_converters/glean/preprocess_cat_train_dataset.py new file mode 100644 index 0000000000..58781f931f --- /dev/null +++ b/tools/dataset_converters/glean/preprocess_cat_train_dataset.py @@ -0,0 +1,169 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os +import os.path as osp +from multiprocessing import Pool + +import lmdb +import mmengine +import numpy as np +from PIL import Image +from skimage import img_as_float +from skimage.io import imread, imsave + +from mmedit.datasets.transforms import MATLABLikeResize + + +def export_images(lmdb_path, meta_file_path, out_dir): + """Export images from lmdb file. + + Ref: https://github.com/fyu/lsun + + Args: + lmdb_path (str): Lmdb file path. + meta_file_path (str): Meta file path. + out_dir (str): Output directory of dataset. + """ + + print('Exporting', lmdb_path, 'to', out_dir) + env = lmdb.open( + lmdb_path, map_size=1099511627776, max_readers=100, readonly=True) + meta_file = open(meta_file_path, 'r') + img_list = [_.split('.')[0] for _ in meta_file.readlines()] + txn = env.begin(write=False) + cursor = txn.cursor() + count = 0 + for key, val in cursor: + if key.decode('ascii') in img_list: + image_out_path = osp.join(out_dir, key.decode('ascii') + '.webp') + with open(image_out_path, 'wb') as fp: + fp.write(val) + count += 1 + if count % 1000 == 0: + print('Finished', count, 'images') + if count > len(img_list): + break + print('\nFinish exporting images.') + + +def imresize(img_path, output_path, scale=None, output_shape=None): + """Resize the image using MATLAB-like downsampling. + + Args: + img_path (str): Input image path. + output_path (str): Output image path. + scale (float | None, optional): The scale factor of the resize + operation. If None, it will be determined by output_shape. + Default: None. + output_shape (tuple(int) | None, optional): The size of the output + image. If None, it will be determined by scale. Note that if + scale is provided, output_shape will not be used. + Default: None. + """ + + matlab_resize = MATLABLikeResize( + keys=['data'], scale=scale, output_shape=output_shape) + img = imread(img_path) + img = img_as_float(img) + data = {'data': img} + output = matlab_resize(data)['data'] + output = np.clip(output, 0.0, 1.0) * 255 + output = np.around(output).astype(np.uint8) + imsave(output_path, output) + + +def worker(img_name, out_dir): + """Worker for each process. + + Args: + img_name (str): Image filename. + out_dir (str): Output directory of dataset. + + Returns: + process_info (str): Process information displayed in progress bar. + """ + + _gt_dir = osp.join(out_dir, '_GT') + gt_dir = osp.join(out_dir, 'GT') + bix8_dir = osp.join(out_dir, 'BIx8_down') + bix16_dir = osp.join(out_dir, 'BIx16_down') + + new_img_name = img_name + '.png' + img = Image.open(osp.join(_gt_dir, img_name + '.webp')) + img.load() + img.save(osp.join(_gt_dir, new_img_name)) + + imresize( + osp.join(_gt_dir, new_img_name), + osp.join(gt_dir, new_img_name), + output_shape=(256, 256)) + imresize( + osp.join(gt_dir, new_img_name), + osp.join(bix8_dir, new_img_name), + scale=1 / 8) + imresize( + osp.join(gt_dir, new_img_name), + osp.join(bix16_dir, new_img_name), + scale=1 / 16) + + process_info = f'Processing {new_img_name} ...' + return process_info + + +def downsample_images(args): + """Downsample images for cat_train datasets from the ground-truth.""" + + meta_file = open(args.meta_file_path, 'r') + img_list = [_.split('.')[0] for _ in meta_file.readlines()] + prog_bar = mmengine.ProgressBar(len(img_list)) + pool = Pool(args.n_thread) + for path in img_list: + pool.apply_async( + worker, + args=(path, args.out_dir), + callback=lambda arg: prog_bar.update()) + pool.close() + pool.join() + print('All processes done.') + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Prepare cat dataset', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('--lmdb-path', help='lmdb file path') + parser.add_argument('--meta-file-path', help='meta file path') + parser.add_argument('--out-dir', help='output directory of dataset') + parser.add_argument( + '--n-thread', + nargs='?', + default=8, + type=int, + help='thread number when using multiprocessing') + args = parser.parse_args() + return args + + +if __name__ == '__main__': + args = parse_args() + + if not osp.exists(args.out_dir): + os.makedirs(args.out_dir) + _gt_dir = osp.join(args.out_dir, '_GT') + gt_dir = osp.join(args.out_dir, 'GT') + bix8_dir = osp.join(args.out_dir, 'BIx8_down') + bix16_dir = osp.join(args.out_dir, 'BIx16_down') + if not osp.exists(_gt_dir): + os.makedirs(_gt_dir) + if not osp.exists(gt_dir): + os.makedirs(gt_dir) + if not osp.exists(bix8_dir): + os.makedirs(bix8_dir) + if not osp.exists(bix16_dir): + os.makedirs(bix16_dir) + + # export images + export_images(args.lmdb_path, args.meta_file_path, _gt_dir) + + # downsample images + downsample_images(args) diff --git a/tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py b/tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py new file mode 100644 index 0000000000..18bf8f7fca --- /dev/null +++ b/tools/dataset_converters/glean/preprocess_ffhq_celebahq_dataset.py @@ -0,0 +1,104 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os +import os.path as osp +from multiprocessing import Pool + +import mmengine +import numpy as np +from skimage import img_as_float +from skimage.io import imread, imsave + +from mmedit.datasets.transforms import MATLABLikeResize + + +def imresize(img_path, output_path, scale=None, output_shape=None): + """Resize the image using MATLAB-like downsampling. + + Args: + img_path (str): Input image path. + output_path (str): Output image path. + scale (float | None, optional): The scale factor of the resize + operation. If None, it will be determined by output_shape. + Default: None. + output_shape (tuple(int) | None, optional): The size of the output + image. If None, it will be determined by scale. Note that if + scale is provided, output_shape will not be used. + Default: None. + """ + + matlab_resize = MATLABLikeResize( + keys=['data'], scale=scale, output_shape=output_shape) + img = imread(img_path) + img = img_as_float(img) + data = {'data': img} + output = matlab_resize(data)['data'] + output = np.clip(output, 0.0, 1.0) * 255 + output = np.around(output).astype(np.uint8) + imsave(output_path, output) + + +def worker(img_name, args): + """Worker for each process. + + Args: + img_name (str): Image filename. + + Returns: + process_info (str): Process information displayed in progress bar. + """ + + gt_dir = args.data_root + bix8_dir = osp.join(gt_dir, '../BIx8_down') + bix16_dir = osp.join(gt_dir, '../BIx16_down') + imresize( + osp.join(gt_dir, img_name), osp.join(bix8_dir, img_name), scale=1 / 8) + imresize( + osp.join(gt_dir, img_name), + osp.join(bix16_dir, img_name), + scale=1 / 16) + process_info = f'Processing {img_name} ...' + return process_info + + +def downsample_images(args): + """Downsample images from the ground-truth.""" + + img_list = sorted(os.listdir(args.data_root)) + prog_bar = mmengine.ProgressBar(len(img_list)) + pool = Pool(args.n_thread) + for path in img_list: + pool.apply_async( + worker, args=(path, args), callback=lambda arg: prog_bar.update()) + pool.close() + pool.join() + print('All processes done.') + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Prepare ffhq dataset', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('--data-root', help='dataset root') + parser.add_argument( + '--n-thread', + nargs='?', + default=8, + type=int, + help='thread number when using multiprocessing') + args = parser.parse_args() + return args + + +if __name__ == '__main__': + args = parse_args() + + bix8_dir = osp.join(args.data_root, '../BIx8_down') + bix16_dir = osp.join(args.data_root, '../BIx16_down') + if not osp.exists(bix16_dir): + os.makedirs(bix16_dir) + if not osp.exists(bix8_dir): + os.makedirs(bix8_dir) + + # downsample images + downsample_images(args) diff --git a/tools/dataset_converters/gopro/README.md b/tools/dataset_converters/gopro/README.md new file mode 100644 index 0000000000..6d2015b5ca --- /dev/null +++ b/tools/dataset_converters/gopro/README.md @@ -0,0 +1,31 @@ +# Preparing GoPro Dataset + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +The train datasets can be download from [here](https://drive.google.com/file/d/1zgALzrLCC_tcXKu_iHQTHukKUVT1aodI/). The test datasets can be download from [here](https://drive.google.com/file/d/1k6DTSHu4saUgrGTYkkZXTptILyG9RRll/). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── GoPro +|   |   ├── train +|   |   | ├── input +|   |   | ├── target +|   |   ├── test +|   |   | ├── input +|   |   | ├── target +``` diff --git a/tools/dataset_converters/gopro/README_zh-CN.md b/tools/dataset_converters/gopro/README_zh-CN.md new file mode 100644 index 0000000000..32652e6064 --- /dev/null +++ b/tools/dataset_converters/gopro/README_zh-CN.md @@ -0,0 +1,31 @@ +# 准备 GoPro 数据集 + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +训练数据集可以从 [此处](https://drive.google.com/file/d/1zgALzrLCC_tcXKu_iHQTHukKUVT1aodI/) 下载。测试数据集可以从 [此处](https://drive.google.com/file/d/1k6DTSHu4saUgrGTYkkZXTptILyG9RRll/) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── GoPro +|   |   ├── train +|   |   | ├── input +|   |   | ├── target +|   |   ├── test +|   |   | ├── input +|   |   | ├── target +``` diff --git a/tools/dataset_converters/hide/README.md b/tools/dataset_converters/hide/README.md new file mode 100644 index 0000000000..b925ea7f45 --- /dev/null +++ b/tools/dataset_converters/hide/README.md @@ -0,0 +1,27 @@ +# Preparing HIDE Dataset + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +The test datasets can be download from [here](https://drive.google.com/file/d/1XRomKYJF1H92g1EuD06pCQe4o6HlwB7A/). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── HIDE +|   |   ├── input +|   |   ├── target +``` diff --git a/tools/dataset_converters/hide/README_zh-CN.md b/tools/dataset_converters/hide/README_zh-CN.md new file mode 100644 index 0000000000..81f3ea4868 --- /dev/null +++ b/tools/dataset_converters/hide/README_zh-CN.md @@ -0,0 +1,27 @@ +# 准备 HIDE 数据集 + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +测试数据集可以从 [此处](https://drive.google.com/file/d/1XRomKYJF1H92g1EuD06pCQe4o6HlwB7A/) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── HIDE +|   |   ├── input +|   |   ├── target +``` diff --git a/tools/dataset_converters/live1/README.md b/tools/dataset_converters/live1/README.md new file mode 100644 index 0000000000..8db4cee15a --- /dev/null +++ b/tools/dataset_converters/live1/README.md @@ -0,0 +1,28 @@ +# Preparing LIVE1 Dataset + + + +```bibtex +@article{zhang2017beyond, + title={Beyond a {Gaussian} denoiser: Residual learning of deep {CNN} for image denoising}, + author={Zhang, Kai and Zuo, Wangmeng and Chen, Yunjin and Meng, Deyu and Zhang, Lei}, + journal={IEEE Transactions on Image Processing}, + year={2017}, + volume={26}, + number={7}, + pages={3142-3155}, +} +``` + +The test datasets can be download from [here](https://github.com/cszn/DnCNN/tree/master/testsets). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── LIVE1 +``` diff --git a/tools/dataset_converters/live1/README_zh-CN.md b/tools/dataset_converters/live1/README_zh-CN.md new file mode 100644 index 0000000000..f3bb5483aa --- /dev/null +++ b/tools/dataset_converters/live1/README_zh-CN.md @@ -0,0 +1,28 @@ +# 准备 LIVE1 数据集 + + + +```bibtex +@article{zhang2017beyond, + title={Beyond a {Gaussian} denoiser: Residual learning of deep {CNN} for image denoising}, + author={Zhang, Kai and Zuo, Wangmeng and Chen, Yunjin and Meng, Deyu and Zhang, Lei}, + journal={IEEE Transactions on Image Processing}, + year={2017}, + volume={26}, + number={7}, + pages={3142-3155}, +} +``` + +测试数据集可以从 [此处](https://github.com/cszn/DnCNN/tree/master/testsets) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── LIVE1 +``` diff --git a/tools/dataset_converters/ntire21_decompression/README.md b/tools/dataset_converters/ntire21_decompression/README.md new file mode 100644 index 0000000000..e5814eecf0 --- /dev/null +++ b/tools/dataset_converters/ntire21_decompression/README.md @@ -0,0 +1,46 @@ +# Preparing NTIRE21 decompression Dataset + + + +```bibtex +@inproceedings{yang2021dataset, + title={{NTIRE 2021} Challenge on Quality Enhancement of Compressed Video: Dataset and Study}, + author={Ren Yang and Radu Timofte}, + booktitle={IEEE/CVF Conference on Computer Vision and Pattern Recognition Workshops}, + year={2021} +} + +``` + +The test datasets can be download from it's [Homepage](https://github.com/RenYang-home/NTIRE21_VEnh). + +Please follows the tutorials of the [Homepage](https://github.com/RenYang-home/NTIRE21_VEnh) to generate datasets. + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── NTIRE21_decompression_track1 +|   |   ├── GT +|   |   | ├── 001 +|   |   | | ├── 001.png +|   |   | | ├── ... +|   |   | ├── ... +|   |   | ├── 010 +|   |   ├── LQ +|   |   | ├── 001 +|   |   | | ├── 001.png +|   |   | | ├── ... +|   |   | ├── ... +|   |   | ├── 010 +|   ├── NTIRE21_decompression_track2 +|   |   ├── GT +|   |   ├── LQ +|   ├── NTIRE21_decompression_track3 +|   |   ├── GT +|   |   ├── LQ +``` diff --git a/tools/dataset_converters/ntire21_decompression/README_zh-CN.md b/tools/dataset_converters/ntire21_decompression/README_zh-CN.md new file mode 100644 index 0000000000..b02bc45b15 --- /dev/null +++ b/tools/dataset_converters/ntire21_decompression/README_zh-CN.md @@ -0,0 +1,45 @@ +# 准备 NTIRE21 decompression 数据集 + + + +```bibtex +@inproceedings{yang2021dataset, + title={{NTIRE 2021} Challenge on Quality Enhancement of Compressed Video: Dataset and Study}, + author={Ren Yang and Radu Timofte}, + booktitle={IEEE/CVF Conference on Computer Vision and Pattern Recognition Workshops}, + year={2021} +} +``` + +测试数据集可以从其[主页](https://github.com/RenYang-home/NTIRE21_VEnh)下载。 + +请按照[主页](https://github.com/RenYang-home/NTIRE21_VEnh)教程生成数据集。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── NTIRE21_decompression_track1 +|   |   ├── GT +|   |   | ├── 001 +|   |   | | ├── 001.png +|   |   | | ├── ... +|   |   | ├── ... +|   |   | ├── 010 +|   |   ├── LQ +|   |   | ├── 001 +|   |   | | ├── 001.png +|   |   | | ├── ... +|   |   | ├── ... +|   |   | ├── 010 +|   ├── NTIRE21_decompression_track2 +|   |   ├── GT +|   |   ├── LQ +|   ├── NTIRE21_decompression_track3 +|   |   ├── GT +|   |   ├── LQ +``` diff --git a/tools/dataset_converters/realblur/README.md b/tools/dataset_converters/realblur/README.md new file mode 100644 index 0000000000..cc14d25efd --- /dev/null +++ b/tools/dataset_converters/realblur/README.md @@ -0,0 +1,31 @@ +# Preparing RealBlur Dataset + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +The test datasets RealBlurR can be download from [here](https://drive.google.com/file/d/1glgeWXCy7Y0qWDc0MXBTUlZYJf8984hS/). +The test datasets RealBlurJ can be download from [here](https://drive.google.com/file/d/1Rb1DhhXmX7IXfilQ-zL9aGjQfAAvQTrW/). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── RealBlur_R +|   |   ├── input +|   |   ├── target +|   ├── RealBlur_J +|   |   ├── input +|   |   ├── target +``` diff --git a/tools/dataset_converters/realblur/README_zh-CN.md b/tools/dataset_converters/realblur/README_zh-CN.md new file mode 100644 index 0000000000..b6009879a9 --- /dev/null +++ b/tools/dataset_converters/realblur/README_zh-CN.md @@ -0,0 +1,31 @@ +# 准备 RealBlur 数据集 + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +测试数据集 RealBlurR 可以从 [此处](https://drive.google.com/file/d/1glgeWXCy7Y0qWDc0MXBTUlZYJf8984hS/) 下载。 +测试数据集 RealBlurJ 可以从 [此处](https://drive.google.com/file/d/1Rb1DhhXmX7IXfilQ-zL9aGjQfAAvQTrW/) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── RealBlur_R +|   |   ├── input +|   |   ├── target +|   ├── RealBlur_J +|   |   ├── input +|   |   ├── target +``` diff --git a/tools/dataset_converters/realsrset/README.md b/tools/dataset_converters/realsrset/README.md new file mode 100644 index 0000000000..39ed3167fc --- /dev/null +++ b/tools/dataset_converters/realsrset/README.md @@ -0,0 +1,29 @@ +# Preparing RealSRSet Dataset + + + +```bibtex +@inproceedings{zhang2021designing, + title={Designing a Practical Degradation Model for Deep Blind Image Super-Resolution}, + author={Zhang, Kai and Liang, Jingyun and Van Gool, Luc and Timofte, Radu}, + booktitle={IEEE International Conference on Computer Vision}, + pages={4791--4800}, + year={2021} +} +``` + +The datasets RealSRSet can be download from [here](https://github.com/cszn/BSRGAN/tree/main/testsets/RealSRSet). + +The datasets RealSRSet+5images can be download from [here](https://github.com/JingyunLiang/SwinIR/releases/download/v0.0/RealSRSet+5images.zip). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── realsrset +|   ├── RealSRSet+5images +``` diff --git a/tools/dataset_converters/realsrset/README_zh-CN.md b/tools/dataset_converters/realsrset/README_zh-CN.md new file mode 100644 index 0000000000..690dd45056 --- /dev/null +++ b/tools/dataset_converters/realsrset/README_zh-CN.md @@ -0,0 +1,29 @@ +# 准备 RealSRSet 数据集 + + + +```bibtex +@inproceedings{zhang2021designing, + title={Designing a Practical Degradation Model for Deep Blind Image Super-Resolution}, + author={Zhang, Kai and Liang, Jingyun and Van Gool, Luc and Timofte, Radu}, + booktitle={IEEE International Conference on Computer Vision}, + pages={4791--4800}, + year={2021} +} +``` + +数据集 RealSRSet 可以从 [此处](https://github.com/cszn/BSRGAN/tree/main/testsets/RealSRSet) 下载。 + +数据集 RealSRSet+5images 可以从 [此处](https://github.com/JingyunLiang/SwinIR/releases/download/v0.0/RealSRSet+5images.zip) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── realsrset +|   ├── RealSRSet+5images +``` diff --git a/tools/dataset_converters/reds/README.md b/tools/dataset_converters/reds/README.md index 69ccdf7795..6e6c9fdb76 100644 --- a/tools/dataset_converters/reds/README.md +++ b/tools/dataset_converters/reds/README.md @@ -36,9 +36,15 @@ mmediting │ │ │ ├── 001 │ │ │ ├── ... │ │ ├── train_sharp_bicubic -│ │ │ ├── 000 -│ │ │ ├── 001 -│ │ │ ├── ... +│ │ │ ├── X4 +│ │ │ | ├── 000 +│ │ │ | ├── 001 +│ │ │ | ├── ... +│ │ ├── meta_info_reds4_train.txt +│ │ ├── meta_info_reds4_val.txt +│ │ ├── meta_info_official_train.txt +│ │ ├── meta_info_official_val.txt +│ │ ├── meta_info_REDS_GT.txt │ ├── REDS4 │ │ ├── GT │ │ ├── sharp_bicubic diff --git a/tools/dataset_converters/reds/README_zh-CN.md b/tools/dataset_converters/reds/README_zh-CN.md index 6350b848a1..fc088371ec 100644 --- a/tools/dataset_converters/reds/README_zh-CN.md +++ b/tools/dataset_converters/reds/README_zh-CN.md @@ -37,9 +37,15 @@ mmediting │ │ │ ├── 001 │ │ │ ├── ... │ │ ├── train_sharp_bicubic -│ │ │ ├── 000 -│ │ │ ├── 001 -│ │ │ ├── ... +│ │ │ ├── X4 +│ │ │ | ├── 000 +│ │ │ | ├── 001 +│ │ │ | ├── ... +│ │ ├── meta_info_reds4_train.txt +│ │ ├── meta_info_reds4_val.txt +│ │ ├── meta_info_official_train.txt +│ │ ├── meta_info_official_val.txt +│ │ ├── meta_info_REDS_GT.txt │ ├── REDS4 │ │ ├── GT │ │ ├── sharp_bicubic diff --git a/tools/dataset_converters/reds/crop_sub_images.py b/tools/dataset_converters/reds/crop_sub_images.py index 9cdabcb93c..67bf7a3418 100644 --- a/tools/dataset_converters/reds/crop_sub_images.py +++ b/tools/dataset_converters/reds/crop_sub_images.py @@ -8,6 +8,7 @@ import cv2 import mmcv +import mmengine import numpy as np @@ -54,7 +55,7 @@ def worker(path, opt): cropped_img = img[x:x + crop_size, y:y + crop_size, ...] sub_folder = osp.join(opt['save_folder'], f'{sequence}_s{index:03d}') - mmcv.mkdir_or_exist(sub_folder) + mmengine.mkdir_or_exist(sub_folder) cv2.imwrite( osp.join(sub_folder, f'{img_name}{extension}'), cropped_img, [cv2.IMWRITE_PNG_COMPRESSION, opt['compression_level']]) @@ -80,10 +81,10 @@ def extract_subimages(opt): print(f'Folder {save_folder} already exists. Exit.') sys.exit(1) - img_list = list(mmcv.scandir(input_folder, recursive=True)) + img_list = list(mmengine.scandir(input_folder, recursive=True)) img_list = [osp.join(input_folder, v) for v in img_list] - prog_bar = mmcv.ProgressBar(len(img_list)) + prog_bar = mmengine.ProgressBar(len(img_list)) pool = Pool(opt['n_thread']) for path in img_list: pool.apply_async( diff --git a/tools/dataset_converters/reds/preprocess_reds_dataset.py b/tools/dataset_converters/reds/preprocess_reds_dataset.py index 0f39483b36..d7f8723da3 100644 --- a/tools/dataset_converters/reds/preprocess_reds_dataset.py +++ b/tools/dataset_converters/reds/preprocess_reds_dataset.py @@ -10,6 +10,7 @@ import cv2 import lmdb import mmcv +import mmengine def make_lmdb(mode, data_path, lmdb_path, batch=5000, compress_level=1): @@ -69,7 +70,7 @@ def make_lmdb(mode, data_path, lmdb_path, batch=5000, compress_level=1): print('Reading image path list ...') img_path_list = sorted( - list(mmcv.scandir(data_path, suffix='png', recursive=True))) + list(mmengine.scandir(data_path, suffix='png', recursive=True))) keys = [] for img_path in img_path_list: parts = re.split(r'[\\/]', img_path) @@ -88,7 +89,7 @@ def make_lmdb(mode, data_path, lmdb_path, batch=5000, compress_level=1): env = lmdb.open(lmdb_path, map_size=data_size * 10) # write data to lmdb - pbar = mmcv.ProgressBar(len(img_path_list)) + pbar = mmengine.ProgressBar(len(img_path_list)) txn = env.begin(write=True) txt_file = open(osp.join(lmdb_path, 'meta_info.txt'), 'w') for idx, (path, key) in enumerate(zip(img_path_list, keys)): @@ -145,7 +146,7 @@ def generate_anno_file(root_path, file_name='meta_info_REDS_GT.txt'): print(f'Generate annotation files {file_name}...') txt_file = osp.join(root_path, file_name) - mmcv.utils.mkdir_or_exist(osp.dirname(txt_file)) + mmengine.utils.mkdir_or_exist(osp.dirname(txt_file)) with open(txt_file, 'w') as f: for i in range(270): for j in range(100): @@ -180,11 +181,11 @@ def split_anno_file(root_path, val_partition='REDS4'): else: train_list.append(f'{i:03d}/{j:08d}.png (720, 1280, 3)') - mmcv.utils.mkdir_or_exist(osp.dirname(train_txt_file)) + mmengine.utils.mkdir_or_exist(osp.dirname(train_txt_file)) with open(train_txt_file, 'w') as f: f.write('\n'.join(train_list)) - mmcv.utils.mkdir_or_exist(osp.dirname(val_txt_file)) + mmengine.utils.mkdir_or_exist(osp.dirname(val_txt_file)) with open(val_txt_file, 'w') as f: f.write('\n'.join(val_list)) @@ -199,7 +200,7 @@ def unzip(zip_path): Returns: list: unzip folder names. """ - zip_files = mmcv.scandir(zip_path, suffix='zip', recursive=False) + zip_files = mmengine.scandir(zip_path, suffix='zip', recursive=False) import shutil import zipfile unzip_folders = [] diff --git a/tools/dataset_converters/sidd/README.md b/tools/dataset_converters/sidd/README.md new file mode 100644 index 0000000000..bf52558500 --- /dev/null +++ b/tools/dataset_converters/sidd/README.md @@ -0,0 +1,40 @@ +# Preparing SIDD Dataset + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +The train datasets can be download from [here](https://drive.google.com/file/d/1UHjWZzLPGweA9ZczmV8lFSRcIxqiOVJw/). The validation datasets can be download from [here](https://drive.google.com/file/d/1Fw6Ey1R-nCHN9WEpxv0MnMqxij-ECQYJ/). The test datasets can be download from [here](https://drive.google.com/file/d/11vfqV-lqousZTuAit1Qkqghiv_taY0KZ/). + +For test datasets, we need to export images from mat file. We provide such a script: + +```shell +python tools/dataset_converters/sidd/preprocess_sidd_test_dataset.py --data-root ./data/SIDD/test --out-dir ./data/SIDD/test +``` + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── SIDD +|   |   ├── train +|   |   | ├── gt +|   |   | ├── noisy +|   |   ├── val +|   |   | ├── input_crops +|   |   | ├── target_crops +|   |   ├── test +|   |   | ├── gt +|   |   | ├── noisy +``` diff --git a/tools/dataset_converters/sidd/README_zh-CN.md b/tools/dataset_converters/sidd/README_zh-CN.md new file mode 100644 index 0000000000..7a4de40bda --- /dev/null +++ b/tools/dataset_converters/sidd/README_zh-CN.md @@ -0,0 +1,40 @@ +# 准备 SIDD 数据集 + + + +```bibtex +@inproceedings{Zamir2021Restormer, + title={Restormer: Efficient Transformer for High-Resolution Image Restoration}, + author={Syed Waqas Zamir and Aditya Arora and Salman Khan and Munawar Hayat and Fahad Shahbaz Khan and Ming-Hsuan Yang}, + booktitle={CVPR}, + year={2022} +} +``` + +训练数据集可以从 [此处](https://drive.google.com/file/d/1UHjWZzLPGweA9ZczmV8lFSRcIxqiOVJw/) 下载。验证数据集可以从 [此处](https://drive.google.com/file/d/1Fw6Ey1R-nCHN9WEpxv0MnMqxij-ECQYJ/) 下载。测试数据集可以从 [此处](https://drive.google.com/file/d/11vfqV-lqousZTuAit1Qkqghiv_taY0KZ/) 下载。 + +测试数据集需要从 mat 文件中导出,为此,我们提供了一个脚本: + +```shell +python tools/dataset_converters/sidd/preprocess_sidd_test_dataset.py --data-root ./data/SIDD/test --out-dir ./data/SIDD/test +``` + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── SIDD +|   |   ├── train +|   |   | ├── gt +|   |   | ├── noisy +|   |   ├── val +|   |   | ├── input_crops +|   |   | ├── target_crops +|   |   ├── test +|   |   | ├── gt +|   |   | ├── noisy +``` diff --git a/tools/dataset_converters/sidd/preprocess_sidd_test_dataset.py b/tools/dataset_converters/sidd/preprocess_sidd_test_dataset.py new file mode 100644 index 0000000000..60a83e7dce --- /dev/null +++ b/tools/dataset_converters/sidd/preprocess_sidd_test_dataset.py @@ -0,0 +1,77 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os +import os.path as osp + +import cv2 +import numpy as np +import scipy.io as sio +import torch +from skimage import img_as_ubyte +from tqdm import tqdm + + +def export_images(args): + """Export images from mat file.""" + + noisy_dir = osp.join(args.out_dir, 'noisy') + os.makedirs(noisy_dir, exist_ok=True) + gt_dir = osp.join(args.out_dir, 'gt') + os.makedirs(gt_dir, exist_ok=True) + + noisy_matfile = osp.join(args.data_root, 'ValidationNoisyBlocksSrgb.mat') + gt_matfile = osp.join(args.data_root, 'ValidationGtBlocksSrgb.mat') + noisy_images = sio.loadmat(noisy_matfile) + gt_images = sio.loadmat(gt_matfile) + + noisy_images = np.float32( + np.array(noisy_images['ValidationNoisyBlocksSrgb'])) + noisy_images /= 255. + gt_images = np.float32(np.array(gt_images['ValidationGtBlocksSrgb'])) + gt_images /= 255. + + # processing noisy images + print('Exporting', noisy_matfile, 'to', noisy_dir) + for i in tqdm(range(40)): + for k in range(32): + noisy_patch = torch.from_numpy( + noisy_images[i, k, :, :, :]).unsqueeze(0).permute(0, 3, 1, 2) + noisy_patch = torch.clamp(noisy_patch, 0, + 1).detach().permute(0, 2, 3, + 1).squeeze(0) + save_path = osp.join(noisy_dir, '%04d_%02d.png' % (i + 1, k + 1)) + cv2.imwrite( + save_path, + cv2.cvtColor(img_as_ubyte(noisy_patch), cv2.COLOR_RGB2BGR)) + + # processing gt images + print('Exporting', gt_matfile, 'to', gt_dir) + for i in tqdm(range(40)): + for k in range(32): + gt_patch = torch.from_numpy( + gt_images[i, k, :, :, :]).unsqueeze(0).permute(0, 3, 1, 2) + gt_patch = torch.clamp(gt_patch, 0, + 1).detach().permute(0, 2, 3, 1).squeeze(0) + save_path = osp.join(gt_dir, '%04d_%02d.png' % (i + 1, k + 1)) + cv2.imwrite( + save_path, + cv2.cvtColor(img_as_ubyte(gt_patch), cv2.COLOR_RGB2BGR)) + + print('\nFinish exporting images.') + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Prepare SIDD test dataset', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('--data-root', help='dataset root') + parser.add_argument('--out-dir', help='output directory of dataset') + args = parser.parse_args() + return args + + +if __name__ == '__main__': + args = parse_args() + + # export images + export_images(args) diff --git a/tools/dataset_converters/spmcs/README.md b/tools/dataset_converters/spmcs/README.md new file mode 100644 index 0000000000..256c293af4 --- /dev/null +++ b/tools/dataset_converters/spmcs/README.md @@ -0,0 +1,30 @@ +# Preparing SPMCS Dataset + + + +```bibtex +@InProceedings{tao2017spmc, + author={Xin Tao and Hongyun Gao and Renjie Liao and Jue Wang and Jiaya Jia}, + title = {Detail-Revealing Deep Video Super-Resolution}, + booktitle = {The IEEE International Conference on Computer Vision (ICCV)}, + month = {Oct}, + year = {2017} +} +``` + +The datasets can be download from [here](https://opendatalab.org.cn/SPMCS). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── SPMCS +|   |   ├── GT +|   |   ├── BIx4 +|   |   ├── BDx4 +|   |   ├── meta_info_SPMCS_GT.txt +``` diff --git a/tools/dataset_converters/spmcs/README_zh-CN.md b/tools/dataset_converters/spmcs/README_zh-CN.md new file mode 100644 index 0000000000..685fc34459 --- /dev/null +++ b/tools/dataset_converters/spmcs/README_zh-CN.md @@ -0,0 +1,30 @@ +# 准备 SPMCS 数据集 + + + +```bibtex +@InProceedings{tao2017spmc, + author={Xin Tao and Hongyun Gao and Renjie Liao and Jue Wang and Jiaya Jia}, + title = {Detail-Revealing Deep Video Super-Resolution}, + booktitle = {The IEEE International Conference on Computer Vision (ICCV)}, + month = {Oct}, + year = {2017} +} +``` + +数据集可以从 [此处](https://opendatalab.org.cn/SPMCS) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── SPMCS +|   |   ├── GT +|   |   ├── BIx4 +|   |   ├── BDx4 +|   |   ├── meta_info_SPMCS_GT.txt +``` diff --git a/tools/dataset_converters/udm10/README.md b/tools/dataset_converters/udm10/README.md new file mode 100644 index 0000000000..f5ee2be9b0 --- /dev/null +++ b/tools/dataset_converters/udm10/README.md @@ -0,0 +1,29 @@ +# Preparing UDM10 Dataset + + + +```bibtex +@inproceedings{PFNL, + title={Progressive Fusion Video Super-Resolution Network via Exploiting Non-Local Spatio-Temporal Correlations}, + author={Yi, Peng and Wang, Zhongyuan and Jiang, Kui and Jiang, Junjun and Ma, Jiayi}, + booktitle={IEEE International Conference on Computer Vision (ICCV)}, + pages={3106-3115}, + year={2019}, +} +``` + +The datasets can be download from [here](https://drive.google.com/file/d/1G4V4KZZhhfzUlqHiSBBuWyqLyIOvOs0W/). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── UDM10 +|   |   ├── GT +|   |   ├── BIx4 +|   |   ├── BDx4 +``` diff --git a/tools/dataset_converters/udm10/README_zh-CN.md b/tools/dataset_converters/udm10/README_zh-CN.md new file mode 100644 index 0000000000..e1f289428e --- /dev/null +++ b/tools/dataset_converters/udm10/README_zh-CN.md @@ -0,0 +1,29 @@ +# 准备 UDM10 数据集 + + + +```bibtex +@inproceedings{PFNL, + title={Progressive Fusion Video Super-Resolution Network via Exploiting Non-Local Spatio-Temporal Correlations}, + author={Yi, Peng and Wang, Zhongyuan and Jiang, Kui and Jiang, Junjun and Ma, Jiayi}, + booktitle={IEEE International Conference on Computer Vision (ICCV)}, + pages={3106-3115}, + year={2019}, +} +``` + +数据集可以从 [此处](https://drive.google.com/file/d/1G4V4KZZhhfzUlqHiSBBuWyqLyIOvOs0W/) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── UDM10 +|   |   ├── GT +|   |   ├── BIx4 +|   |   ├── BDx4 +``` diff --git a/tools/dataset_converters/vid4/README.md b/tools/dataset_converters/vid4/README.md index d7f3cef610..3d9511ab7c 100644 --- a/tools/dataset_converters/vid4/README.md +++ b/tools/dataset_converters/vid4/README.md @@ -19,3 +19,38 @@ The Vid4 dataset can be downloaded from [here](https://drive.google.com/file/d/1 1. BIx4 contains images downsampled by bicubic interpolation 2. BDx4 contains images blurred by Gaussian kernel with σ=1.6, followed by a subsampling every four pixels. + +Note that we should prepare a annotation file (such as meta_info_Vid4_GT.txt) for Vid4 dataset as follows. + +```text +calendar 41 (576,720,3) +city 34 (576,704,3) +foliage 49 (480,720,3) +walk 47 (480,720,3) +``` + +For ToFlow, we should prepare directly upsampling dataset. We provide such a script: + +```shell +python tools/dataset_converters/vid4/preprocess_vid4_dataset.py --data-root ./data/Vid4/BIx4 +``` + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +│ ├── Vid4 +│ │ ├── GT +│ │ │ ├── calendar +│ │ │ ├── city +│ │ │ ├── foliage +│ │ │ ├── walk +│ │ ├── BDx4 +│ │ ├── BIx4 +│ │ ├── BIx4up_direct +│ │ ├── meta_info_Vid4_GT.txt +``` diff --git a/tools/dataset_converters/vid4/README_zh-CN.md b/tools/dataset_converters/vid4/README_zh-CN.md index 5645daceec..21e00fc92f 100644 --- a/tools/dataset_converters/vid4/README_zh-CN.md +++ b/tools/dataset_converters/vid4/README_zh-CN.md @@ -19,3 +19,38 @@ 1. BIx4 包含了由双线性插值下采样得到的图片 2. BDx4 包含了由 `σ=1.6` 的高斯核模糊,然后每4个像素进行一次采样得到的图片 + +请注意,应为 Vid4 数据集准备一个如下所列的标注文件(例如 meta_info_Vid4_GT.txt)。 + +```text +calendar 41 (576,720,3) +city 34 (576,704,3) +foliage 49 (480,720,3) +walk 47 (480,720,3) +``` + +对于 ToFlow,应准备直接上采样的数据集,为此,我们提供了一个脚本: + +```shell +python tools/dataset_converters/vid4/preprocess_vid4_dataset.py --data-root ./data/Vid4/BIx4 +``` + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +│ ├── Vid4 +│ │ ├── GT +│ │ │ ├── calendar +│ │ │ ├── city +│ │ │ ├── foliage +│ │ │ ├── walk +│ │ ├── BDx4 +│ │ ├── BIx4 +│ │ ├── BIx4up_direct +│ │ ├── meta_info_Vid4_GT.txt +``` diff --git a/tools/dataset_converters/vid4/preprocess_vid4_dataset.py b/tools/dataset_converters/vid4/preprocess_vid4_dataset.py new file mode 100644 index 0000000000..26d34b28d3 --- /dev/null +++ b/tools/dataset_converters/vid4/preprocess_vid4_dataset.py @@ -0,0 +1,103 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os +import os.path as osp +from multiprocessing import Pool + +import mmengine +import numpy as np +from skimage import img_as_float +from skimage.io import imread, imsave + +from mmedit.datasets.transforms import MATLABLikeResize + + +def imresize(img_path, output_path, scale=None, output_shape=None): + """Resize the image using MATLAB-like downsampling. + + Args: + img_path (str): Input image path. + output_path (str): Output image path. + scale (float | None, optional): The scale factor of the resize + operation. If None, it will be determined by output_shape. + Default: None. + output_shape (tuple(int) | None, optional): The size of the output + image. If None, it will be determined by scale. Note that if + scale is provided, output_shape will not be used. + Default: None. + """ + + matlab_resize = MATLABLikeResize( + keys=['data'], scale=scale, output_shape=output_shape) + img = imread(img_path) + img = img_as_float(img) + data = {'data': img} + output = matlab_resize(data)['data'] + output = np.clip(output, 0.0, 1.0) * 255 + output = np.around(output).astype(np.uint8) + imsave(output_path, output) + + +def worker(img_name, args): + """Worker for each process. + + Args: + img_name (str): Image filename. + + Returns: + process_info (str): Process information displayed in progress bar. + """ + + up_dir = osp.join(args.data_root, '../BIx4up_direct') + mmengine.utils.mkdir_or_exist(osp.dirname(osp.join(up_dir, img_name))) + imresize( + osp.join(args.data_root, img_name), + osp.join(up_dir, img_name), + scale=4) + process_info = f'Processing {img_name} ...' + return process_info + + +def upsample_images(args): + """Upsample images.""" + + img_list = [] + clip_list = sorted(os.listdir(args.data_root)) + for clip in clip_list: + clip_root = osp.join(args.data_root, clip) + img_list.extend( + [osp.join(clip, i) for i in sorted(os.listdir(clip_root))]) + prog_bar = mmengine.ProgressBar(len(img_list)) + pool = Pool(args.n_thread) + for path in img_list: + pool.apply_async( + worker, args=(path, args), callback=lambda arg: prog_bar.update()) + pool.close() + pool.join() + print('All processes done.') + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Prepare cat dataset', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('--data-root', help='dataset root') + parser.add_argument( + '--n-thread', + nargs='?', + default=8, + type=int, + help='thread number when using multiprocessing') + args = parser.parse_args() + return args + + +if __name__ == '__main__': + args = parse_args() + + up_dir = osp.join(args.data_root, '../BIx4up_direct') + if not osp.exists(up_dir): + os.makedirs(up_dir) + + # upsample images + upsample_images(args) diff --git a/tools/dataset_converters/videolq/README.md b/tools/dataset_converters/videolq/README.md new file mode 100644 index 0000000000..68ccb8776c --- /dev/null +++ b/tools/dataset_converters/videolq/README.md @@ -0,0 +1,32 @@ +# Preparing VideoLQ Dataset + + + +```bibtex +@inproceedings{chan2022investigating, + author = {Chan, Kelvin C.K. and Zhou, Shangchen and Xu, Xiangyu and Loy, Chen Change}, + title = {Investigating Tradeoffs in Real-World Video Super-Resolution}, + booktitle = {IEEE Conference on Computer Vision and Pattern Recognition}, + year = {2022} +} +``` + +You can download the dataset using [Dropbox](https://www.dropbox.com/sh/hc06f1livdhutbo/AAAMPy92EOqVjRN8waT0ie8ja?dl=0) / [Google Drive](https://drive.google.com/drive/folders/1-1iJRNdqdFZWOnoUU4xG1Z1QhwsGwMDy?usp=sharing) / [OneDrive](https://entuedu-my.sharepoint.com/:f:/g/personal/chan0899_e_ntu_edu_sg/ErSugvUBxoBMlvSAHhqT5BEB9-4ZaqxzJIcc9uvVa8JGHg?e=WpHJTc). + +The folder structure should look like: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── VideoLQ +│ │ ├── 000 +│ │ │ ├── 00000000.png +│ │ │ ├── 00000001.png +│ │ │ ├── ... +│ │ ├── 001 +│ │ ├── 002 +│ │ ├── ... +``` diff --git a/tools/dataset_converters/videolq/README_zh-CN.md b/tools/dataset_converters/videolq/README_zh-CN.md new file mode 100644 index 0000000000..cff8da1459 --- /dev/null +++ b/tools/dataset_converters/videolq/README_zh-CN.md @@ -0,0 +1,32 @@ +# 准备 VideoLQ 数据集 + + + +```bibtex +@inproceedings{chan2022investigating, + author = {Chan, Kelvin C.K. and Zhou, Shangchen and Xu, Xiangyu and Loy, Chen Change}, + title = {Investigating Tradeoffs in Real-World Video Super-Resolution}, + booktitle = {IEEE Conference on Computer Vision and Pattern Recognition}, + year = {2022} +} +``` + +数据集可以从 [Dropbox](https://www.dropbox.com/sh/hc06f1livdhutbo/AAAMPy92EOqVjRN8waT0ie8ja?dl=0) / [Google Drive](https://drive.google.com/drive/folders/1-1iJRNdqdFZWOnoUU4xG1Z1QhwsGwMDy?usp=sharing) / [OneDrive](https://entuedu-my.sharepoint.com/:f:/g/personal/chan0899_e_ntu_edu_sg/ErSugvUBxoBMlvSAHhqT5BEB9-4ZaqxzJIcc9uvVa8JGHg?e=WpHJTc) 下载。 + +文件目录结构应如下所示: + +```text +mmediting +├── mmedit +├── tools +├── configs +├── data +|   ├── VideoLQ +│ │ ├── 000 +│ │ │ ├── 00000000.png +│ │ │ ├── 00000001.png +│ │ │ ├── ... +│ │ ├── 001 +│ │ ├── 002 +│ │ ├── ... +``` diff --git a/tools/dataset_converters/vimeo90k/README.md b/tools/dataset_converters/vimeo90k/README.md index 26f9ce521a..3ef492d0d7 100644 --- a/tools/dataset_converters/vimeo90k/README.md +++ b/tools/dataset_converters/vimeo90k/README.md @@ -17,7 +17,32 @@ The training and test datasets can be download from [here](http://toflow.csail.mit.edu/). -The Vimeo90K dataset has a `clip/sequence/img` folder structure: +Then you can rename the directory `vimeo_septuplet/sequences` to `vimeo90k/GT`. The Vimeo90K dataset has a `clip/sequence/img` folder structure: + +```text +vimeo90k +├── GT +│ ├── 00001 +│ │ ├── 0001 +│ │ │ ├── im1.png +│ │ │ ├── im2.png +│ │ │ ├── ... +│ │ ├── 0002 +│ │ ├── 0003 +│ │ ├── ... +│ ├── 00002 +│ ├── ... +├── sep_trainlist.txt +├── sep_testlist.txt +``` + +To generate the downsampling images BIx4 and BDx4 and prepare the annotation file, you need to run the following command: + +```shell +python tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py --data-root ./data/vimeo90k +``` + +The folder structure should look like: ```text mmediting @@ -26,7 +51,7 @@ mmediting ├── configs ├── data │ ├── vimeo_triplet -│ │ ├── BDx4 +│ │ ├── GT │ │ │ ├── 00001 │ │ │ │ ├── 0001 │ │ │ │ │ ├── im1.png @@ -38,25 +63,15 @@ mmediting │ │ │ ├── 00002 │ │ │ ├── ... │ │ ├── BIx4 -│ │ ├── GT +│ │ ├── BDx4 │ │ ├── meta_info_Vimeo90K_test_GT.txt │ │ ├── meta_info_Vimeo90K_train_GT.txt ``` -## Prepare the annotation files for Vimeo90K dataset - -To prepare the annotation file for training, you need to download the official training list path for Vimeo90K from the official website, and run the following command: - -```shell -python tools/dataset_converters/super-resolution/vimeo90k/preprocess_vimeo90k_dataset.py ./data/Vimeo90K/official_train_list.txt -``` - -The annotation file for test is generated similarly. - ## Prepare LMDB dataset for Vimeo90K If you want to use LMDB datasets for faster IO speed, you can make LMDB files by: ```shell -python tools/dataset_converters/super-resolution/vimeo90k/preprocess_vimeo90k_dataset.py ./data/Vimeo90K/official_train_list.txt --gt-path ./data/Vimeo90K/GT --lq-path ./data/Vimeo90K/LQ --make-lmdb +python tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py --data-root ./data/vimeo90k --train_list ./data/vimeo90k/sep_trainlist.txt --gt-path ./data/vimeo90k/GT --lq-path ./data/Vimeo90k/BIx4 --make-lmdb ``` diff --git a/tools/dataset_converters/vimeo90k/README_zh-CN.md b/tools/dataset_converters/vimeo90k/README_zh-CN.md index 4b25d6bfe3..600973f52c 100644 --- a/tools/dataset_converters/vimeo90k/README_zh-CN.md +++ b/tools/dataset_converters/vimeo90k/README_zh-CN.md @@ -17,7 +17,32 @@ 训练集和测试集可以从 [此处](http://toflow.csail.mit.edu/) 下载。 -Vimeo90K 数据集包含了如下所示的 `clip/sequence/img` 目录结构: +将数据集路径 `vimeo_septuplet/sequences` 重命名为 `vimeo90k/GT`。Vimeo90K 数据集包含了如下所示的 `clip/sequence/img` 目录结构: + +```text +vimeo90k +├── GT +│ ├── 00001 +│ │ ├── 0001 +│ │ │ ├── im1.png +│ │ │ ├── im2.png +│ │ │ ├── ... +│ │ ├── 0002 +│ │ ├── 0003 +│ │ ├── ... +│ ├── 00002 +│ ├── ... +├── sep_trainlist.txt +├── sep_testlist.txt +``` + +为了生成下采样图像BIx4和BDx4,以及准备所需的标注文件,需要执行如下命令: + +```shell +python tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py --data-root ./data/vimeo90k +``` + +文件目录结构应如下所示: ```text mmediting @@ -26,7 +51,7 @@ mmediting ├── configs ├── data │ ├── vimeo_triplet -│ │ ├── BDx4 +│ │ ├── GT │ │ │ ├── 00001 │ │ │ │ ├── 0001 │ │ │ │ │ ├── im1.png @@ -38,25 +63,15 @@ mmediting │ │ │ ├── 00002 │ │ │ ├── ... │ │ ├── BIx4 -│ │ ├── GT +│ │ ├── BDx4 │ │ ├── meta_info_Vimeo90K_test_GT.txt │ │ ├── meta_info_Vimeo90K_train_GT.txt ``` -## 准备 Vimeo90K 数据集的标注文件 - -为了准备好训练所需的标注文件,请先从 Vimeo90K 数据集官网下载训练路径列表,随后执行如下命令: - -```shell -python tools/dataset_converters/super-resolution/vimeo90k/preprocess_vimeo90k_dataset.py ./data/Vimeo90K/official_train_list.txt -``` - -测试集的标注文件可通过类似方式生成. - ## 准备 LMDB 格式的 Vimeo90K 数据集 如果您想使用 `LMDB` 以获得更快的 IO 速度,可以通过以下脚本来构建 LMDB 文件 ```shell -python tools/dataset_converters/super-resolution/vimeo90k/preprocess_vimeo90k_dataset.py ./data/Vimeo90K/official_train_list.txt --gt-path ./data/Vimeo90K/GT --lq-path ./data/Vimeo90K/LQ --make-lmdb +python tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py --data-root ./data/vimeo90k --train_list ./data/vimeo90k/sep_trainlist.txt --gt-path ./data/vimeo90k/GT --lq-path ./data/Vimeo90k/BIx4 --make-lmdb ``` diff --git a/tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py b/tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py index ba12d40b55..a1d104c749 100644 --- a/tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py +++ b/tools/dataset_converters/vimeo90k/preprocess_vimeo90k_dataset.py @@ -1,12 +1,20 @@ # Copyright (c) OpenMMLab. All rights reserved. import argparse +import math +import os import os.path as osp import sys +from multiprocessing import Pool import cv2 import lmdb import mmcv +import mmengine +import numpy as np +from skimage import img_as_float +from skimage.io import imread, imsave +from mmedit.datasets.transforms import MATLABLikeResize, blur_kernels from mmedit.utils import modify_args @@ -116,22 +124,146 @@ def make_lmdb(mode, print('\nFinish writing lmdb.') -def generate_anno_file(train_list, file_name='meta_info_Vimeo90K_GT.txt'): - """Generate anno file for Vimeo90K datasets from the official train list. +def generate_anno_file(clip_list, file_name='meta_info_Vimeo90K_GT.txt'): + """Generate anno file for Vimeo90K datasets from the official clip list. Args: - train_list (str): Train list path for Vimeo90K datasets. + clip_list (str): Clip list path for Vimeo90K datasets. file_name (str): Saved file name. Default: 'meta_info_Vimeo90K_GT.txt'. """ print(f'Generate annotation files {file_name}...') - # read official train list - with open(train_list) as f: + with open(clip_list) as f: lines = [line.rstrip() for line in f] - txt_file = osp.join(osp.dirname(train_list), file_name) + txt_file = osp.join(osp.dirname(clip_list), file_name) with open(txt_file, 'w') as f: for line in lines: - f.write(f'{line} (256, 448, 3)\n') + f.write(f'{line} 7 (256, 448, 3)\n') + + +def imresize(img_path, output_path, scale=None, output_shape=None): + """Resize the image using MATLAB-like downsampling. + + Args: + img_path (str): Input image path. + output_path (str): Output image path. + scale (float | None, optional): The scale factor of the resize + operation. If None, it will be determined by output_shape. + Default: None. + output_shape (tuple(int) | None, optional): The size of the output + image. If None, it will be determined by scale. Note that if + scale is provided, output_shape will not be used. + Default: None. + """ + + matlab_resize = MATLABLikeResize( + keys=['data'], scale=scale, output_shape=output_shape) + img = imread(img_path) + img = img_as_float(img) + data = {'data': img} + output = matlab_resize(data)['data'] + output = np.clip(output, 0.0, 1.0) * 255 + output = np.around(output).astype(np.uint8) + imsave(output_path, output) + + +def mesh_grid(kernel_size): + """Generate the mesh grid, centering at zero. + + Args: + kernel_size (int): The size of the kernel. + + Returns: + xy_grid (np.ndarray): stacked xy coordinates with shape + (kernel_size, kernel_size, 2). + """ + range_ = np.arange(-(kernel_size - 1.) / 2., (kernel_size - 1.) / 2. + 1.) + x_grid, y_grid = np.meshgrid(range_, range_) + xy_grid = np.hstack((x_grid.reshape((kernel_size * kernel_size, 1)), + y_grid.reshape(kernel_size * kernel_size, + 1))).reshape(kernel_size, kernel_size, + 2) + + return xy_grid + + +def bd_downsample(img_path, output_path, sigma=1.6, scale=4): + """Downsampling using BD degradation(Gaussian blurring and downsampling). + + Args: + img_path (str): Input image path. + output_path (str): Output image path. + sigma (float): The sigma of Gaussian blurring kernel. Default: 1.6. + scale (int): The scale factor of the downsampling. Default: 4. + """ + + # Gaussian blurring + kernelsize = math.ceil(sigma * 3) * 2 + 2 + kernel = blur_kernels.bivariate_gaussian( + kernelsize, sigma, grid=mesh_grid(kernelsize)) + img = cv2.imread(img_path) + img = img_as_float(img) + output = cv2.filter2D( + img, + -1, + kernel, + anchor=((kernelsize - 1) // 2, (kernelsize - 1) // 2), + borderType=cv2.BORDER_REPLICATE) + + # downsampling + output = output[int(scale / 2) - 1:-int(scale / 2) + 1:scale, + int(scale / 2) - 1:-int(scale / 2) + 1:scale, :] + + output = np.clip(output, 0.0, 1.0) * 255 + output = output.astype(np.float32) + output = np.floor(output + 0.5) + cv2.imwrite(output_path, output) + + +def worker(clip_path, args): + """Worker for each process. + + Args: + clip_name (str): Path of the clip. + + Returns: + process_info (str): Process information displayed in progress bar. + """ + + gt_dir = osp.join(args.data_root, 'GT', clip_path) + bi_dir = osp.join(args.data_root, 'BIx4', clip_path) + bd_dir = osp.join(args.data_root, 'BDx4', clip_path) + mmengine.utils.mkdir_or_exist(bi_dir) + mmengine.utils.mkdir_or_exist(bd_dir) + + img_list = sorted(os.listdir(gt_dir)) + for img in img_list: + imresize(osp.join(gt_dir, img), osp.join(bi_dir, img), scale=1 / 4) + bd_downsample(osp.join(gt_dir, img), osp.join(bd_dir, img)) + + process_info = f'Processing {clip_path} ...' + return process_info + + +def downsample_images(args): + """Downsample images.""" + + clip_list = [] + gt_dir = osp.join(args.data_root, 'GT') + sequence_list = sorted(os.listdir(gt_dir)) + for sequence in sequence_list: + sequence_root = osp.join(gt_dir, sequence) + clip_list.extend( + [osp.join(sequence, i) for i in sorted(os.listdir(sequence_root))]) + + prog_bar = mmengine.ProgressBar(len(clip_list)) + pool = Pool(args.n_thread) + for path in clip_list: + pool.apply_async( + worker, args=(path, args), callback=lambda arg: prog_bar.update()) + pool.close() + pool.join() + print('All processes done.') def parse_args(): @@ -140,8 +272,17 @@ def parse_args(): description='Preprocess Vimeo90K datasets', epilog='You can download the Vimeo90K dataset ' 'from:http://toflow.csail.mit.edu/') + parser.add_argument('--data-root', help='dataset root') parser.add_argument( - 'train_list', help='official training list path for Vimeo90K') + '--n-thread', + nargs='?', + default=8, + type=int, + help='thread number when using multiprocessing') + parser.add_argument( + '--train_list', + default=None, + help='official training list path for Vimeo90K') parser.add_argument('--gt-path', default=None, help='GT path for Vimeo90K') parser.add_argument('--lq-path', default=None, help='LQ path for Vimeo90K') parser.add_argument( @@ -154,8 +295,16 @@ def parse_args(): if __name__ == '__main__': args = parse_args() + # generate BIx4 and BDx4 + downsample_images(args) + # generate image list anno file - generate_anno_file(args.train_list) + generate_anno_file( + osp.join(args.data_root, 'sep_trainlist.txt'), + 'meta_info_Vimeo90K_train_GT.txt') + generate_anno_file( + osp.join(args.data_root, 'sep_testlist.txt'), + 'meta_info_Vimeo90K_test_GT.txt') # create lmdb files if args.make_lmdb: From c6afd0545fbc75d840876f32da40b8b264ea9712 Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Wed, 15 Mar 2023 13:14:24 +0800 Subject: [PATCH 07/39] Corrected iterator counting logic of sampler (#1696) --- mmedit/utils/sampler.py | 6 +++--- tests/test_utils/test_sampler.py | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mmedit/utils/sampler.py b/mmedit/utils/sampler.py index 8cb8ab566d..44f87e8bda 100644 --- a/mmedit/utils/sampler.py +++ b/mmedit/utils/sampler.py @@ -83,7 +83,7 @@ def __iter__(self): return self def __next__(self): - if self.idx > self.max_times: + if self.idx >= self.max_times: raise StopIteration self.idx += 1 @@ -116,7 +116,7 @@ def __iter__(self): return self def __next__(self): - if self.idx > self.max_times: + if self.idx >= self.max_times: self._iterator = iter(self._dataloader) raise StopIteration self.idx += 1 @@ -152,7 +152,7 @@ def __iter__(self): return self def __next__(self): - if self.idx > self.max_times: + if self.idx >= self.max_times: self._iterator = iter(self._dataloader) raise StopIteration self.idx += 1 diff --git a/tests/test_utils/test_sampler.py b/tests/test_utils/test_sampler.py index 8173a8d7c3..de923a0728 100644 --- a/tests/test_utils/test_sampler.py +++ b/tests/test_utils/test_sampler.py @@ -62,3 +62,10 @@ def test_val_data_sampler(): assert len(val_sampler._dataloader.dataset) == 8 for idx, out in enumerate(val_sampler): assert out == tar_out[idx] + + # test iteration times + val_sampler = ValDataSampler( + sample_kwargs=dict(max_times=1), runner=runner) + tar_out = [[0, 1, 2, 3]] + for idx, out in enumerate(val_sampler): + assert out == tar_out[idx] From 53010f1fae526e18240bc824e851630a8d7ed5ab Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Wed, 15 Mar 2023 14:26:50 +0800 Subject: [PATCH 08/39] [Fix] fix tof train annotation file (#1699) --- configs/_base_/models/base_tof.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/_base_/models/base_tof.py b/configs/_base_/models/base_tof.py index b3801a6f80..79eee49575 100644 --- a/configs/_base_/models/base_tof.py +++ b/configs/_base_/models/base_tof.py @@ -35,7 +35,7 @@ sampler=dict(type='InfiniteSampler', shuffle=True), dataset=dict( type=train_dataset_type, - ann_file='tri_testlist.txt', + ann_file='tri_trainlist.txt', metainfo=dict(dataset_type='vimeo90k', task_name='vfi'), data_root=data_root, data_prefix=dict(img='sequences', gt='sequences'), From 10198b76a39e3b4bd044d9dd528b77c91ba3f4a6 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:42:36 +0800 Subject: [PATCH 09/39] [Refactor] refactor tools/get_flops (#1675) * [Refactor] refactor tools/get_flops * [Refactor] refactor tools/get_flops * add help * add examples --- tools/analysis_tools/get_flops.py | 103 +++++++++++++++++++++++------- 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/tools/analysis_tools/get_flops.py b/tools/analysis_tools/get_flops.py index 0f8685066b..d9c82dfc44 100644 --- a/tools/analysis_tools/get_flops.py +++ b/tools/analysis_tools/get_flops.py @@ -8,60 +8,115 @@ from mmedit.registry import MODELS try: - from mmcv.cnn import get_model_complexity_info + from mmengine.analysis import get_model_complexity_info except ImportError: - raise ImportError('Please upgrade mmcv to >0.6.2') + raise ImportError('Please upgrade mmengine >= 0.6.0') def parse_args(): - parser = argparse.ArgumentParser(description='Train a editor') + parser = argparse.ArgumentParser( + description='Get a editor complexity', + formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('config', help='train config file path') parser.add_argument( '--shape', type=int, nargs='+', - default=[250, 250], - help='input image size') + default=[3, 250, 250], + help='Input shape. Supported tasks:\n' + 'Image Super-Resolution: --shape 3 h w\n' + 'Video Super-Resolution: --shape t 3 h w\n' + 'Video Interpolation: --shape t 3 h w\n' + 'Image Restoration: --shape 3 h w\n' + 'Inpainting: --shape 4 h w\n' + 'Matting: --shape 4 h w\n' + 'Unconditional GANs: --shape noisy_size\n' + 'Image Translation: --shape 3 h w') + parser.add_argument( + '--activations', + action='store_true', + help='Whether to show the Activations') + parser.add_argument( + '--out-table', + action='store_true', + help='Whether to show the complexity table') + parser.add_argument( + '--out-arch', + action='store_true', + help='Whether to show the complexity arch') args = parser.parse_args() return args def main(): + """ + Examples: + + Image Super-Resolution: + `python tools/analysis_tools/get_flops.py configs/srcnn/srcnn_x4k915_1xb16-1000k_div2k.py --shape 3 250 250` # noqa + + Video Super-Resolution: + `python tools/analysis_tools/get_flops.py configs/edvr/edvrm_8xb4-600k_reds.py --shape 5 3 256 256` # noqa + + Video Interpolation: + `python tools/analysis_tools/get_flops.py configs/flavr/flavr_in4out1_8xb4_vimeo90k-septuplet.py --shape 4 3 64 64` # noqa + + Image Restoration: + `python tools/analysis_tools/get_flops.py configs/nafnet/nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py --shape 3 128 128` # noqa + + Inpainting: + `python tools/analysis_tools/get_flops.py configs/aot_gan/aot-gan_smpgan_4xb4_places-512x512.py --shape 4 64 64` # noqa + + Matting: + `python tools/analysis_tools/get_flops.py configs/dim/dim_stage1-v16_1xb1-1000k_comp1k.py --shape 4 256 256` # noqa + + Unconditional GANs: + `python tools/analysis_tools/get_flops.py configs/wgan-gp/wgangp_GN_1xb64-160kiters_celeba-cropped-128x128.py --shape 128` # noqa + + Image Translation: + `python tools/analysis_tools/get_flops.py configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py --shape 3 250 250` + """ args = parse_args() - if len(args.shape) == 1: - input_shape = (3, args.shape[0], args.shape[0]) - elif len(args.shape) == 2: - input_shape = (3, ) + tuple(args.shape) - elif len(args.shape) in [3, 4]: # 4 for video inputs (t, c, h, w) - input_shape = tuple(args.shape) - else: - raise ValueError('invalid input shape') + input_shape = tuple(args.shape) cfg = Config.fromfile(args.config) init_default_scope(cfg.get('default_scope', 'mmedit')) model = MODELS.build(cfg.model) + inputs = torch.randn(1, *input_shape) if torch.cuda.is_available(): model.cuda() + inputs = inputs.cuda() model.eval() - if hasattr(model, 'forward_dummy'): - model.forward = model.forward_dummy - elif hasattr(model, 'forward_tensor'): - model.forward = model.forward_tensor - # else: - # raise NotImplementedError( - # 'FLOPs counter is currently not currently supported ' - # f'with {model.__class__.__name__}') - - flops, params = get_model_complexity_info(model, input_shape) + if hasattr(model, 'generator'): + model = model.generator + elif hasattr(model, 'backbone'): + model = model.backbone + if hasattr(model, 'translation'): + model.forward = model.translation + elif hasattr(model, 'infer'): + model.forward = model.infer + + analysis_results = get_model_complexity_info( + model, input_shape, inputs=inputs) + flops = analysis_results['flops_str'] + params = analysis_results['params_str'] + activations = analysis_results['activations_str'] split_line = '=' * 30 print(f'{split_line}\nInput shape: {input_shape}\n' - f'Flops: {flops}\nParams: {params}\n{split_line}') + f'Flops: {flops}\nParams: {params}\n{split_line}\n') + if args.activations: + print(f'Activations: {activations}\n{split_line}\n') + if args.out_table: + print(analysis_results['out_table'], '\n') + if args.out_arch: + print(analysis_results['out_arch'], '\n') + if len(input_shape) == 4: print('!!!If your network computes N frames in one forward pass, you ' 'may want to divide the FLOPs by N to get the average FLOPs ' From f64de1167a63e58d068d2b503f20d186514d3bb8 Mon Sep 17 00:00:00 2001 From: zhangjingdong <1396925302@qq.com> Date: Fri, 24 Mar 2023 13:14:34 +0800 Subject: [PATCH 10/39] [Fix] fix nafnet optimizer config --- ...fnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py | 3 --- ...afnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py | 11 +++-------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/configs/nafnet/nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py b/configs/nafnet/nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py index fcb87e7b80..bf68b89a35 100644 --- a/configs/nafnet/nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py +++ b/configs/nafnet/nafnet_c64eb11128mb1db1111_8xb8-lr1e-3-400k_gopro.py @@ -4,9 +4,6 @@ work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' -# DistributedDataParallel -model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') - # model settings model = dict( type='BaseEditModel', diff --git a/configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py b/configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py index 1b12cc0053..5235d3c79a 100644 --- a/configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py +++ b/configs/nafnet/nafnet_c64eb2248mb12db2222_8xb8-lr1e-3-400k_sidd.py @@ -4,9 +4,6 @@ work_dir = f'./work_dirs/{experiment_name}' save_dir = './work_dirs/' -# DistributedDataParallel -model_wrapper_cfg = dict(type='MMSeparateDistributedDataParallel') - # model settings model = dict( type='BaseEditModel', @@ -94,11 +91,9 @@ # optimizer optim_wrapper = dict( - constructor='MultiOptimWrapperConstructor', - generator=dict( - type='OptimWrapper', - optimizer=dict( - type='AdamW', lr=1e-3, weight_decay=1e-3, betas=(0.9, 0.9)))) + constructor='DefaultOptimWrapperConstructor', + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=1e-3, weight_decay=1e-3, betas=(0.9, 0.9))) # learning policy param_scheduler = dict( From d98ef72c4e02c0476029449bc6d58d841730dcbf Mon Sep 17 00:00:00 2001 From: Mashiro <57566630+HAOCHENYE@users.noreply.github.com> Date: Fri, 24 Mar 2023 14:51:36 +0800 Subject: [PATCH 11/39] [Fix] Fix accepting an unexpected argument `local-rank` in PyTorch 2.0 (#1712) * [Fix] Fix accepting an unexpected argument in PyTorch 2.0 * Add comments * Add comments * refine comments --- tools/train.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/train.py b/tools/train.py index 37d6214ea4..ab9a3fed93 100644 --- a/tools/train.py +++ b/tools/train.py @@ -40,7 +40,10 @@ def parse_args(): choices=['none', 'pytorch', 'slurm', 'mpi'], default='none', help='job launcher') - parser.add_argument('--local_rank', type=int, default=0) + # When using PyTorch version >= 2.0.0, the `torch.distributed.launch` + # will pass the `--local-rank` parameter to `tools/train.py` instead + # of `--local_rank`. + parser.add_argument('--local_rank', '--local-rank', type=int, default=0) args = parser.parse_args() if 'LOCAL_RANK' not in os.environ: os.environ['LOCAL_RANK'] = str(args.local_rank) From bcaa1231ca86fb9206e798f422fb6347d162ecab Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Fri, 24 Mar 2023 17:21:00 +0800 Subject: [PATCH 12/39] [Fix] Revise the `forward` function for `DiffusersWrapper`. (#1697) * reduce the memory cost in diffusers wrapper's unit test and revise 'forward' operation for diffusers wrapper * modify getattr in DiffusersWrapper * fix unit test of diffusers wrapper --- mmedit/models/base_archs/wrapper.py | 27 +++++++++++++++++-- .../configs/diffuser_wrapper_cfg/config.json | 8 +++--- .../test_base_archs/test_wrapper.py | 18 +++++++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/mmedit/models/base_archs/wrapper.py b/mmedit/models/base_archs/wrapper.py index 6329ac50ed..bfdb02c348 100644 --- a/mmedit/models/base_archs/wrapper.py +++ b/mmedit/models/base_archs/wrapper.py @@ -113,11 +113,23 @@ def __getattr__(self, name: str) -> Any: Returns: Any: The got attribute. """ + # Q: why we need end of recursion for 'model'? + # A: In `nn.Module.__setattr__`, if value is instance of `nn.Module`, + # it will be removed from `__dict__` and added to + # `__dict__._modules`. Therefore, `model` cannot be found in + # `self.__dict__`. When we call `self.model`, python cannot found + # 'model' in `self.__dict__` and then `self.__getattr__('model')` + # will be called. If we call `self.model` in `self.__getattr__` + # which does not have any exit about 'model',`RecursionError` + # will be raised. + if name == 'model': + return super().__getattr__('model') + try: - return super().__getattr__(name) + return getattr(self.model, name) except AttributeError: try: - return getattr(self.model, name) + return super().__getattr__(name) except AttributeError: raise AttributeError('\'name\' cannot be found in both ' f'\'{self.__class__.__name__}\' and ' @@ -134,3 +146,14 @@ def __repr__(self): prefix += f'From Config: {self._from_config}\n' s = prefix + s return s + + def forward(self, *args, **kwargs) -> Any: + """Forward function of wrapped module. + + Args: + *args, **kwargs: The arguments of the wrapped module. + + Returns: + Any: The output of wrapped module's forward function. + """ + return self.model(*args, **kwargs) diff --git a/tests/configs/diffuser_wrapper_cfg/config.json b/tests/configs/diffuser_wrapper_cfg/config.json index dc533598cc..2709f4d4dd 100644 --- a/tests/configs/diffuser_wrapper_cfg/config.json +++ b/tests/configs/diffuser_wrapper_cfg/config.json @@ -2,18 +2,18 @@ "_class_name": "ControlNetModel", "_diffusers_version": "0.14.0", "act_fn": "silu", - "attention_head_dim": 8, + "attention_head_dim": 2, "block_out_channels": [ - 320 + 32 ], "class_embed_type": null, "conditioning_embedding_out_channels": [ 16 ], "controlnet_conditioning_channel_order": "rgb", - "cross_attention_dim": 32, + "cross_attention_dim": 16, "down_block_types": [ - "CrossAttnDownBlock2D" + "DownBlock2D" ], "downsample_padding": 1, "flip_sin_to_cos": true, diff --git a/tests/test_models/test_base_archs/test_wrapper.py b/tests/test_models/test_base_archs/test_wrapper.py index 55c1e3ee85..7621cc465d 100644 --- a/tests/test_models/test_base_archs/test_wrapper.py +++ b/tests/test_models/test_base_archs/test_wrapper.py @@ -3,6 +3,7 @@ import os.path as osp import shutil from unittest import TestCase +from unittest.mock import MagicMock import torch from mmengine.utils import digit_version @@ -74,6 +75,8 @@ def test_build(self): in_channels=3, down_block_types=['DownBlock2D'], block_out_channels=(32, ), + cross_attention_dim=16, + attention_head_dim=2, conditioning_embedding_out_channels=(16, )), ) model_str = repr(model) self.assertNotIn('From Config:', model_str) @@ -85,3 +88,18 @@ def test_build(self): # 6. test init_weights model.init_weights() + + # 7. test forward function + forward_mock = MagicMock() + model.model.forward = forward_mock + model(**dict(t='t', control='control')) + _, called_kwargs = forward_mock.call_args + self.assertEqual(called_kwargs['t'], 't') + self.assertEqual(called_kwargs['control'], 'control') + + # 8. test other attribute share with BaseModule and model + register_buffer_mock = MagicMock() + model.model.registrer_buffer = register_buffer_mock + model.registrer_buffer('buffer', 123) + called_args, _ = register_buffer_mock.call_args + self.assertEqual(called_args, ('buffer', 123)) From ce1069702cedca2436c558a05fd480c3aecfbb69 Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Fri, 24 Mar 2023 17:22:33 +0800 Subject: [PATCH 13/39] [Enhancement] Support string type (prompt) in EditDataSample (#1698) * support string type (prompt) in EditDataSample * use 'set_field' instead of 'set_prompt' --- mmedit/structures/edit_data_sample.py | 7 +++++-- tests/test_structures/test_edit_data_sample.py | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/mmedit/structures/edit_data_sample.py b/mmedit/structures/edit_data_sample.py index 1d299e3036..01914f7d21 100644 --- a/mmedit/structures/edit_data_sample.py +++ b/mmedit/structures/edit_data_sample.py @@ -28,7 +28,6 @@ def format_label(value: Union[torch.Tensor, np.ndarray, Sequence, int], Returns: :obj:`mmengine.LabelData`: The foramtted label data. """ - # Handle single number if isinstance(value, (torch.Tensor, np.ndarray)) and value.ndim == 0: value = int(value.item()) @@ -165,7 +164,9 @@ class EditDataSample(BaseDataElement): 'gray': 'gray', 'cropped_img': 'cropped_img', 'pred_img': 'pred_img', - 'ori_trimap': 'ori_trimap' + 'ori_trimap': 'ori_trimap', + # For text to images + 'prompt': 'prompt' } def set_predefined_data(self, data: dict) -> None: @@ -202,6 +203,8 @@ def set_tensor_data(self, data: dict) -> None: for k, v in data.items(): if k == 'gt_label': self.set_gt_label(v) + elif k == 'prompt': + self.set_field(v, k, dtype=(str, list)) else: self.set_field(all_to_tensor(v), k, dtype=torch.Tensor) diff --git a/tests/test_structures/test_edit_data_sample.py b/tests/test_structures/test_edit_data_sample.py index 036e760a7e..cd83f9980e 100644 --- a/tests/test_structures/test_edit_data_sample.py +++ b/tests/test_structures/test_edit_data_sample.py @@ -61,6 +61,7 @@ def test_set_prefined_data(self): # METAINFO img_path, gt_path, merged_path = 'aaa', 'bbb', 'ccc' gt_channel_order, gt_color_type = 'rgb', 'color' + prompt = 'prompt' data = dict( gt=gt, @@ -74,7 +75,8 @@ def test_set_prefined_data(self): gt_path=gt_path, merged_path=merged_path, gt_channel_order=gt_channel_order, - gt_color_type=gt_color_type) + gt_color_type=gt_color_type, + prompt=prompt) data_sample = EditDataSample() data_sample.set_predefined_data(data) @@ -91,6 +93,7 @@ def test_set_prefined_data(self): gt_channel_order, True) self._check_in_and_same(data_sample, 'gt_color_type', gt_color_type, True) + self._check_in_and_same(data_sample, 'prompt', prompt, False) # check gt label data_sample.gt_label.data = gt_label @@ -182,6 +185,7 @@ def test_stack_and_split(self): data_sample1.set_gt_label(1) data_sample1.set_tensor_data({'img': torch.randn(3, 4, 5)}) data_sample1.set_data({'mode': 'a'}) + data_sample1.set_data({'prompt': 'I\'m a prompt!'}) data_sample1.set_metainfo({ 'channel_order': 'rgb', 'color_flag': 'color' @@ -190,6 +194,7 @@ def test_stack_and_split(self): data_sample2.set_gt_label(2) data_sample2.set_tensor_data({'img': torch.randn(3, 4, 5)}) data_sample2.set_data({'mode': 'b'}) + data_sample2.set_data({'prompt': 'I\'m an another prompt!'}) data_sample2.set_metainfo({ 'channel_order': 'rgb', 'color_flag': 'color' @@ -204,6 +209,9 @@ def test_stack_and_split(self): assert data_sample_merged.metainfo == dict( channel_order=['rgb', 'rgb'], color_flag=['color', 'color']) assert len(data_sample_merged) == 2 + assert data_sample_merged.prompt == [ + 'I\'m a prompt!', 'I\'m an another prompt!' + ] # test split data_sample_merged.sample_model = 'ema' @@ -225,6 +233,8 @@ def test_stack_and_split(self): assert data_splited_2.sample_model == 'ema' assert data_splited_1.fake_img.img.shape == (3, 4, 4) assert data_splited_2.fake_img.img.shape == (3, 4, 4) + assert data_splited_1.prompt == 'I\'m a prompt!' + assert data_splited_2.prompt == 'I\'m an another prompt!' with self.assertRaises(TypeError): data_sample_merged.split() @@ -234,6 +244,7 @@ def test_stack_and_split(self): data_sample.set_gt_label(3) data_sample.set_tensor_data({'img': torch.randn(3, 4, 5)}) data_sample.set_data({'mode': 'c'}) + data_sample.set_data({'prompt': 'proooommmmpt'}) data_sample.set_metainfo({ 'channel_order': 'rgb', 'color_flag': 'color' @@ -246,6 +257,7 @@ def test_stack_and_split(self): assert data_sample_merged.mode == ['c'] assert data_sample_merged.metainfo == dict( channel_order=['rgb'], color_flag=['color']) + data_sample_merged.prompt == ['proooommmmpt'] assert len(data_sample_merged) == 1 # test split @@ -254,6 +266,7 @@ def test_stack_and_split(self): data_splited = data_splited[0] assert (data_splited.gt_label.label == 3).all() assert (data_splited.img == data_sample.img).all() + assert data_splited.prompt == 'proooommmmpt' assert (data_splited.metainfo == dict( channel_order='rgb', color_flag='color')) From 9ad2d3d07f7d8d54f5f3d8e1b86ef654da9c8aea Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Fri, 24 Mar 2023 17:42:42 +0800 Subject: [PATCH 14/39] [Feature] Support convert base model for ControlNet (#1701) support convert base model for controlnet --- .../editors/controlnet/controlnet_utils.py | 55 +++++++++++++++++ .../test_controlnet/test_controlnet_utils.py | 61 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 mmedit/models/editors/controlnet/controlnet_utils.py create mode 100644 tests/test_models/test_editors/test_controlnet/test_controlnet_utils.py diff --git a/mmedit/models/editors/controlnet/controlnet_utils.py b/mmedit/models/editors/controlnet/controlnet_utils.py new file mode 100644 index 0000000000..193c3c2c27 --- /dev/null +++ b/mmedit/models/editors/controlnet/controlnet_utils.py @@ -0,0 +1,55 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from logging import ERROR +from typing import Optional + +import torch.nn as nn +from mmengine import print_log +from mmengine.runner import save_checkpoint + + +def change_base_model(controlnet: nn.Module, + curr_model: nn.Module, + base_model: nn.Module, + save_path: Optional[str] = None, + *args, + **kwargs) -> nn.Module: + """This function is used to change the base model of ControlNet. Refers to + https://github.com/lllyasviel/ControlNet/blob/main/tool_transfer_control.py + . + + # noqa. + + Args: + controlnet (nn.Module): The model for ControlNet to convert. + curr_model (nn.Module): The model of current Stable Diffusion's Unet. + base_model (nn.Module): The model of Stable Diffusion's Unet which + ControlNet initialized with. + save_path (str, optional): The path to save the converted model. + Defaults to None. + + *args, **kwargs: Arguments for `save_checkpoint`. + """ + base_state_dict = base_model.state_dict() + curr_state_dict = curr_model.state_dict() + + print_log('Start convert ControlNet to new Unet.', 'current') + for k, v in controlnet.state_dict().items(): + if k in base_state_dict: + base_v = base_state_dict[k] + curr_v = curr_state_dict[k] + try: + offset = v - base_v + new_v = offset + curr_v + controlnet.state_dict()[k].data.copy_(new_v) + print_log(f'Convert success: \'{k}\'.', 'current') + except Exception as exception: + print_log( + f'Error occurs when convert \'{k}\'. ' + 'Please check that the model structure of ' + '\'ControlNet\', \'BaseModel\' and \'CurrentModel\' ' + 'are consistent.', 'current', ERROR) + raise exception + if save_path: + save_checkpoint(controlnet.state_dict(), save_path, *args, **kwargs) + + return controlnet diff --git a/tests/test_models/test_editors/test_controlnet/test_controlnet_utils.py b/tests/test_models/test_editors/test_controlnet/test_controlnet_utils.py new file mode 100644 index 0000000000..d915dda639 --- /dev/null +++ b/tests/test_models/test_editors/test_controlnet/test_controlnet_utils.py @@ -0,0 +1,61 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +from unittest.mock import MagicMock + +import pytest +import torch + +from mmedit.models.editors.controlnet.controlnet_utils import change_base_model + + +def make_state_dict(d): + new_d = dict() + for k, v in d.items(): + new_d[k] = torch.FloatTensor([v]) + return new_d + + +def check_state_dict(s1, s2): + # s1, s2 = m1.state_dict(), m2.state_dict() + assert s1.keys() == s2.keys() + for k in s1.keys(): + assert (s1[k] == s2[k]).all() + + +def test_change_base_model(): + control_state_dict = make_state_dict(dict(k1=1, k2=2, k3=3)) + target_control_state_dict = make_state_dict(dict(k1=1.5, k2=2.5, k3=3)) + + base_state_dict = make_state_dict(dict(k1=2, k2=3)) + curr_state_dict = make_state_dict(dict(k1=2.5, k2=3.5)) + + controlnet = MagicMock() + basemodel = MagicMock() + currmodel = MagicMock() + + controlnet.state_dict = MagicMock(return_value=control_state_dict) + basemodel.state_dict = MagicMock(return_value=base_state_dict) + currmodel.state_dict = MagicMock(return_value=curr_state_dict) + + change_base_model(controlnet, currmodel, basemodel) + check_state_dict(controlnet.state_dict(), target_control_state_dict) + + # test save + control_state_dict = make_state_dict(dict(k1=1, k2=2, k3=3)) + controlnet.state_dict = MagicMock(return_value=control_state_dict) + save_path = osp.abspath( + osp.join(__file__, '../../../../data/out', 'test.pth')) + change_base_model(controlnet, currmodel, basemodel, save_path=save_path) + assert os.path.isfile(save_path) + control_state_dict_loaded = torch.load(save_path) + check_state_dict(control_state_dict_loaded, target_control_state_dict) + os.remove(save_path) + + # test error + wrong_base_state_dict = make_state_dict(dict(k1=2, k2=[3, 5])) + wrong_model = MagicMock() + wrong_model.state_dict = MagicMock(return_value=wrong_base_state_dict) + with pytest.raises(Exception): + change_base_model(controlnet, currmodel, wrong_model) + # change_base_model(controlnet, currmodel, wrong_base_state_dict) From edffdde5b7687367a64829bb45437de20f65a4b5 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Fri, 24 Mar 2023 17:44:27 +0800 Subject: [PATCH 15/39] [Doc] fix typos of datasets docs (#1706) --- tools/dataset_converters/df2k_ost/README.md | 2 +- tools/dataset_converters/df2k_ost/README_zh-CN.md | 2 +- tools/dataset_converters/reds/README.md | 8 ++++---- tools/dataset_converters/reds/README_zh-CN.md | 6 +++--- tools/dataset_converters/udm10/README.md | 2 +- tools/dataset_converters/vimeo90k/README.md | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/dataset_converters/df2k_ost/README.md b/tools/dataset_converters/df2k_ost/README.md index 4371efe2dc..a18b74a56b 100644 --- a/tools/dataset_converters/df2k_ost/README.md +++ b/tools/dataset_converters/df2k_ost/README.md @@ -75,5 +75,5 @@ Note that `preprocess_df2k_ost_dataset.py` will generate default annotation file If you want to use LMDB datasets for faster IO speed, you can make LMDB files by: ```shell -python tools/dataset_converters/super-resolution/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost --make-lmdb +python tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost --make-lmdb ``` diff --git a/tools/dataset_converters/df2k_ost/README_zh-CN.md b/tools/dataset_converters/df2k_ost/README_zh-CN.md index efda1da681..875dcd4b41 100644 --- a/tools/dataset_converters/df2k_ost/README_zh-CN.md +++ b/tools/dataset_converters/df2k_ost/README_zh-CN.md @@ -75,5 +75,5 @@ mmediting 如果你想使用 LMDB 数据集来获得更快的 IO 速度,你可以通过以下方式制作 LMDB 文件: ```shell -python tools/dataset_converters/super-resolution/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost --make-lmdb +python tools/dataset_converters/df2k_ost/preprocess_df2k_ost_dataset.py --data-root ./data/df2k_ost --make-lmdb ``` diff --git a/tools/dataset_converters/reds/README.md b/tools/dataset_converters/reds/README.md index 6e6c9fdb76..143aa30306 100644 --- a/tools/dataset_converters/reds/README.md +++ b/tools/dataset_converters/reds/README.md @@ -21,7 +21,7 @@ The original val dataset (clip names from 000 to 029) are modified to avoid conf You can prepare the REDS dataset by running: ```shell -python tools/dataset_converters/super-resolution/reds/preprocess_reds_dataset.py --root-path ./data/REDS +python tools/dataset_converters/reds/preprocess_reds_dataset.py --root-path ./data/REDS ``` ```text @@ -55,15 +55,15 @@ mmediting If you want to use LMDB datasets for faster IO speed, you can make LMDB files by: ```shell -python tools/dataset_converters/super-resolution/reds/preprocess_reds_dataset.py --root-path ./data/REDS --make-lmdb +python tools/dataset_converters/reds/preprocess_reds_dataset.py --root-path ./data/REDS --make-lmdb ``` ## Crop to sub-images -MMEditing also support cropping REDS images to sub-images for faster IO. We provide such a script: +MMEditing also supports cropping REDS images to sub-images for faster IO. We provide such a script: ```shell -python tools/dataset_converters/super-resolution/reds/crop_sub_images.py --data-root ./data/REDS -scales 4 +python tools/dataset_converters/reds/crop_sub_images.py --data-root ./data/REDS -scales 4 ``` The generated data is stored under `REDS` and the data structure is as follows, where `_sub` indicates the sub-images. diff --git a/tools/dataset_converters/reds/README_zh-CN.md b/tools/dataset_converters/reds/README_zh-CN.md index fc088371ec..a160ee72c0 100644 --- a/tools/dataset_converters/reds/README_zh-CN.md +++ b/tools/dataset_converters/reds/README_zh-CN.md @@ -22,7 +22,7 @@ 可通过运行以下命令来准备 REDS 数据集: ```shell -python tools/dataset_converters/super-resolution/reds/preprocess_reds_dataset.py ./data/REDS +python tools/dataset_converters/reds/preprocess_reds_dataset.py ./data/REDS ``` ```text @@ -56,7 +56,7 @@ mmediting 如果您想使用 `LMDB` 以获得更快的 IO 速度,可以通过以下脚本来构建 LMDB 文件: ```shell -python tools/dataset_converters/super-resolution/reds/preprocess_reds_dataset.py --root-path ./data/REDS --make-lmdb +python tools/dataset_converters/reds/preprocess_reds_dataset.py --root-path ./data/REDS --make-lmdb ``` ## 裁剪为子图 @@ -64,7 +64,7 @@ python tools/dataset_converters/super-resolution/reds/preprocess_reds_dataset.py MMEditing 支持将 REDS 图像裁剪为子图像以加快 IO。我们提供了这样一个脚本: ```shell -python tools/dataset_converters/super-resolution/reds/crop_sub_images.py --data-root ./data/REDS -scales 4 +python tools/dataset_converters/reds/crop_sub_images.py --data-root ./data/REDS -scales 4 ``` 生成的数据存储在 `REDS` 下,数据结构如下,其中`_sub`表示子图像。 diff --git a/tools/dataset_converters/udm10/README.md b/tools/dataset_converters/udm10/README.md index f5ee2be9b0..07c8e07beb 100644 --- a/tools/dataset_converters/udm10/README.md +++ b/tools/dataset_converters/udm10/README.md @@ -12,7 +12,7 @@ } ``` -The datasets can be download from [here](https://drive.google.com/file/d/1G4V4KZZhhfzUlqHiSBBuWyqLyIOvOs0W/). +The datasets can be downloaded from [here](https://drive.google.com/file/d/1G4V4KZZhhfzUlqHiSBBuWyqLyIOvOs0W/). The folder structure should look like: diff --git a/tools/dataset_converters/vimeo90k/README.md b/tools/dataset_converters/vimeo90k/README.md index 3ef492d0d7..9f455014b4 100644 --- a/tools/dataset_converters/vimeo90k/README.md +++ b/tools/dataset_converters/vimeo90k/README.md @@ -15,7 +15,7 @@ } ``` -The training and test datasets can be download from [here](http://toflow.csail.mit.edu/). +The training and test datasets can be downloaded from [here](http://toflow.csail.mit.edu/). Then you can rename the directory `vimeo_septuplet/sequences` to `vimeo90k/GT`. The Vimeo90K dataset has a `clip/sequence/img` folder structure: From 76a9f3526907da3c70cd72b944d96704cb152dec Mon Sep 17 00:00:00 2001 From: Qunliang Xing Date: Fri, 24 Mar 2023 17:56:35 +0800 Subject: [PATCH 16/39] [Fix] Fix warp typo (#1711) Fix warp typo --- mmedit/models/editors/tof/tof_vfi_net.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mmedit/models/editors/tof/tof_vfi_net.py b/mmedit/models/editors/tof/tof_vfi_net.py index e9faceec6a..badea6a085 100644 --- a/mmedit/models/editors/tof/tof_vfi_net.py +++ b/mmedit/models/editors/tof/tof_vfi_net.py @@ -60,11 +60,11 @@ def forward(self, imgs): flow_10 = self.spynet(imgs[:, 0], imgs[:, 1]).permute(0, 2, 3, 1) flow_01 = self.spynet(imgs[:, 1], imgs[:, 0]).permute(0, 2, 3, 1) - wrap_frame0 = flow_warp(imgs[:, 0], flow_01 / 2) - wrap_frame1 = flow_warp(imgs[:, 1], flow_10 / 2) + warp_frame0 = flow_warp(imgs[:, 0], flow_01 / 2) + warp_frame1 = flow_warp(imgs[:, 1], flow_10 / 2) - wrap_frames = torch.stack([wrap_frame0, wrap_frame1], dim=1) - output = self.resnet(wrap_frames) + warp_frames = torch.stack([warp_frame0, warp_frame1], dim=1) + output = self.resnet(warp_frames) return output From ee0cca73ad6da586c8e8c17c7f53c5dbc73e5b36 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Fri, 24 Mar 2023 18:10:22 +0800 Subject: [PATCH 17/39] [Fix] Add 'mask_bbox' key in EditDataSample (#1714) * [Fix] fix deepfillv1 mask_bbox * [Fix] fix deepfillv1 mask_bbox * [Fix] fix deepfillv1 mask_bbox --- mmedit/structures/edit_data_sample.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmedit/structures/edit_data_sample.py b/mmedit/structures/edit_data_sample.py index 01914f7d21..c35f541191 100644 --- a/mmedit/structures/edit_data_sample.py +++ b/mmedit/structures/edit_data_sample.py @@ -139,6 +139,7 @@ class EditDataSample(BaseDataElement): 'sample_idx': 'sample_idx', 'num_input_frames': 'num_input_frames', 'num_output_frames': 'num_output_frames', + 'mask_bbox': 'mask_bbox', # for LIIF 'coord': 'coord', 'cell': 'cell', From fcb39147a7312fa78e8df4a8b37e0e3b0eefc88b Mon Sep 17 00:00:00 2001 From: rangoliu Date: Tue, 28 Mar 2023 13:08:26 +0800 Subject: [PATCH 18/39] [Enhance] support all image super resolution models inference (#1662) * support models * add comment * remove unused code --- .../dic/dic_x8c48b6_4xb2-150k_celeba-hq.py | 24 +++++++++++++++++ configs/glean/glean_x8_2xb8_cat.py | 15 +++++++++++ ...y => image_super_resolution_inferencer.py} | 26 +++++++++---------- mmedit/apis/inferencers/mmedit_inferencer.py | 6 ++--- mmedit/edit.py | 14 ++++++++-- ...test_image_super_resolution_inferencer.py} | 10 +++---- 6 files changed, 72 insertions(+), 23 deletions(-) rename mmedit/apis/inferencers/{restoration_inferencer.py => image_super_resolution_inferencer.py} (83%) rename tests/test_apis/test_inferencers/{test_restoration_inferencer.py => test_image_super_resolution_inferencer.py} (77%) diff --git a/configs/dic/dic_x8c48b6_4xb2-150k_celeba-hq.py b/configs/dic/dic_x8c48b6_4xb2-150k_celeba-hq.py index c4e8a3779e..0249756208 100644 --- a/configs/dic/dic_x8c48b6_4xb2-150k_celeba-hq.py +++ b/configs/dic/dic_x8c48b6_4xb2-150k_celeba-hq.py @@ -78,6 +78,30 @@ ] test_pipeline = valid_pipeline +inference_pipeline = [ + dict( + type='LoadImageFromFile', + key='img', + color_type='color', + channel_order='rgb', + imdecode_backend='cv2'), + dict( + type='Resize', + scale=(128, 128), + keys=['img'], + interpolation='bicubic', + backend='pillow'), + dict( + type='Resize', + scale=1 / 8, + keep_ratio=True, + keys=['img'], + output_keys=['img'], + interpolation='bicubic', + backend='pillow'), + dict(type='PackEditInputs') +] + # dataset settings dataset_type = 'BasicImageDataset' data_root = 'data' diff --git a/configs/glean/glean_x8_2xb8_cat.py b/configs/glean/glean_x8_2xb8_cat.py index e0d501f940..c9c8a07a1a 100644 --- a/configs/glean/glean_x8_2xb8_cat.py +++ b/configs/glean/glean_x8_2xb8_cat.py @@ -85,6 +85,21 @@ dict(type='PackEditInputs') ] +inference_pipeline = [ + dict( + type='LoadImageFromFile', + key='img', + color_type='color', + channel_order='rgb'), + dict( + type='Resize', + scale=(32, 32), + keys=['img'], + interpolation='bicubic', + backend='pillow'), + dict(type='PackEditInputs') +] + # dataset settings dataset_type = 'BasicImageDataset' diff --git a/mmedit/apis/inferencers/restoration_inferencer.py b/mmedit/apis/inferencers/image_super_resolution_inferencer.py similarity index 83% rename from mmedit/apis/inferencers/restoration_inferencer.py rename to mmedit/apis/inferencers/image_super_resolution_inferencer.py index a04bfa4bf5..59ba88fea7 100644 --- a/mmedit/apis/inferencers/restoration_inferencer.py +++ b/mmedit/apis/inferencers/image_super_resolution_inferencer.py @@ -8,17 +8,16 @@ from mmengine import mkdir_or_exist from mmengine.dataset import Compose from mmengine.dataset.utils import default_collate as collate -from torch.nn.parallel import scatter from mmedit.utils import tensor2img from .base_mmedit_inferencer import BaseMMEditInferencer, InputsType, PredType -class RestorationInferencer(BaseMMEditInferencer): +class ImageSuperResolutionInferencer(BaseMMEditInferencer): """inferencer that predicts with restoration models.""" func_kwargs = dict( - preprocess=['img'], + preprocess=['img', 'ref'], forward=[], visualize=['result_out_dir'], postprocess=[]) @@ -38,14 +37,15 @@ def preprocess(self, img: InputsType, ref: InputsType = None) -> Dict: device = next(self.model.parameters()).device # model device # select the data pipeline - if cfg.get('demo_pipeline', None): + if cfg.get('inference_pipeline', None): + test_pipeline = cfg.inference_pipeline + elif cfg.get('demo_pipeline', None): test_pipeline = cfg.demo_pipeline elif cfg.get('test_pipeline', None): test_pipeline = cfg.test_pipeline else: test_pipeline = cfg.val_pipeline - # remove gt from test_pipeline keys_to_remove = ['gt', 'gt_path'] for key in keys_to_remove: for pipeline in list(test_pipeline): @@ -57,31 +57,31 @@ def preprocess(self, img: InputsType, ref: InputsType = None) -> Dict: test_pipeline.remove(pipeline) if 'meta_keys' in pipeline and key in pipeline['meta_keys']: pipeline['meta_keys'].remove(key) + # build the data pipeline test_pipeline = Compose(test_pipeline) + # prepare data if ref: # Ref-SR - data = dict(img_path=img, ref_path=ref) + data = dict(img_path=img, gt_path=ref) else: # SISR data = dict(img_path=img) _data = test_pipeline(data) + data = dict() data_preprocessor = cfg['model']['data_preprocessor'] mean = torch.Tensor(data_preprocessor['mean']).view([3, 1, 1]) std = torch.Tensor(data_preprocessor['std']).view([3, 1, 1]) data['inputs'] = (_data['inputs'] - mean) / std data = collate([data]) + if ref: data['data_samples'] = [_data['data_samples']] if 'cuda' in str(device): - data = scatter(data, [device])[0] + data['inputs'] = data['inputs'].cuda() if ref: - data['data_samples'][0].img_lq.data = data['data_samples'][ - 0].img_lq.data.to(device) - data['data_samples'][0].ref_lq.data = data['data_samples'][ - 0].ref_lq.data.to(device) - data['data_samples'][0].ref_img.data = data['data_samples'][ - 0].ref_img.data.to(device) + data['data_samples'][0] = data['data_samples'][0].cuda() + return data def forward(self, inputs: InputsType) -> PredType: diff --git a/mmedit/apis/inferencers/mmedit_inferencer.py b/mmedit/apis/inferencers/mmedit_inferencer.py index a05de7095c..c149df0b2c 100644 --- a/mmedit/apis/inferencers/mmedit_inferencer.py +++ b/mmedit/apis/inferencers/mmedit_inferencer.py @@ -7,9 +7,9 @@ from .colorization_inferencer import ColorizationInferencer from .conditional_inferencer import ConditionalInferencer from .eg3d_inferencer import EG3DInferencer +from .image_super_resolution_inferencer import ImageSuperResolutionInferencer from .inpainting_inferencer import InpaintingInferencer from .matting_inferencer import MattingInferencer -from .restoration_inferencer import RestorationInferencer from .text2image_inferencer import Text2ImageInferencer from .translation_inferencer import TranslationInferencer from .unconditional_inferencer import UnconditionalInferencer @@ -55,8 +55,8 @@ def __init__(self, elif self.task in ['translation', 'Image2Image']: self.inferencer = TranslationInferencer( config, ckpt, device, extra_parameters, seed=seed) - elif self.task in ['restoration', 'Image Super-Resolution']: - self.inferencer = RestorationInferencer( + elif self.task in ['Image super-resolution', 'Image Super-Resolution']: + self.inferencer = ImageSuperResolutionInferencer( config, ckpt, device, extra_parameters, seed=seed) elif self.task in ['video_restoration', 'Video Super-Resolution']: self.inferencer = VideoRestorationInferencer( diff --git a/mmedit/edit.py b/mmedit/edit.py index 99d25ecc47..596b8e8876 100644 --- a/mmedit/edit.py +++ b/mmedit/edit.py @@ -39,7 +39,9 @@ class MMEdit: >>> # see demo/mmediting_inference_tutorial.ipynb for more examples """ # unsupported now - # singan + # singan, liif + # output should be checked + # dic, glean inference_supported_models = [ # colorization models @@ -71,8 +73,16 @@ class MMEdit: 'pix2pix', 'cyclegan', - # restoration models + # image super-resolution models + 'srcnn', + 'srgan_resnet', + 'edsr', 'esrgan', + 'rdn', + 'dic', + 'ttsr', + 'glean', + 'real_esrgan', # video_interpolation models 'flavr', diff --git a/tests/test_apis/test_inferencers/test_restoration_inferencer.py b/tests/test_apis/test_inferencers/test_image_super_resolution_inferencer.py similarity index 77% rename from tests/test_apis/test_inferencers/test_restoration_inferencer.py rename to tests/test_apis/test_inferencers/test_image_super_resolution_inferencer.py index eb457775f9..c49327b879 100644 --- a/tests/test_apis/test_inferencers/test_restoration_inferencer.py +++ b/tests/test_apis/test_inferencers/test_image_super_resolution_inferencer.py @@ -5,8 +5,8 @@ import pytest import torch -from mmedit.apis.inferencers.restoration_inferencer import \ - RestorationInferencer +from mmedit.apis.inferencers.image_super_resolution_inferencer import \ + ImageSuperResolutionInferencer from mmedit.utils import register_all_modules register_all_modules() @@ -15,16 +15,16 @@ @pytest.mark.skipif( 'win' in platform.system().lower() and 'cu' in torch.__version__, reason='skip on windows-cuda due to limited RAM.') -def test_restoration_inferencer(): +def test_image_super_resolution_inferencer(): data_root = osp.join(osp.dirname(__file__), '../../../') config = data_root + 'configs/esrgan/esrgan_x4c64b23g32_1xb16-400k_div2k.py' # noqa img_path = data_root + 'tests/data/image/lq/baboon_x4.png' result_out_dir = osp.join( osp.dirname(__file__), '..', '..', 'data/out', - 'restoration_result.png') + 'image_super_resolution_result.png') inferencer_instance = \ - RestorationInferencer(config, None) + ImageSuperResolutionInferencer(config, None) inferencer_instance(img=img_path) inference_result = inferencer_instance( img=img_path, result_out_dir=result_out_dir) From b26b3ece4209199da862435b4744349331a77186 Mon Sep 17 00:00:00 2001 From: rangoliu Date: Thu, 30 Mar 2023 15:33:10 +0800 Subject: [PATCH 19/39] [Fix] add instruction in sd readme (#1719) * add instruction in sd readme * misc * revert init scope --- configs/stable_diffusion/README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/configs/stable_diffusion/README.md b/configs/stable_diffusion/README.md index 8d83643a0f..2337a8ee7e 100644 --- a/configs/stable_diffusion/README.md +++ b/configs/stable_diffusion/README.md @@ -41,12 +41,21 @@ Stable Diffusion is a latent diffusion model conditioned on the text embeddings ## Pretrained models -We use stable diffusion v1.5 weights. This model has several weights including vae, unet and clip. You should download the weights from [stable-diffusion-1.5](https://huggingface.co/runwayml/stable-diffusion-v1-5) and change the 'pretrained_model_path' in config to the weights dir. - | Model | Dataset | Download | | :---------------------------------------------------------------: | :-----: | :------------------------------------------------------------: | | [stable_diffusion_v1.5](./stable-diffusion_ddim_denoisingunet.py) | - | [model](https://huggingface.co/runwayml/stable-diffusion-v1-5) | +We use stable diffusion v1.5 weights. This model has several weights including vae, unet and clip. + +You should download the weights from [stable-diffusion-1.5](https://huggingface.co/runwayml/stable-diffusion-v1-5) and change the 'pretrained_model_path' in config to the weights dir. + +Download with git: + +```shell +git lfs install +git clone https://huggingface.co/runwayml/stable-diffusion-v1-5 +``` + ## Quick Start Running the following codes, you can get a text-generated image. @@ -60,7 +69,10 @@ from mmengine.registry import init_default_scope init_default_scope('mmedit') config = 'configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py' -StableDiffuser = MODELS.build(Config.fromfile(config).model) +config = Config.fromfile(config).copy() +config.model.init_cfg.pretrained_model_path = '/path/to/your/stable-diffusion-v1-5' + +StableDiffuser = MODELS.build(config.model) prompt = 'A mecha robot in a favela in expressionist style' StableDiffuser = StableDiffuser.to('cuda') From 49445e06f413aa3bdccad01dd58e9d825d930951 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 30 Mar 2023 17:06:44 +0800 Subject: [PATCH 20/39] [Fix] fix clip import error (#1725) * [Fix] fix clip import error * add assert --- mmedit/models/editors/disco_diffusion/guider.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mmedit/models/editors/disco_diffusion/guider.py b/mmedit/models/editors/disco_diffusion/guider.py index 03adda874c..5e9535d524 100644 --- a/mmedit/models/editors/disco_diffusion/guider.py +++ b/mmedit/models/editors/disco_diffusion/guider.py @@ -1,7 +1,6 @@ # Copyright (c) OpenMMLab. All rights reserved. import math -import clip import lpips import numpy as np import pandas as pd @@ -15,8 +14,11 @@ from torchvision import __version__ as TORCHVISION_VERSION from mmedit.models.losses import tv_loss +from mmedit.utils import try_import from .secondary_model import alpha_sigma_to_t +clip = try_import('clip') + normalize = T.Normalize( mean=[0.48145466, 0.4578275, 0.40821073], std=[0.26862954, 0.26130258, 0.27577711]) @@ -309,6 +311,11 @@ class ImageTextGuider(nn.Module): def __init__(self, clip_models): super().__init__() + + assert clip is not None, ( + "Cannot import 'clip'. Please install 'clip' via " + "\"pip install git+https://github.com/openai/CLIP.git\".") + self.clip_models = clip_models self.lpips_model = lpips.LPIPS(net='vgg') From 6edd588f47629d7c9b03e4675923dc33e98cb160 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 30 Mar 2023 17:26:32 +0800 Subject: [PATCH 21/39] [Enhance] support all Video Super-Resolution models inferencer (#1720) --- ...ealbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py | 6 ++++++ mmedit/edit.py | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/configs/real_basicvsr/realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py b/configs/real_basicvsr/realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py index c8e4774b8e..956cd02b16 100644 --- a/configs/real_basicvsr/realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py +++ b/configs/real_basicvsr/realbasicvsr_wogan-c64b20-2x30x8_8xb2-lr1e-4-300k_reds.py @@ -214,6 +214,12 @@ dict(type='PackEditInputs') ] +demo_pipeline = [ + dict(type='GenerateSegmentIndices', interval_list=[1]), + dict(type='LoadImageFromFile', key='img', channel_order='rgb'), + dict(type='PackEditInputs') +] + data_root = 'data' train_dataloader = dict( diff --git a/mmedit/edit.py b/mmedit/edit.py index 596b8e8876..bd9bac604a 100644 --- a/mmedit/edit.py +++ b/mmedit/edit.py @@ -90,6 +90,11 @@ class MMEdit: # video_restoration models 'edvr', + 'tdan', + 'basicvsr', + 'iconvsr', + 'basicvsr_pp', + 'real_basicvsr', # text2image models 'disco_diffusion', From 7a1de9ecee885da66484f20e7f79a3e57cf27ddf Mon Sep 17 00:00:00 2001 From: Yifei Yang <2744335995@qq.com> Date: Thu, 30 Mar 2023 18:52:59 +0800 Subject: [PATCH 22/39] [Enhancement] Move ops to MMCV (#1383) * move ops out of mmgeneration * fix arguments * fix padding error * fix lint * fix demo * solve import error on cpu-only and windows * add try import * fix ut bugs * fix ci --- demo/unconditional_demo.py | 4 +- mmedit/models/base_archs/__init__.py | 10 +- mmedit/models/base_archs/conv2d_gradfix.py | 281 ---- .../editors/mspie/mspie_stylegan2_modules.py | 9 +- .../models/editors/stylegan2/ada/augment.py | 11 +- .../models/editors/stylegan2/ada/upfirdn2d.py | 13 +- .../editors/stylegan2/stylegan2_modules.py | 12 +- .../editors/stylegan3/stylegan3_modules.py | 24 +- .../stylegan3/stylegan3_ops/__init__.py | 12 - .../stylegan3/stylegan3_ops/custom_ops.py | 183 --- .../stylegan3/stylegan3_ops/ops/__init__.py | 9 - .../stylegan3/stylegan3_ops/ops/bias_act.cpp | 99 -- .../stylegan3/stylegan3_ops/ops/bias_act.cu | 173 --- .../stylegan3/stylegan3_ops/ops/bias_act.h | 38 - .../stylegan3/stylegan3_ops/ops/bias_act.py | 307 ---- .../stylegan3_ops/ops/filtered_lrelu.cpp | 300 ---- .../stylegan3_ops/ops/filtered_lrelu.cu | 1284 ----------------- .../stylegan3_ops/ops/filtered_lrelu.h | 90 -- .../stylegan3_ops/ops/filtered_lrelu.py | 373 ----- .../stylegan3_ops/ops/filtered_lrelu_ns.cu | 27 - .../stylegan3_ops/ops/filtered_lrelu_rd.cu | 27 - .../stylegan3_ops/ops/filtered_lrelu_wr.cu | 27 - .../stylegan3/stylegan3_ops/ops/upfirdn2d.cpp | 107 -- .../stylegan3/stylegan3_ops/ops/upfirdn2d.cu | 384 ----- .../stylegan3/stylegan3_ops/ops/upfirdn2d.h | 59 - .../stylegan3/stylegan3_ops/ops/upfirdn2d.py | 460 ------ .../editors/stylegan3/stylegan3_utils.py | 19 +- .../test_metrics/test_equivariance.py | 17 - .../test_eg3d/test_dual_discriminator.py | 5 + .../test_mspie/test_mspie_stylegan2.py | 3 +- .../test_mspie_stylegan2_generator.py | 8 + .../test_mspie_stylegan2_modules.py | 17 + .../test_stylegan2/test_ada/test_augment.py | 7 +- .../test_stylegan2_discriminator.py | 3 +- .../test_stylegan3/test_stylegan3.py | 8 + .../test_stylegan3_generator.py | 3 +- .../test_stylegan3/test_stylegan3_modules.py | 5 + .../test_stylegan3/test_stylegan3_utils.py | 14 +- 38 files changed, 138 insertions(+), 4294 deletions(-) delete mode 100644 mmedit/models/base_archs/conv2d_gradfix.py delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/__init__.py delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/custom_ops.py delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/__init__.py delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.cpp delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.cu delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.h delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.py delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.cpp delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.cu delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.h delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.py delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_ns.cu delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_rd.cu delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_wr.cu delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.cpp delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.cu delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.h delete mode 100644 mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.py diff --git a/demo/unconditional_demo.py b/demo/unconditional_demo.py index 9520a8012e..bae007ec77 100644 --- a/demo/unconditional_demo.py +++ b/demo/unconditional_demo.py @@ -69,7 +69,9 @@ def main(): results = sample_unconditional_model(model, args.num_samples, args.num_batches, args.sample_model, **args.sample_cfg) - results = (results[:, [2, 1, 0]] + 1.) / 2. + + results = results / 255 + results = results[:, [2, 1, 0]] # save images mmengine.mkdir_or_exist(os.path.dirname(args.save_path)) diff --git a/mmedit/models/base_archs/__init__.py b/mmedit/models/base_archs/__init__.py index 7454266a31..2d420b4ec9 100644 --- a/mmedit/models/base_archs/__init__.py +++ b/mmedit/models/base_archs/__init__.py @@ -7,7 +7,6 @@ from .all_gather_layer import AllGatherLayer from .aspp import ASPP from .conv import * # noqa: F401, F403 -from .conv2d_gradfix import conv2d, conv_transpose2d from .downsample import pixel_unshuffle from .ensemble import SpatialTemporalEnsemble from .gated_conv_module import SimpleGatedConvModule @@ -67,9 +66,8 @@ def gen_wrapped_cls(module, module_name): __all__ = [ 'ASPP', 'DepthwiseSeparableConvModule', 'SimpleGatedConvModule', - 'LinearModule', 'conv2d', 'conv_transpose2d', 'pixel_unshuffle', - 'PixelShufflePack', 'ImgNormalize', 'SpatialTemporalEnsemble', - 'SoftMaskPatchDiscriminator', 'SimpleEncoderDecoder', - 'MultiLayerDiscriminator', 'PatchDiscriminator', 'VGG16', 'ResNet', - 'AllGatherLayer', 'ResidualBlockNoBN' + 'LinearModule', 'pixel_unshuffle', 'PixelShufflePack', 'ImgNormalize', + 'SpatialTemporalEnsemble', 'SoftMaskPatchDiscriminator', + 'SimpleEncoderDecoder', 'MultiLayerDiscriminator', 'PatchDiscriminator', + 'VGG16', 'ResNet', 'AllGatherLayer', 'ResidualBlockNoBN' ] diff --git a/mmedit/models/base_archs/conv2d_gradfix.py b/mmedit/models/base_archs/conv2d_gradfix.py deleted file mode 100644 index 58b1dd3f99..0000000000 --- a/mmedit/models/base_archs/conv2d_gradfix.py +++ /dev/null @@ -1,281 +0,0 @@ -# Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# NVIDIA CORPORATION and its licensors retain all intellectual property -# and proprietary rights in and to this software, related documentation -# and any modifications thereto. Any use, reproduction, disclosure or -# distribution of this software and related documentation without an express -# license agreement from NVIDIA CORPORATION is strictly prohibited. -"""Custom replacement for `torch.nn.functional.conv2d` that supports -arbitrarily high order gradients with zero performance penalty.""" - -import contextlib - -import torch - -enabled = True -weight_gradients_disabled = False - - -@contextlib.contextmanager -def no_weight_gradients(disable=True): - global weight_gradients_disabled - old = weight_gradients_disabled - if disable: - weight_gradients_disabled = True - yield - weight_gradients_disabled = old - - -def conv2d(input, - weight, - bias=None, - stride=1, - padding=0, - dilation=1, - groups=1): - if _should_use_custom_op(input): - return _conv2d_gradfix( - transpose=False, - weight_shape=weight.shape, - stride=stride, - padding=padding, - output_padding=0, - dilation=dilation, - groups=groups).apply(input, weight, bias) - return torch.nn.functional.conv2d( - input=input, - weight=weight, - bias=bias, - stride=stride, - padding=padding, - dilation=dilation, - groups=groups) - - -def conv_transpose2d(input, - weight, - bias=None, - stride=1, - padding=0, - output_padding=0, - groups=1, - dilation=1): - if _should_use_custom_op(input): - return _conv2d_gradfix( - transpose=True, - weight_shape=weight.shape, - stride=stride, - padding=padding, - output_padding=output_padding, - groups=groups, - dilation=dilation).apply(input, weight, bias) - return torch.nn.functional.conv_transpose2d( - input=input, - weight=weight, - bias=bias, - stride=stride, - padding=padding, - output_padding=output_padding, - groups=groups, - dilation=dilation) - - -def _should_use_custom_op(input): - assert isinstance(input, torch.Tensor) - if (not enabled) or (not torch.backends.cudnn.enabled): - return False - if input.device.type != 'cuda': - return False - return True - - -def _tuple_of_ints(xs, ndim): - xs = tuple(xs) if isinstance(xs, (tuple, list)) else (xs, ) * ndim - assert len(xs) == ndim - assert all(isinstance(x, int) for x in xs) - return xs - - -_conv2d_gradfix_cache = dict() -_null_tensor = torch.empty([0]) - - -def _conv2d_gradfix(transpose, weight_shape, stride, padding, output_padding, - dilation, groups): - # Parse arguments. - ndim = 2 - weight_shape = tuple(weight_shape) - stride = _tuple_of_ints(stride, ndim) - padding = _tuple_of_ints(padding, ndim) - output_padding = _tuple_of_ints(output_padding, ndim) - dilation = _tuple_of_ints(dilation, ndim) - - # Lookup from cache. - key = (transpose, weight_shape, stride, padding, output_padding, dilation, - groups) - if key in _conv2d_gradfix_cache: - return _conv2d_gradfix_cache[key] - - # Validate arguments. - - assert groups >= 1 - assert len(weight_shape) == ndim + 2 - assert all(stride[i] >= 1 for i in range(ndim)) - assert all(padding[i] >= 0 for i in range(ndim)) - assert all(dilation[i] >= 0 for i in range(ndim)) - if not transpose: - assert all(output_padding[i] == 0 for i in range(ndim)) - else: # transpose - assert all(0 <= output_padding[i] < max(stride[i], dilation[i]) - for i in range(ndim)) - - # Helpers. - common_kwargs = dict( - stride=stride, padding=padding, dilation=dilation, groups=groups) - - def calc_output_padding(input_shape, output_shape): - if transpose: - return [0, 0] - return [ - input_shape[i + 2] - (output_shape[i + 2] - 1) * stride[i] - - (1 - 2 * padding[i]) - dilation[i] * (weight_shape[i + 2] - 1) - for i in range(ndim) - ] - - # Forward & backward. - class Conv2d(torch.autograd.Function): - - @staticmethod - def forward(ctx, input, weight, bias): - assert weight.shape == weight_shape - ctx.save_for_backward( - input if weight.requires_grad else _null_tensor, - weight if input.requires_grad else _null_tensor, - ) - ctx.input_shape = input.shape - - # Simple 1x1 convolution => cuBLAS (only on Volta, not on Ampere). - if weight_shape[2:] == stride == dilation == ( - 1, 1) and padding == ( - 0, 0) and torch.cuda.get_device_capability( - input.device) < (8, 0): - a = weight.reshape(groups, weight_shape[0] // groups, - weight_shape[1]) - b = input.reshape(input.shape[0], groups, - input.shape[1] // groups, -1) - c = (a.transpose(1, 2) if transpose else a) @ b.permute( - 1, 2, 0, 3).flatten(2) - c = c.reshape(-1, input.shape[0], - *input.shape[2:]).transpose(0, 1) - c = c if bias is None else c + bias.unsqueeze(0).unsqueeze( - 2).unsqueeze(3) - return c.contiguous( - memory_format=(torch.channels_last if input.stride(1) == - 1 else torch.contiguous_format)) - - # General case => cuDNN. - if transpose: - return torch.nn.functional.conv_transpose2d( - input=input, - weight=weight, - bias=bias, - output_padding=output_padding, - **common_kwargs) - return torch.nn.functional.conv2d( - input=input, weight=weight, bias=bias, **common_kwargs) - - @staticmethod - def backward(ctx, grad_output): - input, weight = ctx.saved_tensors - input_shape = ctx.input_shape - grad_input = None - grad_weight = None - grad_bias = None - - if ctx.needs_input_grad[0]: - p = calc_output_padding( - input_shape=input_shape, output_shape=grad_output.shape) - op = _conv2d_gradfix( - transpose=(not transpose), - weight_shape=weight_shape, - output_padding=p, - **common_kwargs) - grad_input = op.apply(grad_output, weight, None) - assert grad_input.shape == input_shape - - if ctx.needs_input_grad[1] and not weight_gradients_disabled: - grad_weight = Conv2dGradWeight.apply(grad_output, input) - assert grad_weight.shape == weight_shape - - if ctx.needs_input_grad[2]: - grad_bias = grad_output.sum([0, 2, 3]) - - return grad_input, grad_weight, grad_bias - - # Gradient with respect to the weights. - class Conv2dGradWeight(torch.autograd.Function): - - @staticmethod - def forward(ctx, grad_output, input): - ctx.save_for_backward( - grad_output if input.requires_grad else _null_tensor, - input if grad_output.requires_grad else _null_tensor, - ) - ctx.grad_output_shape = grad_output.shape - ctx.input_shape = input.shape - - # Simple 1x1 convolution => cuBLAS (on both Volta and Ampere). - if weight_shape[2:] == stride == dilation == ( - 1, 1) and padding == (0, 0): - a = grad_output.reshape(grad_output.shape[0], groups, - grad_output.shape[1] // groups, - -1).permute(1, 2, 0, 3).flatten(2) - b = input.reshape(input.shape[0], groups, - input.shape[1] // groups, - -1).permute(1, 2, 0, 3).flatten(2) - c = (b @ a.transpose(1, 2) if transpose else - a @ b.transpose(1, 2)).reshape(weight_shape) - return c.contiguous( - memory_format=(torch.channels_last if input.stride(1) == - 1 else torch.contiguous_format)) - - # General case => cuDNN. - name = ('aten::cudnn_convolution_transpose_backward_weight' if - transpose else 'aten::cudnn_convolution_backward_weight') - flags = [ - torch.backends.cudnn.benchmark, - torch.backends.cudnn.deterministic, - torch.backends.cudnn.allow_tf32 - ] - return torch._C._jit_get_operation(name)(weight_shape, grad_output, - input, padding, stride, - dilation, groups, *flags) - - @staticmethod - def backward(ctx, grad2_grad_weight): - grad_output, input = ctx.saved_tensors - grad_output_shape = ctx.grad_output_shape - input_shape = ctx.input_shape - grad2_grad_output = None - grad2_input = None - - if ctx.needs_input_grad[0]: - grad2_grad_output = Conv2d.apply(input, grad2_grad_weight, - None) - assert grad2_grad_output.shape == grad_output_shape - - if ctx.needs_input_grad[1]: - p = calc_output_padding( - input_shape=input_shape, output_shape=grad_output_shape) - op = _conv2d_gradfix( - transpose=(not transpose), - weight_shape=weight_shape, - output_padding=p, - **common_kwargs) - grad2_input = op.apply(grad_output, grad2_grad_weight, None) - assert grad2_input.shape == input_shape - - return grad2_grad_output, grad2_input - - _conv2d_gradfix_cache[key] = Conv2d - return Conv2d diff --git a/mmedit/models/editors/mspie/mspie_stylegan2_modules.py b/mmedit/models/editors/mspie/mspie_stylegan2_modules.py index 4034934035..a480016543 100644 --- a/mmedit/models/editors/mspie/mspie_stylegan2_modules.py +++ b/mmedit/models/editors/mspie/mspie_stylegan2_modules.py @@ -5,7 +5,14 @@ import torch.nn as nn import torch.nn.functional as F -from ...base_archs import conv2d, conv_transpose2d +try: + from mmcv.ops import conv2d, conv_transpose2d +except ImportError: + conv2d = None + conv_transpose2d = None + print('Warning: mmcv.ops.conv2d, mmcv.ops.conv_transpose2d' + 'are not available.') + from ..pggan import equalized_lr from ..stylegan1 import Blur, EqualLinearActModule, NoiseInjection from ..stylegan2.stylegan2_modules import _FusedBiasLeakyReLU diff --git a/mmedit/models/editors/stylegan2/ada/augment.py b/mmedit/models/editors/stylegan2/ada/augment.py index d9c5a89089..11a8d27092 100644 --- a/mmedit/models/editors/stylegan2/ada/augment.py +++ b/mmedit/models/editors/stylegan2/ada/augment.py @@ -10,7 +10,12 @@ import scipy.signal import torch -from ....base_archs import conv2d_gradfix +try: + from mmcv.ops import conv2d +except ImportError: + conv2d = None + print('Warning: mmcv.ops.conv2d are not available.') + from . import grid_sample_gradfix, misc, upfirdn2d # ---------------------------------------------------------------------------- @@ -730,11 +735,11 @@ def forward(self, images, debug_percentile=None): [1, batch_size * num_channels, height, width]) images = torch.nn.functional.pad( input=images, pad=[p, p, p, p], mode='reflect') - images = conv2d_gradfix.conv2d( + images = conv2d( input=images, weight=Hz_prime.unsqueeze(2), groups=batch_size * num_channels) - images = conv2d_gradfix.conv2d( + images = conv2d( input=images, weight=Hz_prime.unsqueeze(3), groups=batch_size * num_channels) diff --git a/mmedit/models/editors/stylegan2/ada/upfirdn2d.py b/mmedit/models/editors/stylegan2/ada/upfirdn2d.py index 51ead27caf..8479d713bd 100644 --- a/mmedit/models/editors/stylegan2/ada/upfirdn2d.py +++ b/mmedit/models/editors/stylegan2/ada/upfirdn2d.py @@ -1,7 +1,12 @@ # Copyright (c) OpenMMLab. All rights reserved. import numpy as np import torch -from mmcv.ops.upfirdn2d import upfirdn2d + +try: + from mmcv.ops import upfirdn2d +except ImportError: + upfirdn2d = None + print('Warning: mmcv.ops.upfirdn2d is not available.') def _parse_scaling(scaling): @@ -81,8 +86,10 @@ def upsample2d(x, f, up=2, padding=0, flip_filter=False, gain=1, impl='cuda'): if flip_filter: f = f.flip(list(range(f.ndim))) if f.ndim == 1: - x = upfirdn2d(x, f.unsqueeze(0), up=(upx, 1), pad=(p[0], p[1], 0, 0)) - x = upfirdn2d(x, f.unsqueeze(1), up=(1, upy), pad=(0, 0, p[2], p[3])) + x = upfirdn2d( + x, f.unsqueeze(0), up=(upx, 1), padding=(p[0], p[1], 0, 0)) + x = upfirdn2d( + x, f.unsqueeze(1), up=(1, upy), padding=(0, 0, p[2], p[3])) return x diff --git a/mmedit/models/editors/stylegan2/stylegan2_modules.py b/mmedit/models/editors/stylegan2/stylegan2_modules.py index b1b50b2fe0..a1faa0e423 100644 --- a/mmedit/models/editors/stylegan2/stylegan2_modules.py +++ b/mmedit/models/editors/stylegan2/stylegan2_modules.py @@ -10,10 +10,18 @@ from mmengine.runner.amp import autocast from mmedit.models.base_archs import AllGatherLayer -from ...base_archs import conv2d, conv_transpose2d from ..pggan import EqualizedLRConvModule, equalized_lr from ..stylegan1 import Blur, EqualLinearActModule, NoiseInjection, make_kernel +try: + from mmcv.ops import conv2d, conv_transpose2d +except ImportError: + import torch.nn.functional as F + conv2d = F.conv2d + conv_transpose2d = F.conv_transpose2d + print('Warning: mmcv.ops.conv2d, mmcv.ops.conv_transpose2d' + ' and mmcv.ops.upfirdn2d are not available.') + class _FusedBiasLeakyReLU(FusedBiasLeakyReLU): """Wrap FusedBiasLeakyReLU to support FP16 training.""" @@ -54,7 +62,7 @@ def __init__(self, kernel, factor=2): pad0 = (p + 1) // 2 + factor - 1 pad1 = p // 2 - self.pad = (pad0, pad1) + self.pad = (pad0, pad1, pad0, pad1) def forward(self, x): """Forward function. diff --git a/mmedit/models/editors/stylegan3/stylegan3_modules.py b/mmedit/models/editors/stylegan3/stylegan3_modules.py index 9e366f816f..215a6afa5d 100644 --- a/mmedit/models/editors/stylegan3/stylegan3_modules.py +++ b/mmedit/models/editors/stylegan3/stylegan3_modules.py @@ -3,11 +3,19 @@ import scipy import torch import torch.nn as nn + +try: + from mmcv.ops import bias_act, conv2d_gradfix, filtered_lrelu +except ImportError: + bias_act = None + conv2d_gradfix = None + filtered_lrelu = None + print('Warning: mmcv.ops.bias_act, mmcv.ops.conv2d_gradfix' + ' and mmcv.ops.filtered_lrelu are not available.') + from mmengine.runner.amp import autocast -from mmedit.models.base_archs import conv2d_gradfix from mmedit.registry import MODELS -from .stylegan3_ops.ops import bias_act, filtered_lrelu def modulated_conv2d( @@ -116,7 +124,7 @@ def forward(self, x): x = torch.addmm(b.unsqueeze(0), x, w.t()) else: x = x.matmul(w.t()) - x = bias_act.bias_act(x, b, act=self.activation) + x = bias_act(x, b, act=self.activation) return x @@ -528,11 +536,11 @@ def forward(self, x, w, force_fp32=False, update_emas=False): # Execute bias, filtered leaky ReLU, and clamping. gain = 1 if self.is_torgb else np.sqrt(2) slope = 1 if self.is_torgb else 0.2 - x = filtered_lrelu.filtered_lrelu( - x=x, - fu=self.up_filter, - fd=self.down_filter, - b=self.bias.to(x.dtype), + x = filtered_lrelu( + input=x, + filter_up=self.up_filter, + filter_down=self.down_filter, + bias=self.bias.to(x.dtype), up=self.up_factor, down=self.down_factor, padding=self.padding, diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/__init__.py b/mmedit/models/editors/stylegan3/stylegan3_ops/__init__.py deleted file mode 100644 index 92d915f5c2..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# NVIDIA CORPORATION and its licensors retain all intellectual property -# and proprietary rights in and to this software, related documentation -# and any modifications thereto. Any use, reproduction, disclosure or -# distribution of this software and related documentation without an express -# license agreement from NVIDIA CORPORATION is strictly prohibited. - -# empty -# from .ops import filtered_lrelu - -# __all__ = ['filtered_lrelu'] diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/custom_ops.py b/mmedit/models/editors/stylegan3/stylegan3_ops/custom_ops.py deleted file mode 100644 index f7c0fec977..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/custom_ops.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# NVIDIA CORPORATION and its licensors retain all intellectual property -# and proprietary rights in and to this software, related documentation -# and any modifications thereto. Any use, reproduction, disclosure or -# distribution of this software and related documentation without an express -# license agreement from NVIDIA CORPORATION is strictly prohibited. - -import glob -import hashlib -import importlib -import os -import re -import shutil -import uuid - -import torch -import torch.utils.cpp_extension - -# Global options. - -verbosity = 'brief' # Verbosity level: 'none', 'brief', 'full' - -# Internal helper funcs. - - -def _find_compiler_bindir(): - patterns = [ - 'C:/Program Files (x86)/Microsoft Visual Studio/*/Professional/VC/Tools/MSVC/*/bin/Hostx64/x64', # noqa - 'C:/Program Files (x86)/Microsoft Visual Studio/*/BuildTools/VC/Tools/MSVC/*/bin/Hostx64/x64', # noqa - 'C:/Program Files (x86)/Microsoft Visual Studio/*/Community/VC/Tools/MSVC/*/bin/Hostx64/x64', # noqa - 'C:/Program Files (x86)/Microsoft Visual Studio */vc/bin', - ] - for pattern in patterns: - matches = sorted(glob.glob(pattern)) - if len(matches): - return matches[-1] - return None - - -def _get_mangled_gpu_name(): - name = torch.cuda.get_device_name().lower() - out = [] - for c in name: - if re.match('[a-z0-9_-]+', c): - out.append(c) - else: - out.append('-') - return ''.join(out) - - -# Main entry point for compiling and loading C++/CUDA plugins. - -_cached_plugins = dict() - - -def get_plugin(module_name, - sources, - headers=None, - source_dir=None, - **build_kwargs): - assert verbosity in ['none', 'brief', 'full'] - if headers is None: - headers = [] - if source_dir is not None: - sources = [os.path.join(source_dir, fname) for fname in sources] - headers = [os.path.join(source_dir, fname) for fname in headers] - - # Already cached? - if module_name in _cached_plugins: - return _cached_plugins[module_name] - - # Print status. - if verbosity == 'full': - print(f'Setting up PyTorch plugin "{module_name}"...') - elif verbosity == 'brief': - print( - f'Setting up PyTorch plugin "{module_name}"... ', - end='', - flush=True) - verbose_build = (verbosity == 'full') - - # Compile and load. - try: # pylint: disable=too-many-nested-blocks - # Make sure we can find the necessary compiler binaries. - if os.name == 'nt' and os.system('where cl.exe >nul 2>nul') != 0: - compiler_bindir = _find_compiler_bindir() - if compiler_bindir is None: - raise RuntimeError( - 'Could not find MSVC/GCC/CLANG installation on this ' - f'computer. Check _find_compiler_bindir() in "{__file__}".' - ) - os.environ['PATH'] += ';' + compiler_bindir - - # Some containers set TORCH_CUDA_ARCH_LIST to a list that can either - # break the build or unnecessarily restrict what's available to nvcc. - # Unset it to let nvcc decide based on what's available on the - # machine. - os.environ['TORCH_CUDA_ARCH_LIST'] = '' - - # Incremental build md5sum trickery. Copies all the input source files - # into a cached build directory under a combined md5 digest of the - # input source files. Copying is done only if the combined digest has - # changed. - # This keeps input file timestamps and filenames the same as in - # previous extension builds, allowing for fast incremental rebuilds. - # - # This optimization is done only in case all the source files reside in - # a single directory (just for simplicity) and if the - # TORCH_EXTENSIONS_DIR environment variable is set (we take this as a - # signal that the user - # actually cares about this.) - # - # EDIT: We now do it regardless of TORCH_EXTENSIOS_DIR, in order to - # work around the *.cu dependency bug in ninja config. - - all_source_files = sorted(sources + headers) - all_source_dirs = set( - os.path.dirname(fname) for fname in all_source_files) - if len(all_source_dirs - ) == 1: # and ('TORCH_EXTENSIONS_DIR' in os.environ): - - # Compute combined hash digest for all source files. - hash_md5 = hashlib.md5() - for src in all_source_files: - with open(src, 'rb') as f: - hash_md5.update(f.read()) - - # Select cached build directory name. - source_digest = hash_md5.hexdigest() - build_top_dir = torch.utils.cpp_extension._get_build_directory( - module_name, verbose=verbose_build) - cached_build_dir = os.path.join( - build_top_dir, f'{source_digest}-{_get_mangled_gpu_name()}') - - if not os.path.isdir(cached_build_dir): - tmpdir = f'{build_top_dir}/srctmp-{uuid.uuid4().hex}' - os.makedirs(tmpdir) - for src in all_source_files: - shutil.copyfile( - src, os.path.join(tmpdir, os.path.basename(src))) - try: - os.replace(tmpdir, cached_build_dir) # atomic - except OSError: - # source directory already exists - # delete tmpdir and its contents. - shutil.rmtree(tmpdir) - if not os.path.isdir(cached_build_dir): - raise - - # Compile. - cached_sources = [ - os.path.join(cached_build_dir, os.path.basename(fname)) - for fname in sources - ] - torch.utils.cpp_extension.load( - name=module_name, - build_directory=cached_build_dir, - verbose=verbose_build, - sources=cached_sources, - **build_kwargs) - else: - torch.utils.cpp_extension.load( - name=module_name, - verbose=verbose_build, - sources=sources, - **build_kwargs) - - # Load. - module = importlib.import_module(module_name) - - except Exception as err: - if verbosity == 'brief': - print('Failed!') - raise err - - # Print status and add to cache dict. - if verbosity == 'full': - print(f'Done setting up PyTorch plugin "{module_name}".') - elif verbosity == 'brief': - print('Done.') - _cached_plugins[module_name] = module - return module diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/__init__.py b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/__init__.py deleted file mode 100644 index 939e7c6c8f..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# NVIDIA CORPORATION and its licensors retain all intellectual property -# and proprietary rights in and to this software, related documentation -# and any modifications thereto. Any use, reproduction, disclosure or -# distribution of this software and related documentation without an express -# license agreement from NVIDIA CORPORATION is strictly prohibited. - -# empty diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.cpp b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.cpp deleted file mode 100644 index 3adaeee2ae..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include -#include -#include -#include "bias_act.h" - -//------------------------------------------------------------------------ - -static bool has_same_layout(torch::Tensor x, torch::Tensor y) -{ - if (x.dim() != y.dim()) - return false; - for (int64_t i = 0; i < x.dim(); i++) - { - if (x.size(i) != y.size(i)) - return false; - if (x.size(i) >= 2 && x.stride(i) != y.stride(i)) - return false; - } - return true; -} - -//------------------------------------------------------------------------ - -static torch::Tensor bias_act(torch::Tensor x, torch::Tensor b, torch::Tensor xref, torch::Tensor yref, torch::Tensor dy, int grad, int dim, int act, float alpha, float gain, float clamp) -{ - // Validate arguments. - TORCH_CHECK(x.is_cuda(), "x must reside on CUDA device"); - TORCH_CHECK(b.numel() == 0 || (b.dtype() == x.dtype() && b.device() == x.device()), "b must have the same dtype and device as x"); - TORCH_CHECK(xref.numel() == 0 || (xref.sizes() == x.sizes() && xref.dtype() == x.dtype() && xref.device() == x.device()), "xref must have the same shape, dtype, and device as x"); - TORCH_CHECK(yref.numel() == 0 || (yref.sizes() == x.sizes() && yref.dtype() == x.dtype() && yref.device() == x.device()), "yref must have the same shape, dtype, and device as x"); - TORCH_CHECK(dy.numel() == 0 || (dy.sizes() == x.sizes() && dy.dtype() == x.dtype() && dy.device() == x.device()), "dy must have the same dtype and device as x"); - TORCH_CHECK(x.numel() <= INT_MAX, "x is too large"); - TORCH_CHECK(b.dim() == 1, "b must have rank 1"); - TORCH_CHECK(b.numel() == 0 || (dim >= 0 && dim < x.dim()), "dim is out of bounds"); - TORCH_CHECK(b.numel() == 0 || b.numel() == x.size(dim), "b has wrong number of elements"); - TORCH_CHECK(grad >= 0, "grad must be non-negative"); - - // Validate layout. - TORCH_CHECK(x.is_non_overlapping_and_dense(), "x must be non-overlapping and dense"); - TORCH_CHECK(b.is_contiguous(), "b must be contiguous"); - TORCH_CHECK(xref.numel() == 0 || has_same_layout(xref, x), "xref must have the same layout as x"); - TORCH_CHECK(yref.numel() == 0 || has_same_layout(yref, x), "yref must have the same layout as x"); - TORCH_CHECK(dy.numel() == 0 || has_same_layout(dy, x), "dy must have the same layout as x"); - - // Create output tensor. - const at::cuda::OptionalCUDAGuard device_guard(device_of(x)); - torch::Tensor y = torch::empty_like(x); - TORCH_CHECK(has_same_layout(y, x), "y must have the same layout as x"); - - // Initialize CUDA kernel parameters. - bias_act_kernel_params p; - p.x = x.data_ptr(); - p.b = (b.numel()) ? b.data_ptr() : NULL; - p.xref = (xref.numel()) ? xref.data_ptr() : NULL; - p.yref = (yref.numel()) ? yref.data_ptr() : NULL; - p.dy = (dy.numel()) ? dy.data_ptr() : NULL; - p.y = y.data_ptr(); - p.grad = grad; - p.act = act; - p.alpha = alpha; - p.gain = gain; - p.clamp = clamp; - p.sizeX = (int)x.numel(); - p.sizeB = (int)b.numel(); - p.stepB = (b.numel()) ? (int)x.stride(dim) : 1; - - // Choose CUDA kernel. - void* kernel; - AT_DISPATCH_FLOATING_TYPES_AND_HALF(x.scalar_type(), "upfirdn2d_cuda", [&] - { - kernel = choose_bias_act_kernel(p); - }); - TORCH_CHECK(kernel, "no CUDA kernel found for the specified activation func"); - - // Launch CUDA kernel. - p.loopX = 4; - int blockSize = 4 * 32; - int gridSize = (p.sizeX - 1) / (p.loopX * blockSize) + 1; - void* args[] = {&p}; - AT_CUDA_CHECK(cudaLaunchKernel(kernel, gridSize, blockSize, args, 0, at::cuda::getCurrentCUDAStream())); - return y; -} - -//------------------------------------------------------------------------ - -PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) -{ - m.def("bias_act", &bias_act); -} - -//------------------------------------------------------------------------ diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.cu b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.cu deleted file mode 100644 index ed1d16f14e..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.cu +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include -#include "bias_act.h" - -//------------------------------------------------------------------------ -// Helpers. - -template struct InternalType; -template <> struct InternalType { typedef double scalar_t; }; -template <> struct InternalType { typedef float scalar_t; }; -template <> struct InternalType { typedef float scalar_t; }; - -//------------------------------------------------------------------------ -// CUDA kernel. - -template -__global__ void bias_act_kernel(bias_act_kernel_params p) -{ - typedef typename InternalType::scalar_t scalar_t; - int G = p.grad; - scalar_t alpha = (scalar_t)p.alpha; - scalar_t gain = (scalar_t)p.gain; - scalar_t clamp = (scalar_t)p.clamp; - scalar_t one = (scalar_t)1; - scalar_t two = (scalar_t)2; - scalar_t expRange = (scalar_t)80; - scalar_t halfExpRange = (scalar_t)40; - scalar_t seluScale = (scalar_t)1.0507009873554804934193349852946; - scalar_t seluAlpha = (scalar_t)1.6732632423543772848170429916717; - - // Loop over elements. - int xi = blockIdx.x * p.loopX * blockDim.x + threadIdx.x; - for (int loopIdx = 0; loopIdx < p.loopX && xi < p.sizeX; loopIdx++, xi += blockDim.x) - { - // Load. - scalar_t x = (scalar_t)((const T*)p.x)[xi]; - scalar_t b = (p.b) ? (scalar_t)((const T*)p.b)[(xi / p.stepB) % p.sizeB] : 0; - scalar_t xref = (p.xref) ? (scalar_t)((const T*)p.xref)[xi] : 0; - scalar_t yref = (p.yref) ? (scalar_t)((const T*)p.yref)[xi] : 0; - scalar_t dy = (p.dy) ? (scalar_t)((const T*)p.dy)[xi] : one; - scalar_t yy = (gain != 0) ? yref / gain : 0; - scalar_t y = 0; - - // Apply bias. - ((G == 0) ? x : xref) += b; - - // linear - if (A == 1) - { - if (G == 0) y = x; - if (G == 1) y = x; - } - - // relu - if (A == 2) - { - if (G == 0) y = (x > 0) ? x : 0; - if (G == 1) y = (yy > 0) ? x : 0; - } - - // lrelu - if (A == 3) - { - if (G == 0) y = (x > 0) ? x : x * alpha; - if (G == 1) y = (yy > 0) ? x : x * alpha; - } - - // tanh - if (A == 4) - { - if (G == 0) { scalar_t c = exp(x); scalar_t d = one / c; y = (x < -expRange) ? -one : (x > expRange) ? one : (c - d) / (c + d); } - if (G == 1) y = x * (one - yy * yy); - if (G == 2) y = x * (one - yy * yy) * (-two * yy); - } - - // sigmoid - if (A == 5) - { - if (G == 0) y = (x < -expRange) ? 0 : one / (exp(-x) + one); - if (G == 1) y = x * yy * (one - yy); - if (G == 2) y = x * yy * (one - yy) * (one - two * yy); - } - - // elu - if (A == 6) - { - if (G == 0) y = (x >= 0) ? x : exp(x) - one; - if (G == 1) y = (yy >= 0) ? x : x * (yy + one); - if (G == 2) y = (yy >= 0) ? 0 : x * (yy + one); - } - - // selu - if (A == 7) - { - if (G == 0) y = (x >= 0) ? seluScale * x : (seluScale * seluAlpha) * (exp(x) - one); - if (G == 1) y = (yy >= 0) ? x * seluScale : x * (yy + seluScale * seluAlpha); - if (G == 2) y = (yy >= 0) ? 0 : x * (yy + seluScale * seluAlpha); - } - - // softplus - if (A == 8) - { - if (G == 0) y = (x > expRange) ? x : log(exp(x) + one); - if (G == 1) y = x * (one - exp(-yy)); - if (G == 2) { scalar_t c = exp(-yy); y = x * c * (one - c); } - } - - // swish - if (A == 9) - { - if (G == 0) - y = (x < -expRange) ? 0 : x / (exp(-x) + one); - else - { - scalar_t c = exp(xref); - scalar_t d = c + one; - if (G == 1) - y = (xref > halfExpRange) ? x : x * c * (xref + d) / (d * d); - else - y = (xref > halfExpRange) ? 0 : x * c * (xref * (two - d) + two * d) / (d * d * d); - yref = (xref < -expRange) ? 0 : xref / (exp(-xref) + one) * gain; - } - } - - // Apply gain. - y *= gain * dy; - - // Clamp. - if (clamp >= 0) - { - if (G == 0) - y = (y > -clamp & y < clamp) ? y : (y >= 0) ? clamp : -clamp; - else - y = (yref > -clamp & yref < clamp) ? y : 0; - } - - // Store. - ((T*)p.y)[xi] = (T)y; - } -} - -//------------------------------------------------------------------------ -// CUDA kernel selection. - -template void* choose_bias_act_kernel(const bias_act_kernel_params& p) -{ - if (p.act == 1) return (void*)bias_act_kernel; - if (p.act == 2) return (void*)bias_act_kernel; - if (p.act == 3) return (void*)bias_act_kernel; - if (p.act == 4) return (void*)bias_act_kernel; - if (p.act == 5) return (void*)bias_act_kernel; - if (p.act == 6) return (void*)bias_act_kernel; - if (p.act == 7) return (void*)bias_act_kernel; - if (p.act == 8) return (void*)bias_act_kernel; - if (p.act == 9) return (void*)bias_act_kernel; - return NULL; -} - -//------------------------------------------------------------------------ -// Template specializations. - -template void* choose_bias_act_kernel (const bias_act_kernel_params& p); -template void* choose_bias_act_kernel (const bias_act_kernel_params& p); -template void* choose_bias_act_kernel (const bias_act_kernel_params& p); - -//------------------------------------------------------------------------ diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.h b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.h deleted file mode 100644 index 60b81c6058..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -//------------------------------------------------------------------------ -// CUDA kernel parameters. - -struct bias_act_kernel_params -{ - const void* x; // [sizeX] - const void* b; // [sizeB] or NULL - const void* xref; // [sizeX] or NULL - const void* yref; // [sizeX] or NULL - const void* dy; // [sizeX] or NULL - void* y; // [sizeX] - - int grad; - int act; - float alpha; - float gain; - float clamp; - - int sizeX; - int sizeB; - int stepB; - int loopX; -}; - -//------------------------------------------------------------------------ -// CUDA kernel selection. - -template void* choose_bias_act_kernel(const bias_act_kernel_params& p); - -//------------------------------------------------------------------------ diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.py b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.py deleted file mode 100644 index 38c7b6e261..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/bias_act.py +++ /dev/null @@ -1,307 +0,0 @@ -# Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# NVIDIA CORPORATION and its licensors retain all intellectual property -# and proprietary rights in and to this software, related documentation -# and any modifications thereto. Any use, reproduction, disclosure or -# distribution of this software and related documentation without an express -# license agreement from NVIDIA CORPORATION is strictly prohibited. -"""Custom PyTorch ops for efficient bias and activation.""" - -import os -from typing import Any - -import numpy as np -import torch - -from .. import custom_ops - - -class EasyDict(dict): - """Convenience class that behaves like a dict but allows access with the - attribute syntax.""" - - def __getattr__(self, name: str) -> Any: - try: - return self[name] - except KeyError: - raise AttributeError(name) - - def __setattr__(self, name: str, value: Any) -> None: - self[name] = value - - def __delattr__(self, name: str) -> None: - del self[name] - - -activation_funcs = { - 'linear': - EasyDict( - func=lambda x, **_: x, - def_alpha=0, - def_gain=1, - cuda_idx=1, - ref='', - has_2nd_grad=False), - 'relu': - EasyDict( - func=lambda x, **_: torch.nn.functional.relu(x), - def_alpha=0, - def_gain=np.sqrt(2), - cuda_idx=2, - ref='y', - has_2nd_grad=False), - 'lrelu': - EasyDict( - func=lambda x, alpha, **_: torch.nn.functional.leaky_relu(x, alpha), - def_alpha=0.2, - def_gain=np.sqrt(2), - cuda_idx=3, - ref='y', - has_2nd_grad=False), - 'tanh': - EasyDict( - func=lambda x, **_: torch.tanh(x), - def_alpha=0, - def_gain=1, - cuda_idx=4, - ref='y', - has_2nd_grad=True), - 'sigmoid': - EasyDict( - func=lambda x, **_: torch.sigmoid(x), - def_alpha=0, - def_gain=1, - cuda_idx=5, - ref='y', - has_2nd_grad=True), - 'elu': - EasyDict( - func=lambda x, **_: torch.nn.functional.elu(x), - def_alpha=0, - def_gain=1, - cuda_idx=6, - ref='y', - has_2nd_grad=True), - 'selu': - EasyDict( - func=lambda x, **_: torch.nn.functional.selu(x), - def_alpha=0, - def_gain=1, - cuda_idx=7, - ref='y', - has_2nd_grad=True), - 'softplus': - EasyDict( - func=lambda x, **_: torch.nn.functional.softplus(x), - def_alpha=0, - def_gain=1, - cuda_idx=8, - ref='y', - has_2nd_grad=True), - 'swish': - EasyDict( - func=lambda x, **_: torch.sigmoid(x) * x, - def_alpha=0, - def_gain=np.sqrt(2), - cuda_idx=9, - ref='x', - has_2nd_grad=True), -} - -_plugin = None -_null_tensor = torch.empty([0]) - - -def _init(): - global _plugin - if _plugin is None: - _plugin = custom_ops.get_plugin( - module_name='bias_act_plugin', - sources=['bias_act.cpp', 'bias_act.cu'], - headers=['bias_act.h'], - source_dir=os.path.dirname(__file__), - extra_cuda_cflags=['--use_fast_math'], - ) - return True - - -def bias_act(x, - b=None, - dim=1, - act='linear', - alpha=None, - gain=None, - clamp=None, - impl='cuda'): - r"""Fused bias and activation function. - Adds bias `b` to activation tensor `x`, evaluates activation function - `act`, and scales the result by `gain`. Each of the steps is optional. - In most cases, the fused op is considerably more efficient than performing - the same calculation using standard PyTorch ops. It supports first and - second order gradients, but not third order gradients. - - Args: - x: Input activation tensor. Can be of any shape. - b: Bias vector, or `None` to disable. Must be a 1D tensor of the - same type as `x`. The shape must be known, and it must match - the dimension of `x` corresponding to `dim`. - dim: The dimension in `x` corresponding to the elements of `b`. - The value of `dim` is ignored if `b` is not specified. - act: Name of the activation function to evaluate, or `"linear"` to - disable. Can be e.g. `"relu"`, `"lrelu"`, `"tanh"`, - `"sigmoid"`, `"swish"`, etc. See `activation_funcs` for a full - list. `None` is not allowed. - alpha: Shape parameter for the activation function, or `None` to use - the default. - gain: Scaling factor for the output tensor, or `None` to use default. - See `activation_funcs` for the default scaling of each - activation function. If unsure, consider specifying 1. - clamp: Clamp the output values to `[-clamp, +clamp]`, or `None` to - disable the clamping (default). - impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` - (default). - - Returns: - Tensor of the same shape and datatype as `x`. - """ - assert isinstance(x, torch.Tensor) - assert impl in ['ref', 'cuda'] - if impl == 'cuda' and x.device.type == 'cuda' and _init(): - return _bias_act_cuda( - dim=dim, act=act, alpha=alpha, gain=gain, clamp=clamp).apply(x, b) - return _bias_act_ref( - x=x, b=b, dim=dim, act=act, alpha=alpha, gain=gain, clamp=clamp) - - -def _bias_act_ref(x, - b=None, - dim=1, - act='linear', - alpha=None, - gain=None, - clamp=None): - """Slow reference implementation of `bias_act()` using standard TensorFlow - ops.""" - assert isinstance(x, torch.Tensor) - assert clamp is None or clamp >= 0 - spec = activation_funcs[act] - alpha = float(alpha if alpha is not None else spec.def_alpha) - gain = float(gain if gain is not None else spec.def_gain) - clamp = float(clamp if clamp is not None else -1) - - # Add bias. - if b is not None: - assert isinstance(b, torch.Tensor) and b.ndim == 1 - assert 0 <= dim < x.ndim - assert b.shape[0] == x.shape[dim] - x = x + b.reshape([-1 if i == dim else 1 for i in range(x.ndim)]) - - # Evaluate activation function. - alpha = float(alpha) - x = spec.func(x, alpha=alpha) - - # Scale by gain. - gain = float(gain) - if gain != 1: - x = x * gain - - # Clamp. - if clamp >= 0: - # pylint: disable=invalid-unary-operand-type - x = x.clamp(-clamp, clamp) - return x - - -_bias_act_cuda_cache = dict() - - -def _bias_act_cuda(dim=1, act='linear', alpha=None, gain=None, clamp=None): - """Fast CUDA implementation of `bias_act()` using custom ops.""" - # Parse arguments. - assert clamp is None or clamp >= 0 - spec = activation_funcs[act] - alpha = float(alpha if alpha is not None else spec.def_alpha) - gain = float(gain if gain is not None else spec.def_gain) - clamp = float(clamp if clamp is not None else -1) - - # Lookup from cache. - key = (dim, act, alpha, gain, clamp) - if key in _bias_act_cuda_cache: - return _bias_act_cuda_cache[key] - - # Forward op. - class BiasActCuda(torch.autograd.Function): - - @staticmethod - def forward(ctx, x, b): # pylint: disable=arguments-differ - ctx.memory_format = torch.channels_last if x.ndim > 2 and x.stride( - 1) == 1 else torch.contiguous_format - x = x.contiguous(memory_format=ctx.memory_format) - b = b.contiguous() if b is not None else _null_tensor - y = x - if act != 'linear' or gain != 1 or clamp >= 0 or ( - b is not _null_tensor): - y = _plugin.bias_act(x, b, _null_tensor, _null_tensor, - _null_tensor, 0, dim, spec.cuda_idx, - alpha, gain, clamp) - ctx.save_for_backward( - x if 'x' in spec.ref or spec.has_2nd_grad else _null_tensor, - b if 'x' in spec.ref or spec.has_2nd_grad else _null_tensor, - y if 'y' in spec.ref else _null_tensor) - return y - - @staticmethod - def backward(ctx, dy): # pylint: disable=arguments-differ - dy = dy.contiguous(memory_format=ctx.memory_format) - x, b, y = ctx.saved_tensors - dx = None - db = None - - if ctx.needs_input_grad[0] or ctx.needs_input_grad[1]: - dx = dy - if act != 'linear' or gain != 1 or clamp >= 0: - dx = BiasActCudaGrad.apply(dy, x, b, y) - - if ctx.needs_input_grad[1]: - db = dx.sum([i for i in range(dx.ndim) if i != dim]) - - return dx, db - - # Backward op. - class BiasActCudaGrad(torch.autograd.Function): - - @staticmethod - def forward(ctx, dy, x, b, y): # pylint: disable=arguments-differ - ctx.memory_format = torch.channels_last if dy.ndim > 2 and ( - dy.stride(1) == 1) else torch.contiguous_format - dx = _plugin.bias_act(dy, b, x, y, _null_tensor, 1, dim, - spec.cuda_idx, alpha, gain, clamp) - ctx.save_for_backward(dy if spec.has_2nd_grad else _null_tensor, x, - b, y) - return dx - - @staticmethod - def backward(ctx, d_dx): # pylint: disable=arguments-differ - d_dx = d_dx.contiguous(memory_format=ctx.memory_format) - dy, x, b, y = ctx.saved_tensors - d_dy = None - d_x = None - d_b = None - d_y = None - - if ctx.needs_input_grad[0]: - d_dy = BiasActCudaGrad.apply(d_dx, x, b, y) - - if spec.has_2nd_grad and (ctx.needs_input_grad[1] - or ctx.needs_input_grad[2]): - d_x = _plugin.bias_act(d_dx, b, x, y, dy, 2, dim, - spec.cuda_idx, alpha, gain, clamp) - - if spec.has_2nd_grad and ctx.needs_input_grad[2]: - d_b = d_x.sum([i for i in range(d_x.ndim) if i != dim]) - - return d_dy, d_x, d_b, d_y - - # Add to cache. - _bias_act_cuda_cache[key] = BiasActCuda - return BiasActCuda diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.cpp b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.cpp deleted file mode 100644 index ff4149b8b4..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.cpp +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include -#include -#include -#include "filtered_lrelu.h" - -//------------------------------------------------------------------------ - -static std::tuple filtered_lrelu( - torch::Tensor x, torch::Tensor fu, torch::Tensor fd, torch::Tensor b, torch::Tensor si, - int up, int down, int px0, int px1, int py0, int py1, int sx, int sy, float gain, float slope, float clamp, bool flip_filters, bool writeSigns) -{ - // Set CUDA device. - TORCH_CHECK(x.is_cuda(), "x must reside on CUDA device"); - const at::cuda::OptionalCUDAGuard device_guard(device_of(x)); - - // Validate arguments. - TORCH_CHECK(fu.device() == x.device() && fd.device() == x.device() && b.device() == x.device(), "all input tensors must reside on the same device"); - TORCH_CHECK(fu.dtype() == torch::kFloat && fd.dtype() == torch::kFloat, "fu and fd must be float32"); - TORCH_CHECK(b.dtype() == x.dtype(), "x and b must have the same dtype"); - TORCH_CHECK(x.dtype() == torch::kHalf || x.dtype() == torch::kFloat, "x and b must be float16 or float32"); - TORCH_CHECK(x.dim() == 4, "x must be rank 4"); - TORCH_CHECK(x.size(0) * x.size(1) <= INT_MAX && x.size(2) <= INT_MAX && x.size(3) <= INT_MAX, "x is too large"); - TORCH_CHECK(x.numel() > 0, "x is empty"); - TORCH_CHECK((fu.dim() == 1 || fu.dim() == 2) && (fd.dim() == 1 || fd.dim() == 2), "fu and fd must be rank 1 or 2"); - TORCH_CHECK(fu.size(0) <= INT_MAX && fu.size(-1) <= INT_MAX, "fu is too large"); - TORCH_CHECK(fd.size(0) <= INT_MAX && fd.size(-1) <= INT_MAX, "fd is too large"); - TORCH_CHECK(fu.numel() > 0, "fu is empty"); - TORCH_CHECK(fd.numel() > 0, "fd is empty"); - TORCH_CHECK(b.dim() == 1 && b.size(0) == x.size(1), "b must be a vector with the same number of channels as x"); - TORCH_CHECK(up >= 1 && down >= 1, "up and down must be at least 1"); - - // Figure out how much shared memory is available on the device. - int maxSharedBytes = 0; - AT_CUDA_CHECK(cudaDeviceGetAttribute(&maxSharedBytes, cudaDevAttrMaxSharedMemoryPerBlockOptin, x.device().index())); - int sharedKB = maxSharedBytes >> 10; - - // Populate enough launch parameters to check if a CUDA kernel exists. - filtered_lrelu_kernel_params p; - p.up = up; - p.down = down; - p.fuShape = make_int2((int)fu.size(-1), fu.dim() == 2 ? (int)fu.size(0) : 0); // shape [n, 0] indicates separable filter. - p.fdShape = make_int2((int)fd.size(-1), fd.dim() == 2 ? (int)fd.size(0) : 0); - filtered_lrelu_kernel_spec test_spec = choose_filtered_lrelu_kernel(p, sharedKB); - if (!test_spec.exec) - { - // No kernel found - return empty tensors and indicate missing kernel with return code of -1. - return std::make_tuple(torch::Tensor(), torch::Tensor(), -1); - } - - // Input/output element size. - int64_t sz = (x.dtype() == torch::kHalf) ? 2 : 4; - - // Input sizes. - int64_t xw = (int)x.size(3); - int64_t xh = (int)x.size(2); - int64_t fut_w = (int)fu.size(-1) - 1; - int64_t fut_h = (int)fu.size(0) - 1; - int64_t fdt_w = (int)fd.size(-1) - 1; - int64_t fdt_h = (int)fd.size(0) - 1; - - // Logical size of upsampled buffer. - int64_t cw = xw * up + (px0 + px1) - fut_w; - int64_t ch = xh * up + (py0 + py1) - fut_h; - TORCH_CHECK(cw > fdt_w && ch > fdt_h, "upsampled buffer must be at least the size of downsampling filter"); - TORCH_CHECK(cw <= INT_MAX && ch <= INT_MAX, "upsampled buffer is too large"); - - // Compute output size and allocate. - int64_t yw = (cw - fdt_w + (down - 1)) / down; - int64_t yh = (ch - fdt_h + (down - 1)) / down; - TORCH_CHECK(yw > 0 && yh > 0, "output must be at least 1x1"); - TORCH_CHECK(yw <= INT_MAX && yh <= INT_MAX, "output is too large"); - torch::Tensor y = torch::empty({x.size(0), x.size(1), yh, yw}, x.options(), x.suggest_memory_format()); - - // Allocate sign tensor. - torch::Tensor so; - torch::Tensor s = si; - bool readSigns = !!s.numel(); - int64_t sw_active = 0; // Active width of sign tensor. - if (writeSigns) - { - sw_active = yw * down - (down - 1) + fdt_w; // Active width in elements. - int64_t sh = yh * down - (down - 1) + fdt_h; // Height = active height. - int64_t sw = (sw_active + 15) & ~15; // Width = active width in elements, rounded up to multiple of 16. - TORCH_CHECK(sh <= INT_MAX && (sw >> 2) <= INT_MAX, "signs is too large"); - s = so = torch::empty({x.size(0), x.size(1), sh, sw >> 2}, x.options().dtype(torch::kUInt8), at::MemoryFormat::Contiguous); - } - else if (readSigns) - sw_active = s.size(3) << 2; - - // Validate sign tensor if in use. - if (readSigns || writeSigns) - { - TORCH_CHECK(s.is_contiguous(), "signs must be contiguous"); - TORCH_CHECK(s.dtype() == torch::kUInt8, "signs must be uint8"); - TORCH_CHECK(s.device() == x.device(), "signs must reside on the same device as x"); - TORCH_CHECK(s.dim() == 4, "signs must be rank 4"); - TORCH_CHECK(s.size(0) == x.size(0) && s.size(1) == x.size(1), "signs must have same batch & channels as x"); - TORCH_CHECK(s.size(2) <= INT_MAX && s.size(3) <= INT_MAX, "signs is too large"); - } - - // Populate rest of CUDA kernel parameters. - p.x = x.data_ptr(); - p.y = y.data_ptr(); - p.b = b.data_ptr(); - p.s = (readSigns || writeSigns) ? s.data_ptr() : 0; - p.fu = fu.data_ptr(); - p.fd = fd.data_ptr(); - p.pad0 = make_int2(px0, py0); - p.gain = gain; - p.slope = slope; - p.clamp = clamp; - p.flip = (flip_filters) ? 1 : 0; - p.xShape = make_int4((int)x.size(3), (int)x.size(2), (int)x.size(1), (int)x.size(0)); - p.yShape = make_int4((int)y.size(3), (int)y.size(2), (int)y.size(1), (int)y.size(0)); - p.sShape = (readSigns || writeSigns) ? make_int2((int)s.size(3), (int)s.size(2)) : make_int2(0, 0); // Width is in bytes. Contiguous. - p.sOfs = make_int2(sx, sy); - p.swLimit = (sw_active + 3) >> 2; // Rounded up to bytes. - - // x, y, b strides are in bytes. - p.xStride = make_longlong4(sz * x.stride(3), sz * x.stride(2), sz * x.stride(1), sz * x.stride(0)); - p.yStride = make_longlong4(sz * y.stride(3), sz * y.stride(2), sz * y.stride(1), sz * y.stride(0)); - p.bStride = sz * b.stride(0); - - // fu, fd strides are in elements. - p.fuStride = make_longlong3(fu.stride(-1), fu.dim() == 2 ? fu.stride(0) : 0, 0); - p.fdStride = make_longlong3(fd.stride(-1), fd.dim() == 2 ? fd.stride(0) : 0, 0); - - // Determine if indices don't fit in int32. Support negative strides although Torch currently never produces those. - bool index64b = false; - if (std::abs(p.bStride * x.size(1)) > INT_MAX) index64b = true; - if (std::min(x.size(0) * p.xStride.w, 0ll) + std::min(x.size(1) * p.xStride.z, 0ll) + std::min(x.size(2) * p.xStride.y, 0ll) + std::min(x.size(3) * p.xStride.x, 0ll) < -INT_MAX) index64b = true; - if (std::max(x.size(0) * p.xStride.w, 0ll) + std::max(x.size(1) * p.xStride.z, 0ll) + std::max(x.size(2) * p.xStride.y, 0ll) + std::max(x.size(3) * p.xStride.x, 0ll) > INT_MAX) index64b = true; - if (std::min(y.size(0) * p.yStride.w, 0ll) + std::min(y.size(1) * p.yStride.z, 0ll) + std::min(y.size(2) * p.yStride.y, 0ll) + std::min(y.size(3) * p.yStride.x, 0ll) < -INT_MAX) index64b = true; - if (std::max(y.size(0) * p.yStride.w, 0ll) + std::max(y.size(1) * p.yStride.z, 0ll) + std::max(y.size(2) * p.yStride.y, 0ll) + std::max(y.size(3) * p.yStride.x, 0ll) > INT_MAX) index64b = true; - if (s.numel() > INT_MAX) index64b = true; - - // Choose CUDA kernel. - filtered_lrelu_kernel_spec spec = { 0 }; - AT_DISPATCH_FLOATING_TYPES_AND_HALF(x.scalar_type(), "filtered_lrelu_cuda", [&] - { - if constexpr (sizeof(scalar_t) <= 4) // Exclude doubles. constexpr prevents template instantiation. - { - // Choose kernel based on index type, datatype and sign read/write modes. - if (!index64b && writeSigns && !readSigns) spec = choose_filtered_lrelu_kernel(p, sharedKB); - else if (!index64b && !writeSigns && readSigns) spec = choose_filtered_lrelu_kernel(p, sharedKB); - else if (!index64b && !writeSigns && !readSigns) spec = choose_filtered_lrelu_kernel(p, sharedKB); - else if ( index64b && writeSigns && !readSigns) spec = choose_filtered_lrelu_kernel(p, sharedKB); - else if ( index64b && !writeSigns && readSigns) spec = choose_filtered_lrelu_kernel(p, sharedKB); - else if ( index64b && !writeSigns && !readSigns) spec = choose_filtered_lrelu_kernel(p, sharedKB); - } - }); - TORCH_CHECK(spec.exec, "internal error - CUDA kernel not found") // This should not happen because we tested earlier that kernel exists. - - // Launch CUDA kernel. - void* args[] = {&p}; - int bx = spec.numWarps * 32; - int gx = (p.yShape.x - 1) / spec.tileOut.x + 1; - int gy = (p.yShape.y - 1) / spec.tileOut.y + 1; - int gz = p.yShape.z * p.yShape.w; - - // Repeat multiple horizontal tiles in a CTA? - if (spec.xrep) - { - p.tilesXrep = spec.xrep; - p.tilesXdim = gx; - - gx = (gx + p.tilesXrep - 1) / p.tilesXrep; - std::swap(gx, gy); - } - else - { - p.tilesXrep = 0; - p.tilesXdim = 0; - } - - // Launch filter setup kernel. - AT_CUDA_CHECK(cudaLaunchKernel(spec.setup, 1, 1024, args, 0, at::cuda::getCurrentCUDAStream())); - - // Copy kernels to constant memory. - if ( writeSigns && !readSigns) AT_CUDA_CHECK((copy_filters(at::cuda::getCurrentCUDAStream()))); - else if (!writeSigns && readSigns) AT_CUDA_CHECK((copy_filters(at::cuda::getCurrentCUDAStream()))); - else if (!writeSigns && !readSigns) AT_CUDA_CHECK((copy_filters(at::cuda::getCurrentCUDAStream()))); - - // Set cache and shared memory configurations for main kernel. - AT_CUDA_CHECK(cudaFuncSetCacheConfig(spec.exec, cudaFuncCachePreferShared)); - if (spec.dynamicSharedKB) // Need dynamically allocated shared memory? - AT_CUDA_CHECK(cudaFuncSetAttribute(spec.exec, cudaFuncAttributeMaxDynamicSharedMemorySize, spec.dynamicSharedKB << 10)); - AT_CUDA_CHECK(cudaFuncSetSharedMemConfig(spec.exec, cudaSharedMemBankSizeFourByte)); - - // Launch main kernel. - const int maxSubGz = 65535; // CUDA maximum for block z dimension. - for (int zofs=0; zofs < gz; zofs += maxSubGz) // Do multiple launches if gz is too big. - { - p.blockZofs = zofs; - int subGz = std::min(maxSubGz, gz - zofs); - AT_CUDA_CHECK(cudaLaunchKernel(spec.exec, dim3(gx, gy, subGz), bx, args, spec.dynamicSharedKB << 10, at::cuda::getCurrentCUDAStream())); - } - - // Done. - return std::make_tuple(y, so, 0); -} - -//------------------------------------------------------------------------ - -static torch::Tensor filtered_lrelu_act(torch::Tensor x, torch::Tensor si, int sx, int sy, float gain, float slope, float clamp, bool writeSigns) -{ - // Set CUDA device. - TORCH_CHECK(x.is_cuda(), "x must reside on CUDA device"); - const at::cuda::OptionalCUDAGuard device_guard(device_of(x)); - - // Validate arguments. - TORCH_CHECK(x.dim() == 4, "x must be rank 4"); - TORCH_CHECK(x.size(0) * x.size(1) <= INT_MAX && x.size(2) <= INT_MAX && x.size(3) <= INT_MAX, "x is too large"); - TORCH_CHECK(x.numel() > 0, "x is empty"); - TORCH_CHECK(x.dtype() == torch::kHalf || x.dtype() == torch::kFloat || x.dtype() == torch::kDouble, "x must be float16, float32 or float64"); - - // Output signs if we don't have sign input. - torch::Tensor so; - torch::Tensor s = si; - bool readSigns = !!s.numel(); - if (writeSigns) - { - int64_t sw = x.size(3); - sw = (sw + 15) & ~15; // Round to a multiple of 16 for coalescing. - s = so = torch::empty({x.size(0), x.size(1), x.size(2), sw >> 2}, x.options().dtype(torch::kUInt8), at::MemoryFormat::Contiguous); - } - - // Validate sign tensor if in use. - if (readSigns || writeSigns) - { - TORCH_CHECK(s.is_contiguous(), "signs must be contiguous"); - TORCH_CHECK(s.dtype() == torch::kUInt8, "signs must be uint8"); - TORCH_CHECK(s.device() == x.device(), "signs must reside on the same device as x"); - TORCH_CHECK(s.dim() == 4, "signs must be rank 4"); - TORCH_CHECK(s.size(0) == x.size(0) && s.size(1) == x.size(1), "signs must have same batch & channels as x"); - TORCH_CHECK(s.size(2) <= INT_MAX && (s.size(3) << 2) <= INT_MAX, "signs tensor is too large"); - } - - // Initialize CUDA kernel parameters. - filtered_lrelu_act_kernel_params p; - p.x = x.data_ptr(); - p.s = (readSigns || writeSigns) ? s.data_ptr() : 0; - p.gain = gain; - p.slope = slope; - p.clamp = clamp; - p.xShape = make_int4((int)x.size(3), (int)x.size(2), (int)x.size(1), (int)x.size(0)); - p.xStride = make_longlong4(x.stride(3), x.stride(2), x.stride(1), x.stride(0)); - p.sShape = (readSigns || writeSigns) ? make_int2((int)s.size(3) << 2, (int)s.size(2)) : make_int2(0, 0); // Width is in elements. Contiguous. - p.sOfs = make_int2(sx, sy); - - // Choose CUDA kernel. - void* func = 0; - AT_DISPATCH_FLOATING_TYPES_AND_HALF(x.scalar_type(), "filtered_lrelu_act_cuda", [&] - { - if (writeSigns) - func = choose_filtered_lrelu_act_kernel(); - else if (readSigns) - func = choose_filtered_lrelu_act_kernel(); - else - func = choose_filtered_lrelu_act_kernel(); - }); - TORCH_CHECK(func, "internal error - CUDA kernel not found"); - - // Launch CUDA kernel. - void* args[] = {&p}; - int bx = 128; // 4 warps per block. - - // Logical size of launch = writeSigns ? p.s : p.x - uint32_t gx = writeSigns ? p.sShape.x : p.xShape.x; - uint32_t gy = writeSigns ? p.sShape.y : p.xShape.y; - uint32_t gz = p.xShape.z * p.xShape.w; // Same as in p.sShape if signs are in use. - gx = (gx - 1) / bx + 1; - - // Make sure grid y and z dimensions are within CUDA launch limits. Kernel loops internally to do the rest. - const uint32_t gmax = 65535; - gy = std::min(gy, gmax); - gz = std::min(gz, gmax); - - // Launch. - AT_CUDA_CHECK(cudaLaunchKernel(func, dim3(gx, gy, gz), bx, args, 0, at::cuda::getCurrentCUDAStream())); - return so; -} - -//------------------------------------------------------------------------ - -PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) -{ - m.def("filtered_lrelu", &filtered_lrelu); // The whole thing. - m.def("filtered_lrelu_act_", &filtered_lrelu_act); // Activation and sign tensor handling only. Modifies data tensor in-place. -} - -//------------------------------------------------------------------------ diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.cu b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.cu deleted file mode 100644 index 8e6f47f873..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.cu +++ /dev/null @@ -1,1284 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include -#include "filtered_lrelu.h" -#include - -//------------------------------------------------------------------------ -// Helpers. - -enum // Filter modes. -{ - MODE_SUSD = 0, // Separable upsampling, separable downsampling. - MODE_FUSD = 1, // Full upsampling, separable downsampling. - MODE_SUFD = 2, // Separable upsampling, full downsampling. - MODE_FUFD = 3, // Full upsampling, full downsampling. -}; - -template struct InternalType; -template <> struct InternalType -{ - typedef double scalar_t; typedef double2 vec2_t; typedef double4 vec4_t; - __device__ __forceinline__ static vec2_t zero_vec2(void) { return make_double2(0, 0); } - __device__ __forceinline__ static vec4_t zero_vec4(void) { return make_double4(0, 0, 0, 0); } - __device__ __forceinline__ static double clamp(double x, double c) { return fmin(fmax(x, -c), c); } -}; -template <> struct InternalType -{ - typedef float scalar_t; typedef float2 vec2_t; typedef float4 vec4_t; - __device__ __forceinline__ static vec2_t zero_vec2(void) { return make_float2(0, 0); } - __device__ __forceinline__ static vec4_t zero_vec4(void) { return make_float4(0, 0, 0, 0); } - __device__ __forceinline__ static float clamp(float x, float c) { return fminf(fmaxf(x, -c), c); } -}; -template <> struct InternalType -{ - typedef float scalar_t; typedef float2 vec2_t; typedef float4 vec4_t; - __device__ __forceinline__ static vec2_t zero_vec2(void) { return make_float2(0, 0); } - __device__ __forceinline__ static vec4_t zero_vec4(void) { return make_float4(0, 0, 0, 0); } - __device__ __forceinline__ static float clamp(float x, float c) { return fminf(fmaxf(x, -c), c); } -}; - -#define MIN(A, B) ((A) < (B) ? (A) : (B)) -#define MAX(A, B) ((A) > (B) ? (A) : (B)) -#define CEIL_DIV(A, B) (((B)==1) ? (A) : \ - ((B)==2) ? ((int)((A)+1) >> 1) : \ - ((B)==4) ? ((int)((A)+3) >> 2) : \ - (((A) + ((A) > 0 ? (B) - 1 : 0)) / (B))) - -// This works only up to blocks of size 256 x 256 and for all N that are powers of two. -template __device__ __forceinline__ void fast_div_mod(int& x, int& y, unsigned int i) -{ - if ((N & (N-1)) && N <= 256) - y = (i * ((1<<24)/N + 1)) >> 24; // Assumes N <= 256, i < N*256. - else - y = i/N; - - x = i - y*N; -} - -// Type cast stride before reading it. -template __device__ __forceinline__ T get_stride(const int64_t& x) -{ - return *reinterpret_cast(&x); -} - -//------------------------------------------------------------------------ -// Filters, setup kernel, copying function. - -#define MAX_FILTER_SIZE 32 - -// Combined up/down filter buffers so that transfer can be done with one copy. -__device__ float g_fbuf[2 * MAX_FILTER_SIZE * MAX_FILTER_SIZE]; // Filters in global memory, written by setup kernel. -__device__ __constant__ float c_fbuf[2 * MAX_FILTER_SIZE * MAX_FILTER_SIZE]; // Filters in constant memory, read by main kernel. - -// Accessors to combined buffers to index up/down filters individually. -#define c_fu (c_fbuf) -#define c_fd (c_fbuf + MAX_FILTER_SIZE * MAX_FILTER_SIZE) -#define g_fu (g_fbuf) -#define g_fd (g_fbuf + MAX_FILTER_SIZE * MAX_FILTER_SIZE) - -// Set up filters into global memory buffer. -static __global__ void setup_filters_kernel(filtered_lrelu_kernel_params p) -{ - for (int idx = threadIdx.x; idx < MAX_FILTER_SIZE * MAX_FILTER_SIZE; idx += blockDim.x) - { - int x, y; - fast_div_mod(x, y, idx); - - int fu_x = p.flip ? x : (p.fuShape.x - 1 - x); - int fu_y = p.flip ? y : (p.fuShape.y - 1 - y); - if (p.fuShape.y > 0) - g_fu[idx] = (x >= p.fuShape.x || y >= p.fuShape.y) ? 0.0f : p.fu[fu_x * p.fuStride.x + fu_y * p.fuStride.y]; - else - g_fu[idx] = (x >= p.fuShape.x || y > 0) ? 0.0f : p.fu[fu_x * p.fuStride.x]; - - int fd_x = p.flip ? x : (p.fdShape.x - 1 - x); - int fd_y = p.flip ? y : (p.fdShape.y - 1 - y); - if (p.fdShape.y > 0) - g_fd[idx] = (x >= p.fdShape.x || y >= p.fdShape.y) ? 0.0f : p.fd[fd_x * p.fdStride.x + fd_y * p.fdStride.y]; - else - g_fd[idx] = (x >= p.fdShape.x || y > 0) ? 0.0f : p.fd[fd_x * p.fdStride.x]; - } -} - -// Host function to copy filters written by setup kernel into constant buffer for main kernel. -template static cudaError_t copy_filters(cudaStream_t stream) -{ - void* src = 0; - cudaError_t err = cudaGetSymbolAddress(&src, g_fbuf); - if (err) return err; - return cudaMemcpyToSymbolAsync(c_fbuf, src, 2 * MAX_FILTER_SIZE * MAX_FILTER_SIZE * sizeof(float), 0, cudaMemcpyDeviceToDevice, stream); -} - -//------------------------------------------------------------------------ -// Coordinate spaces: -// - Relative to input tensor: inX, inY, tileInX, tileInY -// - Relative to input tile: relInX, relInY, tileInW, tileInH -// - Relative to upsampled tile: relUpX, relUpY, tileUpW, tileUpH -// - Relative to output tile: relOutX, relOutY, tileOutW, tileOutH -// - Relative to output tensor: outX, outY, tileOutX, tileOutY -// -// Relationships between coordinate spaces: -// - inX = tileInX + relInX -// - inY = tileInY + relInY -// - relUpX = relInX * up + phaseInX -// - relUpY = relInY * up + phaseInY -// - relUpX = relOutX * down -// - relUpY = relOutY * down -// - outX = tileOutX + relOutX -// - outY = tileOutY + relOutY - -extern __shared__ char s_buf_raw[]; // When sharedKB <= 48, allocate shared memory statically inside the kernel, otherwise use the externally allocated shared memory buffer. - -template -static __global__ void filtered_lrelu_kernel(filtered_lrelu_kernel_params p) -{ - // Check that we don't try to support non-existing filter modes. - static_assert(up == 1 || up == 2 || up == 4, "only up=1, up=2, up=4 scales supported"); - static_assert(down == 1 || down == 2 || down == 4, "only down=1, down=2, down=4 scales supported"); - static_assert(fuSize >= up, "upsampling filter size must be at least upsampling factor"); - static_assert(fdSize >= down, "downsampling filter size must be at least downsampling factor"); - static_assert(fuSize % up == 0, "upsampling filter size must be divisible with upsampling factor"); - static_assert(fdSize % down == 0, "downsampling filter size must be divisible with downsampling factor"); - static_assert(fuSize <= MAX_FILTER_SIZE && fdSize <= MAX_FILTER_SIZE, "filter size greater than MAX_FILTER_SIZE"); - static_assert(up != 1 || (fuSize == 1 && (filterMode == MODE_FUFD || filterMode == MODE_FUSD)), "up=1 supported only for 1x1 full filters"); - static_assert(down != 1 || (fdSize == 1 && (filterMode == MODE_FUFD || filterMode == MODE_SUFD)), "down=1 supported only for 1x1 full filters"); - static_assert(!(up == 4 && (filterMode == MODE_FUFD || filterMode == MODE_FUSD)), "full filters not supported for up=4"); - static_assert(!(down == 4 && (filterMode == MODE_FUFD || filterMode == MODE_SUFD)), "full filters not supported for down=4"); - - // Static definitions. - typedef typename InternalType::scalar_t scalar_t; - typedef typename InternalType::vec2_t vec2_t; - typedef typename InternalType::vec4_t vec4_t; - const int tileUpW = (tileOutW * down + (fdSize - 1) - (down - 1) + 3) & ~3; // Upsampled tile width, rounded up to multiple of 4. - const int tileUpH = tileOutH * down + (fdSize - 1) - (down - 1); // Upsampled tile height. - const int tileInW = CEIL_DIV(tileUpW + (fuSize - 1), up); // Input tile width. - const int tileInH = CEIL_DIV(tileUpH + (fuSize - 1), up); // Input tile height. - const int tileUpH_up = CEIL_DIV(tileUpH, up) * up; // Upsampled tile height rounded up to a multiple of up. - const int tileInH_up = CEIL_DIV(tileUpH_up + (fuSize - 1), up); // For allocations only, to avoid shared memory read overruns with up=2 and up=4. - - // Merge 1x1 downsampling into last upsampling step for upf1 and ups2. - const bool downInline = (down == 1) && ((up == 1 && filterMode == MODE_FUFD) || (up == 2 && filterMode == MODE_SUFD)); - - // Sizes of logical buffers. - const int szIn = tileInH_up * tileInW; - const int szUpX = tileInH_up * tileUpW; - const int szUpXY = downInline ? 0 : (tileUpH * tileUpW); - const int szDownX = tileUpH * tileOutW; - - // Sizes for shared memory arrays. - const int s_buf0_size_base = - (filterMode == MODE_SUSD) ? MAX(szIn, szUpXY) : - (filterMode == MODE_FUSD) ? MAX(szIn, szDownX) : - (filterMode == MODE_SUFD) ? MAX(szIn, szUpXY) : - (filterMode == MODE_FUFD) ? szIn : - -1; - const int s_buf1_size_base = - (filterMode == MODE_SUSD) ? MAX(szUpX, szDownX) : - (filterMode == MODE_FUSD) ? szUpXY : - (filterMode == MODE_SUFD) ? szUpX : - (filterMode == MODE_FUFD) ? szUpXY : - -1; - - // Ensure U128 alignment. - const int s_buf0_size = (s_buf0_size_base + 3) & ~3; - const int s_buf1_size = (s_buf1_size_base + 3) & ~3; - - // Check at compile time that we don't use too much shared memory. - static_assert((s_buf0_size + s_buf1_size) * sizeof(scalar_t) <= (sharedKB << 10), "shared memory overflow"); - - // Declare shared memory arrays. - scalar_t* s_buf0; - scalar_t* s_buf1; - if (sharedKB <= 48) - { - // Allocate shared memory arrays here. - __shared__ scalar_t s_buf0_st[(sharedKB > 48) ? (1<<24) : (s_buf0_size + s_buf1_size)]; // Prevent launching if this isn't optimized away when unused. - s_buf0 = s_buf0_st; - s_buf1 = s_buf0 + s_buf0_size; - } - else - { - // Use the dynamically allocated shared memory array. - s_buf0 = (scalar_t*)s_buf_raw; - s_buf1 = s_buf0 + s_buf0_size; - } - - // Pointers to the buffers. - scalar_t* s_tileIn; // Input tile: [relInX * tileInH + relInY] - scalar_t* s_tileUpX; // After horizontal upsampling: [relInY * tileUpW + relUpX] - scalar_t* s_tileUpXY; // After upsampling: [relUpY * tileUpW + relUpX] - scalar_t* s_tileDownX; // After horizontal downsampling: [relUpY * tileOutW + relOutX] - if (filterMode == MODE_SUSD) - { - s_tileIn = s_buf0; - s_tileUpX = s_buf1; - s_tileUpXY = s_buf0; - s_tileDownX = s_buf1; - } - else if (filterMode == MODE_FUSD) - { - s_tileIn = s_buf0; - s_tileUpXY = s_buf1; - s_tileDownX = s_buf0; - } - else if (filterMode == MODE_SUFD) - { - s_tileIn = s_buf0; - s_tileUpX = s_buf1; - s_tileUpXY = s_buf0; - } - else if (filterMode == MODE_FUFD) - { - s_tileIn = s_buf0; - s_tileUpXY = s_buf1; - } - - // Allow large grids in z direction via per-launch offset. - int channelIdx = blockIdx.z + p.blockZofs; - int batchIdx = channelIdx / p.yShape.z; - channelIdx -= batchIdx * p.yShape.z; - - // Offset to output feature map. In bytes. - index_t mapOfsOut = channelIdx * get_stride(p.yStride.z) + batchIdx * get_stride(p.yStride.w); - - // Sign shift amount. - uint32_t signXo = ((threadIdx.x + p.sOfs.x) << 1) & 6; - - // Inner tile loop. - #pragma unroll 1 - for (int tileIdx = 0; !enableXrep || (tileIdx < MIN(p.tilesXrep, p.tilesXdim - p.tilesXrep * blockIdx.y)); tileIdx++) - { - // Locate output tile. - int tileX = enableXrep ? blockIdx.y * p.tilesXrep + tileIdx : blockIdx.x; - int tileOutX = tileX * tileOutW; - int tileOutY = (enableXrep ? blockIdx.x : blockIdx.y) * tileOutH; - - // Locate input tile. - int tmpX = tileOutX * down - p.pad0.x; - int tmpY = tileOutY * down - p.pad0.y; - int tileInX = CEIL_DIV(tmpX, up); - int tileInY = CEIL_DIV(tmpY, up); - const int phaseInX = tileInX * up - tmpX; - const int phaseInY = tileInY * up - tmpY; - - // Extra sync if input and output buffers are the same and we are not on first tile. - if (enableXrep && tileIdx > 0 && (filterMode == MODE_FUSD || (filterMode == MODE_SUFD && !downInline) || (filterMode == MODE_FUFD && downInline))) - __syncthreads(); - - // Load input tile & apply bias. Unrolled. - scalar_t b = (scalar_t)*(const T*)((const char*)p.b + (channelIdx * get_stride(p.bStride))); - index_t mapOfsIn = channelIdx * get_stride(p.xStride.z) + batchIdx * get_stride(p.xStride.w); - int idx = threadIdx.x; - const int loopCountIN = CEIL_DIV(tileInW * tileInH, threadsPerBlock); - #pragma unroll - for (int loop = 0; loop < loopCountIN; loop++) - { - int relInX, relInY; - fast_div_mod(relInX, relInY, idx); - int inX = tileInX + relInX; - int inY = tileInY + relInY; - scalar_t v = 0; - - if ((uint32_t)inX < p.xShape.x && (uint32_t)inY < p.xShape.y) - v = (scalar_t)*((const T*)((const char*)p.x + (inX * get_stride(p.xStride.x) + inY * get_stride(p.xStride.y) + mapOfsIn))) + b; - - bool skip = (loop == loopCountIN-1) && (idx >= tileInW * tileInH); - if (!skip) - s_tileIn[idx] = v; - - idx += threadsPerBlock; - } - - if (filterMode == MODE_SUSD || filterMode == MODE_SUFD) // Separable upsampling filter. - { - // Horizontal upsampling. - __syncthreads(); - if (up == 4) - { - for (int idx = threadIdx.x*up; idx < tileUpW * tileInH; idx += blockDim.x*up) - { - int relUpX0, relInY; - fast_div_mod(relUpX0, relInY, idx); - int relInX0 = relUpX0 / up; - int src0 = relInX0 + tileInW * relInY; - int dst = relInY * tileUpW + relUpX0; - vec4_t v = InternalType::zero_vec4(); - scalar_t a = s_tileIn[src0]; - if (phaseInX == 0) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileIn[src0 + step + 1]; - v.y += a * (scalar_t)c_fu[step * up + 3]; - v.z += a * (scalar_t)c_fu[step * up + 2]; - v.w += a * (scalar_t)c_fu[step * up + 1]; - } - } - else if (phaseInX == 1) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 1]; - v.y += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileIn[src0 + step + 1]; - v.z += a * (scalar_t)c_fu[step * up + 3]; - v.w += a * (scalar_t)c_fu[step * up + 2]; - } - } - else if (phaseInX == 2) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 2]; - v.y += a * (scalar_t)c_fu[step * up + 1]; - v.z += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileIn[src0 + step + 1]; - v.w += a * (scalar_t)c_fu[step * up + 3]; - } - } - else // (phaseInX == 3) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 3]; - v.y += a * (scalar_t)c_fu[step * up + 2]; - v.z += a * (scalar_t)c_fu[step * up + 1]; - v.w += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileIn[src0 + step + 1]; - } - } - s_tileUpX[dst+0] = v.x; - s_tileUpX[dst+1] = v.y; - s_tileUpX[dst+2] = v.z; - s_tileUpX[dst+3] = v.w; - } - } - else if (up == 2) - { - bool p0 = (phaseInX == 0); - for (int idx = threadIdx.x*up; idx < tileUpW * tileInH; idx += blockDim.x*up) - { - int relUpX0, relInY; - fast_div_mod(relUpX0, relInY, idx); - int relInX0 = relUpX0 / up; - int src0 = relInX0 + tileInW * relInY; - int dst = relInY * tileUpW + relUpX0; - vec2_t v = InternalType::zero_vec2(); - scalar_t a = s_tileIn[src0]; - if (p0) // (phaseInX == 0) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileIn[src0 + step + 1]; - v.y += a * (scalar_t)c_fu[step * up + 1]; - } - } - else // (phaseInX == 1) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 1]; - v.y += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileIn[src0 + step + 1]; - } - } - s_tileUpX[dst+0] = v.x; - s_tileUpX[dst+1] = v.y; - } - } - - // Vertical upsampling & nonlinearity. - - __syncthreads(); - int groupMask = 15 << ((threadIdx.x & 31) & ~3); - int minY = tileOutY ? (tileOutY - tileOutH) * down + tileUpH : 0; // Skip already written signs. - int sShapeMaxY = MIN(p.sShape.y, tileOutY * down + tileUpH); // Avoid out-of-tile sign writes. - if (up == 4) - { - minY -= 3; // Adjust according to block height. - for (int idx = threadIdx.x; idx < tileUpW * tileUpH_up / up; idx += blockDim.x) - { - int relUpX, relInY0; - fast_div_mod(relUpX, relInY0, idx); - int relUpY0 = relInY0 * up; - int src0 = relInY0 * tileUpW + relUpX; - int dst = relUpY0 * tileUpW + relUpX; - vec4_t v = InternalType::zero_vec4(); - - scalar_t a = s_tileUpX[src0]; - if (phaseInY == 0) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileUpX[src0 + (step + 1) * tileUpW]; - v.y += a * (scalar_t)c_fu[step * up + 3]; - v.z += a * (scalar_t)c_fu[step * up + 2]; - v.w += a * (scalar_t)c_fu[step * up + 1]; - } - } - else if (phaseInY == 1) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 1]; - v.y += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileUpX[src0 + (step + 1) * tileUpW]; - v.z += a * (scalar_t)c_fu[step * up + 3]; - v.w += a * (scalar_t)c_fu[step * up + 2]; - } - } - else if (phaseInY == 2) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 2]; - v.y += a * (scalar_t)c_fu[step * up + 1]; - v.z += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileUpX[src0 + (step + 1) * tileUpW]; - v.w += a * (scalar_t)c_fu[step * up + 3]; - } - } - else // (phaseInY == 3) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 3]; - v.y += a * (scalar_t)c_fu[step * up + 2]; - v.z += a * (scalar_t)c_fu[step * up + 1]; - v.w += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileUpX[src0 + (step + 1) * tileUpW]; - } - } - - int x = tileOutX * down + relUpX; - int y = tileOutY * down + relUpY0; - int signX = x + p.sOfs.x; - int signY = y + p.sOfs.y; - int signZ = blockIdx.z + p.blockZofs; - int signXb = signX >> 2; - index_t si0 = signXb + p.sShape.x * (signY + (index_t)p.sShape.y * signZ); - index_t si1 = si0 + p.sShape.x; - index_t si2 = si0 + p.sShape.x * 2; - index_t si3 = si0 + p.sShape.x * 3; - - v.x *= (scalar_t)((float)up * (float)up * p.gain); - v.y *= (scalar_t)((float)up * (float)up * p.gain); - v.z *= (scalar_t)((float)up * (float)up * p.gain); - v.w *= (scalar_t)((float)up * (float)up * p.gain); - - if (signWrite) - { - if (!enableWriteSkip) - { - // Determine and write signs. - int sx = __float_as_uint(v.x) >> 31 << 0; - int sy = __float_as_uint(v.y) >> 31 << 8; - int sz = __float_as_uint(v.z) >> 31 << 16; - int sw = __float_as_uint(v.w) >> 31 << 24; - if (sx) v.x *= p.slope; - if (sy) v.y *= p.slope; - if (sz) v.z *= p.slope; - if (sw) v.w *= p.slope; - if (fabsf(v.x) > p.clamp) { sx = 2 << 0; v.x = InternalType::clamp(v.x, p.clamp); } - if (fabsf(v.y) > p.clamp) { sy = 2 << 8; v.y = InternalType::clamp(v.y, p.clamp); } - if (fabsf(v.z) > p.clamp) { sz = 2 << 16; v.z = InternalType::clamp(v.z, p.clamp); } - if (fabsf(v.w) > p.clamp) { sw = 2 << 24; v.w = InternalType::clamp(v.w, p.clamp); } - - if ((uint32_t)signXb < p.swLimit && signY >= minY) - { - // Combine signs. - uint32_t s = sx + sy + sw + sz; - s <<= (signX & 3) << 1; - s |= __shfl_xor_sync(groupMask, s, 1); - s |= __shfl_xor_sync(groupMask, s, 2); - - // Write signs. - if ((uint32_t)(signY + 0) < sShapeMaxY) { p.s[si0] = (unsigned char)(s >> 0); } - if ((uint32_t)(signY + 1) < sShapeMaxY) { p.s[si1] = (unsigned char)(s >> 8); } - if ((uint32_t)(signY + 2) < sShapeMaxY) { p.s[si2] = (unsigned char)(s >> 16); } - if ((uint32_t)(signY + 3) < sShapeMaxY) { p.s[si3] = (unsigned char)(s >> 24); } - } - } - else - { - // Determine and write signs. - if ((uint32_t)signXb < p.swLimit && signY >= minY) - { - int sx = __float_as_uint(v.x) >> 31 << 0; - int sy = __float_as_uint(v.y) >> 31 << 8; - int sz = __float_as_uint(v.z) >> 31 << 16; - int sw = __float_as_uint(v.w) >> 31 << 24; - if (sx) v.x *= p.slope; - if (sy) v.y *= p.slope; - if (sz) v.z *= p.slope; - if (sw) v.w *= p.slope; - if (fabsf(v.x) > p.clamp) { sx = 2 << 0; v.x = InternalType::clamp(v.x, p.clamp); } - if (fabsf(v.y) > p.clamp) { sy = 2 << 8; v.y = InternalType::clamp(v.y, p.clamp); } - if (fabsf(v.z) > p.clamp) { sz = 2 << 16; v.z = InternalType::clamp(v.z, p.clamp); } - if (fabsf(v.w) > p.clamp) { sw = 2 << 24; v.w = InternalType::clamp(v.w, p.clamp); } - - // Combine signs. - uint32_t s = sx + sy + sw + sz; - s <<= (signX & 3) << 1; - s |= __shfl_xor_sync(groupMask, s, 1); - s |= __shfl_xor_sync(groupMask, s, 2); - - // Write signs. - if ((uint32_t)(signY + 0) < sShapeMaxY) { p.s[si0] = (unsigned char)(s >> 0); } - if ((uint32_t)(signY + 1) < sShapeMaxY) { p.s[si1] = (unsigned char)(s >> 8); } - if ((uint32_t)(signY + 2) < sShapeMaxY) { p.s[si2] = (unsigned char)(s >> 16); } - if ((uint32_t)(signY + 3) < sShapeMaxY) { p.s[si3] = (unsigned char)(s >> 24); } - } - else - { - // Just compute the values. - if (v.x < 0.f) v.x *= p.slope; v.x = InternalType::clamp(v.x, p.clamp); - if (v.y < 0.f) v.y *= p.slope; v.y = InternalType::clamp(v.y, p.clamp); - if (v.z < 0.f) v.z *= p.slope; v.z = InternalType::clamp(v.z, p.clamp); - if (v.w < 0.f) v.w *= p.slope; v.w = InternalType::clamp(v.w, p.clamp); - } - } - } - else if (signRead) // Read signs and apply. - { - if ((uint32_t)signXb < p.swLimit) - { - int ss = (signX & 3) << 1; - if ((uint32_t)(signY + 0) < p.sShape.y) { int s = p.s[si0] >> ss; if (s & 1) v.x *= p.slope; if (s & 2) v.x = 0.f; } - if ((uint32_t)(signY + 1) < p.sShape.y) { int s = p.s[si1] >> ss; if (s & 1) v.y *= p.slope; if (s & 2) v.y = 0.f; } - if ((uint32_t)(signY + 2) < p.sShape.y) { int s = p.s[si2] >> ss; if (s & 1) v.z *= p.slope; if (s & 2) v.z = 0.f; } - if ((uint32_t)(signY + 3) < p.sShape.y) { int s = p.s[si3] >> ss; if (s & 1) v.w *= p.slope; if (s & 2) v.w = 0.f; } - } - } - else // Forward pass with no sign write. - { - if (v.x < 0.f) v.x *= p.slope; v.x = InternalType::clamp(v.x, p.clamp); - if (v.y < 0.f) v.y *= p.slope; v.y = InternalType::clamp(v.y, p.clamp); - if (v.z < 0.f) v.z *= p.slope; v.z = InternalType::clamp(v.z, p.clamp); - if (v.w < 0.f) v.w *= p.slope; v.w = InternalType::clamp(v.w, p.clamp); - } - - s_tileUpXY[dst + 0 * tileUpW] = v.x; - if (relUpY0 + 1 < tileUpH) s_tileUpXY[dst + 1 * tileUpW] = v.y; - if (relUpY0 + 2 < tileUpH) s_tileUpXY[dst + 2 * tileUpW] = v.z; - if (relUpY0 + 3 < tileUpH) s_tileUpXY[dst + 3 * tileUpW] = v.w; - } - } - else if (up == 2) - { - minY -= 1; // Adjust according to block height. - for (int idx = threadIdx.x; idx < tileUpW * tileUpH_up / up; idx += blockDim.x) - { - int relUpX, relInY0; - fast_div_mod(relUpX, relInY0, idx); - int relUpY0 = relInY0 * up; - int src0 = relInY0 * tileUpW + relUpX; - int dst = relUpY0 * tileUpW + relUpX; - vec2_t v = InternalType::zero_vec2(); - - scalar_t a = s_tileUpX[src0]; - if (phaseInY == 0) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileUpX[src0 + (step + 1) * tileUpW]; - v.y += a * (scalar_t)c_fu[step * up + 1]; - } - } - else // (phaseInY == 1) - { - #pragma unroll - for (int step = 0; step < fuSize / up; step++) - { - v.x += a * (scalar_t)c_fu[step * up + 1]; - v.y += a * (scalar_t)c_fu[step * up + 0]; - a = s_tileUpX[src0 + (step + 1) * tileUpW]; - } - } - - int x = tileOutX * down + relUpX; - int y = tileOutY * down + relUpY0; - int signX = x + p.sOfs.x; - int signY = y + p.sOfs.y; - int signZ = blockIdx.z + p.blockZofs; - int signXb = signX >> 2; - index_t si0 = signXb + p.sShape.x * (signY + (index_t)p.sShape.y * signZ); - index_t si1 = si0 + p.sShape.x; - - v.x *= (scalar_t)((float)up * (float)up * p.gain); - v.y *= (scalar_t)((float)up * (float)up * p.gain); - - if (signWrite) - { - if (!enableWriteSkip) - { - // Determine and write signs. - int sx = __float_as_uint(v.x) >> 31 << 0; - int sy = __float_as_uint(v.y) >> 31 << 8; - if (sx) v.x *= p.slope; - if (sy) v.y *= p.slope; - if (fabsf(v.x) > p.clamp) { sx = 2 << 0; v.x = InternalType::clamp(v.x, p.clamp); } - if (fabsf(v.y) > p.clamp) { sy = 2 << 8; v.y = InternalType::clamp(v.y, p.clamp); } - - if ((uint32_t)signXb < p.swLimit && signY >= minY) - { - // Combine signs. - int s = sx + sy; - s <<= signXo; - s |= __shfl_xor_sync(groupMask, s, 1); - s |= __shfl_xor_sync(groupMask, s, 2); - - // Write signs. - if ((uint32_t)(signY + 0) < sShapeMaxY) { p.s[si0] = (unsigned char)(s >> 0); } - if ((uint32_t)(signY + 1) < sShapeMaxY) { p.s[si1] = (unsigned char)(s >> 8); } - } - } - else - { - // Determine and write signs. - if ((uint32_t)signXb < p.swLimit && signY >= minY) - { - int sx = __float_as_uint(v.x) >> 31 << 0; - int sy = __float_as_uint(v.y) >> 31 << 8; - if (sx) v.x *= p.slope; - if (sy) v.y *= p.slope; - if (fabsf(v.x) > p.clamp) { sx = 2 << 0; v.x = InternalType::clamp(v.x, p.clamp); } - if (fabsf(v.y) > p.clamp) { sy = 2 << 8; v.y = InternalType::clamp(v.y, p.clamp); } - - // Combine signs. - int s = sx + sy; - s <<= signXo; - s |= __shfl_xor_sync(groupMask, s, 1); - s |= __shfl_xor_sync(groupMask, s, 2); - - // Write signs. - if ((uint32_t)(signY + 0) < sShapeMaxY) { p.s[si0] = (unsigned char)(s >> 0); } - if ((uint32_t)(signY + 1) < sShapeMaxY) { p.s[si1] = (unsigned char)(s >> 8); } - } - else - { - // Just compute the values. - if (v.x < 0.f) v.x *= p.slope; v.x = InternalType::clamp(v.x, p.clamp); - if (v.y < 0.f) v.y *= p.slope; v.y = InternalType::clamp(v.y, p.clamp); - } - } - } - else if (signRead) // Read signs and apply. - { - if ((uint32_t)signXb < p.swLimit) - { - if ((uint32_t)(signY + 0) < p.sShape.y) { int s = p.s[si0] >> signXo; if (s & 1) v.x *= p.slope; if (s & 2) v.x = 0.f; } - if ((uint32_t)(signY + 1) < p.sShape.y) { int s = p.s[si1] >> signXo; if (s & 1) v.y *= p.slope; if (s & 2) v.y = 0.f; } - } - } - else // Forward pass with no sign write. - { - if (v.x < 0.f) v.x *= p.slope; v.x = InternalType::clamp(v.x, p.clamp); - if (v.y < 0.f) v.y *= p.slope; v.y = InternalType::clamp(v.y, p.clamp); - } - - if (!downInline) - { - // Write into temporary buffer. - s_tileUpXY[dst] = v.x; - if (relUpY0 < tileUpH - 1) - s_tileUpXY[dst + tileUpW] = v.y; - } - else - { - // Write directly into output buffer. - if ((uint32_t)x < p.yShape.x) - { - int ymax = MIN(p.yShape.y, tileUpH + tileOutY * down); - index_t ofs = x * get_stride(p.yStride.x) + y * get_stride(p.yStride.y) + mapOfsOut; - if ((uint32_t)y + 0 < p.yShape.y) *((T*)((char*)p.y + ofs)) = (T)(v.x * (scalar_t)c_fd[0]); - if ((uint32_t)y + 1 < ymax) *((T*)((char*)p.y + ofs + get_stride(p.yStride.y))) = (T)(v.y * (scalar_t)c_fd[0]); - } - } - } - } - } - else if (filterMode == MODE_FUSD || filterMode == MODE_FUFD) - { - // Full upsampling filter. - - if (up == 2) - { - // 2 x 2-wide. - __syncthreads(); - int minY = tileOutY ? (tileOutY - tileOutH) * down + tileUpH + p.sOfs.y : 0; // Skip already written signs. - for (int idx = threadIdx.x * 4; idx < tileUpW * tileUpH; idx += blockDim.x * 4) - { - int relUpX0, relUpY0; - fast_div_mod(relUpX0, relUpY0, idx); - int relInX0 = CEIL_DIV(relUpX0 - phaseInX, up); - int relInY0 = CEIL_DIV(relUpY0 - phaseInY, up); - int src0 = relInX0 + tileInW * relInY0; - int tap0y = (relInY0 * up + phaseInY - relUpY0); - - #define X_LOOP(TAPY, PX) \ - for (int sx = 0; sx < fuSize / up; sx++) \ - { \ - v.x += a * (scalar_t)c_fu[(sx * up + (((PX) - 0) & (up - 1))) + (sy * up + (TAPY)) * MAX_FILTER_SIZE]; \ - v.z += b * (scalar_t)c_fu[(sx * up + (((PX) - 0) & (up - 1))) + (sy * up + (TAPY)) * MAX_FILTER_SIZE]; if ((PX) == 0) { a = b; b = s_tileIn[src0 + 2 + sx + sy * tileInW]; } \ - v.y += a * (scalar_t)c_fu[(sx * up + (((PX) - 1) & (up - 1))) + (sy * up + (TAPY)) * MAX_FILTER_SIZE]; \ - v.w += b * (scalar_t)c_fu[(sx * up + (((PX) - 1) & (up - 1))) + (sy * up + (TAPY)) * MAX_FILTER_SIZE]; if ((PX) == 1) { a = b; b = s_tileIn[src0 + 2 + sx + sy * tileInW]; } \ - } - - vec4_t v = InternalType::zero_vec4(); - if (tap0y == 0 && phaseInX == 0) - #pragma unroll - for (int sy = 0; sy < fuSize / up; sy++) { scalar_t a = s_tileIn[src0 + sy * tileInW]; scalar_t b = s_tileIn[src0 + sy * tileInW + 1]; - #pragma unroll - X_LOOP(0, 0) } - if (tap0y == 0 && phaseInX == 1) - #pragma unroll - for (int sy = 0; sy < fuSize / up; sy++) { scalar_t a = s_tileIn[src0 + sy * tileInW]; scalar_t b = s_tileIn[src0 + sy * tileInW + 1]; - #pragma unroll - X_LOOP(0, 1) } - if (tap0y == 1 && phaseInX == 0) - #pragma unroll - for (int sy = 0; sy < fuSize / up; sy++) { scalar_t a = s_tileIn[src0 + sy * tileInW]; scalar_t b = s_tileIn[src0 + sy * tileInW + 1]; - #pragma unroll - X_LOOP(1, 0) } - if (tap0y == 1 && phaseInX == 1) - #pragma unroll - for (int sy = 0; sy < fuSize / up; sy++) { scalar_t a = s_tileIn[src0 + sy * tileInW]; scalar_t b = s_tileIn[src0 + sy * tileInW + 1]; - #pragma unroll - X_LOOP(1, 1) } - - #undef X_LOOP - - int x = tileOutX * down + relUpX0; - int y = tileOutY * down + relUpY0; - int signX = x + p.sOfs.x; - int signY = y + p.sOfs.y; - int signZ = blockIdx.z + p.blockZofs; - int signXb = signX >> 2; - index_t si = signXb + p.sShape.x * (signY + (index_t)p.sShape.y * signZ); - - v.x *= (scalar_t)((float)up * (float)up * p.gain); - v.y *= (scalar_t)((float)up * (float)up * p.gain); - v.z *= (scalar_t)((float)up * (float)up * p.gain); - v.w *= (scalar_t)((float)up * (float)up * p.gain); - - if (signWrite) - { - if (!enableWriteSkip) - { - // Determine and write signs. - int sx = __float_as_uint(v.x) >> 31; - int sy = __float_as_uint(v.y) >> 31; - int sz = __float_as_uint(v.z) >> 31; - int sw = __float_as_uint(v.w) >> 31; - if (sx) v.x *= p.slope; if (fabsf(v.x) > p.clamp) { sx = 2; v.x = InternalType::clamp(v.x, p.clamp); } - if (sy) v.y *= p.slope; if (fabsf(v.y) > p.clamp) { sy = 2; v.y = InternalType::clamp(v.y, p.clamp); } - if (sz) v.z *= p.slope; if (fabsf(v.z) > p.clamp) { sz = 2; v.z = InternalType::clamp(v.z, p.clamp); } - if (sw) v.w *= p.slope; if (fabsf(v.w) > p.clamp) { sw = 2; v.w = InternalType::clamp(v.w, p.clamp); } - - if ((uint32_t)signXb < p.swLimit && (uint32_t)signY < p.sShape.y && signY >= minY) - { - p.s[si] = sx + (sy << 2) + (sz << 4) + (sw << 6); - } - } - else - { - // Determine and write signs. - if ((uint32_t)signXb < p.swLimit && (uint32_t)signY < p.sShape.y && signY >= minY) - { - int sx = __float_as_uint(v.x) >> 31; - int sy = __float_as_uint(v.y) >> 31; - int sz = __float_as_uint(v.z) >> 31; - int sw = __float_as_uint(v.w) >> 31; - if (sx) v.x *= p.slope; if (fabsf(v.x) > p.clamp) { sx = 2; v.x = InternalType::clamp(v.x, p.clamp); } - if (sy) v.y *= p.slope; if (fabsf(v.y) > p.clamp) { sy = 2; v.y = InternalType::clamp(v.y, p.clamp); } - if (sz) v.z *= p.slope; if (fabsf(v.z) > p.clamp) { sz = 2; v.z = InternalType::clamp(v.z, p.clamp); } - if (sw) v.w *= p.slope; if (fabsf(v.w) > p.clamp) { sw = 2; v.w = InternalType::clamp(v.w, p.clamp); } - - p.s[si] = sx + (sy << 2) + (sz << 4) + (sw << 6); - } - else - { - // Just compute the values. - if (v.x < 0.f) v.x *= p.slope; v.x = InternalType::clamp(v.x, p.clamp); - if (v.y < 0.f) v.y *= p.slope; v.y = InternalType::clamp(v.y, p.clamp); - if (v.z < 0.f) v.z *= p.slope; v.z = InternalType::clamp(v.z, p.clamp); - if (v.w < 0.f) v.w *= p.slope; v.w = InternalType::clamp(v.w, p.clamp); - } - } - } - else if (signRead) // Read sign and apply. - { - if ((uint32_t)signY < p.sShape.y) - { - int s = 0; - if ((uint32_t)signXb < p.swLimit) s = p.s[si]; - if ((uint32_t)signXb + 1 < p.swLimit) s |= p.s[si + 1] << 8; - s >>= (signX & 3) << 1; - if (s & 0x01) v.x *= p.slope; if (s & 0x02) v.x = 0.f; - if (s & 0x04) v.y *= p.slope; if (s & 0x08) v.y = 0.f; - if (s & 0x10) v.z *= p.slope; if (s & 0x20) v.z = 0.f; - if (s & 0x40) v.w *= p.slope; if (s & 0x80) v.w = 0.f; - } - } - else // Forward pass with no sign write. - { - if (v.x < 0.f) v.x *= p.slope; v.x = InternalType::clamp(v.x, p.clamp); - if (v.y < 0.f) v.y *= p.slope; v.y = InternalType::clamp(v.y, p.clamp); - if (v.z < 0.f) v.z *= p.slope; v.z = InternalType::clamp(v.z, p.clamp); - if (v.w < 0.f) v.w *= p.slope; v.w = InternalType::clamp(v.w, p.clamp); - } - - s_tileUpXY[idx + 0] = v.x; - s_tileUpXY[idx + 1] = v.y; - s_tileUpXY[idx + 2] = v.z; - s_tileUpXY[idx + 3] = v.w; - } - } - else if (up == 1) - { - __syncthreads(); - uint32_t groupMask = 15 << ((threadIdx.x & 31) & ~3); - int minY = tileOutY ? (tileOutY - tileOutH) * down + tileUpH : 0; // Skip already written signs. - for (int idx = threadIdx.x; idx < tileUpW * tileUpH; idx += blockDim.x) - { - int relUpX0, relUpY0; - fast_div_mod(relUpX0, relUpY0, idx); - scalar_t v = s_tileIn[idx] * (scalar_t)c_fu[0]; // 1x1 filter. - - int x = tileOutX * down + relUpX0; - int y = tileOutY * down + relUpY0; - int signX = x + p.sOfs.x; - int signY = y + p.sOfs.y; - int signZ = blockIdx.z + p.blockZofs; - int signXb = signX >> 2; - index_t si = signXb + p.sShape.x * (signY + (index_t)p.sShape.y * signZ); - v *= (scalar_t)((float)up * (float)up * p.gain); - - if (signWrite) - { - if (!enableWriteSkip) - { - // Determine and write sign. - uint32_t s = 0; - uint32_t signXbit = (1u << signXo); - if (v < 0.f) - { - s = signXbit; - v *= p.slope; - } - if (fabsf(v) > p.clamp) - { - s = signXbit * 2; - v = InternalType::clamp(v, p.clamp); - } - if ((uint32_t)signXb < p.swLimit && (uint32_t)signY < p.sShape.y && signY >= minY) - { - s += __shfl_xor_sync(groupMask, s, 1); // Coalesce. - s += __shfl_xor_sync(groupMask, s, 2); // Coalesce. - p.s[si] = s; // Write. - } - } - else - { - // Determine and write sign. - if ((uint32_t)signXb < p.swLimit && (uint32_t)signY < p.sShape.y && signY >= minY) - { - uint32_t s = 0; - uint32_t signXbit = (1u << signXo); - if (v < 0.f) - { - s = signXbit; - v *= p.slope; - } - if (fabsf(v) > p.clamp) - { - s = signXbit * 2; - v = InternalType::clamp(v, p.clamp); - } - s += __shfl_xor_sync(groupMask, s, 1); // Coalesce. - s += __shfl_xor_sync(groupMask, s, 2); // Coalesce. - p.s[si] = s; // Write. - } - else - { - // Just compute the value. - if (v < 0.f) v *= p.slope; - v = InternalType::clamp(v, p.clamp); - } - } - } - else if (signRead) - { - // Read sign and apply if within sign tensor bounds. - if ((uint32_t)signXb < p.swLimit && (uint32_t)signY < p.sShape.y) - { - int s = p.s[si]; - s >>= signXo; - if (s & 1) v *= p.slope; - if (s & 2) v = 0.f; - } - } - else // Forward pass with no sign write. - { - if (v < 0.f) v *= p.slope; - v = InternalType::clamp(v, p.clamp); - } - - if (!downInline) // Write into temporary buffer. - s_tileUpXY[idx] = v; - else if ((uint32_t)x < p.yShape.x && (uint32_t)y < p.yShape.y) // Write directly into output buffer - *((T*)((char*)p.y + (x * get_stride(p.yStride.x) + y * get_stride(p.yStride.y) + mapOfsOut))) = (T)(v * (scalar_t)c_fd[0]); - } - } - } - - // Downsampling. - if (filterMode == MODE_SUSD || filterMode == MODE_FUSD) - { - // Horizontal downsampling. - __syncthreads(); - if (down == 4 && tileOutW % 4 == 0) - { - // Calculate 4 pixels at a time. - for (int idx = threadIdx.x * 4; idx < tileOutW * tileUpH; idx += blockDim.x * 4) - { - int relOutX0, relUpY; - fast_div_mod(relOutX0, relUpY, idx); - int relUpX0 = relOutX0 * down; - int src0 = relUpY * tileUpW + relUpX0; - vec4_t v = InternalType::zero_vec4(); - #pragma unroll - for (int step = 0; step < fdSize; step++) - { - v.x += s_tileUpXY[src0 + 0 + step] * (scalar_t)c_fd[step]; - v.y += s_tileUpXY[src0 + 4 + step] * (scalar_t)c_fd[step]; - v.z += s_tileUpXY[src0 + 8 + step] * (scalar_t)c_fd[step]; - v.w += s_tileUpXY[src0 + 12 + step] * (scalar_t)c_fd[step]; - } - s_tileDownX[idx+0] = v.x; - s_tileDownX[idx+1] = v.y; - s_tileDownX[idx+2] = v.z; - s_tileDownX[idx+3] = v.w; - } - } - else if ((down == 2 || down == 4) && (tileOutW % 2 == 0)) - { - // Calculate 2 pixels at a time. - for (int idx = threadIdx.x * 2; idx < tileOutW * tileUpH; idx += blockDim.x * 2) - { - int relOutX0, relUpY; - fast_div_mod(relOutX0, relUpY, idx); - int relUpX0 = relOutX0 * down; - int src0 = relUpY * tileUpW + relUpX0; - vec2_t v = InternalType::zero_vec2(); - #pragma unroll - for (int step = 0; step < fdSize; step++) - { - v.x += s_tileUpXY[src0 + 0 + step] * (scalar_t)c_fd[step]; - v.y += s_tileUpXY[src0 + down + step] * (scalar_t)c_fd[step]; - } - s_tileDownX[idx+0] = v.x; - s_tileDownX[idx+1] = v.y; - } - } - else - { - // Calculate 1 pixel at a time. - for (int idx = threadIdx.x; idx < tileOutW * tileUpH; idx += blockDim.x) - { - int relOutX0, relUpY; - fast_div_mod(relOutX0, relUpY, idx); - int relUpX0 = relOutX0 * down; - int src = relUpY * tileUpW + relUpX0; - scalar_t v = 0.f; - #pragma unroll - for (int step = 0; step < fdSize; step++) - v += s_tileUpXY[src + step] * (scalar_t)c_fd[step]; - s_tileDownX[idx] = v; - } - } - - // Vertical downsampling & store output tile. - __syncthreads(); - for (int idx = threadIdx.x; idx < tileOutW * tileOutH; idx += blockDim.x) - { - int relOutX, relOutY0; - fast_div_mod(relOutX, relOutY0, idx); - int relUpY0 = relOutY0 * down; - int src0 = relUpY0 * tileOutW + relOutX; - scalar_t v = 0; - #pragma unroll - for (int step = 0; step < fdSize; step++) - v += s_tileDownX[src0 + step * tileOutW] * (scalar_t)c_fd[step]; - - int outX = tileOutX + relOutX; - int outY = tileOutY + relOutY0; - - if (outX < p.yShape.x & outY < p.yShape.y) - *((T*)((char*)p.y + (outX * get_stride(p.yStride.x) + outY * get_stride(p.yStride.y) + mapOfsOut))) = (T)v; - } - } - else if (filterMode == MODE_SUFD || filterMode == MODE_FUFD) - { - // Full downsampling filter. - if (down == 2) - { - // 2-wide. - __syncthreads(); - for (int idx = threadIdx.x * 2; idx < tileOutW * tileOutH; idx += blockDim.x * 2) - { - int relOutX0, relOutY0; - fast_div_mod(relOutX0, relOutY0, idx); - int relUpX0 = relOutX0 * down; - int relUpY0 = relOutY0 * down; - int src0 = relUpY0 * tileUpW + relUpX0; - vec2_t v = InternalType::zero_vec2(); - #pragma unroll - for (int sy = 0; sy < fdSize; sy++) - #pragma unroll - for (int sx = 0; sx < fdSize; sx++) - { - v.x += s_tileUpXY[src0 + 0 + sx + sy * tileUpW] * (scalar_t)c_fd[sx + sy * MAX_FILTER_SIZE]; - v.y += s_tileUpXY[src0 + 2 + sx + sy * tileUpW] * (scalar_t)c_fd[sx + sy * MAX_FILTER_SIZE]; - } - - int outX = tileOutX + relOutX0; - int outY = tileOutY + relOutY0; - if ((uint32_t)outY < p.yShape.y) - { - index_t ofs = outX * get_stride(p.yStride.x) + outY * get_stride(p.yStride.y) + mapOfsOut; - if (outX + 0 < p.yShape.x) *((T*)((char*)p.y + ofs)) = (T)v.x; - if (outX + 1 < p.yShape.x) *((T*)((char*)p.y + ofs + get_stride(p.yStride.x))) = (T)v.y; - } - } - } - else if (down == 1 && !downInline) - { - // Thread per pixel. - __syncthreads(); - for (int idx = threadIdx.x; idx < tileOutW * tileOutH; idx += blockDim.x) - { - int relOutX0, relOutY0; - fast_div_mod(relOutX0, relOutY0, idx); - scalar_t v = s_tileUpXY[idx] * (scalar_t)c_fd[0]; // 1x1 filter. - - int outX = tileOutX + relOutX0; - int outY = tileOutY + relOutY0; - if ((uint32_t)outX < p.yShape.x && (uint32_t)outY < p.yShape.y) - *((T*)((char*)p.y + (outX * get_stride(p.yStride.x) + outY * get_stride(p.yStride.y) + mapOfsOut))) = (T)v; - } - } - } - - if (!enableXrep) - break; - } -} - -//------------------------------------------------------------------------ -// Compute activation function and signs for upsampled data tensor, modifying data tensor in-place. Used for accelerating the generic variant. -// Sign tensor is known to be contiguous, and p.x and p.s have the same z, w dimensions. 64-bit indexing is always used. - -template -static __global__ void filtered_lrelu_act_kernel(filtered_lrelu_act_kernel_params p) -{ - typedef typename InternalType::scalar_t scalar_t; - - // Indexing. - int32_t x = threadIdx.x + blockIdx.x * blockDim.x; - int32_t ymax = signWrite ? p.sShape.y : p.xShape.y; - int32_t qmax = p.xShape.z * p.xShape.w; // Combined minibatch*channel maximum index. - - // Loop to accommodate oversized tensors. - for (int32_t q = blockIdx.z; q < qmax; q += gridDim.z) - for (int32_t y = blockIdx.y; y < ymax; y += gridDim.y) - { - // Extract z and w (channel, minibatch index). - int32_t w = q / p.xShape.z; - int32_t z = q - w * p.xShape.z; - - // Choose behavior based on sign read/write mode. - if (signWrite) - { - // Process value if in p.x. - uint32_t s = 0; - if (x < p.xShape.x && y < p.xShape.y) - { - int64_t ix = x * p.xStride.x + y * p.xStride.y + z * p.xStride.z + w * p.xStride.w; - T* pv = ((T*)p.x) + ix; - scalar_t v = (scalar_t)(*pv); - - // Gain, LReLU, clamp. - v *= p.gain; - if (v < 0.f) - { - v *= p.slope; - s = 1; // Sign. - } - if (fabsf(v) > p.clamp) - { - v = InternalType::clamp(v, p.clamp); - s = 2; // Clamp. - } - - *pv = (T)v; // Write value. - } - - // Coalesce into threads 0 and 16 of warp. - uint32_t m = (threadIdx.x & 16) ? 0xffff0000u : 0x0000ffffu; - s <<= ((threadIdx.x & 15) << 1); // Shift into place. - s |= __shfl_xor_sync(m, s, 1); // Distribute. - s |= __shfl_xor_sync(m, s, 2); - s |= __shfl_xor_sync(m, s, 4); - s |= __shfl_xor_sync(m, s, 8); - - // Write signs if leader and in p.s. - if (!(threadIdx.x & 15) && x < p.sShape.x) // y is always in. - { - uint64_t is = x + p.sShape.x * (y + (int64_t)p.sShape.y * q); // Contiguous. - ((uint32_t*)p.s)[is >> 4] = s; - } - } - else if (signRead) - { - // Process value if in p.x. - if (x < p.xShape.x) // y is always in. - { - int64_t ix = x * p.xStride.x + y * p.xStride.y + z * p.xStride.z + w * p.xStride.w; - T* pv = ((T*)p.x) + ix; - scalar_t v = (scalar_t)(*pv); - v *= p.gain; - - // Apply sign buffer offset. - uint32_t sx = x + p.sOfs.x; - uint32_t sy = y + p.sOfs.y; - - // Read and apply signs if we land inside valid region of sign buffer. - if (sx < p.sShape.x && sy < p.sShape.y) - { - uint64_t is = (sx >> 2) + (p.sShape.x >> 2) * (sy + (uint64_t)p.sShape.y * q); // Contiguous. - unsigned char s = p.s[is]; - s >>= (sx & 3) << 1; // Shift into place. - if (s & 1) // Sign? - v *= p.slope; - if (s & 2) // Clamp? - v = 0.f; - } - - *pv = (T)v; // Write value. - } - } - else - { - // Forward pass with no sign write. Process value if in p.x. - if (x < p.xShape.x) // y is always in. - { - int64_t ix = x * p.xStride.x + y * p.xStride.y + z * p.xStride.z + w * p.xStride.w; - T* pv = ((T*)p.x) + ix; - scalar_t v = (scalar_t)(*pv); - v *= p.gain; - if (v < 0.f) - v *= p.slope; - if (fabsf(v) > p.clamp) - v = InternalType::clamp(v, p.clamp); - *pv = (T)v; // Write value. - } - } - } -} - -template void* choose_filtered_lrelu_act_kernel(void) -{ - return (void*)filtered_lrelu_act_kernel; -} - -//------------------------------------------------------------------------ -// CUDA kernel selection. - -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB) -{ - filtered_lrelu_kernel_spec s = { 0 }; - - // Return the first matching kernel. -#define CASE(SH, U, FU, D, FD, MODE, TW, TH, W, XR, WS) \ - if (sharedKB >= SH) \ - if ((p.fuShape.y == 0 && (MODE == MODE_SUSD || MODE == MODE_SUFD)) || (p.fuShape.y > 0 && (MODE == MODE_FUSD || MODE == MODE_FUFD))) \ - if ((p.fdShape.y == 0 && (MODE == MODE_SUSD || MODE == MODE_FUSD)) || (p.fdShape.y > 0 && (MODE == MODE_SUFD || MODE == MODE_FUFD))) \ - if (p.up == U && p.fuShape.x <= FU && p.fuShape.y <= FU && p.down == D && p.fdShape.x <= FD && p.fdShape.y <= FD) \ - { \ - static_assert((D*TW % 4) == 0, "down * tileWidth must be divisible by 4"); \ - static_assert(FU % U == 0, "upscaling filter size must be multiple of upscaling factor"); \ - static_assert(FD % D == 0, "downscaling filter size must be multiple of downscaling factor"); \ - s.setup = (void*)setup_filters_kernel; \ - s.exec = (void*)filtered_lrelu_kernel; \ - s.tileOut = make_int2(TW, TH); \ - s.numWarps = W; \ - s.xrep = XR; \ - s.dynamicSharedKB = (SH == 48) ? 0 : SH; \ - return s; \ - } - - // Launch parameters for various kernel specializations. - // Small filters must be listed before large filters, otherwise the kernel for larger filter will always match first. - // Kernels that use more shared memory must be listed before those that use less, for the same reason. - - CASE(/*sharedKB*/48, /*up,fu*/1,1, /*down,fd*/1,1, /*mode*/MODE_FUFD, /*tw,th,warps,xrep,wskip*/64, 178, 32, 0, 0) // 1t-upf1-downf1 - CASE(/*sharedKB*/48, /*up,fu*/2,8, /*down,fd*/1,1, /*mode*/MODE_SUFD, /*tw,th,warps,xrep,wskip*/152, 95, 16, 0, 0) // 4t-ups2-downf1 - CASE(/*sharedKB*/48, /*up,fu*/1,1, /*down,fd*/2,8, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/56, 22, 16, 0, 0) // 4t-upf1-downs2 - CASE(/*sharedKB*/48, /*up,fu*/2,8, /*down,fd*/2,8, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/56, 29, 16, 11, 0) // 4t-ups2-downs2 - CASE(/*sharedKB*/48, /*up,fu*/2,8, /*down,fd*/2,8, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/60, 28, 16, 0, 0) // 4t-upf2-downs2 - CASE(/*sharedKB*/48, /*up,fu*/2,8, /*down,fd*/2,8, /*mode*/MODE_SUFD, /*tw,th,warps,xrep,wskip*/56, 28, 16, 0, 0) // 4t-ups2-downf2 - CASE(/*sharedKB*/48, /*up,fu*/4,16, /*down,fd*/2,8, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/56, 31, 16, 11, 0) // 4t-ups4-downs2 - CASE(/*sharedKB*/48, /*up,fu*/4,16, /*down,fd*/2,8, /*mode*/MODE_SUFD, /*tw,th,warps,xrep,wskip*/56, 36, 16, 0, 0) // 4t-ups4-downf2 - CASE(/*sharedKB*/48, /*up,fu*/2,8, /*down,fd*/4,16, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/16, 22, 16, 12, 0) // 4t-ups2-downs4 - CASE(/*sharedKB*/48, /*up,fu*/2,8, /*down,fd*/4,16, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/29, 15, 16, 0, 0) // 4t-upf2-downs4 - CASE(/*sharedKB*/48, /*up,fu*/2,12, /*down,fd*/1,1, /*mode*/MODE_SUFD, /*tw,th,warps,xrep,wskip*/96, 150, 28, 0, 0) // 6t-ups2-downf1 - CASE(/*sharedKB*/48, /*up,fu*/1,1, /*down,fd*/2,12, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/32, 35, 24, 0, 0) // 6t-upf1-downs2 - CASE(/*sharedKB*/48, /*up,fu*/2,12, /*down,fd*/2,12, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/32, 46, 16, 10, 0) // 6t-ups2-downs2 - CASE(/*sharedKB*/48, /*up,fu*/2,12, /*down,fd*/2,12, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/58, 28, 24, 8, 0) // 6t-upf2-downs2 - CASE(/*sharedKB*/48, /*up,fu*/2,12, /*down,fd*/2,12, /*mode*/MODE_SUFD, /*tw,th,warps,xrep,wskip*/52, 28, 16, 0, 0) // 6t-ups2-downf2 - CASE(/*sharedKB*/48, /*up,fu*/4,24, /*down,fd*/2,12, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/32, 51, 16, 5, 0) // 6t-ups4-downs2 - CASE(/*sharedKB*/48, /*up,fu*/4,24, /*down,fd*/2,12, /*mode*/MODE_SUFD, /*tw,th,warps,xrep,wskip*/32, 56, 16, 6, 0) // 6t-ups4-downf2 - CASE(/*sharedKB*/48, /*up,fu*/2,12, /*down,fd*/4,24, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/16, 18, 16, 12, 0) // 6t-ups2-downs4 - CASE(/*sharedKB*/96, /*up,fu*/2,12, /*down,fd*/4,24, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/27, 31, 32, 6, 0) // 6t-upf2-downs4 96kB - CASE(/*sharedKB*/48, /*up,fu*/2,12, /*down,fd*/4,24, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/27, 13, 24, 0, 0) // 6t-upf2-downs4 - CASE(/*sharedKB*/48, /*up,fu*/2,16, /*down,fd*/1,1, /*mode*/MODE_SUFD, /*tw,th,warps,xrep,wskip*/148, 89, 24, 0, 0) // 8t-ups2-downf1 - CASE(/*sharedKB*/48, /*up,fu*/1,1, /*down,fd*/2,16, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/32, 31, 16, 5, 0) // 8t-upf1-downs2 - CASE(/*sharedKB*/48, /*up,fu*/2,16, /*down,fd*/2,16, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/32, 41, 16, 9, 0) // 8t-ups2-downs2 - CASE(/*sharedKB*/48, /*up,fu*/2,16, /*down,fd*/2,16, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/56, 26, 24, 0, 0) // 8t-upf2-downs2 - CASE(/*sharedKB*/48, /*up,fu*/2,16, /*down,fd*/2,16, /*mode*/MODE_SUFD, /*tw,th,warps,xrep,wskip*/32, 40, 16, 0, 0) // 8t-ups2-downf2 - CASE(/*sharedKB*/48, /*up,fu*/4,32, /*down,fd*/2,16, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/32, 46, 24, 5, 0) // 8t-ups4-downs2 - CASE(/*sharedKB*/48, /*up,fu*/4,32, /*down,fd*/2,16, /*mode*/MODE_SUFD, /*tw,th,warps,xrep,wskip*/32, 50, 16, 0, 0) // 8t-ups4-downf2 - CASE(/*sharedKB*/96, /*up,fu*/2,16, /*down,fd*/4,32, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/24, 24, 32, 12, 1) // 8t-ups2-downs4 96kB - CASE(/*sharedKB*/48, /*up,fu*/2,16, /*down,fd*/4,32, /*mode*/MODE_SUSD, /*tw,th,warps,xrep,wskip*/16, 13, 16, 10, 1) // 8t-ups2-downs4 - CASE(/*sharedKB*/96, /*up,fu*/2,16, /*down,fd*/4,32, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/25, 28, 28, 4, 0) // 8t-upf2-downs4 96kB - CASE(/*sharedKB*/48, /*up,fu*/2,16, /*down,fd*/4,32, /*mode*/MODE_FUSD, /*tw,th,warps,xrep,wskip*/25, 10, 24, 0, 0) // 8t-upf2-downs4 - - #undef CASE - return s; // No kernel found. -} - -//------------------------------------------------------------------------ diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.h b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.h deleted file mode 100644 index 2c403e3f27..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include - -//------------------------------------------------------------------------ -// CUDA kernel parameters. - -struct filtered_lrelu_kernel_params -{ - // These parameters decide which kernel to use. - int up; // upsampling ratio (1, 2, 4) - int down; // downsampling ratio (1, 2, 4) - int2 fuShape; // [size, 1] | [size, size] - int2 fdShape; // [size, 1] | [size, size] - - int _dummy; // Alignment. - - // Rest of the parameters. - const void* x; // Input tensor. - void* y; // Output tensor. - const void* b; // Bias tensor. - unsigned char* s; // Sign tensor in/out. NULL if unused. - const float* fu; // Upsampling filter. - const float* fd; // Downsampling filter. - - int2 pad0; // Left/top padding. - float gain; // Additional gain factor. - float slope; // Leaky ReLU slope on negative side. - float clamp; // Clamp after nonlinearity. - int flip; // Filter kernel flip for gradient computation. - - int tilesXdim; // Original number of horizontal output tiles. - int tilesXrep; // Number of horizontal tiles per CTA. - int blockZofs; // Block z offset to support large minibatch, channel dimensions. - - int4 xShape; // [width, height, channel, batch] - int4 yShape; // [width, height, channel, batch] - int2 sShape; // [width, height] - width is in bytes. Contiguous. Zeros if unused. - int2 sOfs; // [ofs_x, ofs_y] - offset between upsampled data and sign tensor. - int swLimit; // Active width of sign tensor in bytes. - - longlong4 xStride; // Strides of all tensors except signs, same component order as shapes. - longlong4 yStride; // - int64_t bStride; // - longlong3 fuStride; // - longlong3 fdStride; // -}; - -struct filtered_lrelu_act_kernel_params -{ - void* x; // Input/output, modified in-place. - unsigned char* s; // Sign tensor in/out. NULL if unused. - - float gain; // Additional gain factor. - float slope; // Leaky ReLU slope on negative side. - float clamp; // Clamp after nonlinearity. - - int4 xShape; // [width, height, channel, batch] - longlong4 xStride; // Input/output tensor strides, same order as in shape. - int2 sShape; // [width, height] - width is in elements. Contiguous. Zeros if unused. - int2 sOfs; // [ofs_x, ofs_y] - offset between upsampled data and sign tensor. -}; - -//------------------------------------------------------------------------ -// CUDA kernel specialization. - -struct filtered_lrelu_kernel_spec -{ - void* setup; // Function for filter kernel setup. - void* exec; // Function for main operation. - int2 tileOut; // Width/height of launch tile. - int numWarps; // Number of warps per thread block, determines launch block size. - int xrep; // For processing multiple horizontal tiles per thread block. - int dynamicSharedKB; // How much dynamic shared memory the exec kernel wants. -}; - -//------------------------------------------------------------------------ -// CUDA kernel selection. - -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); -template void* choose_filtered_lrelu_act_kernel(void); -template cudaError_t copy_filters(cudaStream_t stream); - -//------------------------------------------------------------------------ diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.py b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.py deleted file mode 100644 index f3debce594..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu.py +++ /dev/null @@ -1,373 +0,0 @@ -# Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# NVIDIA CORPORATION and its licensors retain all intellectual property -# and proprietary rights in and to this software, related documentation -# and any modifications thereto. Any use, reproduction, disclosure or -# distribution of this software and related documentation without an express -# license agreement from NVIDIA CORPORATION is strictly prohibited. - -import os -import warnings - -import numpy as np -import torch - -from .. import custom_ops -from . import bias_act, upfirdn2d - -_plugin = None - - -def _init(): - global _plugin - if _plugin is None: - _plugin = custom_ops.get_plugin( - module_name='filtered_lrelu_plugin', - sources=[ - 'filtered_lrelu.cpp', 'filtered_lrelu_wr.cu', - 'filtered_lrelu_rd.cu', 'filtered_lrelu_ns.cu' - ], - headers=['filtered_lrelu.h', 'filtered_lrelu.cu'], - source_dir=os.path.dirname(__file__), - extra_cuda_cflags=['--use_fast_math'], - ) - return True - - -def _get_filter_size(f): - if f is None: - return 1, 1 - assert isinstance(f, torch.Tensor) - assert 1 <= f.ndim <= 2 - return f.shape[-1], f.shape[0] # width, height - - -def _parse_padding(padding): - if isinstance(padding, int): - padding = [padding, padding] - assert isinstance(padding, (list, tuple)) - assert all(isinstance(x, (int, np.integer)) for x in padding) - padding = [int(x) for x in padding] - if len(padding) == 2: - px, py = padding - padding = [px, px, py, py] - px0, px1, py0, py1 = padding - return px0, px1, py0, py1 - - -def filtered_lrelu(x, - fu=None, - fd=None, - b=None, - up=1, - down=1, - padding=0, - gain=np.sqrt(2), - slope=0.2, - clamp=None, - flip_filter=False, - impl='cuda'): - r"""Filtered leaky ReLU for a batch of 2D images. - - Performs the following sequence of operations for each channel: - - 1. Add channel-specific bias if provided (`b`). - - 2. Upsample the image by inserting N-1 zeros after each pixel (`up`). - - 3. Pad the image with the specified number of zeros on each side - (`padding`). Negative padding corresponds to cropping the image. - - 4. Convolve the image with the specified upsampling FIR filter (`fu`), - shrinking it so that the footprint of all output pixels lies within the - input image. - - 5. Multiply each value by the provided gain factor (`gain`). - - 6. Apply leaky ReLU activation function to each value. - - 7. Clamp each value between -clamp and +clamp, if `clamp` parameter is - provided. - - 8. Convolve the image with the specified downsampling FIR filter (`fd`), - shrinking it so that the footprint of all output pixels lies within the - input image. - - 9. Downsample the image by keeping every Nth pixel (`down`). - - The fused op is considerably more efficient than performing the same - calculation using standard PyTorch ops. It supports gradients of arbitrary - order. - - Args: - x: Float32/float16/float64 input tensor of the shape - `[batch_size, num_channels, in_height, in_width]`. - fu: Float32 upsampling FIR filter of the shape - `[filter_height, filter_width]` (non-separable), - `[filter_taps]` (separable), or - `None` (identity). - fd: Float32 downsampling FIR filter of the shape - `[filter_height, filter_width]` (non-separable), - `[filter_taps]` (separable), or - `None` (identity). - b: Bias vector, or `None` to disable. Must be a 1D tensor of - the same type as `x`. The length of vector must must match - the channel dimension of `x`. - up: Integer upsampling factor (default: 1). - down: Integer downsampling factor. (default: 1). - padding: Padding with respect to the upsampled image. Can be a - single number or a list/tuple `[x, y]` or `[x_before, - x_after, y_before, y_after]` (default: 0). - gain: Overall scaling factor for signal magnitude (default: - sqrt(2)). - slope: Slope on the negative side of leaky ReLU (default: 0.2). - clamp: Maximum magnitude for leaky ReLU output (default: None). - flip_filter: False = convolution, True = correlation (default: False). - impl: Implementation to use. Can be `'ref'` or `'cuda'` - (default: `'cuda'`). - - Returns: - Tensor of the shape `[batch_size, num_channels, out_height, - out_width]`. - """ - assert isinstance(x, torch.Tensor) - assert impl in ['ref', 'cuda'] - if impl == 'cuda' and x.device.type == 'cuda' and _init(): - return _filtered_lrelu_cuda( - up=up, - down=down, - padding=padding, - gain=gain, - slope=slope, - clamp=clamp, - flip_filter=flip_filter).apply(x, fu, fd, b, None, 0, 0) - return _filtered_lrelu_ref( - x, - fu=fu, - fd=fd, - b=b, - up=up, - down=down, - padding=padding, - gain=gain, - slope=slope, - clamp=clamp, - flip_filter=flip_filter) - - -def _filtered_lrelu_ref(x, - fu=None, - fd=None, - b=None, - up=1, - down=1, - padding=0, - gain=np.sqrt(2), - slope=0.2, - clamp=None, - flip_filter=False): - """Slow and memory-inefficient reference implementation of - `filtered_lrelu()` using existing `upfirdn2n()` and `bias_act()` ops.""" - assert isinstance(x, torch.Tensor) and x.ndim == 4 - fu_w, fu_h = _get_filter_size(fu) - fd_w, fd_h = _get_filter_size(fd) - if b is not None: - assert isinstance(b, torch.Tensor) and b.dtype == x.dtype - assert isinstance(up, int) and up >= 1 - assert isinstance(down, int) and down >= 1 - px0, px1, py0, py1 = _parse_padding(padding) - assert gain == float(gain) and gain > 0 - assert slope == float(slope) and slope >= 0 - assert clamp is None or (clamp == float(clamp) and clamp >= 0) - - # Calculate output size. - batch_size, channels, in_h, in_w = x.shape - in_dtype = x.dtype - out_w = (in_w * up + (px0 + px1) - (fu_w - 1) - (fd_w - 1) + - (down - 1)) // down - out_h = (in_h * up + (py0 + py1) - (fu_h - 1) - (fd_h - 1) + - (down - 1)) // down - - # Compute using existing ops. - x = bias_act.bias_act(x=x, b=b) # Apply bias. - x = upfirdn2d.upfirdn2d( - x=x, - f=fu, - up=up, - padding=[px0, px1, py0, py1], - gain=up**2, - flip_filter=flip_filter) # Upsample. - x = bias_act.bias_act( - x=x, act='lrelu', alpha=slope, gain=gain, - clamp=clamp) # Bias, leaky ReLU, clamp. - x = upfirdn2d.upfirdn2d( - x=x, f=fd, down=down, flip_filter=flip_filter) # Downsample. - - assert x.shape == (batch_size, channels, out_h, out_w) - assert x.dtype == in_dtype - return x - - -_filtered_lrelu_cuda_cache = dict() - - -def _filtered_lrelu_cuda(up=1, - down=1, - padding=0, - gain=np.sqrt(2), - slope=0.2, - clamp=None, - flip_filter=False): - """Fast CUDA implementation of `filtered_lrelu()` using custom ops.""" - assert isinstance(up, int) and up >= 1 - assert isinstance(down, int) and down >= 1 - px0, px1, py0, py1 = _parse_padding(padding) - assert gain == float(gain) and gain > 0 - gain = float(gain) - assert slope == float(slope) and slope >= 0 - slope = float(slope) - assert clamp is None or (clamp == float(clamp) and clamp >= 0) - clamp = float(clamp if clamp is not None else 'inf') - - # Lookup from cache. - key = (up, down, px0, px1, py0, py1, gain, slope, clamp, flip_filter) - if key in _filtered_lrelu_cuda_cache: - return _filtered_lrelu_cuda_cache[key] - - # Forward op. - class FilteredLReluCuda(torch.autograd.Function): - - @staticmethod - def forward(ctx, x, fu, fd, b, si, sx, sy): - # pylint: disable=arguments-differ - assert isinstance(x, torch.Tensor) and x.ndim == 4 - - # Replace empty up/downsample kernels with full 1x1 kernels - # (faster than separable). - if fu is None: - fu = torch.ones([1, 1], dtype=torch.float32, device=x.device) - if fd is None: - fd = torch.ones([1, 1], dtype=torch.float32, device=x.device) - assert 1 <= fu.ndim <= 2 - assert 1 <= fd.ndim <= 2 - - # Replace separable 1x1 kernels with full 1x1 kernels when scale - # factor is 1. - if up == 1 and fu.ndim == 1 and fu.shape[0] == 1: - fu = fu.square()[None] - if down == 1 and fd.ndim == 1 and fd.shape[0] == 1: - fd = fd.square()[None] - - # Missing sign input tensor. - if si is None: - si = torch.empty([0]) - - # Missing bias tensor. - if b is None: - b = torch.zeros([x.shape[1]], dtype=x.dtype, device=x.device) - - # Construct internal sign tensor only if gradients are needed. - write_signs = (si.numel() == 0) and (x.requires_grad - or b.requires_grad) - - # Warn if input storage strides are not in decreasing order due to - # e.g. channels-last layout. - strides = [x.stride(i) for i in range(x.ndim) if x.size(i) > 1] - if any(a < b for a, b in zip(strides[:-1], strides[1:])): - warnings.warn( - 'low-performance memory layout detected in filtered_lrelu ' - 'input', RuntimeWarning) - - # Call C++/Cuda plugin if datatype is supported. - if x.dtype in [torch.float16, torch.float32]: - if torch.cuda.current_stream( - x.device) != torch.cuda.default_stream(x.device): - warnings.warn( - 'filtered_lrelu called with non-default cuda stream ' - 'but concurrent execution is not supported', - RuntimeWarning) - y, so, return_code = _plugin.filtered_lrelu( - x, fu, fd, b, si, up, down, px0, px1, py0, py1, sx, sy, - gain, slope, clamp, flip_filter, write_signs) - else: - return_code = -1 - - # No Cuda kernel found? Fall back to generic implementation. - # Still more memory efficient than the reference implementation - # because only the bit-packed sign tensor is retained for gradient - # computation. - if return_code < 0: - warnings.warn( - 'filtered_lrelu called with parameters that have no ' - 'optimized CUDA kernel, using generic fallback', - RuntimeWarning) - - y = x.add(b.unsqueeze(-1).unsqueeze(-1)) # Add bias. - y = upfirdn2d.upfirdn2d( - x=y, - f=fu, - up=up, - padding=[px0, px1, py0, py1], - gain=up**2, - flip_filter=flip_filter) # Upsample. - # Activation function and sign handling. Modifies y in-place. - so = _plugin.filtered_lrelu_act_(y, si, sx, sy, gain, slope, - clamp, write_signs) - y = upfirdn2d.upfirdn2d( - x=y, f=fd, down=down, - flip_filter=flip_filter) # Downsample. - - # Prepare for gradient computation. - ctx.save_for_backward(fu, fd, (si if si.numel() else so)) - ctx.x_shape = x.shape - ctx.y_shape = y.shape - ctx.s_ofs = sx, sy - return y - - @staticmethod - def backward(ctx, dy): # pylint: disable=arguments-differ - fu, fd, si = ctx.saved_tensors - _, _, xh, xw = ctx.x_shape - _, _, yh, yw = ctx.y_shape - sx, sy = ctx.s_ofs - dx = None # 0 - dfu = None - assert not ctx.needs_input_grad[1] - dfd = None - assert not ctx.needs_input_grad[2] - db = None # 3 - dsi = None - assert not ctx.needs_input_grad[4] - dsx = None - assert not ctx.needs_input_grad[5] - dsy = None - assert not ctx.needs_input_grad[6] - - if ctx.needs_input_grad[0] or ctx.needs_input_grad[3]: - pp = [ - (fu.shape[-1] - 1) + (fd.shape[-1] - 1) - px0, - xw * up - yw * down + px0 - (up - 1), - (fu.shape[0] - 1) + (fd.shape[0] - 1) - py0, - xh * up - yh * down + py0 - (up - 1), - ] - gg = gain * (up**2) / (down**2) - ff = (not flip_filter) - sx = sx - (fu.shape[-1] - 1) + px0 - sy = sy - (fu.shape[0] - 1) + py0 - dx = _filtered_lrelu_cuda( - up=down, - down=up, - padding=pp, - gain=gg, - slope=slope, - clamp=None, - flip_filter=ff).apply(dy, fd, fu, None, si, sx, sy) - - if ctx.needs_input_grad[3]: - db = dx.sum([0, 2, 3]) - - return dx, dfu, dfd, db, dsi, dsx, dsy - - # Add to cache. - _filtered_lrelu_cuda_cache[key] = FilteredLReluCuda - return FilteredLReluCuda diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_ns.cu b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_ns.cu deleted file mode 100644 index ef5d948c4f..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_ns.cu +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include "filtered_lrelu.cu" - -// Template/kernel specializations for no signs mode (no gradients required). - -// Full op, 32-bit indexing. -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); - -// Full op, 64-bit indexing. -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); - -// Activation/signs only for generic variant. 64-bit indexing. -template void* choose_filtered_lrelu_act_kernel(void); -template void* choose_filtered_lrelu_act_kernel(void); -template void* choose_filtered_lrelu_act_kernel(void); - -// Copy filters to constant memory. -template cudaError_t copy_filters(cudaStream_t stream); diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_rd.cu b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_rd.cu deleted file mode 100644 index 968347882e..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_rd.cu +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include "filtered_lrelu.cu" - -// Template/kernel specializations for sign read mode. - -// Full op, 32-bit indexing. -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); - -// Full op, 64-bit indexing. -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); - -// Activation/signs only for generic variant. 64-bit indexing. -template void* choose_filtered_lrelu_act_kernel(void); -template void* choose_filtered_lrelu_act_kernel(void); -template void* choose_filtered_lrelu_act_kernel(void); - -// Copy filters to constant memory. -template cudaError_t copy_filters(cudaStream_t stream); diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_wr.cu b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_wr.cu deleted file mode 100644 index a4c6a24aae..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/filtered_lrelu_wr.cu +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include "filtered_lrelu.cu" - -// Template/kernel specializations for sign write mode. - -// Full op, 32-bit indexing. -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); - -// Full op, 64-bit indexing. -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); -template filtered_lrelu_kernel_spec choose_filtered_lrelu_kernel(const filtered_lrelu_kernel_params& p, int sharedKB); - -// Activation/signs only for generic variant. 64-bit indexing. -template void* choose_filtered_lrelu_act_kernel(void); -template void* choose_filtered_lrelu_act_kernel(void); -template void* choose_filtered_lrelu_act_kernel(void); - -// Copy filters to constant memory. -template cudaError_t copy_filters(cudaStream_t stream); diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.cpp b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.cpp deleted file mode 100644 index 44fa337d8d..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include -#include -#include -#include "upfirdn2d.h" - -//------------------------------------------------------------------------ - -static torch::Tensor upfirdn2d(torch::Tensor x, torch::Tensor f, int upx, int upy, int downx, int downy, int padx0, int padx1, int pady0, int pady1, bool flip, float gain) -{ - // Validate arguments. - TORCH_CHECK(x.is_cuda(), "x must reside on CUDA device"); - TORCH_CHECK(f.device() == x.device(), "f must reside on the same device as x"); - TORCH_CHECK(f.dtype() == torch::kFloat, "f must be float32"); - TORCH_CHECK(x.numel() <= INT_MAX, "x is too large"); - TORCH_CHECK(f.numel() <= INT_MAX, "f is too large"); - TORCH_CHECK(x.numel() > 0, "x has zero size"); - TORCH_CHECK(f.numel() > 0, "f has zero size"); - TORCH_CHECK(x.dim() == 4, "x must be rank 4"); - TORCH_CHECK(f.dim() == 2, "f must be rank 2"); - TORCH_CHECK((x.size(0)-1)*x.stride(0) + (x.size(1)-1)*x.stride(1) + (x.size(2)-1)*x.stride(2) + (x.size(3)-1)*x.stride(3) <= INT_MAX, "x memory footprint is too large"); - TORCH_CHECK(f.size(0) >= 1 && f.size(1) >= 1, "f must be at least 1x1"); - TORCH_CHECK(upx >= 1 && upy >= 1, "upsampling factor must be at least 1"); - TORCH_CHECK(downx >= 1 && downy >= 1, "downsampling factor must be at least 1"); - - // Create output tensor. - const at::cuda::OptionalCUDAGuard device_guard(device_of(x)); - int outW = ((int)x.size(3) * upx + padx0 + padx1 - (int)f.size(1) + downx) / downx; - int outH = ((int)x.size(2) * upy + pady0 + pady1 - (int)f.size(0) + downy) / downy; - TORCH_CHECK(outW >= 1 && outH >= 1, "output must be at least 1x1"); - torch::Tensor y = torch::empty({x.size(0), x.size(1), outH, outW}, x.options(), x.suggest_memory_format()); - TORCH_CHECK(y.numel() <= INT_MAX, "output is too large"); - TORCH_CHECK((y.size(0)-1)*y.stride(0) + (y.size(1)-1)*y.stride(1) + (y.size(2)-1)*y.stride(2) + (y.size(3)-1)*y.stride(3) <= INT_MAX, "output memory footprint is too large"); - - // Initialize CUDA kernel parameters. - upfirdn2d_kernel_params p; - p.x = x.data_ptr(); - p.f = f.data_ptr(); - p.y = y.data_ptr(); - p.up = make_int2(upx, upy); - p.down = make_int2(downx, downy); - p.pad0 = make_int2(padx0, pady0); - p.flip = (flip) ? 1 : 0; - p.gain = gain; - p.inSize = make_int4((int)x.size(3), (int)x.size(2), (int)x.size(1), (int)x.size(0)); - p.inStride = make_int4((int)x.stride(3), (int)x.stride(2), (int)x.stride(1), (int)x.stride(0)); - p.filterSize = make_int2((int)f.size(1), (int)f.size(0)); - p.filterStride = make_int2((int)f.stride(1), (int)f.stride(0)); - p.outSize = make_int4((int)y.size(3), (int)y.size(2), (int)y.size(1), (int)y.size(0)); - p.outStride = make_int4((int)y.stride(3), (int)y.stride(2), (int)y.stride(1), (int)y.stride(0)); - p.sizeMajor = (p.inStride.z == 1) ? p.inSize.w : p.inSize.w * p.inSize.z; - p.sizeMinor = (p.inStride.z == 1) ? p.inSize.z : 1; - - // Choose CUDA kernel. - upfirdn2d_kernel_spec spec; - AT_DISPATCH_FLOATING_TYPES_AND_HALF(x.scalar_type(), "upfirdn2d_cuda", [&] - { - spec = choose_upfirdn2d_kernel(p); - }); - - // Set looping options. - p.loopMajor = (p.sizeMajor - 1) / 16384 + 1; - p.loopMinor = spec.loopMinor; - p.loopX = spec.loopX; - p.launchMinor = (p.sizeMinor - 1) / p.loopMinor + 1; - p.launchMajor = (p.sizeMajor - 1) / p.loopMajor + 1; - - // Compute grid size. - dim3 blockSize, gridSize; - if (spec.tileOutW < 0) // large - { - blockSize = dim3(4, 32, 1); - gridSize = dim3( - ((p.outSize.y - 1) / blockSize.x + 1) * p.launchMinor, - (p.outSize.x - 1) / (blockSize.y * p.loopX) + 1, - p.launchMajor); - } - else // small - { - blockSize = dim3(256, 1, 1); - gridSize = dim3( - ((p.outSize.y - 1) / spec.tileOutH + 1) * p.launchMinor, - (p.outSize.x - 1) / (spec.tileOutW * p.loopX) + 1, - p.launchMajor); - } - - // Launch CUDA kernel. - void* args[] = {&p}; - AT_CUDA_CHECK(cudaLaunchKernel(spec.kernel, gridSize, blockSize, args, 0, at::cuda::getCurrentCUDAStream())); - return y; -} - -//------------------------------------------------------------------------ - -PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) -{ - m.def("upfirdn2d", &upfirdn2d); -} - -//------------------------------------------------------------------------ diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.cu b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.cu deleted file mode 100644 index 3a33e31bbb..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.cu +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include -#include "upfirdn2d.h" - -//------------------------------------------------------------------------ -// Helpers. - -template struct InternalType; -template <> struct InternalType { typedef double scalar_t; }; -template <> struct InternalType { typedef float scalar_t; }; -template <> struct InternalType { typedef float scalar_t; }; - -static __device__ __forceinline__ int floor_div(int a, int b) -{ - int t = 1 - a / b; - return (a + t * b) / b - t; -} - -//------------------------------------------------------------------------ -// Generic CUDA implementation for large filters. - -template static __global__ void upfirdn2d_kernel_large(upfirdn2d_kernel_params p) -{ - typedef typename InternalType::scalar_t scalar_t; - - // Calculate thread index. - int minorBase = blockIdx.x * blockDim.x + threadIdx.x; - int outY = minorBase / p.launchMinor; - minorBase -= outY * p.launchMinor; - int outXBase = blockIdx.y * p.loopX * blockDim.y + threadIdx.y; - int majorBase = blockIdx.z * p.loopMajor; - if (outXBase >= p.outSize.x | outY >= p.outSize.y | majorBase >= p.sizeMajor) - return; - - // Setup Y receptive field. - int midY = outY * p.down.y + p.up.y - 1 - p.pad0.y; - int inY = min(max(floor_div(midY, p.up.y), 0), p.inSize.y); - int h = min(max(floor_div(midY + p.filterSize.y, p.up.y), 0), p.inSize.y) - inY; - int filterY = midY + p.filterSize.y - (inY + 1) * p.up.y; - if (p.flip) - filterY = p.filterSize.y - 1 - filterY; - - // Loop over major, minor, and X. - for (int majorIdx = 0, major = majorBase; majorIdx < p.loopMajor & major < p.sizeMajor; majorIdx++, major++) - for (int minorIdx = 0, minor = minorBase; minorIdx < p.loopMinor & minor < p.sizeMinor; minorIdx++, minor += p.launchMinor) - { - int nc = major * p.sizeMinor + minor; - int n = nc / p.inSize.z; - int c = nc - n * p.inSize.z; - for (int loopX = 0, outX = outXBase; loopX < p.loopX & outX < p.outSize.x; loopX++, outX += blockDim.y) - { - // Setup X receptive field. - int midX = outX * p.down.x + p.up.x - 1 - p.pad0.x; - int inX = min(max(floor_div(midX, p.up.x), 0), p.inSize.x); - int w = min(max(floor_div(midX + p.filterSize.x, p.up.x), 0), p.inSize.x) - inX; - int filterX = midX + p.filterSize.x - (inX + 1) * p.up.x; - if (p.flip) - filterX = p.filterSize.x - 1 - filterX; - - // Initialize pointers. - const T* xp = &((const T*)p.x)[inX * p.inStride.x + inY * p.inStride.y + c * p.inStride.z + n * p.inStride.w]; - const float* fp = &p.f[filterX * p.filterStride.x + filterY * p.filterStride.y]; - int filterStepX = ((p.flip) ? p.up.x : -p.up.x) * p.filterStride.x; - int filterStepY = ((p.flip) ? p.up.y : -p.up.y) * p.filterStride.y; - - // Inner loop. - scalar_t v = 0; - for (int y = 0; y < h; y++) - { - for (int x = 0; x < w; x++) - { - v += (scalar_t)(*xp) * (scalar_t)(*fp); - xp += p.inStride.x; - fp += filterStepX; - } - xp += p.inStride.y - w * p.inStride.x; - fp += filterStepY - w * filterStepX; - } - - // Store result. - v *= p.gain; - ((T*)p.y)[outX * p.outStride.x + outY * p.outStride.y + c * p.outStride.z + n * p.outStride.w] = (T)v; - } - } -} - -//------------------------------------------------------------------------ -// Specialized CUDA implementation for small filters. - -template -static __global__ void upfirdn2d_kernel_small(upfirdn2d_kernel_params p) -{ - typedef typename InternalType::scalar_t scalar_t; - const int tileInW = ((tileOutW - 1) * downx + filterW - 1) / upx + 1; - const int tileInH = ((tileOutH - 1) * downy + filterH - 1) / upy + 1; - __shared__ volatile scalar_t sf[filterH][filterW]; - __shared__ volatile scalar_t sx[tileInH][tileInW][loopMinor]; - - // Calculate tile index. - int minorBase = blockIdx.x; - int tileOutY = minorBase / p.launchMinor; - minorBase -= tileOutY * p.launchMinor; - minorBase *= loopMinor; - tileOutY *= tileOutH; - int tileOutXBase = blockIdx.y * p.loopX * tileOutW; - int majorBase = blockIdx.z * p.loopMajor; - if (tileOutXBase >= p.outSize.x | tileOutY >= p.outSize.y | majorBase >= p.sizeMajor) - return; - - // Load filter (flipped). - for (int tapIdx = threadIdx.x; tapIdx < filterH * filterW; tapIdx += blockDim.x) - { - int fy = tapIdx / filterW; - int fx = tapIdx - fy * filterW; - scalar_t v = 0; - if (fx < p.filterSize.x & fy < p.filterSize.y) - { - int ffx = (p.flip) ? fx : p.filterSize.x - 1 - fx; - int ffy = (p.flip) ? fy : p.filterSize.y - 1 - fy; - v = (scalar_t)p.f[ffx * p.filterStride.x + ffy * p.filterStride.y]; - } - sf[fy][fx] = v; - } - - // Loop over major and X. - for (int majorIdx = 0, major = majorBase; majorIdx < p.loopMajor & major < p.sizeMajor; majorIdx++, major++) - { - int baseNC = major * p.sizeMinor + minorBase; - int n = baseNC / p.inSize.z; - int baseC = baseNC - n * p.inSize.z; - for (int loopX = 0, tileOutX = tileOutXBase; loopX < p.loopX & tileOutX < p.outSize.x; loopX++, tileOutX += tileOutW) - { - // Load input pixels. - int tileMidX = tileOutX * downx + upx - 1 - p.pad0.x; - int tileMidY = tileOutY * downy + upy - 1 - p.pad0.y; - int tileInX = floor_div(tileMidX, upx); - int tileInY = floor_div(tileMidY, upy); - __syncthreads(); - for (int inIdx = threadIdx.x; inIdx < tileInH * tileInW * loopMinor; inIdx += blockDim.x) - { - int relC = inIdx; - int relInX = relC / loopMinor; - int relInY = relInX / tileInW; - relC -= relInX * loopMinor; - relInX -= relInY * tileInW; - int c = baseC + relC; - int inX = tileInX + relInX; - int inY = tileInY + relInY; - scalar_t v = 0; - if (inX >= 0 & inY >= 0 & inX < p.inSize.x & inY < p.inSize.y & c < p.inSize.z) - v = (scalar_t)((const T*)p.x)[inX * p.inStride.x + inY * p.inStride.y + c * p.inStride.z + n * p.inStride.w]; - sx[relInY][relInX][relC] = v; - } - - // Loop over output pixels. - __syncthreads(); - for (int outIdx = threadIdx.x; outIdx < tileOutH * tileOutW * loopMinor; outIdx += blockDim.x) - { - int relC = outIdx; - int relOutX = relC / loopMinor; - int relOutY = relOutX / tileOutW; - relC -= relOutX * loopMinor; - relOutX -= relOutY * tileOutW; - int c = baseC + relC; - int outX = tileOutX + relOutX; - int outY = tileOutY + relOutY; - - // Setup receptive field. - int midX = tileMidX + relOutX * downx; - int midY = tileMidY + relOutY * downy; - int inX = floor_div(midX, upx); - int inY = floor_div(midY, upy); - int relInX = inX - tileInX; - int relInY = inY - tileInY; - int filterX = (inX + 1) * upx - midX - 1; // flipped - int filterY = (inY + 1) * upy - midY - 1; // flipped - - // Inner loop. - if (outX < p.outSize.x & outY < p.outSize.y & c < p.outSize.z) - { - scalar_t v = 0; - #pragma unroll - for (int y = 0; y < filterH / upy; y++) - #pragma unroll - for (int x = 0; x < filterW / upx; x++) - v += sx[relInY + y][relInX + x][relC] * sf[filterY + y * upy][filterX + x * upx]; - v *= p.gain; - ((T*)p.y)[outX * p.outStride.x + outY * p.outStride.y + c * p.outStride.z + n * p.outStride.w] = (T)v; - } - } - } - } -} - -//------------------------------------------------------------------------ -// CUDA kernel selection. - -template upfirdn2d_kernel_spec choose_upfirdn2d_kernel(const upfirdn2d_kernel_params& p) -{ - int s = p.inStride.z, fx = p.filterSize.x, fy = p.filterSize.y; - upfirdn2d_kernel_spec spec = {(void*)upfirdn2d_kernel_large, -1,-1,1, 4}; // contiguous - if (s == 1) spec = {(void*)upfirdn2d_kernel_large, -1,-1,4, 1}; // channels_last - - // No up/downsampling. - if (p.up.x == 1 && p.up.y == 1 && p.down.x == 1 && p.down.y == 1) - { - // contiguous - if (s != 1 && fx <= 24 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 64,32,1, 1}; - if (s != 1 && fx <= 16 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 64,32,1, 1}; - if (s != 1 && fx <= 7 && fy <= 7 ) spec = {(void*)upfirdn2d_kernel_small, 64,16,1, 1}; - if (s != 1 && fx <= 6 && fy <= 6 ) spec = {(void*)upfirdn2d_kernel_small, 64,16,1, 1}; - if (s != 1 && fx <= 5 && fy <= 5 ) spec = {(void*)upfirdn2d_kernel_small, 64,16,1, 1}; - if (s != 1 && fx <= 4 && fy <= 4 ) spec = {(void*)upfirdn2d_kernel_small, 64,16,1, 1}; - if (s != 1 && fx <= 3 && fy <= 3 ) spec = {(void*)upfirdn2d_kernel_small, 64,16,1, 1}; - if (s != 1 && fx <= 24 && fy <= 1 ) spec = {(void*)upfirdn2d_kernel_small, 128,8,1, 1}; - if (s != 1 && fx <= 16 && fy <= 1 ) spec = {(void*)upfirdn2d_kernel_small, 128,8,1, 1}; - if (s != 1 && fx <= 8 && fy <= 1 ) spec = {(void*)upfirdn2d_kernel_small, 128,8,1, 1}; - if (s != 1 && fx <= 1 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s != 1 && fx <= 1 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s != 1 && fx <= 1 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - // channels_last - if (s == 1 && fx <= 24 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s == 1 && fx <= 16 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s == 1 && fx <= 7 && fy <= 7 ) spec = {(void*)upfirdn2d_kernel_small, 16,16,8, 1}; - if (s == 1 && fx <= 6 && fy <= 6 ) spec = {(void*)upfirdn2d_kernel_small, 16,16,8, 1}; - if (s == 1 && fx <= 5 && fy <= 5 ) spec = {(void*)upfirdn2d_kernel_small, 16,16,8, 1}; - if (s == 1 && fx <= 4 && fy <= 4 ) spec = {(void*)upfirdn2d_kernel_small, 16,16,8, 1}; - if (s == 1 && fx <= 3 && fy <= 3 ) spec = {(void*)upfirdn2d_kernel_small, 16,16,8, 1}; - if (s == 1 && fx <= 24 && fy <= 1 ) spec = {(void*)upfirdn2d_kernel_small, 128,1,16, 1}; - if (s == 1 && fx <= 16 && fy <= 1 ) spec = {(void*)upfirdn2d_kernel_small, 128,1,16, 1}; - if (s == 1 && fx <= 8 && fy <= 1 ) spec = {(void*)upfirdn2d_kernel_small, 128,1,16, 1}; - if (s == 1 && fx <= 1 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 1,128,16, 1}; - if (s == 1 && fx <= 1 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 1,128,16, 1}; - if (s == 1 && fx <= 1 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 1,128,16, 1}; - } - - // 2x upsampling. - if (p.up.x == 2 && p.up.y == 2 && p.down.x == 1 && p.down.y == 1) - { - // contiguous - if (s != 1 && fx <= 24 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 64,32,1, 1}; - if (s != 1 && fx <= 16 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 64,32,1, 1}; - if (s != 1 && fx <= 8 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 64,16,1, 1}; - if (s != 1 && fx <= 6 && fy <= 6 ) spec = {(void*)upfirdn2d_kernel_small, 64,16,1, 1}; - if (s != 1 && fx <= 4 && fy <= 4 ) spec = {(void*)upfirdn2d_kernel_small, 64,16,1, 1}; - if (s != 1 && fx <= 2 && fy <= 2 ) spec = {(void*)upfirdn2d_kernel_small, 64,16,1, 1}; - // channels_last - if (s == 1 && fx <= 24 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s == 1 && fx <= 16 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s == 1 && fx <= 8 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 16,16,8, 1}; - if (s == 1 && fx <= 6 && fy <= 6 ) spec = {(void*)upfirdn2d_kernel_small, 16,16,8, 1}; - if (s == 1 && fx <= 4 && fy <= 4 ) spec = {(void*)upfirdn2d_kernel_small, 16,16,8, 1}; - if (s == 1 && fx <= 2 && fy <= 2 ) spec = {(void*)upfirdn2d_kernel_small, 16,16,8, 1}; - } - if (p.up.x == 2 && p.up.y == 1 && p.down.x == 1 && p.down.y == 1) - { - // contiguous - if (s != 1 && fx <= 24 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,8,1, 1}; - if (s != 1 && fx <= 16 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,8,1, 1}; - if (s != 1 && fx <= 8 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,8,1, 1}; - // channels_last - if (s == 1 && fx <= 24 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,1,16, 1}; - if (s == 1 && fx <= 16 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,1,16, 1}; - if (s == 1 && fx <= 8 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,1,16, 1}; - } - if (p.up.x == 1 && p.up.y == 2 && p.down.x == 1 && p.down.y == 1) - { - // contiguous - if (s != 1 && fx <= 1 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s != 1 && fx <= 1 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s != 1 && fx <= 1 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - // channels_last - if (s == 1 && fx <= 1 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 1,128,16, 1}; - if (s == 1 && fx <= 1 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 1,128,16, 1}; - if (s == 1 && fx <= 1 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 1,128,16, 1}; - } - - // 2x downsampling. - if (p.up.x == 1 && p.up.y == 1 && p.down.x == 2 && p.down.y == 2) - { - // contiguous - if (s != 1 && fx <= 24 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 32,16,1, 1}; - if (s != 1 && fx <= 16 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 32,16,1, 1}; - if (s != 1 && fx <= 8 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 32,8,1, 1}; - if (s != 1 && fx <= 6 && fy <= 6 ) spec = {(void*)upfirdn2d_kernel_small, 32,8,1, 1}; - if (s != 1 && fx <= 4 && fy <= 4 ) spec = {(void*)upfirdn2d_kernel_small, 32,8,1, 1}; - if (s != 1 && fx <= 2 && fy <= 2 ) spec = {(void*)upfirdn2d_kernel_small, 32,8,1, 1}; - // channels_last - if (s == 1 && fx <= 24 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 16,16,1, 1}; - if (s == 1 && fx <= 16 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 16,16,1, 1}; - if (s == 1 && fx <= 8 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 8,8,8, 1}; - if (s == 1 && fx <= 6 && fy <= 6 ) spec = {(void*)upfirdn2d_kernel_small, 8,8,8, 1}; - if (s == 1 && fx <= 4 && fy <= 4 ) spec = {(void*)upfirdn2d_kernel_small, 8,8,8, 1}; - if (s == 1 && fx <= 2 && fy <= 2 ) spec = {(void*)upfirdn2d_kernel_small, 8,8,8, 1}; - } - if (p.up.x == 1 && p.up.y == 1 && p.down.x == 2 && p.down.y == 1) - { - // contiguous - if (s != 1 && fx <= 24 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 64,8,1, 1}; - if (s != 1 && fx <= 16 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 64,8,1, 1}; - if (s != 1 && fx <= 8 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 64,8,1, 1}; - // channels_last - if (s == 1 && fx <= 24 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 64,1,8, 1}; - if (s == 1 && fx <= 16 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 64,1,8, 1}; - if (s == 1 && fx <= 8 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 64,1,8, 1}; - } - if (p.up.x == 1 && p.up.y == 1 && p.down.x == 1 && p.down.y == 2) - { - // contiguous - if (s != 1 && fx <= 1 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 32,16,1, 1}; - if (s != 1 && fx <= 1 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 32,16,1, 1}; - if (s != 1 && fx <= 1 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 32,16,1, 1}; - // channels_last - if (s == 1 && fx <= 1 && fy <= 24) spec = {(void*)upfirdn2d_kernel_small, 1,64,8, 1}; - if (s == 1 && fx <= 1 && fy <= 16) spec = {(void*)upfirdn2d_kernel_small, 1,64,8, 1}; - if (s == 1 && fx <= 1 && fy <= 8 ) spec = {(void*)upfirdn2d_kernel_small, 1,64,8, 1}; - } - - // 4x upsampling. - if (p.up.x == 4 && p.up.y == 4 && p.down.x == 1 && p.down.y == 1) - { - // contiguous - if (s != 1 && fx <= 48 && fy <= 48) spec = {(void*)upfirdn2d_kernel_small, 64,32,1, 1}; - if (s != 1 && fx <= 32 && fy <= 32) spec = {(void*)upfirdn2d_kernel_small, 64,32,1, 1}; - // channels_last - if (s == 1 && fx <= 48 && fy <= 48) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s == 1 && fx <= 32 && fy <= 32) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - } - if (p.up.x == 4 && p.up.y == 1 && p.down.x == 1 && p.down.y == 1) - { - // contiguous - if (s != 1 && fx <= 48 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,8,1, 1}; - if (s != 1 && fx <= 32 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,8,1, 1}; - // channels_last - if (s == 1 && fx <= 48 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,1,16, 1}; - if (s == 1 && fx <= 32 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 128,1,16, 1}; - } - if (p.up.x == 1 && p.up.y == 4 && p.down.x == 1 && p.down.y == 1) - { - // contiguous - if (s != 1 && fx <= 1 && fy <= 48) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - if (s != 1 && fx <= 1 && fy <= 32) spec = {(void*)upfirdn2d_kernel_small, 32,32,1, 1}; - // channels_last - if (s == 1 && fx <= 1 && fy <= 48) spec = {(void*)upfirdn2d_kernel_small, 1,128,16, 1}; - if (s == 1 && fx <= 1 && fy <= 32) spec = {(void*)upfirdn2d_kernel_small, 1,128,16, 1}; - } - - // 4x downsampling (inefficient). - if (p.up.x == 1 && p.up.y == 1 && p.down.x == 4 && p.down.y == 1) - { - // contiguous - if (s != 1 && fx <= 48 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 32,8,1, 1}; - if (s != 1 && fx <= 32 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 32,8,1, 1}; - // channels_last - if (s == 1 && fx <= 48 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 32,1,8, 1}; - if (s == 1 && fx <= 32 && fy <= 1) spec = {(void*)upfirdn2d_kernel_small, 32,1,8, 1}; - } - if (p.up.x == 1 && p.up.y == 1 && p.down.x == 1 && p.down.y == 4) - { - // contiguous - if (s != 1 && fx <= 1 && fy <= 48) spec = {(void*)upfirdn2d_kernel_small, 32,8,1, 1}; - if (s != 1 && fx <= 1 && fy <= 32) spec = {(void*)upfirdn2d_kernel_small, 32,8,1, 1}; - // channels_last - if (s == 1 && fx <= 1 && fy <= 48) spec = {(void*)upfirdn2d_kernel_small, 1,32,8, 1}; - if (s == 1 && fx <= 1 && fy <= 32) spec = {(void*)upfirdn2d_kernel_small, 1,32,8, 1}; - } - return spec; -} - -//------------------------------------------------------------------------ -// Template specializations. - -template upfirdn2d_kernel_spec choose_upfirdn2d_kernel (const upfirdn2d_kernel_params& p); -template upfirdn2d_kernel_spec choose_upfirdn2d_kernel (const upfirdn2d_kernel_params& p); -template upfirdn2d_kernel_spec choose_upfirdn2d_kernel(const upfirdn2d_kernel_params& p); - -//------------------------------------------------------------------------ diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.h b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.h deleted file mode 100644 index 2793daf874..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// -// NVIDIA CORPORATION and its licensors retain all intellectual property -// and proprietary rights in and to this software, related documentation -// and any modifications thereto. Any use, reproduction, disclosure or -// distribution of this software and related documentation without an express -// license agreement from NVIDIA CORPORATION is strictly prohibited. - -#include - -//------------------------------------------------------------------------ -// CUDA kernel parameters. - -struct upfirdn2d_kernel_params -{ - const void* x; - const float* f; - void* y; - - int2 up; - int2 down; - int2 pad0; - int flip; - float gain; - - int4 inSize; // [width, height, channel, batch] - int4 inStride; - int2 filterSize; // [width, height] - int2 filterStride; - int4 outSize; // [width, height, channel, batch] - int4 outStride; - int sizeMinor; - int sizeMajor; - - int loopMinor; - int loopMajor; - int loopX; - int launchMinor; - int launchMajor; -}; - -//------------------------------------------------------------------------ -// CUDA kernel specialization. - -struct upfirdn2d_kernel_spec -{ - void* kernel; - int tileOutW; - int tileOutH; - int loopMinor; - int loopX; -}; - -//------------------------------------------------------------------------ -// CUDA kernel selection. - -template upfirdn2d_kernel_spec choose_upfirdn2d_kernel(const upfirdn2d_kernel_params& p); - -//------------------------------------------------------------------------ diff --git a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.py b/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.py deleted file mode 100644 index 701293fd52..0000000000 --- a/mmedit/models/editors/stylegan3/stylegan3_ops/ops/upfirdn2d.py +++ /dev/null @@ -1,460 +0,0 @@ -# Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# NVIDIA CORPORATION and its licensors retain all intellectual property -# and proprietary rights in and to this software, related documentation -# and any modifications thereto. Any use, reproduction, disclosure or -# distribution of this software and related documentation without an express -# license agreement from NVIDIA CORPORATION is strictly prohibited. -"""Custom PyTorch ops for efficient resampling of 2D images.""" - -import os - -import numpy as np -import torch - -from mmedit.models.base_archs.conv2d_gradfix import conv2d -# from ... import conv2d -from .. import custom_ops - -_plugin = None - - -def _init(): - global _plugin - if _plugin is None: - _plugin = custom_ops.get_plugin( - module_name='upfirdn2d_plugin', - sources=['upfirdn2d.cpp', 'upfirdn2d.cu'], - headers=['upfirdn2d.h'], - source_dir=os.path.dirname(__file__), - extra_cuda_cflags=['--use_fast_math'], - ) - return True - - -def _parse_scaling(scaling): - """parse scaling into list [x, y]""" - if isinstance(scaling, int): - scaling = [scaling, scaling] - assert isinstance(scaling, (list, tuple)) - assert all(isinstance(x, int) for x in scaling) - sx, sy = scaling - assert sx >= 1 and sy >= 1 - return sx, sy - - -def _parse_padding(padding): - """parse padding into list [padx0, padx1, pady0, pady1]""" - if isinstance(padding, int): - padding = [padding, padding] - assert isinstance(padding, (list, tuple)) - assert all(isinstance(x, int) for x in padding) - if len(padding) == 2: - padx, pady = padding - padding = [padx, padx, pady, pady] - padx0, padx1, pady0, pady1 = padding - return padx0, padx1, pady0, pady1 - - -def _get_filter_size(f): - """get width and height of filter kernel.""" - if f is None: - return 1, 1 - assert isinstance(f, torch.Tensor) and f.ndim in [1, 2] - fw = f.shape[-1] - fh = f.shape[0] - fw = int(fw) - fh = int(fh) - assert fw >= 1 and fh >= 1 - return fw, fh - - -def setup_filter(f, - device=torch.device('cpu'), - normalize=True, - flip_filter=False, - gain=1, - separable=None): - r"""Convenience function to setup 2D FIR filter for `upfirdn2d()`. - - Args: - f: Torch tensor, numpy array, or python list of the shape - `[filter_height, filter_width]` (non-separable), - `[filter_taps]` (separable), - `[]` (impulse), or - `None` (identity). - device: Result device (default: cpu). - normalize: Normalize the filter so that it retains the magnitude - for constant input signal (DC)? (default: True). - flip_filter: Flip the filter? (default: False). - gain: Overall scaling factor for signal magnitude (default: 1). - separable: Return a separable filter? (default: select automatically) - . - - Returns: - Float32 tensor of the shape - `[filter_height, filter_width]` (non-separable) or - `[filter_taps]` (separable). - """ - # Validate. - if f is None: - f = 1 - f = torch.as_tensor(f, dtype=torch.float32) - assert f.ndim in [0, 1, 2] - assert f.numel() > 0 - if f.ndim == 0: - f = f[np.newaxis] - - # Separable? - if separable is None: - separable = (f.ndim == 1 and f.numel() >= 8) - if f.ndim == 1 and not separable: - f = f.ger(f) - assert f.ndim == (1 if separable else 2) - - # Apply normalize, flip, gain, and device. - if normalize: - f /= f.sum() - if flip_filter: - f = f.flip(list(range(f.ndim))) - f = f * (gain**(f.ndim / 2)) - f = f.to(device=device) - return f - - -def upfirdn2d(x, - f, - up=1, - down=1, - padding=0, - flip_filter=False, - gain=1, - impl='cuda'): - r"""Pad, upsample, filter, and downsample a batch of 2D images. - - Performs the following sequence of operations for each channel: - - 1. Upsample the image by inserting N-1 zeros after each pixel (`up`). - - 2. Pad the image with the specified number of zeros on each side - (`padding`). Negative padding corresponds to cropping the image. - - 3. Convolve the image with the specified 2D FIR filter (`f`), shrinking it - so that the footprint of all output pixels lies within the input image. - - 4. Downsample the image by keeping every Nth pixel (`down`). - - This sequence of operations bears close resemblance to - scipy.signal.upfirdn(). - - The fused op is considerably more efficient than performing the same - calculation using standard PyTorch ops. It supports gradients of arbitrary - order. - - Args: - x: Float32/float64/float16 input tensor of the shape - `[batch_size, num_channels, in_height, in_width]`. - f: Float32 FIR filter of the shape - `[filter_height, filter_width]` (non-separable), - `[filter_taps]` (separable), or - `None` (identity). - up: Integer upsampling factor. Can be a single int or a - list/tuple - `[x, y]` (default: 1). - down: Integer downsampling factor. Can be a single int or a - list/tuple - `[x, y]` (default: 1). - padding: Padding with respect to the upsampled image. Can be a - single number or a list/tuple `[x, y]` or - `[x_before, x_after, y_before, y_after]` (default: 0). - flip_filter: False = convolution, True = correlation (default: False). - gain: Overall scaling factor for signal magnitude (default: 1). - impl: Implementation to use. Can be `'ref'` or `'cuda'` - (default: `'cuda'`). - - Returns: - Tensor of the shape `[batch_size, num_channels, out_height, out_width]` - . - """ - assert isinstance(x, torch.Tensor) - assert impl in ['ref', 'cuda'] - if impl == 'cuda' and x.device.type == 'cuda' and _init(): - return _upfirdn2d_cuda( - up=up, - down=down, - padding=padding, - flip_filter=flip_filter, - gain=gain).apply(x, f) - return _upfirdn2d_ref( - x, - f, - up=up, - down=down, - padding=padding, - flip_filter=flip_filter, - gain=gain) - - -def _upfirdn2d_ref(x, f, up=1, down=1, padding=0, flip_filter=False, gain=1): - """Slow reference implementation of `upfirdn2d()` using standard PyTorch - ops.""" - # Validate arguments. - assert isinstance(x, torch.Tensor) and x.ndim == 4 - if f is None: - f = torch.ones([1, 1], dtype=torch.float32, device=x.device) - assert isinstance(f, torch.Tensor) and f.ndim in [1, 2] - assert f.dtype == torch.float32 and not f.requires_grad - batch_size, num_channels, in_height, in_width = x.shape - upx, upy = _parse_scaling(up) - downx, downy = _parse_scaling(down) - padx0, padx1, pady0, pady1 = _parse_padding(padding) - - # Check that upsampled buffer is not smaller than the filter. - upW = in_width * upx + padx0 + padx1 - upH = in_height * upy + pady0 + pady1 - assert upW >= f.shape[-1] and upH >= f.shape[0] - - # Upsample by inserting zeros. - x = x.reshape([batch_size, num_channels, in_height, 1, in_width, 1]) - x = torch.nn.functional.pad(x, [0, upx - 1, 0, 0, 0, upy - 1]) - x = x.reshape([batch_size, num_channels, in_height * upy, in_width * upx]) - - # Pad or crop. - x = torch.nn.functional.pad( - x, [max(padx0, 0), - max(padx1, 0), - max(pady0, 0), - max(pady1, 0)]) - x = x[:, :, - max(-pady0, 0):x.shape[2] - max(-pady1, 0), - max(-padx0, 0):x.shape[3] - max(-padx1, 0)] - - # Setup filter. - f = f * (gain**(f.ndim / 2)) - f = f.to(x.dtype) - if not flip_filter: - f = f.flip(list(range(f.ndim))) - - # Convolve with the filter. - f = f[np.newaxis, np.newaxis].repeat([num_channels, 1] + [1] * f.ndim) - if f.ndim == 4: - x = conv2d(input=x, weight=f, groups=num_channels) - else: - x = conv2d(input=x, weight=f.unsqueeze(2), groups=num_channels) - x = conv2d(input=x, weight=f.unsqueeze(3), groups=num_channels) - - # Downsample by throwing away pixels. - x = x[:, :, ::downy, ::downx] - return x - - -_upfirdn2d_cuda_cache = dict() - - -def _upfirdn2d_cuda(up=1, down=1, padding=0, flip_filter=False, gain=1): - """Fast CUDA implementation of `upfirdn2d()` using custom ops.""" - # Parse arguments. - upx, upy = _parse_scaling(up) - downx, downy = _parse_scaling(down) - padx0, padx1, pady0, pady1 = _parse_padding(padding) - - # Lookup from cache. - key = (upx, upy, downx, downy, padx0, padx1, pady0, pady1, flip_filter, - gain) - if key in _upfirdn2d_cuda_cache: - return _upfirdn2d_cuda_cache[key] - - # Forward op. - class Upfirdn2dCuda(torch.autograd.Function): - - @staticmethod - def forward(ctx, x, f): # pylint: disable=arguments-differ - assert isinstance(x, torch.Tensor) and x.ndim == 4 - if f is None: - f = torch.ones([1, 1], dtype=torch.float32, device=x.device) - if f.ndim == 1 and f.shape[0] == 1: - f = f.square().unsqueeze( - 0) # Convert separable-1 into full-1x1. - assert isinstance(f, torch.Tensor) and f.ndim in [1, 2] - y = x - if f.ndim == 2: - y = _plugin.upfirdn2d(y, f, upx, upy, downx, downy, padx0, - padx1, pady0, pady1, flip_filter, gain) - else: - y = _plugin.upfirdn2d(y, f.unsqueeze(0), upx, 1, downx, 1, - padx0, padx1, 0, 0, flip_filter, 1.0) - y = _plugin.upfirdn2d(y, f.unsqueeze(1), 1, upy, 1, downy, 0, - 0, pady0, pady1, flip_filter, gain) - ctx.save_for_backward(f) - ctx.x_shape = x.shape - return y - - @staticmethod - def backward(ctx, dy): # pylint: disable=arguments-differ - f, = ctx.saved_tensors - _, _, ih, iw = ctx.x_shape - _, _, oh, ow = dy.shape - fw, fh = _get_filter_size(f) - p = [ - fw - padx0 - 1, - iw * upx - ow * downx + padx0 - upx + 1, - fh - pady0 - 1, - ih * upy - oh * downy + pady0 - upy + 1, - ] - dx = None - df = None - - if ctx.needs_input_grad[0]: - dx = _upfirdn2d_cuda( - up=down, - down=up, - padding=p, - flip_filter=(not flip_filter), - gain=gain).apply(dy, f) - - assert not ctx.needs_input_grad[1] - return dx, df - - # Add to cache. - _upfirdn2d_cuda_cache[key] = Upfirdn2dCuda - return Upfirdn2dCuda - - -def filter2d(x, f, padding=0, flip_filter=False, gain=1, impl='cuda'): - r"""Filter a batch of 2D images using the given 2D FIR filter. - - By default, the result is padded so that its shape matches the input. - User-specified padding is applied on top of that, with negative values - indicating cropping. Pixels outside the image are assumed to be zero. - - Args: - x: Float32/float64/float16 input tensor of the shape - `[batch_size, num_channels, in_height, in_width]`. - f: Float32 FIR filter of the shape - `[filter_height, filter_width]` (non-separable), - `[filter_taps]` (separable), or - `None` (identity). - padding: Padding with respect to the output. Can be a single number - or a list/tuple `[x, y]` or `[x_before, x_after, y_before, - y_after]` (default: 0). - flip_filter: False = convolution, True = correlation (default: False). - gain: Overall scaling factor for signal magnitude (default: 1). - impl: Implementation to use. Can be `'ref'` or `'cuda'` - (default: `'cuda'`). - - Returns: - Tensor of the shape `[batch_size, num_channels, out_height, - out_width]`. - """ - padx0, padx1, pady0, pady1 = _parse_padding(padding) - fw, fh = _get_filter_size(f) - p = [ - padx0 + fw // 2, - padx1 + (fw - 1) // 2, - pady0 + fh // 2, - pady1 + (fh - 1) // 2, - ] - return upfirdn2d( - x, f, padding=p, flip_filter=flip_filter, gain=gain, impl=impl) - - -def upsample2d(x, f, up=2, padding=0, flip_filter=False, gain=1, impl='cuda'): - r"""Upsample a batch of 2D images using the given 2D FIR filter. - - By default, the result is padded so that its shape is a multiple of the - input. - User-specified padding is applied on top of that, with negative values - indicating cropping. Pixels outside the image are assumed to be zero. - - Args: - x: Float32/float64/float16 input tensor of the shape - `[batch_size, num_channels, in_height, in_width]`. - f: Float32 FIR filter of the shape - `[filter_height, filter_width]` (non-separable), - `[filter_taps]` (separable), or - `None` (identity). - up: Integer upsampling factor. Can be a single int or a - list/tuple `[x, y]` (default: 1). - padding: Padding with respect to the output. Can be a single number - or a list/tuple `[x, y]` or `[x_before, x_after, y_before, - y_after]` (default: 0). - flip_filter: False = convolution, True = correlation (default: False). - gain: Overall scaling factor for signal magnitude (default: 1). - impl: Implementation to use. Can be `'ref'` or `'cuda'` - (default: `'cuda'`). - - Returns: - Tensor of the shape `[batch_size, num_channels, out_height, out_width]` - . - """ - upx, upy = _parse_scaling(up) - padx0, padx1, pady0, pady1 = _parse_padding(padding) - fw, fh = _get_filter_size(f) - p = [ - padx0 + (fw + upx - 1) // 2, - padx1 + (fw - upx) // 2, - pady0 + (fh + upy - 1) // 2, - pady1 + (fh - upy) // 2, - ] - return upfirdn2d( - x, - f, - up=up, - padding=p, - flip_filter=flip_filter, - gain=gain * upx * upy, - impl=impl) - - -def downsample2d(x, - f, - down=2, - padding=0, - flip_filter=False, - gain=1, - impl='cuda'): - r"""Downsample a batch of 2D images using the given 2D FIR filter. - - By default, the result is padded so that its shape is a fraction of the - input. - User-specified padding is applied on top of that, with negative values - indicating cropping. Pixels outside the image are assumed to be zero. - - Args: - x: Float32/float64/float16 input tensor of the shape - `[batch_size, num_channels, in_height, in_width]`. - f: Float32 FIR filter of the shape - `[filter_height, filter_width]` (non-separable), - `[filter_taps]` (separable), or - `None` (identity). - down: Integer downsampling factor. Can be a single int or a - list/tuple `[x, y]` (default: 1). - padding: Padding with respect to the input. Can be a single number - or a list/tuple `[x, y]` or `[x_before, x_after, y_before, - y_after]` (default: 0). - flip_filter: False = convolution, True = correlation (default: False). - gain: Overall scaling factor for signal magnitude (default: 1). - impl: Implementation to use. Can be `'ref'` or `'cuda'` - (default: `'cuda'`). - - Returns: - Tensor of the shape `[batch_size, num_channels, out_height, out_width]` - . - """ - downx, downy = _parse_scaling(down) - padx0, padx1, pady0, pady1 = _parse_padding(padding) - fw, fh = _get_filter_size(f) - p = [ - padx0 + (fw - downx + 1) // 2, - padx1 + (fw - downx) // 2, - pady0 + (fh - downy + 1) // 2, - pady1 + (fh - downy) // 2, - ] - return upfirdn2d( - x, - f, - down=down, - padding=p, - flip_filter=flip_filter, - gain=gain, - impl=impl) diff --git a/mmedit/models/editors/stylegan3/stylegan3_utils.py b/mmedit/models/editors/stylegan3/stylegan3_utils.py index 7179aa0e42..b3b3a628e6 100644 --- a/mmedit/models/editors/stylegan3/stylegan3_utils.py +++ b/mmedit/models/editors/stylegan3/stylegan3_utils.py @@ -2,7 +2,14 @@ import numpy as np import torch -from .stylegan3_ops.ops import upfirdn2d +try: + from mmcv.ops import filter2d, upsample2d +except ImportError: + filter2d = None + upsample2d = None + print( + 'Warning: mmcv.ops.filter2d and mmcv.ops.upsample2d are not available.' + ) def apply_integer_translation(x, tx, ty): @@ -47,10 +54,8 @@ def apply_fractional_translation(x, tx, ty, a=3): filter_x = (sinc(taps - fx) * sinc((taps - fx) / a)).unsqueeze(0) filter_y = (sinc(taps - fy) * sinc((taps - fy) / a)).unsqueeze(1) y = x - y = upfirdn2d.filter2d( - y, filter_x / filter_x.sum(), padding=[b, a, 0, 0]) - y = upfirdn2d.filter2d( - y, filter_y / filter_y.sum(), padding=[0, 0, b, a]) + y = filter2d(y, filter_x / filter_x.sum(), padding=[b, a, 0, 0]) + y = filter2d(y, filter_y / filter_y.sum(), padding=[0, 0, b, a]) y = y[:, :, max(b - iy, 0):H + b + a + min(-iy - a, 0), max(b - ix, 0):W + b + a + min(-ix - a, 0)] @@ -141,7 +146,7 @@ def apply_affine_transformation(x, mat, up=4, **filter_kwargs): g = torch.nn.functional.affine_grid(theta, x.shape, align_corners=False) # Resample image. - y = upfirdn2d.upsample2d(x=x, f=f, up=up, padding=p) + y = upsample2d(input=x, filter=f, up=up, padding=p) z = torch.nn.functional.grid_sample( y, g, mode='bilinear', padding_mode='zeros', align_corners=False) @@ -166,7 +171,7 @@ def apply_fractional_pseudo_rotation(x, angle, a=3, **filter_kwargs): mat = rotation_matrix(-angle) f = construct_affine_bandlimit_filter( mat, a=a, amax=a * 2, up=1, **filter_kwargs) - y = upfirdn2d.filter2d(x=x, f=f) + y = filter2d(input=x, filter=f) m = torch.zeros_like(y) c = f.shape[0] // 2 m[:, :, c:-c, c:-c] = 1 diff --git a/tests/test_evaluation/test_metrics/test_equivariance.py b/tests/test_evaluation/test_metrics/test_equivariance.py index 07f333ad08..743c341ecd 100644 --- a/tests/test_evaluation/test_metrics/test_equivariance.py +++ b/tests/test_evaluation/test_metrics/test_equivariance.py @@ -67,20 +67,3 @@ def test_eq_cuda(self): eq_res = eq.compute_metrics(eq.fake_results) isinstance(eq_res['eqt_int'], float) and isinstance( eq_res['eqt_frac'], float) and isinstance(eq_res['eqr'], float) - - @torch.no_grad() - def test_eq_cpu(self): - eq = Equivariance( - 2, - eq_cfg=dict( - compute_eqt_int=True, compute_eqt_frac=True, compute_eqr=True), - sample_mode='orig') - sampler = eq.get_metric_sampler(self.module, self.dataloader, [eq]) - eq.prepare(self.module, self.dataloader) - for data_batch in sampler: - predictions = self.module.test_step(data_batch) - _data_batch, _predictions = process_fn(data_batch, predictions) - eq.process(_data_batch, _predictions) - eq_res = eq.compute_metrics(eq.fake_results) - isinstance(eq_res['eqt_int'], float) and isinstance( - eq_res['eqt_frac'], float) and isinstance(eq_res['eqr'], float) diff --git a/tests/test_models/test_editors/test_eg3d/test_dual_discriminator.py b/tests/test_models/test_editors/test_eg3d/test_dual_discriminator.py index e4e28338d9..05d0d742b2 100644 --- a/tests/test_models/test_editors/test_eg3d/test_dual_discriminator.py +++ b/tests/test_models/test_editors/test_eg3d/test_dual_discriminator.py @@ -1,7 +1,9 @@ # Copyright (c) OpenMMLab. All rights reserved. +import platform from copy import deepcopy from unittest import TestCase +import pytest import torch from mmedit.models.editors.eg3d.dual_discriminator import DualDiscriminator @@ -25,6 +27,9 @@ def test_init(self): self.assertEqual(disc.convs[0][0].conv.weight.shape[1], 2) self.assertFalse(disc.use_dual_disc) + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_forward(self): cfg = deepcopy(self.default_cfg) disc = DualDiscriminator(**cfg) diff --git a/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2.py b/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2.py index a4e361bfb7..9f998bec3c 100644 --- a/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2.py +++ b/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2.py @@ -41,7 +41,8 @@ def setup_class(cls): pl_batch_shrink=2) @pytest.mark.skipif( - 'win' in platform.system().lower() and 'cu' in torch.__version__, + ('win' in platform.system().lower() and 'cu' in torch.__version__) + or not torch.cuda.is_available(), reason='skip on windows-cuda due to limited RAM.') def test_stylegan2_cpu(self): accu_iter = 1 diff --git a/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_generator.py b/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_generator.py index ba82def074..5fc70ad695 100644 --- a/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_generator.py +++ b/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_generator.py @@ -1,6 +1,8 @@ # Copyright (c) OpenMMLab. All rights reserved. +import platform from copy import deepcopy +import pytest import torch import torch.nn as nn @@ -24,6 +26,9 @@ class TestMSStyleGAN2: def setup_class(cls): cls.default_cfg = dict(out_size=32, style_channels=16) + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_msstylegan2_cpu(self): # test normal forward @@ -112,6 +117,9 @@ def test_mean_latent(self): mean_latent = g.get_mean_latent(num_samples=4, bs_per_repeat=2) assert mean_latent.shape == (1, 16) + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_head_pos_encoding(self): cfg = deepcopy(self.default_cfg) g = MSStyleGANv2Generator(**cfg, head_pos_encoding=dict(type='CSG')) diff --git a/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_modules.py b/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_modules.py index 010ee668ef..02782ec5db 100644 --- a/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_modules.py +++ b/tests/test_models/test_editors/test_mspie/test_mspie_stylegan2_modules.py @@ -1,7 +1,9 @@ # Copyright (c) OpenMMLab. All rights reserved. +import platform from copy import deepcopy from unittest import TestCase +import pytest import torch from mmedit.models.editors.mspie.mspie_stylegan2_modules import ( @@ -15,6 +17,9 @@ def setUpClass(cls): cls.default_cfg = dict( in_channels=8, out_channels=8, kernel_size=3, style_channels=16) + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_upsample(self): cfg = deepcopy(self.default_cfg) conv = ModulatedPEStyleConv(**cfg, upsample=True) @@ -31,6 +36,9 @@ def test_upsample(self): out, noise_return = conv(x, style, noise, return_noise=True) assert (noise_return == noise).all() + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_downsample(self): cfg = deepcopy(self.default_cfg) @@ -56,6 +64,9 @@ def setUpClass(cls): cls.default_cfg = dict( in_channels=8, out_channels=8, kernel_size=3, style_channels=16) + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_equalized_lr_cfg(self): cfg = deepcopy(self.default_cfg) conv = ModulatedPEConv2d(**cfg, equalized_lr_cfg=None) @@ -64,6 +75,9 @@ def test_equalized_lr_cfg(self): out = conv(x, style) self.assertEqual(out.shape, (1, 8, 32, 32)) + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_demodulate(self): cfg = deepcopy(self.default_cfg) conv = ModulatedPEConv2d(**cfg, demodulate=False) @@ -72,6 +86,9 @@ def test_demodulate(self): out = conv(x, style) self.assertEqual(out.shape, (1, 8, 32, 32)) + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_up_after_conv(self): x = torch.randn(1, 8, 32, 32) style = torch.randn(1, 16) diff --git a/tests/test_models/test_editors/test_stylegan2/test_ada/test_augment.py b/tests/test_models/test_editors/test_stylegan2/test_ada/test_augment.py index 28cbec2685..2b34692c68 100644 --- a/tests/test_models/test_editors/test_stylegan2/test_ada/test_augment.py +++ b/tests/test_models/test_editors/test_stylegan2/test_ada/test_augment.py @@ -1,4 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. +import platform from unittest import TestCase import pytest @@ -45,8 +46,10 @@ def setUpClass(cls): ) @pytest.mark.skipif( - digit_version(TORCH_VERSION) <= digit_version('1.6.0'), - reason='torch version lower than 1.7.0 does not have `torch.exp2` api') + digit_version(TORCH_VERSION) <= digit_version('1.6.0') + or 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason=('torch version lower than 1.7.0 does not have ' + '`torch.exp2` api, skip on windows due to uncompiled ops.')) def test_forward(self): augment_pipeline = AugmentPipe(**self.default_cfg) diff --git a/tests/test_models/test_editors/test_stylegan2/test_stylegan2_discriminator.py b/tests/test_models/test_editors/test_stylegan2/test_stylegan2_discriminator.py index 9bbe902f4a..0d9b2a2edd 100644 --- a/tests/test_models/test_editors/test_stylegan2/test_stylegan2_discriminator.py +++ b/tests/test_models/test_editors/test_stylegan2/test_stylegan2_discriminator.py @@ -14,7 +14,8 @@ @pytest.mark.skipif( - 'win' in platform.system().lower() and 'cu' in torch.__version__, + ('win' in platform.system().lower() and 'cu' in torch.__version__) + or not torch.cuda.is_available(), reason='skip on windows-cuda due to limited RAM.') class TestStyleGANv2Disc: diff --git a/tests/test_models/test_editors/test_stylegan3/test_stylegan3.py b/tests/test_models/test_editors/test_stylegan3/test_stylegan3.py index ff4e31d0dd..fc0b808761 100644 --- a/tests/test_models/test_editors/test_stylegan3/test_stylegan3.py +++ b/tests/test_models/test_editors/test_stylegan3/test_stylegan3.py @@ -1,7 +1,9 @@ # Copyright (c) OpenMMLab. All rights reserved. +import platform from copy import deepcopy from unittest import TestCase +import pytest import torch from mmengine import MessageHub from mmengine.optim import OptimWrapper, OptimWrapperDict @@ -50,6 +52,9 @@ def setUpClass(cls): g_reg_weight=8.0, pl_batch_shrink=2)) + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_val_and_test_step(self): cfg = deepcopy(self.default_cfg) stylegan = StyleGAN3(**cfg) @@ -70,6 +75,9 @@ def test_val_and_test_step(self): outputs = stylegan.test_step(data) outputs = stylegan.val_step(data) + @pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_train_step(self): message_hub = MessageHub.get_instance('test-s3-train-step') cfg = deepcopy(self.default_cfg) diff --git a/tests/test_models/test_editors/test_stylegan3/test_stylegan3_generator.py b/tests/test_models/test_editors/test_stylegan3/test_stylegan3_generator.py index 61bad9f107..061556441c 100644 --- a/tests/test_models/test_editors/test_stylegan3/test_stylegan3_generator.py +++ b/tests/test_models/test_editors/test_stylegan3/test_stylegan3_generator.py @@ -40,7 +40,8 @@ def setup_class(cls): synthesis_cfg=synthesis_r_cfg) @pytest.mark.skipif( - 'win' in platform.system().lower() and 'cu' in torch.__version__, + ('win' in platform.system().lower() and 'cu' in torch.__version__) + or not torch.cuda.is_available(), reason='skip on windows-cuda due to limited RAM.') def test_cpu(self): generator = StyleGAN3Generator(**self.default_cfg) diff --git a/tests/test_models/test_editors/test_stylegan3/test_stylegan3_modules.py b/tests/test_models/test_editors/test_stylegan3/test_stylegan3_modules.py index 8f21ee83ed..63192ab195 100644 --- a/tests/test_models/test_editors/test_stylegan3/test_stylegan3_modules.py +++ b/tests/test_models/test_editors/test_stylegan3/test_stylegan3_modules.py @@ -1,10 +1,15 @@ # Copyright (c) OpenMMLab. All rights reserved. +import platform + import pytest import torch from mmedit.models.editors.stylegan3.stylegan3_modules import MappingNetwork +@pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip on windows due to uncompiled ops.') def test_MappingNetwork(): mapping_network = MappingNetwork(16, 4, 5, cond_size=8) z = torch.randn(1, 16) diff --git a/tests/test_models/test_editors/test_stylegan3/test_stylegan3_utils.py b/tests/test_models/test_editors/test_stylegan3/test_stylegan3_utils.py index b995f0baae..4248c7ba45 100644 --- a/tests/test_models/test_editors/test_stylegan3/test_stylegan3_utils.py +++ b/tests/test_models/test_editors/test_stylegan3/test_stylegan3_utils.py @@ -1,4 +1,6 @@ # Copyright (c) OpenMMLab. All rights reserved. +import platform + import pytest import torch from mmengine.utils.dl_utils import TORCH_VERSION @@ -9,6 +11,9 @@ apply_fractional_translation, apply_integer_translation) +@pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip due to uncompiled ops.') def test_integer_transformation(): x = torch.randn(1, 3, 16, 16) t = torch.randn(2) @@ -24,6 +29,9 @@ def test_integer_transformation(): z, m = apply_integer_translation(x, t[0], t[1]) +@pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip due to uncompiled ops.') def test_fractional_translation(): x = torch.randn(1, 3, 16, 16) t = torch.randn(2) @@ -39,6 +47,9 @@ def test_fractional_translation(): z, m = apply_fractional_translation(x, t[0], t[1]) +@pytest.mark.skipif( + 'win' in platform.system().lower() or not torch.cuda.is_available(), + reason='skip due to uncompiled ops.') @pytest.mark.skipif( digit_version(TORCH_VERSION) < digit_version('1.8.0'), reason='version limitation') @@ -51,7 +62,8 @@ def test_fractional_rotation(): @pytest.mark.skipif( - digit_version(TORCH_VERSION) < digit_version('1.8.0'), + digit_version(TORCH_VERSION) < digit_version('1.8.0') + or 'win' in platform.system().lower() or not torch.cuda.is_available(), reason='version limitation') def test_fractional_pseduo_rotation(): angle = torch.randn([]) From 16d8ec0ea73076faad4d1f6bb7085112080e5959 Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Thu, 6 Apr 2023 10:19:45 +0800 Subject: [PATCH 23/39] [Feature] Support demo dataset for ControlNet (#1702) support demo dataset for controlnet --- mmedit/datasets/__init__.py | 3 +- mmedit/datasets/controlnet_dataset.py | 59 +++++++++++++++++++ tests/data/controlnet/prompt.json | 2 + tests/data/controlnet/source/0.png | 0 tests/data/controlnet/source/1.png | 0 .../test_datasets/test_controlnet_dataset.py | 24 ++++++++ 6 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 mmedit/datasets/controlnet_dataset.py create mode 100644 tests/data/controlnet/prompt.json create mode 100644 tests/data/controlnet/source/0.png create mode 100644 tests/data/controlnet/source/1.png create mode 100644 tests/test_datasets/test_controlnet_dataset.py diff --git a/mmedit/datasets/__init__.py b/mmedit/datasets/__init__.py index 91de4a8ac9..22eca611ee 100644 --- a/mmedit/datasets/__init__.py +++ b/mmedit/datasets/__init__.py @@ -4,6 +4,7 @@ from .basic_image_dataset import BasicImageDataset from .cifar10_dataset import CIFAR10 from .comp1k_dataset import AdobeComp1kDataset +from .controlnet_dataset import ControlNetDataset from .grow_scale_image_dataset import GrowScaleImgDataset from .imagenet_dataset import ImageNet from .mscoco_dataset import MSCoCoDataset @@ -15,5 +16,5 @@ 'AdobeComp1kDataset', 'BasicImageDataset', 'BasicFramesDataset', 'BasicConditionalDataset', 'UnpairedImageDataset', 'PairedImageDataset', 'ImageNet', 'CIFAR10', 'GrowScaleImgDataset', 'SinGANDataset', - 'MSCoCoDataset' + 'MSCoCoDataset', 'ControlNetDataset' ] diff --git a/mmedit/datasets/controlnet_dataset.py b/mmedit/datasets/controlnet_dataset.py new file mode 100644 index 0000000000..417fb40b93 --- /dev/null +++ b/mmedit/datasets/controlnet_dataset.py @@ -0,0 +1,59 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import json +import os +from typing import Callable, List, Union + +from mmengine.dataset import BaseDataset + +from mmedit.registry import DATASETS + + +@DATASETS.register_module() +class ControlNetDataset(BaseDataset): + """Demo dataset to test ControlNet. Modified from https://github.com/lllyas + viel/ControlNet/blob/16ea3b5379c1e78a4bc8e3fc9cae8d65c42511b1/tutorial_data + set.py # noqa. + + You can download the demo data from https://huggingface.co/lllyasviel/ControlNet/blob/main/training/fill50k.zip # noqa + and then unzip the file to the ``data`` folder. + + Args: + ann_file (str): Path to the annotation file. Defaults + to 'prompt.json' as ControlNet's default. + data_root (str): Path to the data root. Defaults to './data/fill50k'. + pipeline (list[dict | callable]): A sequence of data transforms. + """ + + def __init__(self, + ann_file: str = 'prompt.json', + data_root: str = './data/fill50k', + pipeline: List[Union[dict, Callable]] = []): + super().__init__( + ann_file=ann_file, data_root=data_root, pipeline=pipeline) + + def load_data_list(self) -> List[dict]: + """Load annotations from an annotation file named as ``self.ann_file`` + + Returns: + list[dict]: A list of annotation. + """ + data_list = [] + with open(self.ann_file, 'rt') as file: + anno_list = file.readlines() + + for anno in anno_list: + anno = json.loads(anno) + source = anno['source'] + target = anno['target'] + prompt = anno['prompt'] + + source = os.path.join(self.data_root, source) + target = os.path.join(self.data_root, target) + + data_list.append({ + 'source_path': source, + 'target_path': target, + 'prompt': prompt + }) + + return data_list diff --git a/tests/data/controlnet/prompt.json b/tests/data/controlnet/prompt.json new file mode 100644 index 0000000000..5f31400b4f --- /dev/null +++ b/tests/data/controlnet/prompt.json @@ -0,0 +1,2 @@ +{"source": "source/0.png", "target": "target/0.png", "prompt": "pale golden rod circle with old lace background"} +{"source": "source/1.png", "target": "target/1.png", "prompt": "light coral circle with white background"} diff --git a/tests/data/controlnet/source/0.png b/tests/data/controlnet/source/0.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/data/controlnet/source/1.png b/tests/data/controlnet/source/1.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_datasets/test_controlnet_dataset.py b/tests/test_datasets/test_controlnet_dataset.py new file mode 100644 index 0000000000..9a36ea9f70 --- /dev/null +++ b/tests/test_datasets/test_controlnet_dataset.py @@ -0,0 +1,24 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os + +from mmedit.datasets import ControlNetDataset + +data_dir = os.path.join(__file__, '../', '../', 'data', 'controlnet') +data_dir = os.path.abspath(data_dir) +anno_path = os.path.join(data_dir, 'prompt.json') +source_path = os.path.join(data_dir, 'source') +target_path = os.path.join(data_dir, 'target') + + +def test_controlnet_dataset(): + print(os.path.abspath(data_dir)) + dataset = ControlNetDataset(data_root=data_dir) + assert len(dataset) == 2 + prompts = [ + 'pale golden rod circle with old lace background', + 'light coral circle with white background' + ] + for idx, data in enumerate(dataset): + assert 'source_path' in data + assert 'target_path' in data + assert data['prompt'] == prompts[idx] From 84e741a9a36f0af07e9dcd13a16252d1f2b447af Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Thu, 6 Apr 2023 11:47:09 +0800 Subject: [PATCH 24/39] [Enhancement] Revise `ClipWrapper` to support HuggingFace `Transformers` (#1704) * support transformers.CLIPTextModel in ClipWrapper * add unit test for clip wrapper and revise docstring * remame unit test to avoid CI error * add open_clip in tests requirements * remove open_clip from test requirements to avoid modify installed torch version * revise mock operation to avoid install open_clip * revise docstring of CLIP wrapper as comment --- .../editors/disco_diffusion/clip_wrapper.py | 69 +++++++++++++------ .../test_disco_diffusion_clip_wrapper.py | 62 +++++++++++++++++ 2 files changed, 111 insertions(+), 20 deletions(-) create mode 100644 tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion_clip_wrapper.py diff --git a/mmedit/models/editors/disco_diffusion/clip_wrapper.py b/mmedit/models/editors/disco_diffusion/clip_wrapper.py index 072c30be3a..3aa83742fa 100644 --- a/mmedit/models/editors/disco_diffusion/clip_wrapper.py +++ b/mmedit/models/editors/disco_diffusion/clip_wrapper.py @@ -7,7 +7,7 @@ @MODELS.register_module() class ClipWrapper(nn.Module): - """Clip Models wrapper for disco-diffusion. + r"""Clip Models wrapper. We provide wrappers for the clip models of ``openai`` and ``mlfoundations``, where the user can specify ``clip_type`` @@ -15,8 +15,7 @@ class ClipWrapper(nn.Module): using the same arguments as in the original codebase. The following clip models settings are provided in the official repo of disco diffusion: - - | Setting | Source | Arguments | # noqa +| Setting | Source | Arguments | # noqa |:-----------------------------:|-----------|--------------------------------------------------------------| # noqa | ViTB32 | clip | name='ViT-B/32', jit=False | # noqa | ViTB16 | clip | name='ViT-B/16', jit=False | # noqa @@ -42,44 +41,74 @@ class ClipWrapper(nn.Module): | RN101_quickgelu_yfcc15m | open_clip | model_name='RN101-quickgelu', pretrained='yfcc15m' | # noqa An example of a ``clip_modes_cfg`` is as follows: - .. code-block:: python - clip_models = [ - dict(type='ClipWrapper', clip_type='clip', name='ViT-B/32', jit=False), - dict(type='ClipWrapper', clip_type='clip', name='ViT-B/16', jit=False), - dict(type='ClipWrapper', clip_type='clip', name='RN50', jit=False) - ] + Examples: + + >>> # Use OpenAI's CLIP + >>> config = dict( + >>> type='ClipWrapper', + >>> clip_type='clip', + >>> name='ViT-B/32', + >>> jit=False) + + >>> # Use OpenCLIP + >>> config = dict( + >>> type='ClipWrapper', + >>> clip_type='open_clip', + >>> model_name='RN50', + >>> pretrained='yfcc15m') + + >>> # Use CLIP from Hugging Face Transformers + >>> config = dict( + >>> type='ClipWrapper', + >>> clip_type='huggingface', + >>> pretrained_model_name_or_path='runwayml/stable-diffusion-v1-5', + >>> subfolder='text_encoder') Args: clip_type (List[Dict]): The original source of the clip model. Whether be - ``clip`` or ``open_clip``. + ``clip``, ``open_clip`` or ``hugging_face``. + + *args, **kwargs: Arguments to initialize corresponding clip model. """ def __init__(self, clip_type, *args, **kwargs): super().__init__() self.clip_type = clip_type - assert clip_type in ['clip', 'open_clip'] + assert clip_type in ['clip', 'open_clip', 'huggingface'] + + error_msg = ('{} need to be installed! Run `pip install -r ' + 'requirements/optional.txt` and try again') if clip_type == 'clip': try: import clip except ImportError: - raise ImportError( - 'clip need to be installed! Run `pip install -r requirements/optional.txt` and try again' # noqa - ) # noqa + raise ImportError(error_msg.format('\'clip\'')) print_log(f'Creating {kwargs["name"]} by OpenAI', 'current') self.model, _ = clip.load(*args, **kwargs) elif clip_type == 'open_clip': try: import open_clip except ImportError: - raise ImportError( - 'open_clip_torch need to be installed! Run `pip install -r requirements/optional.txt` and try again' # noqa - ) # noqa - print_log( - f'Creating {kwargs["model_name"]} by mlfoundations', # noqa - 'current') + raise ImportError(error_msg.format('\'open_clip_torch\'')) + print_log(f'Creating {kwargs["model_name"]} by ' + 'mlfoundations', 'current') self.model = open_clip.create_model(*args, **kwargs) + + elif clip_type == 'huggingface': + try: + import transformers + except ImportError: + raise ImportError(error_msg.format('\'transforms\'')) + # NOTE: use CLIPTextModel to adopt stable diffusion pipeline + model_cls = transformers.CLIPTextModel + self.model = model_cls.from_pretrained(*args, **kwargs) + self.config = self.model.config + print_log( + f'Creating {self.model.name_or_path} ' + 'by \'HuggingFace\'', 'current') + self.model.eval().requires_grad_(False) def forward(self, *args, **kwargs): diff --git a/tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion_clip_wrapper.py b/tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion_clip_wrapper.py new file mode 100644 index 0000000000..b9723d90a1 --- /dev/null +++ b/tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion_clip_wrapper.py @@ -0,0 +1,62 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase +from unittest.mock import MagicMock, patch + +from mmedit.models.editors import ClipWrapper + + +class TestClipWrapper(TestCase): + + def test_clip_not_installed(self): + with patch.dict('sys.modules', {'clip': None}): + with self.assertRaises(ImportError): + ClipWrapper('clip') + + def test_open_clip_not_installed(self): + with patch.dict('sys.modules', {'open_clip': None}): + with self.assertRaises(ImportError): + ClipWrapper('open_clip') + + def test_transformers_not_installed(self): + with patch.dict('sys.modules', {'transformers': None}): + with self.assertRaises(ImportError): + ClipWrapper('huggingface') + + @patch('clip.load') + def test_clip_load(self, mock_clip_load): + mock_model = MagicMock() + mock_clip_load.return_value = (mock_model, None) + + model = ClipWrapper('clip', name='test_model') + + mock_clip_load.assert_called_once_with(name='test_model') + self.assertEqual(model.model, mock_model) + + def test_open_clip_load(self): + mock_model = MagicMock() + create_model_mock = MagicMock() + create_model_mock.return_value = mock_model + + open_clip_mock = MagicMock() + open_clip_mock.create_model = create_model_mock + + with patch.dict('sys.modules', {'open_clip': open_clip_mock}): + model = ClipWrapper('open_clip', model_name='RN50') + create_model_mock.assert_called_once_with(model_name='RN50') + self.assertEqual(model.model, mock_model) + + @patch('transformers.CLIPTextModel.from_pretrained') + def test_huggingface_load(self, mock_from_pretrained): + mock_model = MagicMock() + mock_model.config = MagicMock() + mock_from_pretrained.return_value = mock_model + + model = ClipWrapper( + 'huggingface', + pretrained_model_name_or_path='runwayml/stable-diffusion-v1-5', + subfolder='text_encoder') + mock_from_pretrained.assert_called_once_with( + pretrained_model_name_or_path='runwayml/stable-diffusion-v1-5', + subfolder='text_encoder') + self.assertEqual(model.model, mock_model) + self.assertEqual(model.model.config, mock_model.config) From 55da47c2ada1598c6d32de919ccc7390a13627fe Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 6 Apr 2023 14:37:05 +0800 Subject: [PATCH 25/39] [Fix] fix upfirdn2d arguments (#1729) * [Fix] fix upfirdn2d arguments * fix ada * fix torch min version --- .circleci/test.yml | 6 +++--- mmedit/models/editors/stylegan1/stylegan1_modules.py | 2 +- mmedit/models/editors/stylegan2/stylegan2_modules.py | 8 ++++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.circleci/test.yml b/.circleci/test.yml index 31deec713a..f3333c9ee7 100644 --- a/.circleci/test.yml +++ b/.circleci/test.yml @@ -140,8 +140,8 @@ workflows: - 1.x - build_cpu: name: minimum_version_cpu - torch: 1.6.0 - torchvision: 0.7.0 + torch: 1.8.1 + torchvision: 0.9.1 python: 3.7.4 requires: - lint @@ -171,7 +171,7 @@ workflows: jobs: - build_cuda: name: minimum_version_gpu - torch: 1.6.0 + torch: 1.8.1 # Use double quotation mark to explicitly specify its type # as string instead of number cuda: "10.1" diff --git a/mmedit/models/editors/stylegan1/stylegan1_modules.py b/mmedit/models/editors/stylegan1/stylegan1_modules.py index 4df41f1ea1..5987411526 100644 --- a/mmedit/models/editors/stylegan1/stylegan1_modules.py +++ b/mmedit/models/editors/stylegan1/stylegan1_modules.py @@ -212,7 +212,7 @@ def forward(self, x): """ # In Tero's implementation, he uses fp32 - return upfirdn2d(x, self.kernel.to(x.dtype), pad=self.pad) + return upfirdn2d(x, self.kernel.to(x.dtype), padding=self.pad) class AdaptiveInstanceNorm(nn.Module): diff --git a/mmedit/models/editors/stylegan2/stylegan2_modules.py b/mmedit/models/editors/stylegan2/stylegan2_modules.py index a1faa0e423..db7fd163e8 100644 --- a/mmedit/models/editors/stylegan2/stylegan2_modules.py +++ b/mmedit/models/editors/stylegan2/stylegan2_modules.py @@ -74,7 +74,11 @@ def forward(self, x): Tensor: Output feature map. """ out = upfirdn2d( - x, self.kernel.to(x.dtype), up=self.factor, down=1, pad=self.pad) + x, + self.kernel.to(x.dtype), + up=self.factor, + down=1, + padding=self.pad) return out @@ -117,7 +121,7 @@ def forward(self, input): self.kernel.to(input.dtype), up=1, down=self.factor, - pad=self.pad) + padding=self.pad) return out From 2156a18257afd046731facee544e996cb2a8261e Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 6 Apr 2023 15:56:30 +0800 Subject: [PATCH 26/39] [Fix] update github actions to Ubuntu 22.04 (#1735) * [Fix] update github actions to Ubuntu 22.04 * [Fix] update github actions to Ubuntu 22.04 * [Fix] update github actions to Ubuntu 22.04 * [Fix] update github actions to Ubuntu 22.04 * [Fix] update github actions to Ubuntu 22.04 * [Fix] update github actions to Ubuntu 22.04 * [Fix] update github actions to Ubuntu 22.04 * [Fix] update github actions to Ubuntu 22.04 * fix python * fix libc * fix libc * fix libc --- .github/workflows/merge_stage_test.yml | 59 +++++++++++--------------- .github/workflows/pr_stage_test.yml | 33 ++++++-------- 2 files changed, 39 insertions(+), 53 deletions(-) diff --git a/.github/workflows/merge_stage_test.yml b/.github/workflows/merge_stage_test.yml index 0e395cdde5..455cace6f9 100644 --- a/.github/workflows/merge_stage_test.yml +++ b/.github/workflows/merge_stage_test.yml @@ -23,7 +23,7 @@ concurrency: jobs: build_cpu_py: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.8, 3.9] @@ -32,15 +32,15 @@ jobs: - torch: 1.8.1 torchvision: 0.9.1 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade - name: Install PyTorch - run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu -f https://download.pytorch.org/whl/torch_stable.html + run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html - name: Install MMEngine run: pip install git+https://github.com/open-mmlab/mmengine.git@main - name: Install MMCV @@ -59,7 +59,7 @@ jobs: coverage report -m build_cpu_pt: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.7] @@ -82,15 +82,15 @@ jobs: - torch: 1.13.0 torchvision: 0.14.0 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade - name: Install PyTorch - run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu -f https://download.pytorch.org/whl/torch_stable.html + run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html - name: Install MMEngine run: pip install git+https://github.com/open-mmlab/mmengine.git@main - name: Install MMCV @@ -119,7 +119,7 @@ jobs: fail_ci_if_error: false build_cu102: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 container: image: pytorch/pytorch:1.8.1-cuda10.2-cudnn7-devel strategy: @@ -129,25 +129,22 @@ jobs: - torch: 1.8.1 cuda: 10.2 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade - name: Fetch GPG keys run: | - apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub - apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub - - name: Install Python-dev - run: apt-get update && apt-get install -y python${{matrix.python-version}}-dev - if: ${{matrix.python-version != 3.9}} + apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/3bf863cc.pub + apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu2204/x86_64/7fa2af80.pub - name: Install system dependencies run: | apt-get update && apt-get install -y ffmpeg libsm6 libxext6 git ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 - name: Install PyTorch - run: python -m pip install torch==1.8.1+cpu torchvision==0.9.1+cpu -f https://download.pytorch.org/whl/lts/1.8/torch_lts.html + run: pip install torch==1.8.1+cpu torchvision==0.9.1+cpu -f https://download.pytorch.org/whl/lts/1.8/torch_lts.html - name: Install mmediting dependencies run: | pip install -U openmim @@ -155,11 +152,10 @@ jobs: pip install -r requirements/tests.txt - name: Build and install run: | - python setup.py check -m -s - TORCH_CUDA_ARCH_LIST=7.0 pip install -e . + pip install -e . build_cu116: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 container: image: pytorch/pytorch:1.13.0-cuda11.6-cudnn8-devel strategy: @@ -169,25 +165,22 @@ jobs: - torch: 1.8.1 cuda: 10.2 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade - name: Fetch GPG keys run: | - apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub - apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub - - name: Install Python-dev - run: apt-get update && apt-get install -y python${{matrix.python-version}}-dev - if: ${{matrix.python-version != 3.9}} + apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/3bf863cc.pub + apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu2204/x86_64/7fa2af80.pub - name: Install system dependencies run: | apt-get update && apt-get install -y ffmpeg libsm6 libxext6 git ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 - name: Install PyTorch - run: python -m pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cpu + run: pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cpu - name: Install mmediting dependencies run: | pip install git+https://github.com/open-mmlab/mmengine.git@main @@ -196,8 +189,7 @@ jobs: pip install -r requirements/tests.txt - name: Build and install run: | - python setup.py check -m -s - TORCH_CUDA_ARCH_LIST=7.0 pip install -e . + pip install -e . - name: Run unittests and generate coverage report run: | coverage run --branch --source mmedit -m pytest tests/ @@ -205,16 +197,15 @@ jobs: coverage report -m build_windows: - runs-on: ${{ matrix.os }} + runs-on: windows-2022 strategy: matrix: - os: [windows-2022] python: [3.7] platform: [cpu, cu111] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip diff --git a/.github/workflows/pr_stage_test.yml b/.github/workflows/pr_stage_test.yml index bac567a170..fd381cb372 100644 --- a/.github/workflows/pr_stage_test.yml +++ b/.github/workflows/pr_stage_test.yml @@ -17,7 +17,7 @@ concurrency: jobs: build_cpu: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.7] @@ -25,9 +25,9 @@ jobs: - torch: 1.8.1 torchvision: 0.9.1 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip @@ -64,33 +64,30 @@ jobs: # uses: mxschmitt/action-tmate@v3 build_cu102: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 container: image: pytorch/pytorch:1.8.1-cuda10.2-cudnn7-devel strategy: matrix: python-version: [3.7] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: pip install pip --upgrade - name: Fetch GPG keys run: | - apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub - apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub - - name: Install Python-dev - run: apt-get update && apt-get install -y python${{matrix.python-version}}-dev - if: ${{matrix.python-version != 3.9}} + apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/3bf863cc.pub + apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu2204/x86_64/7fa2af80.pub - name: Install system dependencies run: | apt-get update apt-get install -y ffmpeg libsm6 libxext6 git ninja-build libglib2.0-0 libxrender-dev - name: Install PyTorch - run: python -m pip install torch==1.8.1+cpu torchvision==0.9.1+cpu -f https://download.pytorch.org/whl/torch_stable.html + run: pip install torch==1.8.1+cpu torchvision==0.9.1+cpu -f https://download.pytorch.org/whl/torch_stable.html - name: Install mmedit dependencies run: | pip install git+https://github.com/open-mmlab/mmengine.git@main @@ -99,23 +96,21 @@ jobs: pip install -r requirements/tests.txt - name: Build and install run: | - python setup.py check -m -s - TORCH_CUDA_ARCH_LIST=7.0 pip install -e . + pip install -e . # - name: Setup tmate session # if: ${{ failure() }} # uses: mxschmitt/action-tmate@v3 build_windows: - runs-on: ${{ matrix.os }} + runs-on: windows-2022 strategy: matrix: - os: [windows-2022] - python: [3.7] + python-version: [3.7] platform: [cpu, cu111] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip From ec25c067c791b495da271e518b47aa13acb47367 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 6 Apr 2023 17:03:53 +0800 Subject: [PATCH 27/39] [Enhancement] update version dependency (#1738) * [Enhancement] update version dependency * [Enhancement] update version dependency --- .circleci/test.yml | 8 ++++---- .github/workflows/merge_stage_test.yml | 12 ++++++------ .github/workflows/pr_stage_test.yml | 6 +++--- .github/workflows/test_mim.yml | 6 +++--- README.md | 2 +- README_zh-CN.md | 2 +- configs/disco_diffusion/tutorials.ipynb | 8 ++++---- docs/en/get_started/install.md | 4 ++-- mmedit/datasets/transforms/crop.py | 2 +- requirements/mminstall.txt | 2 +- requirements/optional.txt | 2 +- requirements/readthedocs.txt | 4 ++-- requirements/tests.txt | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.circleci/test.yml b/.circleci/test.yml index f3333c9ee7..9f7086ac1c 100644 --- a/.circleci/test.yml +++ b/.circleci/test.yml @@ -61,7 +61,7 @@ jobs: command: | pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' pip install -r requirements/tests.txt - run: name: Build and install @@ -104,7 +104,7 @@ jobs: command: | docker exec mmedit pip install -e /mmengine docker exec mmedit pip install -U openmim - docker exec mmedit mim install 'mmcv >= 2.0.0rc1' + docker exec mmedit mim install 'mmcv >= 2.0.0' docker exec mmedit pip install -r requirements/tests.txt - run: name: Build and install @@ -125,7 +125,7 @@ workflows: branches: ignore: - dev-1.x - - 1.x + - main pr_stage_test: when: not: @@ -137,7 +137,7 @@ workflows: branches: ignore: - dev-1.x - - 1.x + - main - build_cpu: name: minimum_version_cpu torch: 1.8.1 diff --git a/.github/workflows/merge_stage_test.yml b/.github/workflows/merge_stage_test.yml index 455cace6f9..343ed6996b 100644 --- a/.github/workflows/merge_stage_test.yml +++ b/.github/workflows/merge_stage_test.yml @@ -14,7 +14,7 @@ on: branches: - dev-1.x - test-1.x - - 1.x + - main - test-branch concurrency: @@ -46,7 +46,7 @@ jobs: - name: Install MMCV run: | pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' - name: Install other dependencies run: | pip install -r requirements/tests.txt @@ -96,7 +96,7 @@ jobs: - name: Install MMCV run: | pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' - name: Install other dependencies run: | pip install -r requirements/tests.txt @@ -148,7 +148,7 @@ jobs: - name: Install mmediting dependencies run: | pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' pip install -r requirements/tests.txt - name: Build and install run: | @@ -185,7 +185,7 @@ jobs: run: | pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' pip install -r requirements/tests.txt - name: Build and install run: | @@ -218,7 +218,7 @@ jobs: run: | python -m pip install git+https://github.com/open-mmlab/mmengine.git@main python -m pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' python -m pip install -r requirements/tests.txt - name: Build and install run: | diff --git a/.github/workflows/pr_stage_test.yml b/.github/workflows/pr_stage_test.yml index fd381cb372..eea5973767 100644 --- a/.github/workflows/pr_stage_test.yml +++ b/.github/workflows/pr_stage_test.yml @@ -39,7 +39,7 @@ jobs: - name: Install MMCV run: | pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' - name: Install other dependencies run: | pip install -r requirements/tests.txt @@ -92,7 +92,7 @@ jobs: run: | pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' pip install -r requirements/tests.txt - name: Build and install run: | @@ -123,7 +123,7 @@ jobs: run: | python -m pip install git+https://github.com/open-mmlab/mmengine.git@main python -m pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' python -m pip install -r requirements/tests.txt - name: Build and install run: | diff --git a/.github/workflows/test_mim.yml b/.github/workflows/test_mim.yml index ab95e781b6..b9e838b95e 100644 --- a/.github/workflows/test_mim.yml +++ b/.github/workflows/test_mim.yml @@ -17,7 +17,7 @@ concurrency: jobs: build_cpu: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.7] @@ -27,9 +27,9 @@ jobs: torch_version: torch1.8 torchvision: 0.9.0 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip diff --git a/README.md b/README.md index b21028df9f..e6ea57a799 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ Install MMCV with [MIM](https://github.com/open-mmlab/mim). ```shell pip3 install openmim # wait for more pre-compiled pkgs to release -mim install 'mmcv>=2.0.0rc1' +mim install 'mmcv>=2.0.0' ``` **Step 3.** diff --git a/README_zh-CN.md b/README_zh-CN.md index f413ddf5a1..411919ded0 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -132,7 +132,7 @@ MMEditing 依赖 [PyTorch](https://pytorch.org/),[MMEngine](https://github.com ``` pip3 install openmim # wait for more pre-compiled pkgs to release -mim install 'mmcv>=2.0.0rc1' +mim install 'mmcv>=2.0.0' ``` **步骤 3.** diff --git a/configs/disco_diffusion/tutorials.ipynb b/configs/disco_diffusion/tutorials.ipynb index a730bf18e6..8f0eb8d39c 100644 --- a/configs/disco_diffusion/tutorials.ipynb +++ b/configs/disco_diffusion/tutorials.ipynb @@ -64,7 +64,7 @@ "source": [ "# Install mmcv dependency via openmim\n", "!pip install openmim\n", - "!mim install 'mmcv>=2.0.0rc1'" + "!mim install 'mmcv>=2.0.0'" ] }, { @@ -1417,7 +1417,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3.8.13 ('mmedit2': conda)", + "display_name": "Python 3.9.16 ('mmedit': conda)", "language": "python", "name": "python3" }, @@ -1431,12 +1431,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.9.16" }, "orig_nbformat": 4, "vscode": { "interpreter": { - "hash": "5d897c5c52e082b514ee6f95b827618ca631a30c2bcba2887693dc2fed97e1f9" + "hash": "35fd9fbe4d1b297d4be2b8092ffedf61ac9a34aef1ae0231052d90ec0a3e8f9f" } } }, diff --git a/docs/en/get_started/install.md b/docs/en/get_started/install.md index 78fc8d1be3..e0d4c7c39d 100644 --- a/docs/en/get_started/install.md +++ b/docs/en/get_started/install.md @@ -60,7 +60,7 @@ Install PyTorch following [official instructions](https://pytorch.org/get-starte ```shell pip install -U openmim -mim install 'mmcv>=2.0.0rc1' +mim install 'mmcv>=2.0.0' ``` **Step 1.** Install [MMEngine](https://github.com/open-mmlab/mmengine). @@ -133,7 +133,7 @@ This requires manually specifying a find-url based on PyTorch version and its CU For example, the following command install mmcv-full built for PyTorch 1.10.x and CUDA 11.3. ```shell -pip install 'mmcv>=2.0.0rc1' -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10/index.html +pip install 'mmcv>=2.0.0' -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10/index.html ``` #### Using MMEditing with Docker diff --git a/mmedit/datasets/transforms/crop.py b/mmedit/datasets/transforms/crop.py index 28e2afbfb9..a24b4e3c4e 100644 --- a/mmedit/datasets/transforms/crop.py +++ b/mmedit/datasets/transforms/crop.py @@ -964,7 +964,7 @@ def __init__(self, assert mmdet_apis is not None, ( "Cannot import 'mmdet'. Please install 'mmdet' via " - "\"mim install 'mmdet >= 3.0.0rc2'\".") + "\"mim install 'mmdet >= 3.0.0'\".") cfg = get_config(config_file, pretrained=True) with DefaultScope.overwrite_default_scope('mmdet'): diff --git a/requirements/mminstall.txt b/requirements/mminstall.txt index 992f383c8b..d2b1d8d204 100644 --- a/requirements/mminstall.txt +++ b/requirements/mminstall.txt @@ -1,2 +1,2 @@ -mmcv>=2.0.0rc1 +mmcv>=2.0.0 mmengine>=0.4.0 diff --git a/requirements/optional.txt b/requirements/optional.txt index 3f110c9191..5d542bba17 100644 --- a/requirements/optional.txt +++ b/requirements/optional.txt @@ -1,6 +1,6 @@ -e git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1#egg=clip imageio-ffmpeg==0.4.4 -mmdet >= 3.0.0rc2 +mmdet >= 3.0.0 open_clip_torch PyQt5 transformers diff --git a/requirements/readthedocs.txt b/requirements/readthedocs.txt index 17e5a5c8ea..e449a793ff 100644 --- a/requirements/readthedocs.txt +++ b/requirements/readthedocs.txt @@ -1,7 +1,7 @@ lmdb lpips -mmcv>=2.0.0rc1 -mmdet >= 3.0.0rc2 +mmcv >= 2.0.0rc1 +mmdet >= 3.0.0 mmengine prettytable Pygments diff --git a/requirements/tests.txt b/requirements/tests.txt index d20b4c3785..ffada59c26 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -9,6 +9,6 @@ coverage < 7.0.0 imageio-ffmpeg==0.4.4 interrogate -mmdet >= 3.0.0rc2 +mmdet >= 3.0.0 pytest transformers From b653a38ac333a12d117b0e4d762b0a267c088221 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 6 Apr 2023 17:28:56 +0800 Subject: [PATCH 28/39] [Fix] fix matting metrics (#1728) * [Fix] fix matting metrics * fix ut --- mmedit/evaluation/metrics/connectivity_error.py | 6 ++++-- mmedit/evaluation/metrics/gradient_error.py | 6 ++++-- mmedit/evaluation/metrics/matting_mse.py | 5 +++-- mmedit/evaluation/metrics/metrics_utils.py | 2 +- mmedit/evaluation/metrics/sad.py | 5 +++-- .../test_evaluation/test_metrics/test_connectivity_error.py | 6 +++--- tests/test_evaluation/test_metrics/test_gradient_error.py | 6 +++--- tests/test_evaluation/test_metrics/test_matting_mse.py | 6 +++--- tests/test_evaluation/test_metrics/test_sad.py | 6 +++--- 9 files changed, 27 insertions(+), 21 deletions(-) diff --git a/mmedit/evaluation/metrics/connectivity_error.py b/mmedit/evaluation/metrics/connectivity_error.py index 87254d10bf..0579b07f34 100644 --- a/mmedit/evaluation/metrics/connectivity_error.py +++ b/mmedit/evaluation/metrics/connectivity_error.py @@ -6,16 +6,16 @@ import cv2 import numpy as np import torch.nn as nn -from mmengine.evaluator import BaseMetric from mmengine.model import is_model_wrapper from torch.utils.data.dataloader import DataLoader from mmedit.registry import METRICS +from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import _fetch_data_and_check, average @METRICS.register_module() -class ConnectivityError(BaseMetric): +class ConnectivityError(BaseSampleWiseMetric): """Connectivity error for evaluating alpha matte prediction. .. note:: @@ -40,6 +40,8 @@ class ConnectivityError(BaseMetric): - ConnectivityError (float): Connectivity Error """ + metric = 'ConnectivityError' + def __init__( self, step=0.1, diff --git a/mmedit/evaluation/metrics/gradient_error.py b/mmedit/evaluation/metrics/gradient_error.py index 6e66b9e08b..d69fdd0323 100644 --- a/mmedit/evaluation/metrics/gradient_error.py +++ b/mmedit/evaluation/metrics/gradient_error.py @@ -4,17 +4,17 @@ import cv2 import numpy as np import torch.nn as nn -from mmengine.evaluator import BaseMetric from mmengine.model import is_model_wrapper from torch.utils.data.dataloader import DataLoader from mmedit.registry import METRICS from ..functional import gauss_gradient +from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import _fetch_data_and_check, average @METRICS.register_module() -class GradientError(BaseMetric): +class GradientError(BaseSampleWiseMetric): """Gradient error for evaluating alpha matte prediction. .. note:: @@ -39,6 +39,8 @@ class GradientError(BaseMetric): - GradientError (float): Gradient Error """ + metric = 'GradientError' + def __init__( self, sigma=1.4, diff --git a/mmedit/evaluation/metrics/matting_mse.py b/mmedit/evaluation/metrics/matting_mse.py index 29fbdd81d2..824ffe21ac 100644 --- a/mmedit/evaluation/metrics/matting_mse.py +++ b/mmedit/evaluation/metrics/matting_mse.py @@ -2,16 +2,16 @@ from typing import List, Sequence import torch.nn as nn -from mmengine.evaluator import BaseMetric from mmengine.model import is_model_wrapper from torch.utils.data.dataloader import DataLoader from mmedit.registry import METRICS +from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import _fetch_data_and_check, average @METRICS.register_module() -class MattingMSE(BaseMetric): +class MattingMSE(BaseSampleWiseMetric): """Mean Squared Error metric for image matting. This metric compute per-pixel squared error average across all @@ -39,6 +39,7 @@ class MattingMSE(BaseMetric): """ default_prefix = '' + metric = 'MattingMSE' def __init__( self, diff --git a/mmedit/evaluation/metrics/metrics_utils.py b/mmedit/evaluation/metrics/metrics_utils.py index dc980e9e4e..6e5552c555 100644 --- a/mmedit/evaluation/metrics/metrics_utils.py +++ b/mmedit/evaluation/metrics/metrics_utils.py @@ -33,7 +33,7 @@ def _fetch_data_and_check(data_samples): """ ori_trimap = data_samples['ori_trimap'][0, :, :].cpu().numpy() ori_alpha = data_samples['ori_alpha'][0, :, :].cpu().numpy() - pred_alpha = data_samples['output']['pred_alpha']['data'] # 2D tensor + pred_alpha = data_samples['output']['pred_alpha'] # 2D tensor pred_alpha = pred_alpha.cpu().numpy() _assert_ndim(ori_trimap, 'trimap', 2, 'HxW') diff --git a/mmedit/evaluation/metrics/sad.py b/mmedit/evaluation/metrics/sad.py index 02a10bd3b9..f10f01aef2 100644 --- a/mmedit/evaluation/metrics/sad.py +++ b/mmedit/evaluation/metrics/sad.py @@ -3,16 +3,16 @@ import numpy as np import torch.nn as nn -from mmengine.evaluator import BaseMetric from mmengine.model import is_model_wrapper from torch.utils.data.dataloader import DataLoader from mmedit.registry import METRICS +from .base_sample_wise_metric import BaseSampleWiseMetric from .metrics_utils import _fetch_data_and_check, average @METRICS.register_module() -class SAD(BaseMetric): +class SAD(BaseSampleWiseMetric): """Sum of Absolute Differences metric for image matting. This metric compute per-pixel absolute difference and sum across all @@ -40,6 +40,7 @@ class SAD(BaseMetric): """ default_prefix = '' + metric = 'SAD' def __init__( self, diff --git a/tests/test_evaluation/test_metrics/test_connectivity_error.py b/tests/test_evaluation/test_metrics/test_connectivity_error.py index 37e13c55fe..5a7db39fe4 100644 --- a/tests/test_evaluation/test_metrics/test_connectivity_error.py +++ b/tests/test_evaluation/test_metrics/test_connectivity_error.py @@ -52,19 +52,19 @@ def setup_class(cls): cls.data_samples = [d_['data_samples'] for d_ in cls.data_batch] - cls.bad_preds1_ = [{'pred_alpha': dict(data=pred_alpha)}] + cls.bad_preds1_ = [{'pred_alpha': pred_alpha}] # pred_alpha should be masked by trimap before evaluation cls.bad_preds1 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds1, cls.bad_preds1_): d['output'] = p - cls.bad_preds2_ = [{'pred_alpha': dict(data=pred_alpha[0])}] + cls.bad_preds2_ = [{'pred_alpha': pred_alpha[0]}] # pred_alpha should be 3 dimensional cls.bad_preds2 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds2, cls.bad_preds2_): d['output'] = p - cls.good_preds_ = [{'pred_alpha': dict(data=masked_pred_alpha)}] + cls.good_preds_ = [{'pred_alpha': masked_pred_alpha}] cls.good_preds = copy.deepcopy((cls.data_samples)) for d, p in zip(cls.good_preds, cls.good_preds_): d['output'] = p diff --git a/tests/test_evaluation/test_metrics/test_gradient_error.py b/tests/test_evaluation/test_metrics/test_gradient_error.py index d08a568ed0..3b910f52b6 100644 --- a/tests/test_evaluation/test_metrics/test_gradient_error.py +++ b/tests/test_evaluation/test_metrics/test_gradient_error.py @@ -52,19 +52,19 @@ def setup_class(cls): cls.data_samples = [d_['data_samples'] for d_ in cls.data_batch] - cls.bad_preds1_ = [{'pred_alpha': dict(data=pred_alpha)}] + cls.bad_preds1_ = [{'pred_alpha': pred_alpha}] # pred_alpha should be masked by trimap before evaluation cls.bad_preds1 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds1, cls.bad_preds1_): d['output'] = p - cls.bad_preds2_ = [{'pred_alpha': dict(data=pred_alpha[0])}] + cls.bad_preds2_ = [{'pred_alpha': pred_alpha[0]}] # pred_alpha should be 3 dimensional cls.bad_preds2 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds2, cls.bad_preds2_): d['output'] = p - cls.good_preds_ = [{'pred_alpha': dict(data=masked_pred_alpha)}] + cls.good_preds_ = [{'pred_alpha': masked_pred_alpha}] cls.good_preds = copy.deepcopy((cls.data_samples)) for d, p in zip(cls.good_preds, cls.good_preds_): d['output'] = p diff --git a/tests/test_evaluation/test_metrics/test_matting_mse.py b/tests/test_evaluation/test_metrics/test_matting_mse.py index c7b35df72d..264588102b 100644 --- a/tests/test_evaluation/test_metrics/test_matting_mse.py +++ b/tests/test_evaluation/test_metrics/test_matting_mse.py @@ -52,19 +52,19 @@ def setup_class(cls): cls.data_samples = [d_['data_samples'] for d_ in cls.data_batch] - cls.bad_preds1_ = [{'pred_alpha': dict(data=pred_alpha)}] + cls.bad_preds1_ = [{'pred_alpha': pred_alpha}] # pred_alpha should be masked by trimap before evaluation cls.bad_preds1 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds1, cls.bad_preds1_): d['output'] = p - cls.bad_preds2_ = [{'pred_alpha': dict(data=pred_alpha[0])}] + cls.bad_preds2_ = [{'pred_alpha': pred_alpha[0]}] # pred_alpha should be 3 dimensional cls.bad_preds2 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds2, cls.bad_preds2_): d['output'] = p - cls.good_preds_ = [{'pred_alpha': dict(data=masked_pred_alpha)}] + cls.good_preds_ = [{'pred_alpha': masked_pred_alpha}] cls.good_preds = copy.deepcopy((cls.data_samples)) for d, p in zip(cls.good_preds, cls.good_preds_): d['output'] = p diff --git a/tests/test_evaluation/test_metrics/test_sad.py b/tests/test_evaluation/test_metrics/test_sad.py index 7811a54961..82ecd162ff 100644 --- a/tests/test_evaluation/test_metrics/test_sad.py +++ b/tests/test_evaluation/test_metrics/test_sad.py @@ -52,19 +52,19 @@ def setup_class(cls): cls.data_samples = [d_['data_samples'] for d_ in cls.data_batch] - cls.bad_preds1_ = [{'pred_alpha': dict(data=pred_alpha)}] + cls.bad_preds1_ = [{'pred_alpha': pred_alpha}] # pred_alpha should be masked by trimap before evaluation cls.bad_preds1 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds1, cls.bad_preds1_): d['output'] = p - cls.bad_preds2_ = [{'pred_alpha': dict(data=pred_alpha[0])}] + cls.bad_preds2_ = [{'pred_alpha': pred_alpha[0]}] # pred_alpha should be 3 dimensional cls.bad_preds2 = copy.deepcopy(cls.data_samples) for d, p in zip(cls.bad_preds2, cls.bad_preds2_): d['output'] = p - cls.good_preds_ = [{'pred_alpha': dict(data=masked_pred_alpha)}] + cls.good_preds_ = [{'pred_alpha': masked_pred_alpha}] cls.good_preds = copy.deepcopy((cls.data_samples)) for d, p in zip(cls.good_preds, cls.good_preds_): d['output'] = p From 026e51ce5aa866e36828990971f3a0368604e759 Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Thu, 6 Apr 2023 17:37:40 +0800 Subject: [PATCH 29/39] [Enhancement] Revise StableDiffusion and corresponding components (#1703) * revise StableDiffusion and corresponding components * add docstring and unit test for schedulers wrapper * revise sample_size attribute in denoising unet and revise doocstring and typing for stable diffusion * revise stable diffusion's unit test * revise inference function for stable diffusion * revise output name of MMEditing's denoising unet * support xformers for stable diffusion and revise some unit tests --- .../stable-diffusion_ddim_denoisingunet.py | 14 +- .../edit_data_preprocessor.py | 4 - .../models/diffusion_schedulers/__init__.py | 86 +++++- .../diffusion_schedulers/ddim_scheduler.py | 21 +- mmedit/models/editors/ddpm/denoising_unet.py | 5 +- mmedit/models/editors/guided_diffusion/adm.py | 2 +- .../editors/stable_diffusion/__init__.py | 3 +- .../stable_diffusion/stable_diffusion.py | 261 +++++++++--------- mmedit/models/editors/stable_diffusion/vae.py | 8 + mmedit/models/utils/__init__.py | 11 +- mmedit/models/utils/model_utils.py | 69 ++++- .../test_base_archs/test_wrapper.py | 3 + .../test_diffusion_schedulers/test_init.py | 48 ++++ .../test_ddpm/test_denoising_unet.py | 2 +- .../test_stable_diffusion.py | 72 ++--- .../test_utils/test_model_utils.py | 33 ++- tools/train.py | 2 +- 17 files changed, 447 insertions(+), 197 deletions(-) create mode 100644 tests/test_models/test_diffusion_schedulers/test_init.py diff --git a/configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py b/configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py index 489ff00a57..2cbeca94bd 100644 --- a/configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py +++ b/configs/stable_diffusion/stable-diffusion_ddim_denoisingunet.py @@ -20,6 +20,7 @@ output_cfg=dict(var='fixed')) vae = dict( + type='EditAutoencoderKL', act_fn='silu', block_out_channels=[128, 256, 512, 512], down_block_types=[ @@ -47,12 +48,15 @@ set_alpha_to_one=False, clip_sample=False) -init_cfg = dict(type='Pretrained', pretrained_model_path='') - model = dict( type='StableDiffusion', - diffusion_scheduler=diffusion_scheduler, unet=unet, vae=vae, - init_cfg=init_cfg, -) + text_encoder=dict( + type='ClipWrapper', + clip_type='huggingface', + pretrained_model_name_or_path='runwayml/stable-diffusion-v1-5', + subfolder='text_encoder'), + tokenizer='runwayml/stable-diffusion-v1-5', + scheduler=diffusion_scheduler, + test_scheduler=diffusion_scheduler) diff --git a/mmedit/models/data_preprocessors/edit_data_preprocessor.py b/mmedit/models/data_preprocessors/edit_data_preprocessor.py index f69e04f746..7dcd3f71a9 100644 --- a/mmedit/models/data_preprocessors/edit_data_preprocessor.py +++ b/mmedit/models/data_preprocessors/edit_data_preprocessor.py @@ -758,8 +758,6 @@ def _destruct_padding(self, if data_samples is None: return batch_tensor - # import ipdb - # ipdb.set_trace() if isinstance(data_samples, list): is_batch_data = True if 'padding_size' in data_samples[0].metainfo_keys(): @@ -794,8 +792,6 @@ def _destruct_padding(self, WARNING) return batch_tensor if is_batch_data else batch_tensor[0] - # import ipdb - # ipdb.set_trace() if same_padding: # un-pad with the padding info of the first sample padded_h, padded_w = pad_infos[0][-2:] diff --git a/mmedit/models/diffusion_schedulers/__init__.py b/mmedit/models/diffusion_schedulers/__init__.py index 8e81e1a670..e50af75ae9 100644 --- a/mmedit/models/diffusion_schedulers/__init__.py +++ b/mmedit/models/diffusion_schedulers/__init__.py @@ -1,12 +1,85 @@ # Copyright (c) OpenMMLab. All rights reserved. import warnings -from typing import List +from typing import Any, List from mmedit.utils import try_import from .ddim_scheduler import EditDDIMScheduler from .ddpm_scheduler import EditDDPMScheduler +class SchedulerWrapper: + """Wrapper for schedulers from HuggingFace Diffusers. This wrapper will be + set a attribute called `_scheduler_cls` by wrapping function and will be + used to initialize the model structure. + + Example: + >>> 1. Load pretrained model from HuggingFace Space. + >>> config = dict( + >>> type='DDPMScheduler', + >>> from_pretrained='lllyasviel/sd-controlnet-canny', + >>> subfolder='scheduler') + >>> ddpm_scheduler = DIFFUSION_SCHEDULERS.build(config) + + >>> 2. Initialize model with own defined arguments + >>> config = dict( + >>> type='EulerDiscreteScheduler', + >>> num_train_timesteps=2000, + >>> beta_schedule='scaled_linear') + >>> euler_scheduler = DIFFUSION_SCHEDULERS.build(config) + + Args: + from_pretrained (Union[str, os.PathLike], optional): The *model id* + of a pretrained model or a path to a *directory* containing + model weights and config. Please refers to + `diffusers.model.modeling_utils.ModelMixin.from_pretrained` + for more detail. Defaults to None. + + *args, **kwargs: If `from_pretrained` is passed, *args and **kwargs + will be passed to `from_pretrained` function. Otherwise, *args + and **kwargs will be used to initialize the model by + `self._module_cls(*args, **kwargs)`. + """ + + def __init__(self, from_pretrained=None, *args, **kwargs): + + scheduler_cls = self._scheduler_cls + + self._from_pretrained = from_pretrained + if self._from_pretrained: + self.scheduler = scheduler_cls.from_pretrained( + from_pretrained, *args, **kwargs) + else: + self.scheduler = scheduler_cls(*args, **kwargs) + + def __getattr__(self, name: str) -> Any: + """This function provide a way to access the attributes of the wrapped + scheduler. + + Args: + name (str): The name of the attribute. + + Returns: + Any: The got attribute. + """ + + try: + return getattr(self.scheduler, name) + except AttributeError: + raise AttributeError('\'name\' cannot be found in both ' + f'\'{self.__class__.__name__}\' and ' + f'\'{self.__class__.__name__}.scheduler\'.') + + def __repr__(self): + """The representation of the wrapper.""" + s = super().__repr__() + prefix = f'Wrapped Scheduler Class: {self._scheduler_cls}\n' + prefix += f'Wrapped Scheduler Name: {self._scheduler_name}\n' + if self._from_pretrained: + prefix += f'From Pretrained: {self._from_pretrained}\n' + s = prefix + s + return s + + def register_diffusers_schedulers() -> List[str]: """Register schedulers in ``diffusers.schedulers`` to the ``DIFFUSION_SCHEDULERS`` registry. Specifically, the registered schedulers @@ -30,6 +103,14 @@ def register_diffusers_schedulers() -> List[str]: 'please install diffusers>=0.12.0.') return None + def gen_wrapped_cls(scheduler, scheduler_name): + return type( + scheduler_name, (SchedulerWrapper, ), + dict( + _scheduler_cls=scheduler, + _scheduler_name=scheduler_name, + __module__=__name__)) + DIFFUSERS_SCHEDULERS = [] for module_name in dir(diffusers.schedulers): if module_name.startswith('Flax'): @@ -37,8 +118,9 @@ def register_diffusers_schedulers() -> List[str]: elif module_name.endswith('Scheduler'): _scheduler = getattr(diffusers.schedulers, module_name) if inspect.isclass(_scheduler): + wrapped_scheduler = gen_wrapped_cls(_scheduler, module_name) DIFFUSION_SCHEDULERS.register_module( - name=module_name, module=_scheduler) + name=module_name, module=wrapped_scheduler) DIFFUSERS_SCHEDULERS.append(module_name) return DIFFUSERS_SCHEDULERS diff --git a/mmedit/models/diffusion_schedulers/ddim_scheduler.py b/mmedit/models/diffusion_schedulers/ddim_scheduler.py index a4948267b9..cab9264446 100644 --- a/mmedit/models/diffusion_schedulers/ddim_scheduler.py +++ b/mmedit/models/diffusion_schedulers/ddim_scheduler.py @@ -1,5 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. -from typing import Union +from typing import Optional, Union import numpy as np import torch @@ -77,6 +77,9 @@ def __init__( self.final_alpha_cumprod = np.array( 1.0) if set_alpha_to_one else self.alphas_cumprod[0] + # standard deviation of the initial noise distribution + self.init_noise_sigma = 1.0 + # setable values self.num_inference_steps = None self.timesteps = np.arange(0, num_train_timesteps)[::-1].copy() @@ -90,6 +93,22 @@ def set_timesteps(self, num_inference_steps, offset=0): self.num_train_timesteps // self.num_inference_steps)[::-1].copy() self.timesteps += offset + def scale_model_input(self, + sample: torch.FloatTensor, + timestep: Optional[int] = None) -> torch.FloatTensor: + """Ensures interchangeability with schedulers that need to scale the + denoising model input depending on the current timestep. + + Args: + sample (`torch.FloatTensor`): input sample + timestep (`int`, optional): current timestep + + Returns: + `torch.FloatTensor`: scaled input sample + """ + + return sample + def _get_variance(self, timestep, prev_timestep): """get variance.""" diff --git a/mmedit/models/editors/ddpm/denoising_unet.py b/mmedit/models/editors/ddpm/denoising_unet.py index fa0cbb316c..86bb34dc2e 100644 --- a/mmedit/models/editors/ddpm/denoising_unet.py +++ b/mmedit/models/editors/ddpm/denoising_unet.py @@ -1132,6 +1132,9 @@ def __init__(self, bias=True, order=('norm', 'act', 'conv')) + if self.unet_type == 'stable': + self.sample_size = image_size // 8 # NOTE: hard code here + self.init_weights(pretrained) def forward(self, @@ -1275,7 +1278,7 @@ def forward(self, h = h.type(x_t.dtype) outputs = self.out(h) - return {'outputs': outputs} + return {'sample': outputs} def init_weights(self, pretrained=None): """Init weights for models. diff --git a/mmedit/models/editors/guided_diffusion/adm.py b/mmedit/models/editors/guided_diffusion/adm.py index a286d0aa19..962c8eee15 100644 --- a/mmedit/models/editors/guided_diffusion/adm.py +++ b/mmedit/models/editors/guided_diffusion/adm.py @@ -162,7 +162,7 @@ def infer(self, timesteps = tqdm(timesteps) for t in timesteps: # 1. predicted model_output - model_output = self.unet(image, t, label=labels)['outputs'] + model_output = self.unet(image, t, label=labels)['sample'] # 2. compute previous image: x_t -> x_t-1 if classifier_scale > 0 and self.classifier is not None: diff --git a/mmedit/models/editors/stable_diffusion/__init__.py b/mmedit/models/editors/stable_diffusion/__init__.py index 93dac0131b..5a70f840e1 100644 --- a/mmedit/models/editors/stable_diffusion/__init__.py +++ b/mmedit/models/editors/stable_diffusion/__init__.py @@ -1,4 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. from .stable_diffusion import StableDiffusion +from .vae import AutoencoderKL -__all__ = ['StableDiffusion'] +__all__ = ['StableDiffusion', 'AutoencoderKL'] diff --git a/mmedit/models/editors/stable_diffusion/stable_diffusion.py b/mmedit/models/editors/stable_diffusion/stable_diffusion.py index 1f70b0406e..37e48f064d 100644 --- a/mmedit/models/editors/stable_diffusion/stable_diffusion.py +++ b/mmedit/models/editors/stable_diffusion/stable_diffusion.py @@ -1,111 +1,103 @@ # Copyright (c) OpenMMLab. All rights reserved. import inspect -import os.path as osp +from copy import deepcopy from typing import Dict, List, Optional, Union import torch +import torch.nn as nn from mmengine.logging import MMLogger from mmengine.model import BaseModel from mmengine.runner import set_random_seed -from mmengine.runner.checkpoint import _load_checkpoint +from PIL import Image from tqdm.auto import tqdm +from transformers import CLIPTokenizer +from mmedit.models.utils import build_module, set_xformers from mmedit.registry import DIFFUSION_SCHEDULERS, MODELS -from .clip_wrapper import load_clip_submodels -from .vae import AutoencoderKL logger = MMLogger.get_current_instance() +ModelType = Union[Dict, nn.Module] + @MODELS.register_module('sd') @MODELS.register_module() class StableDiffusion(BaseModel): - """class to run stable diffsuion pipeline. + """Class for Stable Diffusion. Refers to https://github.com/Stability- + AI/stablediffusion and https://github.com/huggingface/diffusers/blob/main/s + rc/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_attend_an + d_excite.py # noqa. Args: - diffusion_scheduler(dict): Diffusion scheduler config. - unet_cfg(dict): Unet config. - vae_cfg(dict): Vae config. - pretrained_ckpt_path(dict): - Pretrained ckpt path for submodels in stable diffusion. - requires_safety_checker(bool): - whether to run safety checker after image generated. - unet_sample_size(int): sampel size for unet. + unet (Union[dict, nn.Module]): The config or module for Unet model. + text_encoder (Union[dict, nn.Module]): The config or module for text + encoder. + vae (Union[dict, nn.Module]): The config or module for VAE model. + tokenizer (str): The **name** for CLIP tokenizer. + schedule (Union[dict, nn.Module]): The config or module for diffusion + scheduler. + test_scheduler (Union[dict, nn.Module], optional): The config or + module for diffusion scheduler in test stage (`self.infer`). If not + passed, will use the same scheduler as `schedule`. Defaults to + None. + enable_xformers (bool, optional): Whether to use xformers. + Defaults to True. + data_preprocessor (dict, optional): The pre-process config of + :class:`BaseDataPreprocessor`. + init_cfg (dict, optional): The weight initialized config for + :class:`BaseModule`. """ def __init__(self, - diffusion_scheduler, - unet, - vae, - requires_safety_checker=True, - unet_sample_size=64, - init_cfg=None): - super().__init__() - - self.device = torch.device('cpu') - self.submodels = [ - 'tokenizer', 'vae', 'scheduler', 'unet', 'feature_extractor', - 'text_encoder' - ] - self.requires_safety_checker = requires_safety_checker - - self.scheduler = DIFFUSION_SCHEDULERS.build( - diffusion_scheduler) if isinstance(diffusion_scheduler, - dict) else diffusion_scheduler - self.scheduler.order = 1 - self.scheduler.init_noise_sigma = 1.0 - - self.unet_sample_size = unet_sample_size - self.unet = MODELS.build(unet) if isinstance(unet, dict) else unet - - self.vae = AutoencoderKL(**vae) if isinstance(vae, dict) else vae + vae: ModelType, + text_encoder: ModelType, + tokenizer: str, + unet: ModelType, + scheduler: ModelType, + test_scheduler: Optional[ModelType] = None, + enable_xformers: bool = True, + data_preprocessor: Optional[ModelType] = dict( + type='EditDataPreprocessor'), + init_cfg: Optional[dict] = None): + + # TODO: support `from_pretrained` for this class + super().__init__(data_preprocessor, init_cfg) + + self.vae = build_module(vae, MODELS) + self.unet = build_module(unet, MODELS) + self.scheduler = build_module(scheduler, DIFFUSION_SCHEDULERS) + if test_scheduler is None: + self.test_scheduler = deepcopy(self.scheduler) + else: + self.test_scheduler = build_module(test_scheduler, + DIFFUSION_SCHEDULERS) + self.text_encoder = build_module(text_encoder, MODELS) + if isinstance(tokenizer, nn.Module): + self.tokenizer = tokenizer + else: + # NOTE: here we assume tokenizer is an string + # TODO: maybe support a tokenizer wrapper later + self.tokenizer = CLIPTokenizer.from_pretrained( + tokenizer, subfolder='tokenizer') + + self.unet_sample_size = self.unet.sample_size self.vae_scale_factor = 2**(len(self.vae.block_out_channels) - 1) - self.init_cfg = init_cfg - self.init_weights() - - def init_weights(self): - """load pretrained ckpt for each submodel.""" - if self.init_cfg is not None and self.init_cfg['type'] == 'Pretrained': - map_location = self.init_cfg.get('map_location', 'cpu') - pretrained_model_path = self.init_cfg.get('pretrained_model_path', - None) - if pretrained_model_path: - unet_ckpt_path = osp.join(pretrained_model_path, 'unet', - 'diffusion_pytorch_model.bin') - if unet_ckpt_path: - state_dict = _load_checkpoint(unet_ckpt_path, map_location) - self.unet.load_state_dict(state_dict, strict=True) - - vae_ckpt_path = osp.join(pretrained_model_path, 'vae', - 'diffusion_pytorch_model.bin') - if vae_ckpt_path: - state_dict = _load_checkpoint(vae_ckpt_path, map_location) - self.vae.load_state_dict(state_dict, strict=True) - - self.tokenizer, self.feature_extractor, self.text_encoder, self.safety_checker = load_clip_submodels( # noqa - self.init_cfg, self.submodels, self.requires_safety_checker) - - def to(self, torch_device: Optional[Union[str, torch.device]] = None): - """put submodels to torch device. + self.enable_xformers = enable_xformers + self.set_xformers() - Args: - torch_device(Optional[Union[str, torch.device]]): - device to put, default to None. + def set_xformers(self) -> nn.Module: + """Set xformers for the model. Returns: - self(StableDiffusion): - class instance itsself. + nn.Module: The model with xformers. """ - if torch_device is None: - return self + if self.enable_xformers: + set_xformers(self) - for name in self.submodels: - module = getattr(self, name) - if isinstance(module, torch.nn.Module): - module.to(torch_device) - self.device = torch.device(torch_device) - return self + @property + def device(self): + return next(self.parameters()).device @torch.no_grad() def infer(self, @@ -120,7 +112,8 @@ def infer(self, generator: Optional[torch.Generator] = None, latents: Optional[torch.FloatTensor] = None, show_progress=True, - seed=1): + seed=1, + return_type='image'): """Function invoked when calling the pipeline for generation. Args: @@ -160,12 +153,18 @@ def infer(self, with different prompts. If not provided, a latents tensor will be generated by sampling using the supplied random `generator`. + return_type (str): The return type of the inference results. + Supported types are 'image', 'numpy', 'tensor'. If 'image' + is passed, a list of PIL images will be returned. If 'numpy' + is passed, a numpy array with shape [N, C, H, W] will be + returned, and the value range will be same as decoder's + output range. If 'tensor' is passed, the decoder's output + will be returned. Defaults to 'image'. Returns: - dict:['samples', 'nsfw_content_detected']: - 'samples': image result samples - 'nsfw_content_detected': nsfw content flags for image samples. + dict: A dict containing the generated images. """ + assert return_type in ['image', 'tensor', 'numpy'] set_random_seed(seed=seed) # 0. Default height and width to unet @@ -192,7 +191,6 @@ def infer(self, negative_prompt) # 4. Prepare timesteps - # self.scheduler.set_timesteps(num_inference_steps, device=device) self.scheduler.set_timesteps(num_inference_steps) timesteps = self.scheduler.timesteps @@ -220,13 +218,13 @@ def infer(self, # expand the latents if we are doing classifier free guidance latent_model_input = torch.cat( [latents] * 2) if do_classifier_free_guidance else latents - # latent_model_input = \ - # self.scheduler.scale_model_input(latent_model_input, t) + latent_model_input = self.scheduler.scale_model_input( + latent_model_input, t) # predict the noise residual noise_pred = self.unet( latent_model_input, t, - encoder_hidden_states=text_embeddings)['outputs'] + encoder_hidden_states=text_embeddings)['sample'] # perform guidance if do_classifier_free_guidance: @@ -239,36 +237,52 @@ def infer(self, noise_pred, t, latents, **extra_step_kwargs)['prev_sample'] # 8. Post-processing - image = self.decode_latents(latents) + image = self.decode_latents(latents.to(self.vae.dtype)) + if return_type == 'image': + image = self.output_to_pil(image) + elif return_type == 'numpy': + image = image.cpu().numpy() + else: + assert return_type == 'tensor', ( + 'Only support \'image\', \'numpy\' and \'tensor\' for ' + f'return_type, but receive {return_type}') - # 9. Run safety checker - image, has_nsfw_concept = self.run_safety_checker( - image, device, text_embeddings.dtype) - image = image[0].permute([2, 0, 1]) + return {'samples': image} - return {'samples': image, 'nsfw_content_detected': has_nsfw_concept} + def output_to_pil(self, image) -> List[Image.Image]: + """Convert output tensor to PIL image. Output tensor will be de-normed + to [0, 255] by `EditDataPreprocessor.destruct`. Due to no + `data_samples` is passed, color order conversion will not be performed. + + Args: + image (torch.Tensor): The output tensor of the decoder. + + Returns: + List[Image.Image]: The list of processed PIL images. + """ + image = self.data_preprocessor.destruct(image) + image = image.permute(0, 2, 3, 1).to(torch.uint8).cpu().numpy() + image = [Image.fromarray(img) for img in image] + return image def _encode_prompt(self, prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt): """Encodes the prompt into text encoder hidden states. Args: - prompt (str or list(int)): - prompt to be encoded. - device: (torch.device): - torch device. - num_images_per_prompt (int): - number of images that should be generated per prompt. - do_classifier_free_guidance (`bool`): - whether to use classifier free guidance or not. - negative_prompt (str or List[str]): - The prompt or prompts not to guide the image generation. - Ignored when not using guidance (i.e., ignored - if `guidance_scale` is less than `1`). + prompt (str or list(int)): prompt to be encoded. + device: (torch.device): torch device. + num_images_per_prompt (int): number of images that should be + generated per prompt. + do_classifier_free_guidance (`bool`): whether to use classifier + free guidance or not. + negative_prompt (str or List[str]): The prompt or prompts not + to guide the image generation. Ignored when not using + guidance (i.e., ignored if `guidance_scale` is less than `1`). Returns: - text_embeddings (torch.Tensor): - text embeddings generated by clip text encoder. + text_embeddings (torch.Tensor): text embeddings generated by + clip text encoder. """ batch_size = len(prompt) if isinstance(prompt, list) else 1 @@ -368,33 +382,6 @@ def _encode_prompt(self, prompt, device, num_images_per_prompt, return text_embeddings - def run_safety_checker(self, image, device, dtype): - """run safety checker to check whether image has nsfw content. - - Args: - image (numpy.ndarray): - image generated by stable diffusion. - device (torch.device): - device to run safety checker. - dtype (torch.dtype): - float type to run. - - Returns: - image (numpy.ndarray): - black image if nsfw content detected else input image. - has_nsfw_concept (list[bool]): - flag list to indicate nsfw content detected. - """ - if self.safety_checker is not None: - safety_checker_input = self.feature_extractor( - image[0], return_tensors='pt').to(device) - image, has_nsfw_concept = self.safety_checker( - images=image, - clip_input=safety_checker_input.pixel_values.to(dtype)) - else: - has_nsfw_concept = None - return image, has_nsfw_concept - def decode_latents(self, latents): """use vae to decode latents. @@ -402,15 +389,13 @@ def decode_latents(self, latents): latents (torch.Tensor): latents to decode. Returns: - image (numpy.ndarray): image result. + image (torch.Tensor): image result. """ latents = 1 / 0.18215 * latents - image = self.vae.decode(latents).sample - image = (image / 2 + 0.5).clamp(0, 1) + image = self.vae.decode(latents)['sample'] # we always cast to float32 as this does not cause # significant overhead and is compatible with bfloa16 - image = image.cpu().permute(0, 2, 3, 1).float() - return image + return image.float() def prepare_extra_step_kwargs(self, generator, eta): """prepare extra kwargs for the scheduler step. diff --git a/mmedit/models/editors/stable_diffusion/vae.py b/mmedit/models/editors/stable_diffusion/vae.py index 38444ba766..064018828c 100644 --- a/mmedit/models/editors/stable_diffusion/vae.py +++ b/mmedit/models/editors/stable_diffusion/vae.py @@ -11,6 +11,8 @@ from mmengine.utils.dl_utils import TORCH_VERSION from mmengine.utils.version_utils import digit_version +from mmedit.registry import MODELS + class Downsample2D(nn.Module): """A downsampling layer with an optional convolution. @@ -874,6 +876,7 @@ def mode(self): return self.mean +@MODELS.register_module('EditAutoencoderKL') class AutoencoderKL(nn.Module): r"""Variational Autoencoder (VAE) model with KL loss from the paper Auto-Encoding Variational Bayes by Diederik P. Kingma @@ -944,6 +947,11 @@ def __init__( self.post_quant_conv = torch.nn.Conv2d(latent_channels, latent_channels, 1) + @property + def dtype(self): + """The data type of the parameters of VAE.""" + return next(self.parameters()).dtype + def encode(self, x: torch.FloatTensor, return_dict: bool = True) -> Dict: """encode input.""" h = self.encoder(x) diff --git a/mmedit/models/utils/__init__.py b/mmedit/models/utils/__init__.py index 45fa9d975c..e90ecddea2 100644 --- a/mmedit/models/utils/__init__.py +++ b/mmedit/models/utils/__init__.py @@ -2,9 +2,11 @@ from .bbox_utils import extract_around_bbox, extract_bbox_patch from .flow_warp import flow_warp -from .model_utils import (default_init_weights, generation_init_weights, - get_module_device, get_valid_noise_size, - get_valid_num_batches, make_layer, set_requires_grad) +from .model_utils import (build_module, default_init_weights, + generation_init_weights, get_module_device, + get_valid_noise_size, get_valid_num_batches, + make_layer, set_requires_grad, set_xformers, + xformers_is_enable) from .sampling_utils import label_sample_fn, noise_sample_fn from .tensor_utils import get_unknown_tensor, normalize_vecs @@ -13,5 +15,6 @@ 'generation_init_weights', 'set_requires_grad', 'extract_bbox_patch', 'extract_around_bbox', 'get_unknown_tensor', 'noise_sample_fn', 'label_sample_fn', 'get_valid_num_batches', 'get_valid_noise_size', - 'get_module_device', 'normalize_vecs' + 'get_module_device', 'normalize_vecs', 'build_module', 'set_xformers', + 'xformers_is_enable' ] diff --git a/mmedit/models/utils/model_utils.py b/mmedit/models/utils/model_utils.py index bace4359c2..cabe4a6f9d 100644 --- a/mmedit/models/utils/model_utils.py +++ b/mmedit/models/utils/model_utils.py @@ -1,12 +1,13 @@ # Copyright (c) OpenMMLab. All rights reserved. import logging -from typing import Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Union import torch import torch.nn as nn from mmengine import print_log from mmengine.model.weight_init import (constant_init, kaiming_init, normal_init, xavier_init) +from mmengine.registry import Registry from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm from torch import Tensor from torch.nn import init @@ -232,3 +233,69 @@ def get_valid_num_batches(batch_inputs: Optional[ForwardInputs] = None, ' Please check your input carefully.') return num_batches_inputs or num_batches_samples + + +def build_module(module: Union[dict, nn.Module], builder: Registry, *args, + **kwargs) -> Any: + """Build module from config or return the module itself. + + Args: + module (Union[dict, nn.Module]): The module to build. + builder (Registry): The registry to build module. + *args, **kwargs: Arguments passed to build function. + + Returns: + Any: The built module. + """ + if isinstance(module, dict): + return builder.build(module, *args, **kwargs) + elif isinstance(module, nn.Module): + return module + else: + raise TypeError( + f'Only support dict and nn.Module, but got {type(module)}.') + + +def xformers_is_enable(verbose: bool = False) -> bool: + """Check whether xformers is installed. + Args: + verbose (bool): Whether to print the log. + + Returns: + bool: Whether xformers is installed. + """ + from mmedit.utils import try_import + xformers = try_import('xformers') + if xformers is None and verbose: + print_log('Do not support Xformers.', 'current') + return xformers is not None + + +def set_xformers(module: nn.Module, prefix: str = '') -> nn.Module: + """Set xformers' efficient Attention for attention modules. + + Args: + module (nn.Module): The module to set xformers. + prefix (str): The prefix of the module name. + + Returns: + nn.Module: The module with xformers' efficient Attention. + """ + + if not xformers_is_enable: + print_log('Do not support Xformers. Please install Xformers first. ' + 'The program will run without Xformers.') + return + + for n, m in module.named_children(): + if hasattr(m, 'set_use_memory_efficient_attention_xformers'): + # set xformers for Diffusers' Cross Attention + m.set_use_memory_efficient_attention_xformers(True) + module_name = f'{prefix}.{n}' if prefix else n + print_log( + 'Enable Xformers for HuggingFace Diffusers\' ' + f'module \'{module_name}\'.', 'current') + else: + set_xformers(m, prefix=n) + + return module diff --git a/tests/test_models/test_base_archs/test_wrapper.py b/tests/test_models/test_base_archs/test_wrapper.py index 7621cc465d..3764cca128 100644 --- a/tests/test_models/test_base_archs/test_wrapper.py +++ b/tests/test_models/test_base_archs/test_wrapper.py @@ -10,12 +10,15 @@ from mmengine.utils.dl_utils import TORCH_VERSION from mmedit.registry import MODELS +from mmedit.utils import register_all_modules test_dir = osp.join(osp.dirname(__file__), '../../..', 'tests') config_path = osp.join(test_dir, 'configs', 'diffuser_wrapper_cfg') model_path = osp.join(test_dir, 'configs', 'tmp_weight') ckpt_path = osp.join(test_dir, 'configs', 'ckpt') +register_all_modules() + class TestWrapper(TestCase): diff --git a/tests/test_models/test_diffusion_schedulers/test_init.py b/tests/test_models/test_diffusion_schedulers/test_init.py new file mode 100644 index 0000000000..555c140053 --- /dev/null +++ b/tests/test_models/test_diffusion_schedulers/test_init.py @@ -0,0 +1,48 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp +import shutil +from unittest import TestCase + +from mmedit.registry import DIFFUSION_SCHEDULERS + +test_dir = osp.join(osp.dirname(__file__), '../../..', 'tests') +config_path = osp.join(test_dir, 'configs', 'scheduler_cfg') + + +class TestWrapper(TestCase): + + def test_build(self): + # 1. test init by args + config = dict( + type='EulerDiscreteScheduler', + num_train_timesteps=2000, + beta_schedule='scaled_linear') + scheduler = DIFFUSION_SCHEDULERS.build(config) + self.assertEqual(scheduler.num_train_timesteps, 2000) + self.assertEqual(scheduler.beta_schedule, 'scaled_linear') + scheduler_str = repr(scheduler) + self.assertIn( + 'Wrapped Scheduler Class: ' + '', scheduler_str) + self.assertIn('Wrapped Scheduler Name: EulerDiscreteScheduler', + scheduler_str) + self.assertNotIn('From Pretrained: ', scheduler_str) + + # 2. test save as diffuser + scheduler.save_pretrained(config_path) + + # 3. test from_pretrained + config = dict( + type='EulerDiscreteScheduler', from_pretrained=config_path) + scheduler = DIFFUSION_SCHEDULERS.build(config) + scheduler_str = repr(scheduler) + self.assertIn('From Pretrained: ', scheduler_str) + + # 4. test attribute error + with self.assertRaises(AttributeError): + scheduler.unsupported_attr('do not support') + + # tear down + shutil.rmtree(config_path) diff --git a/tests/test_models/test_editors/test_ddpm/test_denoising_unet.py b/tests/test_models/test_editors/test_ddpm/test_denoising_unet.py index 02be8c5cb3..1f7f2ef832 100644 --- a/tests/test_models/test_editors/test_ddpm/test_denoising_unet.py +++ b/tests/test_models/test_editors/test_ddpm/test_denoising_unet.py @@ -9,7 +9,7 @@ def test_DenoisingUnet(): input = torch.rand((1, 3, 32, 32)) unet = DenoisingUnet(32) output = unet.forward(input, 10) - assert output['outputs'].shape == (1, 6, 32, 32) + assert output['sample'].shape == (1, 6, 32, 32) def test_NormWithEmbedding(): diff --git a/tests/test_models/test_editors/test_stable_diffusion/test_stable_diffusion.py b/tests/test_models/test_editors/test_stable_diffusion/test_stable_diffusion.py index 4e92650416..6349188373 100644 --- a/tests/test_models/test_editors/test_stable_diffusion/test_stable_diffusion.py +++ b/tests/test_models/test_editors/test_stable_diffusion/test_stable_diffusion.py @@ -3,6 +3,7 @@ import pytest import torch +import torch.nn as nn from addict import Dict from mmengine import MODELS, Config @@ -12,41 +13,32 @@ unet = dict( type='DenoisingUnet', - image_size=512, - base_channels=320, - channels_cfg=[1, 2, 4, 4], + image_size=128, + base_channels=32, + channels_cfg=[1, 2], unet_type='stable', act_cfg=dict(type='silu', inplace=False), cross_attention_dim=768, - num_heads=8, + num_heads=2, in_channels=4, - layers_per_block=2, - down_block_types=[ - 'CrossAttnDownBlock2D', 'CrossAttnDownBlock2D', 'CrossAttnDownBlock2D', - 'DownBlock2D' - ], - up_block_types=[ - 'UpBlock2D', 'CrossAttnUpBlock2D', 'CrossAttnUpBlock2D', - 'CrossAttnUpBlock2D' - ], + layers_per_block=1, + down_block_types=['CrossAttnDownBlock2D', 'DownBlock2D'], + up_block_types=['UpBlock2D', 'CrossAttnUpBlock2D'], output_cfg=dict(var='fixed')) vae = dict( + type='EditAutoencoderKL', act_fn='silu', - block_out_channels=[128, 256, 512, 512], - down_block_types=[ - 'DownEncoderBlock2D', 'DownEncoderBlock2D', 'DownEncoderBlock2D', - 'DownEncoderBlock2D' - ], + block_out_channels=[128], + down_block_types=['DownEncoderBlock2D'], in_channels=3, latent_channels=4, - layers_per_block=2, + layers_per_block=1, norm_num_groups=32, out_channels=3, - sample_size=512, + sample_size=128, up_block_types=[ - 'UpDecoderBlock2D', 'UpDecoderBlock2D', 'UpDecoderBlock2D', - 'UpDecoderBlock2D' + 'UpDecoderBlock2D', ]) diffusion_scheduler = dict( @@ -61,19 +53,11 @@ init_cfg = dict(type='Pretrained', pretrained_model_path=None) -model = dict( - type='StableDiffusion', - diffusion_scheduler=diffusion_scheduler, - unet=unet, - vae=vae, - init_cfg=init_cfg, - requires_safety_checker=False, -) - -class dummy_tokenizer: +class dummy_tokenizer(nn.Module): def __init__(self): + super().__init__() self.model_max_length = 0 def __call__(self, @@ -88,9 +72,10 @@ def __call__(self, return text_inputs -class dummy_text_encoder: +class dummy_text_encoder(nn.Module): def __init__(self): + super().__init__() self.config = None def __call__(self, x, attention_mask): @@ -98,6 +83,16 @@ def __call__(self, x, attention_mask): return [result] +model = dict( + type='StableDiffusion', + scheduler=diffusion_scheduler, + unet=unet, + vae=vae, + init_cfg=init_cfg, + text_encoder=dummy_text_encoder(), + tokenizer=dummy_text_encoder()) + + @pytest.mark.skipif( 'win' in platform.system().lower(), reason='skip on windows due to limited RAM.') @@ -116,6 +111,13 @@ def test_stable_diffusion(): 'an insect robot preparing a delicious meal', height=64, width=64, - num_inference_steps=1) + num_inference_steps=1, + return_type='numpy') + assert result['samples'].shape == (1, 3, 64, 64) - assert result['samples'].shape == (3, 64, 64) + result = StableDiffuser.infer( + 'an insect robot preparing a delicious meal', + height=64, + width=64, + num_inference_steps=1, + return_type='image') diff --git a/tests/test_models/test_utils/test_model_utils.py b/tests/test_models/test_utils/test_model_utils.py index bd9625b335..3348d7ae01 100644 --- a/tests/test_models/test_utils/test_model_utils.py +++ b/tests/test_models/test_utils/test_model_utils.py @@ -5,8 +5,10 @@ import torch import torch.nn as nn -from mmedit.models.utils import (generation_init_weights, get_module_device, - get_valid_num_batches, set_requires_grad) +from mmedit.models.utils import (build_module, generation_init_weights, + get_module_device, get_valid_num_batches, + set_requires_grad) +from mmedit.registry import MODELS def test_generation_init_weights(): @@ -79,3 +81,30 @@ def test_get_valid_num_batches(): batch_inputs = dict(num_batches=2, img=torch.randn(2, 3, 5, 5)) data_samples = [None, None] assert get_valid_num_batches(batch_inputs, data_samples) == 2 + + +def test_build_module(): + module = nn.Conv2d(3, 3, 3) + assert build_module(module, MODELS) == module + + @MODELS.register_module() + class MiniModule(nn.Module): + + def __init__(self, *args, **kwargs): + super().__init__() + for k, v in kwargs.items(): + setattr(self, k, v) + + def forward(self, *args, **kwargs): + return + + module_cfg = dict(type='MiniModule', attr1=1, attr2=2) + module = build_module(module_cfg, MODELS) + assert module.attr1 == 1 + assert module.attr2 == 2 + + with pytest.raises(TypeError): + build_module('MiniModule', MODELS) + + # remove the registered module + MODELS._module_dict.pop('MiniModule') diff --git a/tools/train.py b/tools/train.py index ab9a3fed93..ed8dd4401e 100644 --- a/tools/train.py +++ b/tools/train.py @@ -72,7 +72,7 @@ def main(): # enable automatic-mixed-precision training if args.amp is True: if ('constructor' not in cfg.optim_wrapper) or \ - cfg.optim_wrapper['constructor'] == 'DefaultOptimWrapperConstructor': # noqa + cfg.optim_wrapper['constructor'] == 'DefaultOptimWrapperConstructor': # noqa optim_wrapper = cfg.optim_wrapper.type if optim_wrapper == 'AmpOptimWrapper': print_colored_log( From ddb8167a4d9b4d5cd41e1e025ef434c522f3d3c9 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 6 Apr 2023 17:53:28 +0800 Subject: [PATCH 30/39] [Fix] fix torch min version of ci (#1739) --- .github/workflows/merge_stage_test.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/merge_stage_test.yml b/.github/workflows/merge_stage_test.yml index 343ed6996b..fb76ac62ba 100644 --- a/.github/workflows/merge_stage_test.yml +++ b/.github/workflows/merge_stage_test.yml @@ -63,12 +63,8 @@ jobs: strategy: matrix: python-version: [3.7] - torch: [1.6.0, 1.7.1, 1.8.1, 1.9.1, 1.10.1, 1.11.0, 1.12.1, 1.13.0] + torch: [1.8.1, 1.9.1, 1.10.1, 1.11.0, 1.12.1, 1.13.0] include: - - torch: 1.6.0 - torchvision: 0.7.0 - - torch: 1.7.1 - torchvision: 0.8.2 - torch: 1.8.1 torchvision: 0.9.1 - torch: 1.9.1 From 5f5a757531767efdfdacfa369e8df6140e57ce25 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 6 Apr 2023 18:42:54 +0800 Subject: [PATCH 31/39] [Doc] update docs conf branch (#1740) --- docs/en/conf.py | 8 ++++---- docs/zh_cn/conf.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/en/conf.py b/docs/en/conf.py index 49deffd1f5..2bb373af14 100644 --- a/docs/en/conf.py +++ b/docs/en/conf.py @@ -113,14 +113,14 @@ 'Version', 'children': [ { - 'name': 'MMEditing 0.x', + 'name': 'MMEditing 1.x', 'url': 'https://mmediting.readthedocs.io/en/latest/', 'description': 'Main branch' }, { - 'name': 'MMEditing 1.x', - 'url': 'https://mmediting.readthedocs.io/en/1.x/', - 'description': '1.x branch', + 'name': 'MMEditing 0.x', + 'url': 'https://mmediting.readthedocs.io/en/0.x/', + 'description': '0.x branch', }, ], 'active': diff --git a/docs/zh_cn/conf.py b/docs/zh_cn/conf.py index beb21b8c3d..4e077144d5 100644 --- a/docs/zh_cn/conf.py +++ b/docs/zh_cn/conf.py @@ -109,14 +109,14 @@ '版本', 'children': [ { - 'name': 'MMEditing 0.x', + 'name': 'MMEditing 1.x', 'url': 'https://mmediting.readthedocs.io/en/latest/', 'description': 'Main 分支文档' }, { - 'name': 'MMEditing 1.x', - 'url': 'https://mmediting.readthedocs.io/en/1.x/', - 'description': '1.x 分支文档' + 'name': 'MMEditing 0.x', + 'url': 'https://mmediting.readthedocs.io/en/0.x/', + 'description': '0.x 分支文档' }, ], 'active': From 6759190695752c14b3d85bb991a5730d6babbf41 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 6 Apr 2023 20:17:35 +0800 Subject: [PATCH 32/39] [Doc] update documents links to main branch (#1733) * [Doc] update documents links to main branch * fix readme * fix readme_zh * fix docs * fix migration * fix migration * modify to latest * update changelog --- README.md | 54 ++++++++++---------- README_zh-CN.md | 16 +++--- configs/disco_diffusion/README.md | 2 +- configs/disco_diffusion/README_zh-CN.md | 2 +- configs/disco_diffusion/tutorials.ipynb | 2 +- configs/inst_colorization/README.md | 2 +- configs/inst_colorization/README_zh-CN.md | 2 +- demo/README.md | 2 +- demo/mmediting_inference_tutorial.ipynb | 2 +- docker/Dockerfile | 2 +- docs/en/changelog.md | 2 +- docs/en/community/projects.md | 4 +- docs/en/get_started/install.md | 6 +-- docs/en/howto/dataset.md | 2 +- docs/en/howto/models.md | 22 ++++---- docs/en/howto/transforms.md | 2 +- docs/en/switch_language.md | 4 +- docs/en/user_guides/config.md | 6 +-- docs/en/user_guides/dataset_prepare.md | 2 +- docs/en/user_guides/deploy.md | 10 ++-- docs/en/user_guides/inference.md | 2 +- docs/en/user_guides/metrics.md | 4 +- docs/en/user_guides/train_test.md | 4 +- docs/zh_cn/.dev_scripts/update_model_zoo.py | 2 +- docs/zh_cn/changelog.md | 2 +- docs/zh_cn/switch_language.md | 4 +- docs/zh_cn/user_guides/dataset_prepare.md | 2 +- docs/zh_cn/user_guides/deploy.md | 10 ++-- docs/zh_cn/user_guides/metrics.md | 4 +- mmedit/datasets/basic_conditional_dataset.py | 6 +-- projects/README.md | 4 +- projects/example_project/README.md | 8 +-- tools/gui/README.md | 8 +-- 33 files changed, 100 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index e6ea57a799..da4ccae0f6 100644 --- a/README.md +++ b/README.md @@ -19,17 +19,17 @@
 
[![PyPI](https://badge.fury.io/py/mmedit.svg)](https://pypi.org/project/mmedit/) -[![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmediting.readthedocs.io/en/1.x/) +[![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmediting.readthedocs.io/en/latest/) [![badge](https://github.com/open-mmlab/mmediting/workflows/build/badge.svg)](https://github.com/open-mmlab/mmediting/actions) [![codecov](https://codecov.io/gh/open-mmlab/mmediting/branch/master/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmediting) -[![license](https://img.shields.io/github/license/open-mmlab/mmediting.svg)](https://github.com/open-mmlab/mmediting/blob/1.x/LICENSE) +[![license](https://img.shields.io/github/license/open-mmlab/mmediting.svg)](https://github.com/open-mmlab/mmediting/blob/main/LICENSE) [![open issues](https://isitmaintained.com/badge/open/open-mmlab/mmediting.svg)](https://github.com/open-mmlab/mmediting/issues) [![issue resolution](https://isitmaintained.com/badge/resolution/open-mmlab/mmediting.svg)](https://github.com/open-mmlab/mmediting/issues) -[📘Documentation](https://mmediting.readthedocs.io/en/1.x/) | -[🛠️Installation](https://mmediting.readthedocs.io/en/1.x/get_started/install.html) | -[📊Model Zoo](https://mmediting.readthedocs.io/en/1.x/model_zoo/overview.html) | -[🆕Update News](https://mmediting.readthedocs.io/en/1.x/changelog.html) | +[📘Documentation](https://mmediting.readthedocs.io/en/latest/) | +[🛠️Installation](https://mmediting.readthedocs.io/en/latest/get_started/install.html) | +[📊Model Zoo](https://mmediting.readthedocs.io/en/latest/model_zoo/overview.html) | +[🆕Update News](https://mmediting.readthedocs.io/en/latest/changelog.html) | [🚀Ongoing Projects](https://github.com/open-mmlab/mmediting/projects) | [🤔Reporting Issues](https://github.com/open-mmlab/mmediting/issues) @@ -85,7 +85,7 @@ Currently, MMEditing support multiple image and video generation/editing tasks. https://user-images.githubusercontent.com/12782558/217152698-49169038-9872-4200-80f7-1d5f7613afd7.mp4 -The best practice on our main 1.x branch works with **Python 3.8+** and **PyTorch 1.9+**. +The best practice on our main branch works with **Python 3.8+** and **PyTorch 1.9+**. ### ✨ Major features @@ -99,7 +99,7 @@ The best practice on our main 1.x branch works with **Python 3.8+** and **PyTorc - **New Modular Design for Flexible Combination** - We decompose the editing framework into different modules and one can easily construct a customized editor framework by combining different modules. Specifically, a new design for complex loss modules is proposed for customizing the links between modules, which can achieve flexible combinations among different modules.(Tutorial for [losses](https://mmediting.readthedocs.io/en/dev-1.x/howto/losses.html)) + We decompose the editing framework into different modules and one can easily construct a customized editor framework by combining different modules. Specifically, a new design for complex loss modules is proposed for customizing the links between modules, which can achieve flexible combinations among different modules.(Tutorial for [losses](https://mmediting.readthedocs.io/en/latest/howto/losses.html)) - **Efficient Distributed Training** @@ -142,7 +142,7 @@ mim install 'mmcv>=2.0.0' Install MMEditing from source. ```shell -git clone -b 1.x https://github.com/open-mmlab/mmediting.git +git clone https://github.com/open-mmlab/mmediting.git cd mmediting pip3 install -e . ``` @@ -321,7 +321,7 @@ Please see [quick run](docs/en/get_started/quick_run.md) and [inference](docs/en -Please refer to [model_zoo](https://mmediting.readthedocs.io/en/1.x/model_zoo/overview.html) for more details. +Please refer to [model_zoo](https://mmediting.readthedocs.io/en/latest/model_zoo/overview.html) for more details.

🔝Back to top

@@ -362,24 +362,24 @@ Please refer to [LICENSES](LICENSE) for the careful check, if you are using our ## 🏗️ ️OpenMMLab Family - [MMEngine](https://github.com/open-mmlab/mmengine): OpenMMLab foundational library for training deep learning models. -- [MMCV](https://github.com/open-mmlab/mmcv/tree/2.x): OpenMMLab foundational library for computer vision. +- [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab foundational library for computer vision. - [MIM](https://github.com/open-mmlab/mim): MIM installs OpenMMLab packages. -- [MMClassification](https://github.com/open-mmlab/mmclassification/tree/1.x): OpenMMLab image classification toolbox and benchmark. -- [MMDetection](https://github.com/open-mmlab/mmdetection/tree/3.x): OpenMMLab detection toolbox and benchmark. -- [MMDetection3D](https://github.com/open-mmlab/mmdetection3d/tree/1.x): OpenMMLab's next-generation platform for general 3D object detection. -- [MMRotate](https://github.com/open-mmlab/mmrotate/tree/1.x): OpenMMLab rotated object detection toolbox and benchmark. -- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation/tree/1.x): OpenMMLab semantic segmentation toolbox and benchmark. -- [MMOCR](https://github.com/open-mmlab/mmocr/tree/1.x): OpenMMLab text detection, recognition, and understanding toolbox. -- [MMPose](https://github.com/open-mmlab/mmpose/tree/1.x): OpenMMLab pose estimation toolbox and benchmark. -- [MMHuman3D](https://github.com/open-mmlab/mmhuman3d/tree/1.x): OpenMMLab 3D human parametric model toolbox and benchmark. -- [MMSelfSup](https://github.com/open-mmlab/mmselfsup/tree/1.x): OpenMMLab self-supervised learning toolbox and benchmark. -- [MMRazor](https://github.com/open-mmlab/mmrazor/tree/1.x): OpenMMLab model compression toolbox and benchmark. -- [MMFewShot](https://github.com/open-mmlab/mmfewshot/tree/1.x): OpenMMLab fewshot learning toolbox and benchmark. -- [MMAction2](https://github.com/open-mmlab/mmaction2/tree/1.x): OpenMMLab's next-generation action understanding toolbox and benchmark. -- [MMTracking](https://github.com/open-mmlab/mmtracking/tree/1.x): OpenMMLab video perception toolbox and benchmark. -- [MMFlow](https://github.com/open-mmlab/mmflow/tree/1.x): OpenMMLab optical flow toolbox and benchmark. -- [MMEditing](https://github.com/open-mmlab/mmediting/tree/1.x): OpenMMLab image and video editing toolbox. -- [MMGeneration](https://github.com/open-mmlab/mmgeneration/tree/1.x): OpenMMLab image and video generative models toolbox. +- [MMClassification](https://github.com/open-mmlab/mmclassification): OpenMMLab image classification toolbox and benchmark. +- [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab detection toolbox and benchmark. +- [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab's next-generation platform for general 3D object detection. +- [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab rotated object detection toolbox and benchmark. +- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab semantic segmentation toolbox and benchmark. +- [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab text detection, recognition, and understanding toolbox. +- [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab pose estimation toolbox and benchmark. +- [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab 3D human parametric model toolbox and benchmark. +- [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab self-supervised learning toolbox and benchmark. +- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab model compression toolbox and benchmark. +- [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab fewshot learning toolbox and benchmark. +- [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab's next-generation action understanding toolbox and benchmark. +- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab video perception toolbox and benchmark. +- [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab optical flow toolbox and benchmark. +- [MMEditing](https://github.com/open-mmlab/mmediting): OpenMMLab image and video editing toolbox. +- [MMGeneration](https://github.com/open-mmlab/mmgeneration): OpenMMLab image and video generative models toolbox. - [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab model deployment framework.

🔝Back to top

diff --git a/README_zh-CN.md b/README_zh-CN.md index 411919ded0..125c6e255a 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -19,17 +19,17 @@
 
[![PyPI](https://badge.fury.io/py/mmedit.svg)](https://pypi.org/project/mmedit/) -[![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmediting.readthedocs.io/zh_CN/1.x/) +[![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmediting.readthedocs.io/zh_CN/latest/) [![badge](https://github.com/open-mmlab/mmediting/workflows/build/badge.svg)](https://github.com/open-mmlab/mmediting/actions) [![codecov](https://codecov.io/gh/open-mmlab/mmediting/branch/master/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmediting) -[![license](https://img.shields.io/github/license/open-mmlab/mmediting.svg)](https://github.com/open-mmlab/mmediting/blob/1.x/LICENSE) +[![license](https://img.shields.io/github/license/open-mmlab/mmediting.svg)](https://github.com/open-mmlab/mmediting/blob/main/LICENSE) [![open issues](https://isitmaintained.com/badge/open/open-mmlab/mmediting.svg)](https://github.com/open-mmlab/mmediting/issues) [![issue resolution](https://isitmaintained.com/badge/resolution/open-mmlab/mmediting.svg)](https://github.com/open-mmlab/mmediting/issues) -[📘使用文档](https://mmediting.readthedocs.io/en/1.x/) | -[🛠️安装教程](https://mmediting.readthedocs.io/zh_CN/1.x/get_started/install.html) | -[📊模型库](https://mmediting.readthedocs.io/zh_CN/1.x/model_zoo/overview.html) | -[🆕更新记录](https://mmediting.readthedocs.io/zh_CN/1.x/changelog.html) | +[📘使用文档](https://mmediting.readthedocs.io/zh_CN/latest/) | +[🛠️安装教程](https://mmediting.readthedocs.io/zh_CN/latest/get_started/install.html) | +[📊模型库](https://mmediting.readthedocs.io/zh_CN/latest/model_zoo/overview.html) | +[🆕更新记录](https://mmediting.readthedocs.io/zh_CN/latest/changelog.html) | [🚀进行中的项目](https://github.com/open-mmlab/mmediting/projects) | [🤔提出问题](https://github.com/open-mmlab/mmediting/issues) @@ -139,7 +139,7 @@ mim install 'mmcv>=2.0.0' 从源码安装 MMEditing ``` -git clone -b 1.x https://github.com/open-mmlab/mmediting.git +git clone https://github.com/open-mmlab/mmediting.git cd mmediting pip3 install -e . ``` @@ -318,7 +318,7 @@ pip3 install -e . -请参考[模型库](https://mmediting.readthedocs.io/zh_CN/1.x/model_zoo/overview.html)了解详情。 +请参考[模型库](https://mmediting.readthedocs.io/zh_CN/latest/model_zoo/overview.html)了解详情。

🔝返回顶部

diff --git a/configs/disco_diffusion/README.md b/configs/disco_diffusion/README.md index dcd9ff98aa..90cb59e11c 100644 --- a/configs/disco_diffusion/README.md +++ b/configs/disco_diffusion/README.md @@ -104,7 +104,7 @@ save_image(image, "image.png") ## Tutorials -Considering that `disco-diffusion` contains many adjustable parameters, we provide users with a [jupyter-notebook](./tutorials.ipynb) / [colab](https://githubtocolab.com/open-mmlab/mmediting/blob/dev-1.x/configs/disco_diffusion/tutorials.ipynb) tutorial that exhibits the meaning of different parameters, and gives results corresponding to adjustment. +Considering that `disco-diffusion` contains many adjustable parameters, we provide users with a [jupyter-notebook](./tutorials.ipynb) / [colab](https://githubtocolab.com/open-mmlab/mmediting/blob/main/configs/disco_diffusion/tutorials.ipynb) tutorial that exhibits the meaning of different parameters, and gives results corresponding to adjustment. Refer to [Disco Sheet](https://docs.google.com/document/d/1l8s7uS2dGqjztYSjPpzlmXLjl5PM3IGkRWI3IiCuK7g/edit). ## Credits diff --git a/configs/disco_diffusion/README_zh-CN.md b/configs/disco_diffusion/README_zh-CN.md index f15723f779..51a7f9d99f 100644 --- a/configs/disco_diffusion/README_zh-CN.md +++ b/configs/disco_diffusion/README_zh-CN.md @@ -104,7 +104,7 @@ save_image(image, "image.png") ## 教程 -考虑到`disco-diffusion`包含许多可调整的参数,我们为用户提供了一个[jupyter-notebook](./tutorials.ipynb)/[colab](https://githubtocolab.com/open-mmlab/mmediting/blob/dev-1.x/configs/disco_diffusion/tutorials.ipynb)的教程,展示了不同参数的含义,并给出相应的调整结果。 +考虑到`disco-diffusion`包含许多可调整的参数,我们为用户提供了一个[jupyter-notebook](./tutorials.ipynb)/[colab](https://githubtocolab.com/open-mmlab/mmediting/blob/main/configs/disco_diffusion/tutorials.ipynb)的教程,展示了不同参数的含义,并给出相应的调整结果。 请参考[Disco Sheet](https://docs.google.com/document/d/1l8s7uS2dGqjztYSjPpzlmXLjl5PM3IGkRWI3IiCuK7g/edit)。 ## 鸣谢 diff --git a/configs/disco_diffusion/tutorials.ipynb b/configs/disco_diffusion/tutorials.ipynb index 8f0eb8d39c..0f3409f4f3 100644 --- a/configs/disco_diffusion/tutorials.ipynb +++ b/configs/disco_diffusion/tutorials.ipynb @@ -76,7 +76,7 @@ "# Install mmediting from source\n", "%cd /content/\n", "!rm -rf mmediting\n", - "!git clone -b dev-1.x https://github.com/open-mmlab/mmediting.git \n", + "!git clone https://github.com/open-mmlab/mmediting.git \n", "%cd mmediting\n", "!pip install -r requirements.txt\n", "!pip install -e ." diff --git a/configs/inst_colorization/README.md b/configs/inst_colorization/README.md index 3f792aa9a2..691d14c7a6 100644 --- a/configs/inst_colorization/README.md +++ b/configs/inst_colorization/README.md @@ -36,7 +36,7 @@ You can use the following commands to colorize an image. python demo/colorization_demo.py configs/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256.py https://download.openmmlab.com/mmediting/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256-5b9d4eee.pth input.jpg output.jpg ``` -For more demos, you can refer to [Tutorial 3: inference with pre-trained models](https://mmediting.readthedocs.io/en/1.x/user_guides/3_inference.html). +For more demos, you can refer to [Tutorial 3: inference with pre-trained models](https://mmediting.readthedocs.io/en/latest/user_guides/3_inference.html). diff --git a/configs/inst_colorization/README_zh-CN.md b/configs/inst_colorization/README_zh-CN.md index 6d8184fa2e..38f9183ce1 100644 --- a/configs/inst_colorization/README_zh-CN.md +++ b/configs/inst_colorization/README_zh-CN.md @@ -35,7 +35,7 @@ Image colorization is inherently an ill-posed problem with multi-modal uncertain python demo/colorization_demo.py configs/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256.py https://download.openmmlab.com/mmediting/inst_colorization/inst-colorizatioon_full_official_cocostuff-256x256-5b9d4eee.pth input.jpg output.jpg ``` -更多细节可以参考 [Tutorial 3: inference with pre-trained models](https://mmediting.readthedocs.io/en/1.x/user_guides/3_inference.html)。 +更多细节可以参考 [Tutorial 3: inference with pre-trained models](https://mmediting.readthedocs.io/en/latest/user_guides/3_inference.html)。 diff --git a/demo/README.md b/demo/README.md index 6ce948fd45..fecee98804 100644 --- a/demo/README.md +++ b/demo/README.md @@ -1,6 +1,6 @@ # MMEditing Demo -There are some mmediting demos in this folder. We provide python command line usage here to run these demos and more guidance could also be found in the [documentation](https://mmediting.readthedocs.io/en/dev-1.x/user_guides/3_inference.html) +There are some mmediting demos in this folder. We provide python command line usage here to run these demos and more guidance could also be found in the [documentation](https://mmediting.readthedocs.io/en/latest/user_guides/3_inference.html) Table of contents: diff --git a/demo/mmediting_inference_tutorial.ipynb b/demo/mmediting_inference_tutorial.ipynb index 72595185fc..31220d7b06 100644 --- a/demo/mmediting_inference_tutorial.ipynb +++ b/demo/mmediting_inference_tutorial.ipynb @@ -318,7 +318,7 @@ "\n", "Next we describe how to perform inference with python code snippets.\n", "\n", - "(We also provide command line interface for you to do inference by running mmediting_inference_demo.py. The usage of this interface could be found in [README.md](./README.md) and more guidance could be found in the [documentation](https://mmediting.readthedocs.io/en/dev-1.x/user_guides/3_inference.html#).)\n" + "(We also provide command line interface for you to do inference by running mmediting_inference_demo.py. The usage of this interface could be found in [README.md](./README.md) and more guidance could be found in the [documentation](https://mmediting.readthedocs.io/en/latest/user_guides/3_inference.html#).)\n" ] }, { diff --git a/docker/Dockerfile b/docker/Dockerfile index ff3e47905a..72f312eb59 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y git ninja-build libglib2.0-0 libsm6 lib # Install mmediting RUN conda clean --all -RUN git clone -b 1.x https://github.com/open-mmlab/mmediting.git /mmediting +RUN git clone https://github.com/open-mmlab/mmediting.git /mmediting WORKDIR /mmediting ENV FORCE_CUDA="1" RUN pip install openmim diff --git a/docs/en/changelog.md b/docs/en/changelog.md index b87b79d863..bbf2235ecb 100644 --- a/docs/en/changelog.md +++ b/docs/en/changelog.md @@ -227,4 +227,4 @@ MMEditing 1.0.0rc0 is the first version of MMEditing 1.x, a part of the OpenMMLa Built upon the new [training engine](https://github.com/open-mmlab/mmengine), MMEditing 1.x unifies the interfaces of dataset, models, evaluation, and visualization. -And there are some BC-breaking changes. Please check [the migration tutorial](https://mmediting.readthedocs.io/en/1.x/migration/overview.html) for more details. +And there are some BC-breaking changes. Please check [the migration tutorial](https://mmediting.readthedocs.io/en/latest/migration/overview.html) for more details. diff --git a/docs/en/community/projects.md b/docs/en/community/projects.md index 50e25c903f..544d4e5287 100644 --- a/docs/en/community/projects.md +++ b/docs/en/community/projects.md @@ -18,11 +18,11 @@ You can copy and create your own project from the [example project](../../../pro We also provide some documentation listed below for your reference: -- [Contribution Guide](https://mmediting.readthedocs.io/en/dev-1.x/community/contributing.html) +- [Contribution Guide](https://mmediting.readthedocs.io/en/latest/community/contributing.html) The guides for new contributors about how to add your projects to MMEditing. -- [New Model Guide](https://mmediting.readthedocs.io/en/dev-1.x/howto/models.html) +- [New Model Guide](https://mmediting.readthedocs.io/en/latest/howto/models.html) The documentation of adding new models. diff --git a/docs/en/get_started/install.md b/docs/en/get_started/install.md index e0d4c7c39d..c826b47cd9 100644 --- a/docs/en/get_started/install.md +++ b/docs/en/get_started/install.md @@ -10,7 +10,7 @@ In this section, you will know about: ## Installation -We recommend that users follow our [Best practices](#best-practices) to install MMEditing 1.x. +We recommend that users follow our [Best practices](#best-practices) to install MMEditing. However, the whole process is highly customizable. See [Customize installation](#customize-installation) section for more information. ### Prerequisites @@ -69,11 +69,11 @@ mim install 'mmcv>=2.0.0' pip install git+https://github.com/open-mmlab/mmengine.git ``` -**Step 2.** Install MMEditing 1.x . +**Step 2.** Install MMEditing. Install [MMEditing](https://github.com/open-mmlab/mmediting) from the source code. ```shell -git clone -b 1.x https://github.com/open-mmlab/mmediting.git +git clone https://github.com/open-mmlab/mmediting.git cd mmediting pip3 install -e . -v ``` diff --git a/docs/en/howto/dataset.md b/docs/en/howto/dataset.md index 11086661fe..48e0c00db6 100644 --- a/docs/en/howto/dataset.md +++ b/docs/en/howto/dataset.md @@ -16,7 +16,7 @@ In this document, we will introduce the design of each datasets in MMEditing and ## Supported Data Format -In 1.x version of MMEditing, all datasets are inherited from `BaseDataset`. +In MMEditing, all datasets are inherited from `BaseDataset`. Each dataset load the list of data info (e.g., data path) by `load_data_list`. In `__getitem__`, `prepare_data` is called to get the preprocessed data. In `prepare_data`, data loading pipeline consists of the following steps: diff --git a/docs/en/howto/models.md b/docs/en/howto/models.md index 1d9c5828e9..79cd504cf7 100644 --- a/docs/en/howto/models.md +++ b/docs/en/howto/models.md @@ -23,16 +23,16 @@ In MMEditing, one algorithm can be splited two compents: **Model** and **Module* - **Model** are topmost wrappers and always inherint from `BaseModel` provided in MMEngine. **Model** is responsible to network forward, loss calculation and backward, parameters updating, etc. In MMEditing, **Model** should be registered as `MODELS`. - **Module** includes the neural network **architectures** to train or inference, pre-defined **loss classes**, and **data preprocessors** to preprocess the input data batch. **Module** always present as elements of **Model**. In MMEditing, **Module** should be registered as **MODULES**. -Take DCGAN model as an example, [generator](https://github.com/open-mmlab/mmediting/blob/1.x/mmedit/models/editors/dcgan/dcgan_generator.py) and [discriminator](https://github.com/open-mmlab/mmediting/blob/1.x/mmedit/models/editors/dcgan/dcgan_discriminator.py) are the **Module**, which generate images and discriminate real or fake images. [`DCGAN`](https://github.com/open-mmlab/mmediting/blob/1.x/mmedit/models/editors/dcgan/dcgan.py) is the **Model**, which take data from dataloader and train generator and discriminator alternatively. +Take DCGAN model as an example, [generator](https://github.com/open-mmlab/mmediting/blob/main/mmedit/models/editors/dcgan/dcgan_generator.py) and [discriminator](https://github.com/open-mmlab/mmediting/blob/main/mmedit/models/editors/dcgan/dcgan_discriminator.py) are the **Module**, which generate images and discriminate real or fake images. [`DCGAN`](https://github.com/open-mmlab/mmediting/blob/main/mmedit/models/editors/dcgan/dcgan.py) is the **Model**, which take data from dataloader and train generator and discriminator alternatively. You can find the implementation of **Model** and **Module** by the following link. - **Model**: - - [Editors](https://github.com/open-mmlab/mmediting/tree/1.x/mmedit/models/editors) + - [Editors](https://github.com/open-mmlab/mmediting/tree/main/mmedit/models/editors) - **Module**: - - [Layers](https://github.com/open-mmlab/mmediting/tree/1.x/mmedit/models/layers) - - [Losses](https://github.com/open-mmlab/mmediting/tree/1.x/mmedit/models/losses) - - [Data Preprocessor](https://github.com/open-mmlab/mmediting/tree/1.x/mmedit/models/data_preprocessors) + - [Layers](https://github.com/open-mmlab/mmediting/tree/main/mmedit/models/layers) + - [Losses](https://github.com/open-mmlab/mmediting/tree/main/mmedit/models/losses) + - [Data Preprocessor](https://github.com/open-mmlab/mmediting/tree/main/mmedit/models/data_preprocessors) ## An example of SRCNN @@ -552,7 +552,7 @@ If you want to implement specific weights initialization method for you network, After the implementation of class `DCGANGenerator`, we need to update the model list in `mmedit/models/editors/__init__.py`, so that we can import and use class `DCGANGenerator` by `mmedit.models.editors`. -Implementation of Class `DCGANDiscriminator` follows the similar logic, and you can find the implementation [here](https://github.com/open-mmlab/mmediting/blob/1.x/mmedit/models/editors/dcgan/dcgan_discriminator.py). +Implementation of Class `DCGANDiscriminator` follows the similar logic, and you can find the implementation [here](https://github.com/open-mmlab/mmediting/blob/main/mmedit/models/editors/dcgan/dcgan_discriminator.py). ### Step 2: Design the model of DCGAN @@ -561,14 +561,14 @@ After the implementation of the network **Module**, we need to define our **Mode Your **Model** should inherit from [`BaseModel`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/model/base_model/base_model.py#L16) provided by MMEngine and implement three functions, `train_step`, `val_step` and `test_step`. - `train_step`: This function is responsible to update the parameters of the network and called by MMEngine's Loop ([`IterBasedTrainLoop`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py#L183) or [`EpochBasedTrainLoop`](https://github.com/open-mmlab/mmengine/blob/main/mmengine/runner/loops.py#L18)). `train_step` take data batch and [`OptimWrapper`](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/optim_wrapper.md) as input and return a dict of log. -- `val_step`: This function is responsible for getting output for validation during the training process. and is called by [`GenValLoop`](https://github.com/open-mmlab/mmediting/blob/1.x/mmedit/engine/runner/loops.py#L12). -- `test_step`: This function is responsible for getting output in test process and is called by [`GenTestLoop`](https://github.com/open-mmlab/mmediting/blob/1.x/mmedit/engine/runner/loops.py#L95). +- `val_step`: This function is responsible for getting output for validation during the training process. and is called by [`GenValLoop`](https://github.com/open-mmlab/mmediting/blob/main/mmedit/engine/runner/loops.py#L12). +- `test_step`: This function is responsible for getting output in test process and is called by [`GenTestLoop`](https://github.com/open-mmlab/mmediting/blob/main/mmedit/engine/runner/loops.py#L95). -> Note that, in `train_step`, `val_step` and `test_step`, `DataPreprocessor` is called to preprocess the input data batch before feed them to the neural network. To know more about `DataPreprocessor` please refer to this [file](https://github.com/open-mmlab/mmediting/blob/1.x/mmedit/models/data_preprocessors/gen_preprocessor.py) and this [tutorial](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/tutorials/model.md#%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E5%99%A8datapreprocessor). +> Note that, in `train_step`, `val_step` and `test_step`, `DataPreprocessor` is called to preprocess the input data batch before feed them to the neural network. To know more about `DataPreprocessor` please refer to this [file](https://github.com/open-mmlab/mmediting/blob/main/mmedit/models/data_preprocessors/gen_preprocessor.py) and this [tutorial](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/tutorials/model.md#%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E5%99%A8datapreprocessor). -For simplify using, we provide [`BaseGAN`](https://github.com/open-mmlab/mmediting/blob/1.x/mmedit/models/base_models/base_gan.py) class in MMEditing, which implements generic `train_step`, `val_step` and `test_step` function for GAN models. With `BaseGAN` as base class, each specific GAN algorithm only need to implement `train_generator` and `train_discriminator`. +For simplify using, we provide [`BaseGAN`](https://github.com/open-mmlab/mmediting/blob/main/mmedit/models/base_models/base_gan.py) class in MMEditing, which implements generic `train_step`, `val_step` and `test_step` function for GAN models. With `BaseGAN` as base class, each specific GAN algorithm only need to implement `train_generator` and `train_discriminator`. -In `train_step`, we support data preprocessing, gradient accumulation (realized by [`OptimWrapper`](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/optim_wrapper.md)) and expontial moving averate (EMA) realized by [(`ExponentialMovingAverage`)](https://github.com/open-mmlab/mmediting/blob/1.x/mmedit/models/base_models/average_model.py#L19). With `BaseGAN.train_step`, each specific GAN algorithm only need to implement `train_generator` and `train_discriminator`. +In `train_step`, we support data preprocessing, gradient accumulation (realized by [`OptimWrapper`](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/optim_wrapper.md)) and expontial moving averate (EMA) realized by [(`ExponentialMovingAverage`)](https://github.com/open-mmlab/mmediting/blob/main/mmedit/models/base_models/average_model.py#L19). With `BaseGAN.train_step`, each specific GAN algorithm only need to implement `train_generator` and `train_discriminator`. ```python def train_step(self, data: dict, diff --git a/docs/en/howto/transforms.md b/docs/en/howto/transforms.md index 8701e28476..fbcfcdc900 100644 --- a/docs/en/howto/transforms.md +++ b/docs/en/howto/transforms.md @@ -27,7 +27,7 @@ A pipeline consists of a sequence of operations. Each operation takes a dict as The operations are categorized into data loading, pre-processing, and formatting -In 1.x version of MMEditing, all data transformations are inherited from `BaseTransform`. +In MMEditing, all data transformations are inherited from `BaseTransform`. The input and output types of transformations are both dict. ### A simple example of data transform diff --git a/docs/en/switch_language.md b/docs/en/switch_language.md index 7490e18343..4b4ffc7c9b 100644 --- a/docs/en/switch_language.md +++ b/docs/en/switch_language.md @@ -1,3 +1,3 @@ -# English +# English -# 简体中文 +# 简体中文 diff --git a/docs/en/user_guides/config.md b/docs/en/user_guides/config.md index 72b0d6c734..a4b7d51603 100644 --- a/docs/en/user_guides/config.md +++ b/docs/en/user_guides/config.md @@ -77,7 +77,7 @@ Please refer to [MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs ## An example of EDSR To help the users have a basic idea of a complete config, -we make a brief comments on the [config of the EDSR model](https://github.com/open-mmlab/mmediting/blob/1.x/configs/edsr/edsr_x2c64b16_g1_300k_div2k.py) we implemented as the following. +we make a brief comments on the [config of the EDSR model](https://github.com/open-mmlab/mmediting/blob/main/configs/edsr/edsr_x2c64b16_g1_300k_div2k.py) we implemented as the following. For more detailed usage and the corresponding alternative for each modules, please refer to the API documentation and the [tutorial in MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/config.md). @@ -285,7 +285,7 @@ resume = False # Resume checkpoints from a given path, the training will be res ## An example of StyleGAN2 -Taking [Stylegan2 at 1024x1024 scale](https://github.com/open-mmlab/mmediting/blob/1.x/configs//styleganv2/stylegan2_c2_8xb4-fp16-global-800kiters_quicktest-ffhq-256x256.py) as an example, +Taking [Stylegan2 at 1024x1024 scale](https://github.com/open-mmlab/mmediting/blob/main/configs//styleganv2/stylegan2_c2_8xb4-fp16-global-800kiters_quicktest-ffhq-256x256.py) as an example, we introduce each field in the config according to different function modules. ### Model config @@ -416,7 +416,7 @@ optim_wrapper = dict( `param_scheduler` is a field that configures methods of adjusting optimization hyperparameters such as learning rate and momentum. Users can combine multiple schedulers to create a desired parameter adjustment strategy. Find more in [parameter scheduler tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/param_scheduler.html). -Since StyleGAN2 do not use parameter scheduler, we use config in [CycleGAN](https://github.com/open-mmlab/mmediting/blob/1.x/configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py) as an example: +Since StyleGAN2 do not use parameter scheduler, we use config in [CycleGAN](https://github.com/open-mmlab/mmediting/blob/main/configs/cyclegan/cyclegan_lsgan-id0-resnet-in_1xb1-250kiters_summer2winter.py) as an example: ```python # parameter scheduler in CycleGAN config diff --git a/docs/en/user_guides/dataset_prepare.md b/docs/en/user_guides/dataset_prepare.md index b26ae391cf..b33c3f6640 100644 --- a/docs/en/user_guides/dataset_prepare.md +++ b/docs/en/user_guides/dataset_prepare.md @@ -23,7 +23,7 @@ For example, you can simply prepare Vimeo90K-triplet datasets by downloading dat ## Prepare datasets -Some datasets need to be preprocessed before training or testing. We support many scripts to prepare datasets in [tools/dataset_converters](https://github.com/open-mmlab/mmediting/tree/1.x/tools/dataset_converters). And you can follow the tutorials of every dataset to run scripts. +Some datasets need to be preprocessed before training or testing. We support many scripts to prepare datasets in [tools/dataset_converters](https://github.com/open-mmlab/mmediting/tree/main/tools/dataset_converters). And you can follow the tutorials of every dataset to run scripts. For example, we recommend cropping the DIV2K images to sub-images. We provide a script to prepare cropped DIV2K dataset. You can run the following command: ```shell diff --git a/docs/en/user_guides/deploy.md b/docs/en/user_guides/deploy.md index ce2ff00274..1b80a5eb55 100644 --- a/docs/en/user_guides/deploy.md +++ b/docs/en/user_guides/deploy.md @@ -1,7 +1,7 @@ # Tutorial 8: Deploy models in MMEditing The deployment of OpenMMLab codebases, including MMClassification, MMDetection, MMEditing and so on are supported by [MMDeploy](https://github.com/open-mmlab/mmdeploy). -The latest deployment guide for MMEditing can be found from [here](https://mmdeploy.readthedocs.io/en/1.x/04-supported-codebases/mmedit.html). +The latest deployment guide for MMEditing can be found from [here](https://mmdeploy.readthedocs.io/en/latest/04-supported-codebases/mmedit.html). This tutorial is organized as follows: @@ -15,7 +15,7 @@ This tutorial is organized as follows: ## Installation -Please follow the [guide](../get_started/install.md) to install mmedit. And then install mmdeploy from source by following [this](https://mmdeploy.readthedocs.io/en/1.x/get_started.html#installation) guide. +Please follow the [guide](../get_started/install.md) to install mmedit. And then install mmdeploy from source by following [this](https://mmdeploy.readthedocs.io/en/latest/get_started.html#installation) guide. ```{note} If you install mmdeploy prebuilt package, please also clone its repository by 'git clone https://github.com/open-mmlab/mmdeploy.git --depth=1' to get the deployment config files. @@ -48,7 +48,7 @@ torch2onnx(img, work_dir, save_file, deploy_cfg, model_cfg, export2SDK(deploy_cfg, model_cfg, work_dir, pth=model_checkpoint, device=device) ``` -It is crucial to specify the correct deployment config during model conversion.MMDeploy has already provided builtin deployment config [files](https://github.com/open-mmlab/mmdeploy/tree/1.x/configs/mmedit) of all supported backends for mmedit, under which the config file path follows the pattern: +It is crucial to specify the correct deployment config during model conversion.MMDeploy has already provided builtin deployment config [files](https://github.com/open-mmlab/mmdeploy/tree/main/configs/mmedit) of all supported backends for mmedit, under which the config file path follows the pattern: ``` {task}/{task}_{backend}-{precision}_{static | dynamic}_{shape}.py @@ -151,8 +151,8 @@ result = restorer(img) cv2.imwrite('output_restorer.bmp', result) ``` -Besides python API, MMDeploy SDK also provides other FFI (Foreign Function Interface), such as C, C++, C#, Java and so on. You can learn their usage from [demos](https://github.com/open-mmlab/mmdeploy/tree/1.x/demo). +Besides python API, MMDeploy SDK also provides other FFI (Foreign Function Interface), such as C, C++, C#, Java and so on. You can learn their usage from [demos](https://github.com/open-mmlab/mmdeploy/tree/main/demo). ## Supported models -Please refer to [here](https://mmdeploy.readthedocs.io/en/1.x/04-supported-codebases/mmedit.html#supported-models) for the supported model list. +Please refer to [here](https://mmdeploy.readthedocs.io/en/latest/04-supported-codebases/mmedit.html#supported-models) for the supported model list. diff --git a/docs/en/user_guides/inference.md b/docs/en/user_guides/inference.md index cc71aaf608..c2a87f4df1 100644 --- a/docs/en/user_guides/inference.md +++ b/docs/en/user_guides/inference.md @@ -113,7 +113,7 @@ model = init_model(config_file, checkpoint_file, device=device) fake_imgs = sample_ddpm_model(model, 4) ``` -Indeed, we have already provided a more friendly demo script to users. You can use [demo/ddpm_demo.py](https://github.com/open-mmlab/mmediting/blob/1.x/demo/ddpm_demo.py) with the following commands: +Indeed, we have already provided a more friendly demo script to users. You can use [demo/ddpm_demo.py](https://github.com/open-mmlab/mmediting/blob/main/demo/ddpm_demo.py) with the following commands: ```shell python demo/ddpm_demo.py \ diff --git a/docs/en/user_guides/metrics.md b/docs/en/user_guides/metrics.md index 500bd4f07e..5e04a8e4a8 100644 --- a/docs/en/user_guides/metrics.md +++ b/docs/en/user_guides/metrics.md @@ -141,7 +141,7 @@ val_evaluator = [ Fréchet Inception Distance is a measure of similarity between two datasets of images. It was shown to correlate well with the human judgment of visual quality and is most often used to evaluate the quality of samples of Generative Adversarial Networks. FID is calculated by computing the Fréchet distance between two Gaussians fitted to feature representations of the Inception network. -In `MMEditing`, we provide two versions for FID calculation. One is the commonly used PyTorch version and the other one is used in StyleGAN paper. Meanwhile, we have compared the difference between these two implementations in the StyleGAN2-FFHQ1024 model (the details can be found [here](https://github.com/open-mmlab/mmediting/blob/1.x/configs/styleganv2/README.md)). Fortunately, there is a marginal difference in the final results. Thus, we recommend users adopt the more convenient PyTorch version. +In `MMEditing`, we provide two versions for FID calculation. One is the commonly used PyTorch version and the other one is used in StyleGAN paper. Meanwhile, we have compared the difference between these two implementations in the StyleGAN2-FFHQ1024 model (the details can be found [here](https://github.com/open-mmlab/mmediting/blob/main/configs/styleganv2/README.md)). Fortunately, there is a marginal difference in the final results. Thus, we recommend users adopt the more convenient PyTorch version. **About PyTorch version and Tero's version:** The commonly used PyTorch version adopts the modified InceptionV3 network to extract features for real and fake images. However, Tero's FID requires a [script module](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt) for Tensorflow InceptionV3. Note that applying this script module needs `PyTorch >= 1.6.0`. @@ -227,7 +227,7 @@ to [evaluation](../user_guides/train_test.md) for details. ## Precision and Recall -Our `Precision and Recall` implementation follows the version used in StyleGAN2. In this metric, a VGG network will be adopted to extract the features for images. Unfortunately, we have not found a PyTorch VGG implementation leading to similar results with Tero's version used in StyleGAN2. (About the differences, please see this [file](https://github.com/open-mmlab/mmediting/blob/1.x/configs/styleganv2/README.md).) Thus, in our implementation, we adopt [Teor's VGG](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/vgg16.pt) network by default. Importantly, applying this script module needs `PyTorch >= 1.6.0`. If with a lower PyTorch version, we will use the PyTorch official VGG network for feature extraction. +Our `Precision and Recall` implementation follows the version used in StyleGAN2. In this metric, a VGG network will be adopted to extract the features for images. Unfortunately, we have not found a PyTorch VGG implementation leading to similar results with Tero's version used in StyleGAN2. (About the differences, please see this [file](https://github.com/open-mmlab/mmediting/blob/main/configs/styleganv2/README.md).) Thus, in our implementation, we adopt [Teor's VGG](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/vgg16.pt) network by default. Importantly, applying this script module needs `PyTorch >= 1.6.0`. If with a lower PyTorch version, we will use the PyTorch official VGG network for feature extraction. To evaluate with `P&R`, please add the following configuration in the config file: diff --git a/docs/en/user_guides/train_test.md b/docs/en/user_guides/train_test.md index ecc60fe58f..6b1d9cb55a 100644 --- a/docs/en/user_guides/train_test.md +++ b/docs/en/user_guides/train_test.md @@ -72,7 +72,7 @@ You can check [slurm_test.sh](../../../tools/slurm_test.sh) for full arguments a ### Test with specific metrics MMEditing provides various **evaluation metrics**, i.e., MS-SSIM, SWD, IS, FID, Precision&Recall, PPL, Equivarience, TransFID, TransIS, etc. -We have provided unified evaluation scripts in [tools/test.py](https://github.com/open-mmlab/mmediting/tree/1.x/tools/test.py) for all models. +We have provided unified evaluation scripts in [tools/test.py](https://github.com/open-mmlab/mmediting/tree/main/tools/test.py) for all models. If users want to evaluate their models with some metrics, you can add the `metrics` into your config file like this: ```python @@ -102,7 +102,7 @@ Then users can test models with the command below: bash tools/dist_test.sh ${CONFIG_FILE} ${CKPT_FILE} ``` -If you are in slurm environment, please switch to the [tools/slurm_test.sh](https://github.com/open-mmlab/mmediting/tree/1.x/tools/slurm_test.sh) by using the following commands: +If you are in slurm environment, please switch to the [tools/slurm_test.sh](https://github.com/open-mmlab/mmediting/tree/main/tools/slurm_test.sh) by using the following commands: ```shell sh slurm_test.sh ${PLATFORM} ${JOBNAME} ${CONFIG_FILE} ${CKPT_FILE} diff --git a/docs/zh_cn/.dev_scripts/update_model_zoo.py b/docs/zh_cn/.dev_scripts/update_model_zoo.py index c780bb314e..7940cf4b62 100755 --- a/docs/zh_cn/.dev_scripts/update_model_zoo.py +++ b/docs/zh_cn/.dev_scripts/update_model_zoo.py @@ -12,7 +12,7 @@ import titlecase from tqdm import tqdm -github_link = 'https://github.com/open-mmlab/mmediting/blob/1.x/' +github_link = 'https://github.com/open-mmlab/mmediting/blob/main/' def anchor(name): diff --git a/docs/zh_cn/changelog.md b/docs/zh_cn/changelog.md index 315591008a..8c16e2f9bd 100644 --- a/docs/zh_cn/changelog.md +++ b/docs/zh_cn/changelog.md @@ -186,4 +186,4 @@ MMEditing 1.0.0rc0 是 MMEditing 1.x 的第一个版本,是 OpenMMLab 2.0 项 基于新的[训练引擎](https://github.com/open-mmlab/mmengine), MMEditing 1.x 统一了数据、模型、评测和可视化的接口。 -该版本存在有一些 BC-breaking 的修改。 请在[迁移指南](https://mmediting.readthedocs.io/zh_CN/1.x/migration/overview.html)中查看更多细节。 +该版本存在有一些 BC-breaking 的修改。 请在[迁移指南](https://mmediting.readthedocs.io/zh_CN/latest/migration/overview.html)中查看更多细节。 diff --git a/docs/zh_cn/switch_language.md b/docs/zh_cn/switch_language.md index 5fc8dc67b1..5f17de764a 100644 --- a/docs/zh_cn/switch_language.md +++ b/docs/zh_cn/switch_language.md @@ -1,3 +1,3 @@ -## English +## English -## 简体中文 +## 简体中文 diff --git a/docs/zh_cn/user_guides/dataset_prepare.md b/docs/zh_cn/user_guides/dataset_prepare.md index c263aa8d37..234378b0ad 100644 --- a/docs/zh_cn/user_guides/dataset_prepare.md +++ b/docs/zh_cn/user_guides/dataset_prepare.md @@ -24,7 +24,7 @@ ## 准备数据集 一些数据集需要在训练或测试之前进行预处理。我们在 -[tools/dataset_converters](https://github.com/open-mmlab/mmediting/tree/1.x/tools/dataset_converters)中支持许多用来准备数据集的脚本。 +[tools/dataset_converters](https://github.com/open-mmlab/mmediting/tree/main/tools/dataset_converters)中支持许多用来准备数据集的脚本。 您可以遵循每个数据集的教程来运行脚本。例如,我们建议将DIV2K图像裁剪为子图像。我们提供了一个脚本来准备裁剪的DIV2K数据集。可以运行以下命令: ```shell diff --git a/docs/zh_cn/user_guides/deploy.md b/docs/zh_cn/user_guides/deploy.md index d5ac375884..77be5c0fe0 100644 --- a/docs/zh_cn/user_guides/deploy.md +++ b/docs/zh_cn/user_guides/deploy.md @@ -1,7 +1,7 @@ # 教程 8:模型部署指南 [MMDeploy](https://github.com/open-mmlab/mmdeploy) 是 OpenMMLab 的部署仓库,负责包括 MMClassification、MMDetection、MMEditing 等在内的各算法库的部署工作。 -你可以从[这里](https://mmdeploy.readthedocs.io/zh_CN/1.x/04-supported-codebases/mmedit.html)获取 MMDeploy 对 MMClassification 部署支持的最新文档。 +你可以从[这里](https://mmdeploy.readthedocs.io/zh_CN/latest/04-supported-codebases/mmedit.html)获取 MMDeploy 对 MMClassification 部署支持的最新文档。 本文的结构如下: @@ -15,7 +15,7 @@ ## 安装 -请参考[此处](../get_started/install.md)安装 mmedit。然后,按照[说明](https://mmdeploy.readthedocs.io/zh_CN/1.x/get_started.html#mmdeploy)安装 mmdeploy。 +请参考[此处](../get_started/install.md)安装 mmedit。然后,按照[说明](https://mmdeploy.readthedocs.io/zh_CN/latest/get_started.html#mmdeploy)安装 mmdeploy。 ```{note} 如果安装的是 mmdeploy 预编译包,那么也请通过 'git clone https://github.com/open-mmlab/mmdeploy.git --depth=1' 下载 mmdeploy 源码。因为它包含了部署时要用到的配置文件 @@ -45,7 +45,7 @@ torch2onnx(img, work_dir, save_file, deploy_cfg, model_cfg, export2SDK(deploy_cfg, model_cfg, work_dir, pth=model_checkpoint, device=device) ``` -转换的关键之一是使用正确的配置文件。项目中已内置了各后端部署[配置文件](https://github.com/open-mmlab/mmdeploy/tree/1.x/configs/mmedit)。 +转换的关键之一是使用正确的配置文件。项目中已内置了各后端部署[配置文件](https://github.com/open-mmlab/mmdeploy/tree/main/configs/mmedit)。 文件的命名模式是: ``` @@ -148,8 +148,8 @@ cv2.imwrite('output_restorer.bmp', result) ``` 除了python API,mmdeploy SDK 还提供了诸如 C、C++、C#、Java等多语言接口。 -你可以参考[样例](https://github.com/open-mmlab/mmdeploy/tree/1.x/demo)学习其他语言接口的使用方法。 +你可以参考[样例](https://github.com/open-mmlab/mmdeploy/tree/main/demo)学习其他语言接口的使用方法。 ## 模型支持列表 -请参考[这里](https://mmdeploy.readthedocs.io/zh_CN/1.x/04-supported-codebases/mmedit.html#id7) +请参考[这里](https://mmdeploy.readthedocs.io/zh_CN/latest/04-supported-codebases/mmedit.html#id7) diff --git a/docs/zh_cn/user_guides/metrics.md b/docs/zh_cn/user_guides/metrics.md index 11620db4bf..30b1ce5eb0 100644 --- a/docs/zh_cn/user_guides/metrics.md +++ b/docs/zh_cn/user_guides/metrics.md @@ -140,7 +140,7 @@ val_evaluator = [ Fréchet初始距离是两个图像数据集之间相似度的度量。它被证明与人类对视觉质量的判断有很好的相关性,最常用于评估生成对抗网络样本的质量。FID是通过计算两个高斯函数之间的Fréchet距离来计算的,这些高斯函数适合于Inception网络的特征表示。 -在`MMEditing`中,我们提供了两个版本的FID计算。一个是常用的PyTorch版本,另一个用于StyleGAN。同时,我们在StyleGAN2-FFHQ1024模型中比较了这两种实现之间的差异(详细信息可以在这里找到\[https://github.com/open-mmlab/mmediting/blob/1.x/configs/styleganv2/README.md\])。幸运的是,最终结果只是略有不同。因此,我们建议用户采用更方便的PyTorch版本。 +在`MMEditing`中,我们提供了两个版本的FID计算。一个是常用的PyTorch版本,另一个用于StyleGAN。同时,我们在StyleGAN2-FFHQ1024模型中比较了这两种实现之间的差异(详细信息可以在这里找到\[https://github.com/open-mmlab/mmediting/blob/main/configs/styleganv2/README.md\])。幸运的是,最终结果只是略有不同。因此,我们建议用户采用更方便的PyTorch版本。 **关于PyTorch版本和Tero版本:** 常用的PyTorch版本采用修改后的InceptionV3网络提取真假图像特征。然而,Tero的FID需要Tensorflow InceptionV3的[脚本模块](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/inception-2015-12-05.pt)。注意,应用此脚本模块需要' PyTorch >= 1.6.0 '。 @@ -224,7 +224,7 @@ metrics = [ ## Precision and Recall -我们的'Precision and Recall'实现遵循StyleGAN2中使用的版本。在该度量中,采用VGG网络对图像进行特征提取。不幸的是,我们还没有发现PyTorch VGG实现与StyleGAN2中使用的Tero版本产生类似的结果。(关于差异,请参阅这个[文件](https://github.com/open-mmlab/mmediting/blob/1.x/configs/styleganv2/README.md)。)因此,在我们的实现中,我们默认采用[Teor's VGG](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/vgg16.pt)网络。需要注意的是,应用这个脚本模块需要'PyTorch >= 1.6.0'。如果使用较低的PyTorch版本,我们将使用PyTorch官方VGG网络进行特征提取。 +我们的'Precision and Recall'实现遵循StyleGAN2中使用的版本。在该度量中,采用VGG网络对图像进行特征提取。不幸的是,我们还没有发现PyTorch VGG实现与StyleGAN2中使用的Tero版本产生类似的结果。(关于差异,请参阅这个[文件](https://github.com/open-mmlab/mmediting/blob/main/configs/styleganv2/README.md)。)因此,在我们的实现中,我们默认采用[Teor's VGG](https://nvlabs-fi-cdn.nvidia.com/stylegan2-ada-pytorch/pretrained/metrics/vgg16.pt)网络。需要注意的是,应用这个脚本模块需要'PyTorch >= 1.6.0'。如果使用较低的PyTorch版本,我们将使用PyTorch官方VGG网络进行特征提取。 要使用' P&R '进行评估,请在配置文件中添加以下配置: ```python diff --git a/mmedit/datasets/basic_conditional_dataset.py b/mmedit/datasets/basic_conditional_dataset.py index 5e61c41223..562f9f3f17 100644 --- a/mmedit/datasets/basic_conditional_dataset.py +++ b/mmedit/datasets/basic_conditional_dataset.py @@ -15,9 +15,9 @@ class BasicConditionalDataset(BaseDataset): """Custom dataset for conditional GAN. This class is based on the combination of `BaseDataset` (https://github.com/open- - mmlab/mmclassification/blob/1.x/mmcls/datasets/base_dataset.py) # noqa and - `CustomDataset` (https://github.com/open- - mmlab/mmclassification/blob/1.x/mmcls/datasets/custom.py). # noqa. + mmlab/mmclassification/blob/main/mmcls/datasets/base_dataset.py) # noqa + and `CustomDataset` (https://github.com/open- + mmlab/mmclassification/blob/main/mmcls/datasets/custom.py). # noqa. The dataset supports two kinds of annotation format. diff --git a/projects/README.md b/projects/README.md index f6e6c0ca9e..f0da689ed8 100644 --- a/projects/README.md +++ b/projects/README.md @@ -18,11 +18,11 @@ You can copy and create your own project from the [example project](./example_pr We also provide some documentation listed below for your reference: -- [Contribution Guide](https://mmediting.readthedocs.io/en/dev-1.x/community/contributing.html) +- [Contribution Guide](https://mmediting.readthedocs.io/en/latest/community/contributing.html) The guides for new contributors about how to add your projects to MMEditing. -- [New Model Guide](https://mmediting.readthedocs.io/en/dev-1.x/howto/models.html) +- [New Model Guide](https://mmediting.readthedocs.io/en/latest/howto/models.html) The documentation of adding new models. diff --git a/projects/example_project/README.md b/projects/example_project/README.md index 7675bfb700..06cd1e561d 100644 --- a/projects/example_project/README.md +++ b/projects/example_project/README.md @@ -18,7 +18,7 @@ This is an implementation of \[XXX\]. ### Setup Environment \[required\] -Please refer to [Get Started](https://mmediting.readthedocs.io/en/1.x/get_started/I.html) to install +Please refer to [Get Started](https://mmediting.readthedocs.io/en/latest/get_started/I.html) to install MMEditing. At first, add the current folder to `PYTHONPATH`, so that Python can find your code. Run command in the current directory to add it. @@ -31,7 +31,7 @@ export PYTHONPATH=`pwd`:$PYTHONPATH ### Data Preparation \[optional\] -Prepare the ImageNet-2012 dataset according to the [instruction](https://mmediting.readthedocs.io/en/dev-1.x/user_guides/dataset_prepare.html#imagenet). +Prepare the ImageNet-2012 dataset according to the [instruction](https://mmediting.readthedocs.io/en/latest/user_guides/dataset_prepare.html#imagenet). ### Training commands \[optional\] @@ -129,7 +129,7 @@ to MMediting projects. - [ ] Unit tests - + - [ ] Code style @@ -137,4 +137,4 @@ to MMediting projects. - [ ] `metafile.yml` and `README.md` - + diff --git a/tools/gui/README.md b/tools/gui/README.md index 6de87446a7..483ad8e1da 100644 --- a/tools/gui/README.md +++ b/tools/gui/README.md @@ -58,13 +58,7 @@ pip install opencv-python-headless Install MMEditing. ```shell -git clone -b 1.x https://github.com/open-mmlab/mmediting.git -``` - -If you want to follow the newest features, you can clone `dev-1.x` branch. - -```shell -git clone -b dev-1.x https://github.com/open-mmlab/mmediting.git +git clone https://github.com/open-mmlab/mmediting.git ``` **Step 3.** From 082b940aaa5b16b7c1ad1f4349a48190e3e49860 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 6 Apr 2023 20:19:00 +0800 Subject: [PATCH 33/39] [Doc] update migration and doc links (#1734) --- docs/en/faq.md | 4 ++-- docs/en/howto/dataset.md | 2 +- docs/en/migration/schedule.md | 2 +- docs/en/user_guides/config.md | 12 ++++++------ docs/en/user_guides/visualization.md | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/en/faq.md b/docs/en/faq.md index 7205a47449..42f40788bc 100644 --- a/docs/en/faq.md +++ b/docs/en/faq.md @@ -37,9 +37,9 @@ If mmcv and mmcv-full are both installed, there will be `ModuleNotFoundError`. **A5**: Sometimes, you may set `_delete_=True` to ignore some of fields in base configs. -You may refer to [MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/tutorials/config.md#%E5%88%A0%E9%99%A4%E5%AD%97%E5%85%B8%E4%B8%AD%E7%9A%84-key) for simple illustration. +You may refer to [MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md#delete-key-in-dict) for simple illustration. -You may have a careful look at [this tutorial](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/config.md) for better understanding of this feature. +You may have a careful look at [this tutorial](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md) for better understanding of this feature. **Q6**:: How can I use intermediate variables in configs? diff --git a/docs/en/howto/dataset.md b/docs/en/howto/dataset.md index 48e0c00db6..49e4e9f646 100644 --- a/docs/en/howto/dataset.md +++ b/docs/en/howto/dataset.md @@ -578,4 +578,4 @@ dataset_A_train = dict( ) ``` -You may refer to [tutorial in MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/basedataset.md). +You may refer to [tutorial in MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/basedataset.md). diff --git a/docs/en/migration/schedule.md b/docs/en/migration/schedule.md index 3e2c58a978..e5c3016435 100644 --- a/docs/en/migration/schedule.md +++ b/docs/en/migration/schedule.md @@ -47,4 +47,4 @@ test_cfg = dict(type='TestLoop') # The name of test loop type -> More details of schedule settings are shown in [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/migration/migrate_param_scheduler_from_mmcv.md). +> More details of schedule settings are shown in [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/migration/param_scheduler.md). diff --git a/docs/en/user_guides/config.md b/docs/en/user_guides/config.md index a4b7d51603..43608a452d 100644 --- a/docs/en/user_guides/config.md +++ b/docs/en/user_guides/config.md @@ -58,7 +58,7 @@ then modify the necessary fields in the config files. If you are building an entirely new method that does not share the structure with any of the existing methods, you may create a folder `xxx` under `configs`, -Please refer to [MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/config.md) for detailed documentation. +Please refer to [MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md) for detailed documentation. ## Config name style @@ -79,7 +79,7 @@ Please refer to [MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs To help the users have a basic idea of a complete config, we make a brief comments on the [config of the EDSR model](https://github.com/open-mmlab/mmediting/blob/main/configs/edsr/edsr_x2c64b16_g1_300k_div2k.py) we implemented as the following. For more detailed usage and the corresponding alternative for each modules, -please refer to the API documentation and the [tutorial in MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/config.md). +please refer to the API documentation and the [tutorial in MMEngine](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/config.md). ### Model config @@ -190,7 +190,7 @@ test_dataloader = val_dataloader ### Evaluation config -[Evaluators](https://mmengine.readthedocs.io/en/latest/tutorials/metric_and_evaluator.html) are used to compute the metrics of the trained model on the validation and testing datasets. +[Evaluators](https://mmengine.readthedocs.io/en/latest/tutorials/evaluation.html) are used to compute the metrics of the trained model on the validation and testing datasets. The config of evaluators consists of one or a list of metric configs: ```python @@ -220,7 +220,7 @@ test_cfg = dict(type='TestLoop') # The name of test loop type ### Optimization config `optim_wrapper` is the field to configure optimization related settings. -The optimizer wrapper not only provides the functions of the optimizer, but also supports functions such as gradient clipping, mixed precision training, etc. Find more in [optimizer wrapper tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/optimizer.html). +The optimizer wrapper not only provides the functions of the optimizer, but also supports functions such as gradient clipping, mixed precision training, etc. Find more in [optimizer wrapper tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/optim_wrapper.html). ```python optim_wrapper = dict( @@ -362,7 +362,7 @@ val_dataloader = dict( # The config of validation dataloader test_dataloader = val_dataloader # The config of the testing dataloader ``` -[Evaluators](https://mmengine.readthedocs.io/en/latest/tutorials/metric_and_evaluator.html) are used to compute the metrics of the trained model on the validation and testing datasets. +[Evaluators](https://mmengine.readthedocs.io/en/latest/tutorials/evaluation.html) are used to compute the metrics of the trained model on the validation and testing datasets. The config of evaluators consists of one or a list of metric configs: ```python @@ -399,7 +399,7 @@ test_cfg = dict(type='GenTestLoop') # The testing loop type ### Optimization config `optim_wrapper` is the field to configure optimization related settings. -The optimizer wrapper not only provides the functions of the optimizer, but also supports functions such as gradient clipping, mixed precision training, etc. Find more in [optimizer wrapper tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/optimizer.html). +The optimizer wrapper not only provides the functions of the optimizer, but also supports functions such as gradient clipping, mixed precision training, etc. Find more in [optimizer wrapper tutorial](https://mmengine.readthedocs.io/en/latest/tutorials/optim_wrapper.html). ```python optim_wrapper = dict( diff --git a/docs/en/user_guides/visualization.md b/docs/en/user_guides/visualization.md index 31a0326cff..c3eb099daa 100644 --- a/docs/en/user_guides/visualization.md +++ b/docs/en/user_guides/visualization.md @@ -1,7 +1,7 @@ # Tutorial 6: Visualization The visualization of images is an important way to measure the quality of image processing, editing and synthesis. -Using `visualizer` in config file can save visual results when training or testing. You can follow [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/visualization.md) to learn the usage of visualization. MMEditing provides a rich set of visualization functions. +Using `visualizer` in config file can save visual results when training or testing. You can follow [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/visualization.md) to learn the usage of visualization. MMEditing provides a rich set of visualization functions. In this tutorial, we introduce the usage of the visualization functions provided by MMEditing. - [Overview](#overview) @@ -253,7 +253,7 @@ Then `show` or `add_image` will be called to directly show the results or pass t In general, users do not need to manipulate `VisBackend` objects, only when the current visualization storage can not meet the needs, users will want to manipulate the storage backend directly. MMEditing supports a variety of different visualization backends, including: -- Basic VisBackend of MMEngine: including LocalVisBackend, TensorboardVisBackend and WandbVisBackend. You can follow [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/visualization.md) to learn more about them +- Basic VisBackend of MMEngine: including LocalVisBackend, TensorboardVisBackend and WandbVisBackend. You can follow [MMEngine Documents](https://github.com/open-mmlab/mmengine/blob/main/docs/en/advanced_tutorials/visualization.md) to learn more about them - GenVisBackend: Backend for **File System**. Save the visualization results to the corresponding position. - TensorboardGenVisBackend: Backend for **Tensorboard**. Send the visualization results to Tensorboard. - PaviGenVisBackend: Backend for **Pavi**. Send the visualization results to Tensorboard. From 0766b37e42858cba6afe0eacc8ff0eabd9d4dccf Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Thu, 6 Apr 2023 22:24:15 +0800 Subject: [PATCH 34/39] [Feature] Support ControlNet (#1744) * support ControlNet model * support ControlNet and corresponding README * revise year in readme * revise convert base model's unit test --- configs/controlnet/README.md | 195 +++++++ configs/controlnet/controlnet-1xb1-fill50k.py | 80 +++ configs/controlnet/controlnet-canny.py | 32 ++ configs/controlnet/controlnet-pose.py | 32 ++ configs/controlnet/controlnet-seg.py | 32 ++ configs/controlnet/metafile.yml | 41 ++ mmedit/models/editors/__init__.py | 4 +- mmedit/models/editors/controlnet/__init__.py | 5 + .../models/editors/controlnet/controlnet.py | 540 ++++++++++++++++++ .../editors/controlnet/controlnet_utils.py | 9 +- model-index.yml | 1 + .../test_controlnet/test_controlnet.py | 184 ++++++ .../test_controlnet/test_controlnet_utils.py | 10 +- 13 files changed, 1159 insertions(+), 6 deletions(-) create mode 100644 configs/controlnet/README.md create mode 100644 configs/controlnet/controlnet-1xb1-fill50k.py create mode 100644 configs/controlnet/controlnet-canny.py create mode 100644 configs/controlnet/controlnet-pose.py create mode 100644 configs/controlnet/controlnet-seg.py create mode 100644 configs/controlnet/metafile.yml create mode 100644 mmedit/models/editors/controlnet/__init__.py create mode 100644 mmedit/models/editors/controlnet/controlnet.py create mode 100644 tests/test_models/test_editors/test_controlnet/test_controlnet.py diff --git a/configs/controlnet/README.md b/configs/controlnet/README.md new file mode 100644 index 0000000000..e9faa85066 --- /dev/null +++ b/configs/controlnet/README.md @@ -0,0 +1,195 @@ +# Control Net (2023) + +> [Adding Conditional Control to Text-to-Image Diffusion Models](https://arxiv.org/abs/2302.05543) + +> **Task**: Text2Image + + + +## Abstract + + + +We present a neural network structure, ControlNet, to control pretrained large diffusion models to support additional input conditions. The ControlNet learns task-specific conditions in an end-to-end way, and the learning is robust even when the training dataset is small (\< 50k). Moreover, training a ControlNet is as fast as fine-tuning a diffusion model, and the model can be trained on a personal devices. Alternatively, if powerful computation clusters are available, the model can scale to large amounts (millions to billions) of data. We report that large diffusion models like Stable Diffusion can be augmented with ControlNets to enable conditional inputs like edge maps, segmentation maps, keypoints, etc. This may enrich the methods to control large diffusion models and further facilitate related applications. + + + +
+ +
+ +## Pretrained models + +We use ControlNet's weights provided by HuggingFace Diffusers. You do not have to download the weights manually. If you use Diffusers wrapper, the weights will be downloaded automatically. + +This model has several weights including vae, unet and clip. You should download the weights from [stable-diffusion-1.5](https://huggingface.co/runwayml/stable-diffusion-v1-5) and change the 'pretrained_model_path' in config to the weights dir. + +| Model | Dataset | Download | +| :---------------------------------------------: | :-----: | :----------------------------------------------------------------------------------------------: | +| [ControlNet-Canny](./controlnet-canny.py) | - | [model](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_canny.pth) | +| [ControlNet-Segmentation](./controlnet-seg.py) | - | [model](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_seg.pth) | +| [ControlNet-Pose](./controlnet-pose.py) | - | [model](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_openpose.pth) | +| [ControlNet-Demo](./controlnet-1xb1-fill50k.py) | - | - | + +Noted that, [ControlNet-Demo](./controlnet-1xb1-demo_dataset.py) is a demo config to train ControlNet with toy dataset named Fill50K. + +Besides above configs, ControlNet have weight with other condition inputs, such as [depth](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_depth.pth), [hed](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_hed.pth), [mlsd](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_mlsd.pth), [normal](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_normal.pth), [scribble](https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_scribble.pth). You can simple change the `from_pretrained` field of ControlNet to use these weights. For example: + +```python +# Switch from canny.... +controlnet=dict( + type='ControlNetModel', + from_pretrained='lllyasviel/sd-controlnet-canny') + +# To normal.... +controlnet=dict( + type='ControlNetModel', + from_pretrained='lllyasviel/sd-controlnet-normal') +``` + +## Quick Start + +Running the following codes, you can get a text-generated image. + +```python +import mmcv +from mmengine import Config +from PIL import Image + +from mmedit.registry import MODELS +from mmedit.utils import register_all_modules + +register_all_modules() + +cfg = Config.fromfile('configs/controlnet/controlnet_canny.py') +controlnet = MODELS.build(cfg.model).cuda() + +prompt = 'Room with blue walls and a yellow ceiling.' +control_url = 'https://user-images.githubusercontent.com/28132635/230288866-99603172-04cb-47b3-8adb-d1aa532d1d2c.jpg' +control_img = mmcv.imread(control_url) +control = cv2.Canny(control_img, 100, 200) +control = control[:, :, None] +control = np.concatenate([control] * 3, axis=2) +control = Image.fromarray(control) + +output_dict = controlnet.infer(prompt, control=control) +samples = output_dict['samples'] +for idx, sample in enumerate(samples): + sample.save(f'sample_{idx}.png') +controls = output_dict['controls'] +for idx, control in enumerate(controls): + control.save(f'control_{idx}.png') +``` + + + + + + + +
+
+ +
+ 'control_0.png' +
+
+ +
+ 'sample_0.png' +
+
+ +If you want to pretrained weights rather than original Stable-Diffusion v1.5, you can refers to the following codes. + +```python +import mmcv +from mmengine import Config +from PIL import Image + +from mmedit.registry import MODELS +from mmedit.utils import register_all_modules + +register_all_modules() + +cfg = Config.fromfile('configs/controlnet/controlnet_pose.py') +# convert ControlNet's weight from SD-v1.5 to Counterfeit-v2.5 +cfg.model.unet.from_pretrained = 'gsdf/Counterfeit-V2.5' +cfg.model.vae.from_pretrained = 'gsdf/Counterfeit-V2.5' +cfg.model.init_cfg['type'] = 'convert_from_unet' + +controlnet = MODELS.build(cfg.model).cuda() +# call init_weights manually to convert weight +controlnet.init_weights() + +prompt = 'masterpiece, best quality, sky, black hair, skirt, sailor collar, looking at viewer, short hair, building, bangs, neckerchief, long sleeves, cloudy sky, power lines, shirt, cityscape, pleated skirt, scenery, blunt bangs, city, night, black sailor collar, closed mouth' + +control_url = 'https://user-images.githubusercontent.com/28132635/230380893-2eae68af-d610-4f7f-aa68-c2f22c2abf7e.png' +control_img = mmcv.imread(control_url) +control = Image.fromarray(control_img) +control.save('control.png') + +output_dict = controlnet.infer(prompt, control=control, width=512, height=512, guidance_scale=7.5) +samples = output_dict['samples'] +for idx, sample in enumerate(samples): + sample.save(f'sample_{idx}.png') +controls = output_dict['controls'] +for idx, control in enumerate(controls): + control.save(f'control_{idx}.png') +``` + + + + + + + +
+
+ +
+ 'control_0.png' +
+
+ +
+ 'sample_0.png' +
+
+ +## Train your own ControlNet! + +You can start training your own ControlNet with the toy dataset [Fill50K](https://huggingface.co/lllyasviel/ControlNet/blob/main/training/fill50k.zip) with the following command: + +```bash +bash tools/dist_train.sh configs/controlnet/controlnet-1xb1-demo_dataset 1 +``` + +If you want use gradient accumulation, you can add `accumulative_counts` field to the optimizer's config as follow: + +```python +# From... +optim_wrapper = dict(controlnet=dict(optimizer=dict(type='AdamW', lr=1e-5))) +# To... +optim_wrapper = dict( + controlnet=dict(accumulative_counts=4, optimizer=dict(type='AdamW', lr=1e-5))) +``` + +## Comments + +Our codebase for the stable diffusion models builds heavily on [diffusers codebase](https://github.com/huggingface/diffusers) and the model weights are from [stable-diffusion-1.5](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion_controlnet.py) and [ControlNet](https://huggingface.co/lllyasviel/ControlNet/tree/main/models). + +Thanks for the efforts of the community! + +## Citation + +```bibtex +@misc{zhang2023adding, + title={Adding Conditional Control to Text-to-Image Diffusion Models}, + author={Lvmin Zhang and Maneesh Agrawala}, + year={2023}, + eprint={2302.05543}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +``` diff --git a/configs/controlnet/controlnet-1xb1-fill50k.py b/configs/controlnet/controlnet-1xb1-fill50k.py new file mode 100644 index 0000000000..b3bc93d2d6 --- /dev/null +++ b/configs/controlnet/controlnet-1xb1-fill50k.py @@ -0,0 +1,80 @@ +_base_ = '../_base_/gen_default_runtime.py' + +# config for model +stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' +controlnet_canny_url = 'lllyasviel/sd-controlnet-canny' + +model = dict( + type='ControlStableDiffusion', + vae=dict( + type='AutoencoderKL', + from_pretrained=stable_diffusion_v15_url, + subfolder='vae'), + unet=dict( + type='UNet2DConditionModel', + subfolder='unet', + from_pretrained=stable_diffusion_v15_url), + text_encoder=dict( + type='ClipWrapper', + clip_type='huggingface', + pretrained_model_name_or_path=stable_diffusion_v15_url, + subfolder='text_encoder'), + tokenizer=stable_diffusion_v15_url, + controlnet=dict( + type='ControlNetModel', + # from_pretrained=controlnet_canny_rul + from_config=controlnet_canny_url # train from scratch + ), + scheduler=dict( + type='DDPMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + test_scheduler=dict( + type='DDIMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + data_preprocessor=dict(type='EditDataPreprocessor'), + init_cfg=dict(type='init_from_unet')) + +# config for training +train_cfg = dict(max_iters=10000) +optim_wrapper = dict(controlnet=dict(optimizer=dict(type='AdamW', lr=1e-5))) + +# Config for data loader +pipeline = [ + dict(type='LoadImageFromFile', key='source', channel_order='rgb'), + dict(type='LoadImageFromFile', key='target', channel_order='rgb'), + dict( + type='PackEditInputs', + keys=['source', 'target'], + data_keys='prompt', + meta_keys=[ + 'source_channel_order', 'source_color_type', + 'target_channel_order', 'target_color_type' + ]) +] +dataset = dict( + type='ControlDataset', + data_root='./data/fill50k', + ann_file='prompt.json', + pipeline=pipeline) +train_dataloader = dict( + dataset=dataset, + num_workers=16, + sampler=dict(type='InfiniteSampler', shuffle=True), + persistent_workers=True, + batch_size=4) +val_cfg = val_evaluator = val_dataloader = None +test_cfg = test_evaluator = test_dataloader = None + +# hooks +custom_hooks = [ + dict( + type='GenVisualizationHook', + interval=300, + fixed_input=True, + # visualize train dataset + vis_kwargs_list=dict(type='Data', name='fake_img'), + n_samples=4, + n_row=2) +] diff --git a/configs/controlnet/controlnet-canny.py b/configs/controlnet/controlnet-canny.py new file mode 100644 index 0000000000..e965b93cd8 --- /dev/null +++ b/configs/controlnet/controlnet-canny.py @@ -0,0 +1,32 @@ +# config for model +stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' +controlnet_canny_url = 'lllyasviel/sd-controlnet-canny' + +model = dict( + type='ControlStableDiffusion', + vae=dict( + type='AutoencoderKL', + from_pretrained=stable_diffusion_v15_url, + subfolder='vae'), + unet=dict( + type='UNet2DConditionModel', + subfolder='unet', + from_pretrained=stable_diffusion_v15_url), + text_encoder=dict( + type='ClipWrapper', + clip_type='huggingface', + pretrained_model_name_or_path=stable_diffusion_v15_url, + subfolder='text_encoder'), + tokenizer=stable_diffusion_v15_url, + controlnet=dict( + type='ControlNetModel', from_pretrained=controlnet_canny_url), + scheduler=dict( + type='DDPMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + test_scheduler=dict( + type='DDIMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + data_preprocessor=dict(type='EditDataPreprocessor'), + init_cfg=dict(type='init_from_unet')) diff --git a/configs/controlnet/controlnet-pose.py b/configs/controlnet/controlnet-pose.py new file mode 100644 index 0000000000..91360a5232 --- /dev/null +++ b/configs/controlnet/controlnet-pose.py @@ -0,0 +1,32 @@ +# config for model +stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' +controlnet_canny_url = 'lllyasviel/sd-controlnet-openpose' + +model = dict( + type='ControlStableDiffusion', + vae=dict( + type='AutoencoderKL', + from_pretrained=stable_diffusion_v15_url, + subfolder='vae'), + unet=dict( + type='UNet2DConditionModel', + subfolder='unet', + from_pretrained=stable_diffusion_v15_url), + text_encoder=dict( + type='ClipWrapper', + clip_type='huggingface', + pretrained_model_name_or_path=stable_diffusion_v15_url, + subfolder='text_encoder'), + tokenizer=stable_diffusion_v15_url, + controlnet=dict( + type='ControlNetModel', from_pretrained=controlnet_canny_url), + scheduler=dict( + type='DDPMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + test_scheduler=dict( + type='DDIMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + data_preprocessor=dict(type='EditDataPreprocessor'), + init_cfg=dict(type='init_from_unet')) diff --git a/configs/controlnet/controlnet-seg.py b/configs/controlnet/controlnet-seg.py new file mode 100644 index 0000000000..9d65016c51 --- /dev/null +++ b/configs/controlnet/controlnet-seg.py @@ -0,0 +1,32 @@ +# config for model +stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' +controlnet_canny_url = 'lllyasviel/sd-controlnet-seg' + +model = dict( + type='ControlStableDiffusion', + vae=dict( + type='AutoencoderKL', + from_pretrained=stable_diffusion_v15_url, + subfolder='vae'), + unet=dict( + type='UNet2DConditionModel', + subfolder='unet', + from_pretrained=stable_diffusion_v15_url), + text_encoder=dict( + type='ClipWrapper', + clip_type='huggingface', + pretrained_model_name_or_path=stable_diffusion_v15_url, + subfolder='text_encoder'), + tokenizer=stable_diffusion_v15_url, + controlnet=dict( + type='ControlNetModel', from_pretrained=controlnet_canny_url), + scheduler=dict( + type='DDPMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + test_scheduler=dict( + type='DDIMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + data_preprocessor=dict(type='EditDataPreprocessor'), + init_cfg=dict(type='init_from_unet')) diff --git a/configs/controlnet/metafile.yml b/configs/controlnet/metafile.yml new file mode 100644 index 0000000000..d6a06c26cd --- /dev/null +++ b/configs/controlnet/metafile.yml @@ -0,0 +1,41 @@ +Collections: +- Name: Control Net + Paper: + Title: Adding Conditional Control to Text-to-Image Diffusion Models + URL: https://arxiv.org/abs/2302.05543 + README: configs/controlnet/README.md + Task: + - text2image + Year: 2023 +Models: +- Config: configs/controlnet/controlnet-canny.py + In Collection: Control Net + Name: controlnet-canny + Results: + - Dataset: '-' + Metrics: {} + Task: Text2Image + Weights: https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_canny.pth +- Config: configs/controlnet/controlnet-seg.py + In Collection: Control Net + Name: controlnet-seg + Results: + - Dataset: '-' + Metrics: {} + Task: Text2Image + Weights: https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_seg.pth +- Config: configs/controlnet/controlnet-pose.py + In Collection: Control Net + Name: controlnet-pose + Results: + - Dataset: '-' + Metrics: {} + Task: Text2Image + Weights: https://huggingface.co/lllyasviel/ControlNet/blob/main/models/control_sd15_openpose.pth +- Config: configs/controlnet/controlnet-1xb1-fill50k.py + In Collection: Control Net + Name: controlnet-1xb1-fill50k + Results: + - Dataset: '-' + Metrics: {} + Task: Text2Image diff --git a/mmedit/models/editors/__init__.py b/mmedit/models/editors/__init__.py index fdb6702b8e..8e01ec2863 100644 --- a/mmedit/models/editors/__init__.py +++ b/mmedit/models/editors/__init__.py @@ -5,6 +5,7 @@ from .basicvsr_plusplus_net import BasicVSRPlusPlusNet from .biggan import BigGAN from .cain import CAIN, CAINNet +from .controlnet import ControlStableDiffusion from .cyclegan import CycleGAN from .dcgan import DCGAN from .ddpm import DenoisingUnet @@ -85,5 +86,6 @@ 'DiscoDiffusion', 'IDLossModel', 'PESinGAN', 'MSPIEStyleGAN2', 'StyleGAN3Generator', 'InstColorization', 'NAFBaseline', 'NAFBaselineLocal', 'NAFNet', 'NAFNetLocal', 'DenoisingUnet', - 'ClipWrapper', 'EG3D', 'Restormer', 'SwinIRNet', 'StableDiffusion' + 'ClipWrapper', 'EG3D', 'Restormer', 'SwinIRNet', 'StableDiffusion', + 'ControlStableDiffusion' ] diff --git a/mmedit/models/editors/controlnet/__init__.py b/mmedit/models/editors/controlnet/__init__.py new file mode 100644 index 0000000000..de0f8c7c65 --- /dev/null +++ b/mmedit/models/editors/controlnet/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .controlnet import ControlStableDiffusion +from .controlnet_utils import change_base_model + +__all__ = ['ControlStableDiffusion', 'change_base_model'] diff --git a/mmedit/models/editors/controlnet/controlnet.py b/mmedit/models/editors/controlnet/controlnet.py new file mode 100644 index 0000000000..700473bb35 --- /dev/null +++ b/mmedit/models/editors/controlnet/controlnet.py @@ -0,0 +1,540 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from logging import WARNING +from typing import Dict, List, Optional, Tuple, Union + +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +from mmengine import print_log +from mmengine.model import is_model_wrapper +from mmengine.optim import OptimWrapperDict +from PIL import Image +from torch import Tensor +from tqdm import tqdm + +from mmedit.models.utils import build_module +from mmedit.registry import MODELS +from mmedit.structures import EditDataSample +from mmedit.utils.typing import SampleList +from ..stable_diffusion import StableDiffusion +from .controlnet_utils import change_base_model + +ModelType = Union[Dict, nn.Module] + + +@MODELS.register_module() +class ControlStableDiffusion(StableDiffusion): + """Implementation of `ControlNet with Stable Diffusion. + + `_ (ControlNet). + + Args: + vae (Union[dict, nn.Module]): The config or module for VAE model. + text_encoder (Union[dict, nn.Module]): The config or module for text + encoder. + tokenizer (str): The **name** for CLIP tokenizer. + unet (Union[dict, nn.Module]): The config or module for Unet model. + controlnet (Union[dict, nn.Module]): The config or module for + ControlNet. + schedule (Union[dict, nn.Module]): The config or module for diffusion + scheduler. + test_scheduler (Union[dict, nn.Module], optional): The config or + module for diffusion scheduler in test stage (`self.infer`). If not + passed, will use the same scheduler as `schedule`. Defaults to + None. + enable_xformers (bool, optional): Whether to use xformers. + Defaults to True. + data_preprocessor (dict, optional): The pre-process config of + :class:`BaseDataPreprocessor`. Defaults to + dict(type='EditDataPreprocessor'). + init_cfg (dict, optional): The weight initialized config for + :class:`BaseModule`. Defaults to None/ + """ + + def __init__(self, + vae: ModelType, + text_encoder: ModelType, + tokenizer: str, + unet: ModelType, + controlnet: ModelType, + scheduler: ModelType, + test_scheduler: Optional[ModelType] = None, + enable_xformers: bool = True, + data_preprocessor=dict(type='EditDataPreprocessor'), + init_cfg: Optional[dict] = None): + super().__init__(vae, text_encoder, tokenizer, unet, scheduler, + test_scheduler, enable_xformers, data_preprocessor, + init_cfg) + + self.controlnet = build_module(controlnet, MODELS) + + self.vae.requires_grad_(False) + self.text_encoder.requires_grad_(False) + self.unet.requires_grad_(False) + + def init_weights(self): + """Initialize the weights. Noted that this function will only be called + at train. If you want to inference with a different unet model, you can + call this function manually or use + `mmedit.models.editors.controlnet.controlnet_utils.change_base_model` + to convert the weight of ControlNet manually. + + Example: + >>> 1. init controlnet from unet + >>> init_cfg = dict(type='init_from_unet') + + >>> 2. switch controlnet weight from unet + >>> # base model is not defined, use `runwayml/stable-diffusion-v1-5` + >>> # as default + >>> init_cfg = dict(type='convert_from_unet') + >>> # base model is defined + >>> init_cfg = dict( + >>> type='convert_from_unet', + >>> base_model=dict( + >>> type='UNet2DConditionModel', + >>> from_pretrained='REPO_ID', + >>> subfolder='unet')) + """ + if self.init_cfg is not None: + init_type = self.init_cfg.get('type', None) + else: + init_type = None + + if init_type == 'init_from_unet': + # fetch module + if is_model_wrapper(self.controlnet): + controlnet = self.controlnet.module + else: + controlnet = self.controlnet + + if is_model_wrapper(self.unet): + unet = self.unet.module + else: + unet = self.unet + + if controlnet._from_pretrained is not None: + print_log( + 'ControlNet has initialized from pretrained ' + f'weight \'{controlnet._from_pretrained}\'.' + ' Re-initialize ControlNet from Unet.', 'current', WARNING) + + # copy weight + log_template = 'Initialize weight ControlNet from Unet: {}' + for n, p in unet.named_parameters(): + if n in controlnet.state_dict(): + print_log(log_template.format(n), 'current') + controlnet.state_dict()[n].copy_(p.data) + + # check zero_conv + zero_conv_blocks = controlnet.controlnet_down_blocks + for n, p in zero_conv_blocks.named_parameters(): + if not (p == 0).all(): + print_log(f'{n} in ControlNet is not initialized with ' + 'zero. Set to zero manually.') + p.data.zero_() + + elif init_type == 'convert_from_unet': + # fetch module + if is_model_wrapper(self.controlnet): + controlnet = self.controlnet.module + else: + controlnet = self.controlnet + + if is_model_wrapper(self.unet): + unet = self.unet.module + else: + unet = self.unet + + # use sd-v15 as base model by default + base_model_default_cfg = dict( + type='UNet2DConditionModel', + from_pretrained='runwayml/stable-diffusion-v1-5', + subfolder='unet') + base_model_cfg = self.init_cfg.get('base_model', + base_model_default_cfg) + base_model = MODELS.build(base_model_cfg) + change_base_model(controlnet, unet, base_model) + + else: + assert init_type is None, ( + 'Only support \'init_from_unet\', \'convert_from_unet\' or ' + f'None. But receive {init_type}.') + + def train_step(self, data: dict, + optim_wrapper: OptimWrapperDict) -> Dict[str, Tensor]: + """Train step for ControlNet model. + Args: + data (dict): Data sampled from dataloader. + optim_wrapper (OptimWrapperDict): OptimWrapperDict instance + contains OptimWrapper of generator and discriminator. + + Returns: + Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. + """ + data = self.data_preprocessor(data) + inputs, data_samples = data['inputs'], data['data_samples'] + optimizer = optim_wrapper['controlnet'] + + with optimizer.optim_context(self.controlnet): + target = inputs['target'] + control = (inputs['source'] + 1) / 2 # [-1, 1] -> [0, 1] + prompt = data_samples.prompt + + num_batches = target.shape[0] + + latents = self.vae.encode(target).latent_dist.sample() + latents = latents * self.vae.config.scaling_factor + + noise = torch.randn_like(latents) + timesteps = torch.randint( + 0, + self.scheduler.num_train_timesteps, (num_batches, ), + device=self.device) + timesteps = timesteps.long() + + noisy_latents = self.scheduler.add_noise(latents, noise, timesteps) + + input_ids = self.tokenizer( + prompt, + max_length=self.tokenizer.model_max_length, + return_tensors='pt', + padding='max_length', + truncation=True)['input_ids'].to(self.device) + + encoder_hidden_states = self.text_encoder(input_ids)[0] + + if self.scheduler.config.prediction_type == 'epsilon': + gt = noise + elif self.scheduler.config.prediction_type == 'v_prediction': + gt = self.scheduler.get_velocity(latents, noise, timesteps) + else: + raise ValueError('Unknown prediction type ' + f'{self.scheduler.config.prediction_type}') + + # forward control + down_block_res_samples, mid_block_res_sample = self.controlnet( + noisy_latents, + timesteps, + encoder_hidden_states=encoder_hidden_states, + controlnet_cond=control, + return_dict=False, + ) + + # Predict the noise residual and compute loss + model_output = self.unet( + noisy_latents, + timesteps, + encoder_hidden_states=encoder_hidden_states, + down_block_additional_residuals=down_block_res_samples, + mid_block_additional_residual=mid_block_res_sample) + model_pred = model_output['sample'] + + loss = F.mse_loss(model_pred.float(), gt.float(), reduction='mean') + + optimizer.update_params(loss) + + return dict(loss=loss) + + def val_step(self, data: dict) -> SampleList: + """Gets the generated image of given data. Calls + ``self.data_preprocessor`` and ``self.infer`` in order. Return the + generated results which will be passed to evaluator or visualizer. + + Args: + data (dict or tuple or list): Data sampled from dataset. + + Returns: + SampleList: Generated image or image dict. + """ + data = self.data_preprocessor(data) + prompt = data['data_samples'].prompt + control = data['inputs']['source'] + output = self.infer( + prompt, control=((control + 1) / 2), return_type='tensor') + + samples = output['samples'] + samples = self.data_preprocessor.destruct( + samples, data['data_samples'], key='target') + control = self.data_preprocessor.destruct( + control, data['data_samples'], key='source') + + data_sample = EditDataSample( + fake_img=samples, + control=control, + prompt=data['data_samples'].prompt) + data_sample_list = data_sample.split() + return data_sample_list + + def test_step(self, data: dict) -> SampleList: + """Gets the generated image of given data. Calls + ``self.data_preprocessor`` and ``self.infer`` in order. Return the + generated results which will be passed to evaluator or visualizer. + + Args: + data (dict or tuple or list): Data sampled from dataset. + + Returns: + SampleList: Generated image or image dict. + """ + data = self.data_preprocessor(data) + prompt = data['data_samples'].prompt + control = data['inputs']['source'] + output = self.infer( + prompt, control=((control + 1) / 2), return_type='tensor') + + samples = output['samples'] + samples = self.data_preprocessor.destruct( + samples, data['data_samples'], key='target') + control = self.data_preprocessor.destruct( + control, data['data_samples'], key='source') + + data_sample = EditDataSample( + fake_img=samples, + control=control, + prompt=data['data_samples'].prompt) + data_sample_list = data_sample.split() + return data_sample_list + + # NOTE: maybe we should do this in a controlnet preprocessor + @staticmethod + def prepare_control(image: Tuple[Image.Image, List[Image.Image], Tensor, + List[Tensor]], width: int, height: int, + batch_size: int, num_images_per_prompt: int, + device: str, dtype: str) -> Tensor: + """A helper function to prepare single control images. + + Args: + image (Tuple[Image.Image, List[Image.Image], Tensor, List[Tensor]]): # noqa + The input image for control. + batch_size (int): The batch size of the control. The control will + be repeated for `batch_size` times. + num_images_per_prompt (int): The number images generate for one + prompt. + device (str): The device of the control. + dtype (str): The dtype of the control. + + Returns: + Tensor: The control in torch.tensor. + """ + if not isinstance(image, torch.Tensor): + if isinstance(image, Image.Image): + image = [image] + + if isinstance(image[0], Image.Image): + image = [ + img.resize((width, height), resample=Image.LANCZOS) + for img in image + ] + image = [np.array(img)[None, :] for img in image] + image = np.concatenate(image, axis=0) + image = np.array(image).astype(np.float32) / 255.0 + image = image.transpose(0, 3, 1, 2) + image = torch.from_numpy(image) + elif isinstance(image[0], torch.Tensor): + image = torch.cat(image, dim=0) + + image_batch_size = image.shape[0] + + if image_batch_size == 1: + repeat_by = batch_size + else: + # image batch size is the same as prompt batch size + repeat_by = num_images_per_prompt + + image = image.repeat_interleave(repeat_by, dim=0) + + image = image.to(device=device, dtype=dtype) + + return image + + @torch.no_grad() + def infer(self, + prompt: Union[str, List[str]], + height: Optional[int] = None, + width: Optional[int] = None, + control: Optional[Union[str, np.ndarray, torch.Tensor]] = None, + num_inference_steps: int = 20, + guidance_scale: float = 7.5, + negative_prompt: Optional[Union[str, List[str]]] = None, + num_images_per_prompt: Optional[int] = 1, + eta: float = 0.0, + generator: Optional[torch.Generator] = None, + latents: Optional[torch.FloatTensor] = None, + return_type='image', + show_progress=True): + """Function invoked when calling the pipeline for generation. + + Args: + prompt (str or List[str]): The prompt or prompts to guide + the image generation. + height (int, Optional): The height in pixels of the generated + image. If not passed, the height will be + `self.unet_sample_size * self.vae_scale_factor` Defaults + to None. + width (int, Optional): The width in pixels of the generated image. + If not passed, the width will be + `self.unet_sample_size * self.vae_scale_factor` Defaults + to None. + num_inference_steps (int): The number of denoising steps. + More denoising steps usually lead to a higher quality image at + the expense of slower inference. Defaults to 50. + guidance_scale (float): Guidance scale as defined in Classifier- + Free Diffusion Guidance (https://arxiv.org/abs/2207.12598). + Defaults to 7.5 + negative_prompt (str or List[str], optional): The prompt or + prompts not to guide the image generation. Ignored when not + using guidance (i.e., ignored if `guidance_scale` is less + than 1). Defaults to None. + num_images_per_prompt (int): The number of images to generate + per prompt. Defaults to 1. + eta (float): Corresponds to parameter eta (η) in the DDIM paper: + https://arxiv.org/abs/2010.02502. Only applies to + DDIMScheduler, will be ignored for others. Defaults to 0.0. + generator (torch.Generator, optional): A torch generator to make + generation deterministic. Defaults to None. + latents (torch.FloatTensor, optional): Pre-generated noisy latents, + sampled from a Gaussian distribution, to be used as inputs for + image generation. Can be used to tweak the same generation with + different prompts. If not provided, a latents tensor will be + generated by sampling using the supplied random `generator`. + Defaults to None. + return_type (str): The return type of the inference results. + Supported types are 'image', 'numpy', 'tensor'. If 'image' + is passed, a list of PIL images will be returned. If 'numpy' + is passed, a numpy array with shape [N, C, H, W] will be + returned, and the value range will be same as decoder's + output range. If 'tensor' is passed, the decoder's output + will be returned. Defaults to 'image'. + + Returns: + dict: A dict containing the generated images and Control image. + """ + assert return_type in ['image', 'tensor', 'numpy'] + + # 0. Default height and width to unet + height = height or self.unet_sample_size * self.vae_scale_factor + width = width or self.unet_sample_size * self.vae_scale_factor + + # 1. Check inputs. Raise error if not correct + self.check_inputs(prompt, height, width) + + # 2. Define call parameters + batch_size = 1 if isinstance(prompt, str) else len(prompt) + device = self.device + # here `guidance_scale` is defined analog to the + # guidance weight `w` of equation (2) + # of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . + # `guidance_scale = 1` + # corresponds to doing no classifier free guidance. + do_classifier_free_guidance = guidance_scale > 1.0 + + if is_model_wrapper(self.controlnet): + control_dtype = self.controlnet.module.dtype + else: + control_dtype = self.controlnet.dtype + controls = self.prepare_control( + control, + width, + height, + batch_size, + num_images_per_prompt, + device, + dtype=control_dtype) + if do_classifier_free_guidance: + controls = torch.cat([controls] * 2) + + # 3. Encode input prompt + text_embeddings = self._encode_prompt(prompt, device, + num_images_per_prompt, + do_classifier_free_guidance, + negative_prompt) + + # 4. Prepare timesteps + # self.scheduler.set_timesteps(num_inference_steps, device=device) + self.test_scheduler.set_timesteps(num_inference_steps) + timesteps = self.test_scheduler.timesteps + + # 5. Prepare latent variables + num_channels_latents = self.unet.in_channels + latents = self.prepare_latents( + batch_size * num_images_per_prompt, + num_channels_latents, + height, + width, + text_embeddings.dtype, + device, + generator, + latents, + ) + + # 6. Prepare extra step kwargs. + extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta) + + # 7. Denoising loop + if show_progress: + timesteps = tqdm(timesteps) + for i, t in enumerate(timesteps): + # expand the latents if we are doing classifier free guidance + latent_model_input = torch.cat( + [latents] * 2) if do_classifier_free_guidance else latents + latent_model_input = self.test_scheduler.scale_model_input( + latent_model_input, t) + + down_block_res_samples, mid_block_res_sample = self.controlnet( + latent_model_input, + t, + encoder_hidden_states=text_embeddings, + controlnet_cond=controls, + return_dict=False, + ) + + controlnet_conditioning_scale = 1.0 + down_block_res_samples = [ + down_block_res_sample * controlnet_conditioning_scale + for down_block_res_sample in down_block_res_samples + ] + mid_block_res_sample *= controlnet_conditioning_scale + + # predict the noise residual + noise_pred = self.unet( + latent_model_input, + t, + encoder_hidden_states=text_embeddings, + down_block_additional_residuals=down_block_res_samples, + mid_block_additional_residual=mid_block_res_sample, + )['sample'] + + # perform guidance + if do_classifier_free_guidance: + noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) + noise_pred = noise_pred_uncond + guidance_scale * ( + noise_pred_text - noise_pred_uncond) + + # compute the previous noisy sample x_t -> x_t-1 + latents = self.test_scheduler.step( + noise_pred, t, latents, **extra_step_kwargs)['prev_sample'] + + # 8. Post-processing + image = self.decode_latents(latents) + + if do_classifier_free_guidance: + controls = torch.split(controls, controls.shape[0] // 2, dim=0)[0] + + if return_type == 'image': + image = self.output_to_pil(image) + controls = self.output_to_pil(controls * 2 - 1) + elif return_type == 'numpy': + image = image.cpu().numpy() + controls = controls.cpu().numpy() + else: + assert return_type == 'tensor', ( + 'Only support \'image\', \'numpy\' and \'tensor\' for ' + f'return_type, but receive {return_type}') + + return {'samples': image, 'controls': controls} + + def forward(self, *args, **kwargs): + """forward is not implemented now.""" + raise NotImplementedError( + 'Forward is not implemented now, please use infer.') diff --git a/mmedit/models/editors/controlnet/controlnet_utils.py b/mmedit/models/editors/controlnet/controlnet_utils.py index 193c3c2c27..ce4b18c67e 100644 --- a/mmedit/models/editors/controlnet/controlnet_utils.py +++ b/mmedit/models/editors/controlnet/controlnet_utils.py @@ -29,18 +29,19 @@ def change_base_model(controlnet: nn.Module, *args, **kwargs: Arguments for `save_checkpoint`. """ + dtype = next(controlnet.parameters()).dtype base_state_dict = base_model.state_dict() curr_state_dict = curr_model.state_dict() print_log('Start convert ControlNet to new Unet.', 'current') for k, v in controlnet.state_dict().items(): if k in base_state_dict: - base_v = base_state_dict[k] - curr_v = curr_state_dict[k] + base_v = base_state_dict[k].cpu() + curr_v = curr_state_dict[k].cpu() try: - offset = v - base_v + offset = v.cpu() - base_v new_v = offset + curr_v - controlnet.state_dict()[k].data.copy_(new_v) + controlnet.state_dict()[k].data.copy_(new_v.to(dtype)) print_log(f'Convert success: \'{k}\'.', 'current') except Exception as exception: print_log( diff --git a/model-index.yml b/model-index.yml index f1de04f77e..9e989fa0c6 100644 --- a/model-index.yml +++ b/model-index.yml @@ -4,6 +4,7 @@ Import: - configs/basicvsr_pp/metafile.yml - configs/biggan/metafile.yml - configs/cain/metafile.yml +- configs/controlnet/metafile.yml - configs/cyclegan/metafile.yml - configs/dcgan/metafile.yml - configs/deepfillv1/metafile.yml diff --git a/tests/test_models/test_editors/test_controlnet/test_controlnet.py b/tests/test_models/test_editors/test_controlnet/test_controlnet.py new file mode 100644 index 0000000000..f078372ec5 --- /dev/null +++ b/tests/test_models/test_editors/test_controlnet/test_controlnet.py @@ -0,0 +1,184 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp +from unittest import TestCase +from unittest.mock import MagicMock + +import torch +import torch.nn as nn +from mmengine.utils import digit_version +from mmengine.utils.dl_utils import TORCH_VERSION + +from mmedit.registry import MODELS +from mmedit.structures import EditDataSample +from mmedit.utils import register_all_modules + +test_dir = osp.join(osp.dirname(__file__), '../../../..', 'tests') +config_path = osp.join(test_dir, 'configs', 'diffuser_wrapper_cfg') +model_path = osp.join(test_dir, 'configs', 'tmp_weight') +ckpt_path = osp.join(test_dir, 'configs', 'ckpt') + +register_all_modules() + +stable_diffusion_v15_url = 'runwayml/stable-diffusion-v1-5' +config = dict( + type='ControlStableDiffusion', + vae=dict(type='AutoencoderKL', sample_size=64), + unet=dict( + sample_size=64, + type='UNet2DConditionModel', + down_block_types=('DownBlock2D', ), + up_block_types=('UpBlock2D', ), + block_out_channels=(32, ), + cross_attention_dim=16, + ), + text_encoder=dict( + type='ClipWrapper', + clip_type='huggingface', + pretrained_model_name_or_path=stable_diffusion_v15_url, + subfolder='text_encoder'), + tokenizer=stable_diffusion_v15_url, + controlnet=dict( + type='ControlNetModel', + # from_pretrained=controlnet_canny_rul + from_config=config_path # train from scratch + ), + scheduler=dict( + type='DDPMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + test_scheduler=dict( + type='DDIMScheduler', + from_pretrained=stable_diffusion_v15_url, + subfolder='scheduler'), + data_preprocessor=dict(type='EditDataPreprocessor'), + enable_xformers=False, + init_cfg=dict(type='init_from_unet')) + + +class TestControlStableDiffusion(TestCase): + + def setUp(self): + # mock SiLU + if digit_version(TORCH_VERSION) <= digit_version('1.6.0'): + from mmedit.models.editors.ddpm.denoising_unet import SiLU + torch.nn.SiLU = SiLU + control_sd = MODELS.build(config) + assert not any([p.requires_grad for p in control_sd.vae.parameters()]) + assert not any( + [p.requires_grad for p in control_sd.text_encoder.parameters()]) + assert not any([p.requires_grad for p in control_sd.unet.parameters()]) + self.control_sd = control_sd + + def test_init_weights(self): + control_sd = self.control_sd + # test init_from_unet + control_sd.init_weights() + + # test init_convert_from_unet + unet = dict( + type='UNet2DConditionModel', + down_block_types=('DownBlock2D', ), + up_block_types=('UpBlock2D', ), + block_out_channels=(32, ), + cross_attention_dim=16) + control_sd.init_cfg = dict(type='convert_from_unet', base_model=unet) + control_sd.init_weights() + + def test_infer(self): + control_sd = self.control_sd + control = torch.ones([1, 3, 64, 64]) + + def mock_encode_prompt(*args, **kwargs): + return torch.randn(2, 5, 16) # 2 for cfg + + encode_prompt = control_sd._encode_prompt + control_sd._encode_prompt = mock_encode_prompt + + result = control_sd.infer( + 'an insect robot preparing a delicious meal', + control=control, + height=64, + width=64, + num_inference_steps=1, + return_type='numpy') + assert result['samples'].shape == (1, 3, 64, 64) + + control_sd._encode_prompt = encode_prompt + + def test_val_step(self): + control_sd = self.control_sd + data = dict( + inputs=[ + dict( + target=torch.ones([3, 64, 64]), + source=torch.ones([3, 64, 64])) + ], + data_samples=[ + EditDataSample( + prompt='an insect robot preparing a delicious meal') + ]) + + def mock_encode_prompt(*args, **kwargs): + return torch.randn(2, 5, 16) # 2 for cfg + + encode_prompt = control_sd._encode_prompt + control_sd._encode_prompt = mock_encode_prompt + + # control_sd.text_encoder = mock_text_encoder() + output = control_sd.val_step(data) + assert len(output) == 1 + control_sd._encode_prompt = encode_prompt + + def test_test_step(self): + control_sd = self.control_sd + data = dict( + inputs=[ + dict( + target=torch.ones([3, 64, 64]), + source=torch.ones([3, 64, 64])) + ], + data_samples=[ + EditDataSample( + prompt='an insect robot preparing a delicious meal') + ]) + + def mock_encode_prompt(*args, **kwargs): + return torch.randn(2, 5, 16) # 2 for cfg + + encode_prompt = control_sd._encode_prompt + control_sd._encode_prompt = mock_encode_prompt + + # control_sd.text_encoder = mock_text_encoder() + output = control_sd.test_step(data) + assert len(output) == 1 + control_sd._encode_prompt = encode_prompt + + def test_train_step(self): + control_sd = self.control_sd + data = dict( + inputs=[ + dict( + target=torch.ones([3, 64, 64]), + source=torch.ones([3, 64, 64])) + ], + data_samples=[ + EditDataSample( + prompt='an insect robot preparing a delicious meal') + ]) + + optimizer = MagicMock() + update_params = MagicMock() + optimizer.update_params = update_params + optim_wrapper = {'controlnet': optimizer} + + class mock_text_encoder(nn.Module): + + def __init__(self): + super().__init__() + + def forward(self, *args, **kwargs): + return [torch.randn(1, 5, 16)] + + control_sd.text_encoder = mock_text_encoder() + + control_sd.train_step(data, optim_wrapper) diff --git a/tests/test_models/test_editors/test_controlnet/test_controlnet_utils.py b/tests/test_models/test_editors/test_controlnet/test_controlnet_utils.py index d915dda639..c76bd3904a 100644 --- a/tests/test_models/test_editors/test_controlnet/test_controlnet_utils.py +++ b/tests/test_models/test_editors/test_controlnet/test_controlnet_utils.py @@ -23,6 +23,12 @@ def check_state_dict(s1, s2): assert (s1[k] == s2[k]).all() +def parameters(model): + state_dict = model.state_dict() + for v in state_dict.values(): + yield v + + def test_change_base_model(): control_state_dict = make_state_dict(dict(k1=1, k2=2, k3=3)) target_control_state_dict = make_state_dict(dict(k1=1.5, k2=2.5, k3=3)) @@ -33,7 +39,9 @@ def test_change_base_model(): controlnet = MagicMock() basemodel = MagicMock() currmodel = MagicMock() - + controlnet.parameters = MagicMock(return_value=parameters(controlnet)) + basemodel.parameters = MagicMock(return_value=parameters(basemodel)) + currmodel.parameters = MagicMock(return_value=parameters(currmodel)) controlnet.state_dict = MagicMock(return_value=control_state_dict) basemodel.state_dict = MagicMock(return_value=base_state_dict) currmodel.state_dict = MagicMock(return_value=curr_state_dict) From 73e676e40c2f16f1410692ff819277d798e41774 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Thu, 6 Apr 2023 23:40:04 +0800 Subject: [PATCH 35/39] [Fix] fix pytorch2.0 bugs for basicvsr++, realbasicvsr, srgan, deepfillv1, global_local (#1742) * [Fix] fix pytorch2.0 bugs * add comments * fix ut * fix ut * fix ut --- .../basicvsr_plusplus_net.py | 7 +- .../models/editors/deepfillv1/deepfillv1.py | 5 +- mmedit/models/editors/dic/dic.py | 68 ++++++++++++++---- .../editors/global_local/gl_inpaintor.py | 4 +- .../editors/real_basicvsr/real_basicvsr.py | 69 ++++++++++++++----- mmedit/models/editors/srgan/srgan.py | 3 +- mmedit/models/editors/ttsr/ttsr.py | 62 +++++++++++++---- .../test_deepfillv1/test_deepfillv1.py | 13 ++-- .../test_global_local/test_gl_inpaintor.py | 13 ++-- 9 files changed, 186 insertions(+), 58 deletions(-) diff --git a/mmedit/models/editors/basicvsr_plusplus_net/basicvsr_plusplus_net.py b/mmedit/models/editors/basicvsr_plusplus_net/basicvsr_plusplus_net.py index 1bf41e5207..bea6c60822 100644 --- a/mmedit/models/editors/basicvsr_plusplus_net/basicvsr_plusplus_net.py +++ b/mmedit/models/editors/basicvsr_plusplus_net/basicvsr_plusplus_net.py @@ -168,8 +168,11 @@ def propagate(self, feats, flows, module_name): n, t, _, h, w = flows.size() - frame_idx = range(0, t + 1) - flow_idx = range(-1, t) + # PyTorch 2.0 could not compile data type of 'range' + # frame_idx = range(0, t + 1) + # flow_idx = range(-1, t) + frame_idx = list(range(0, t + 1)) + flow_idx = list(range(-1, t)) mapping_idx = list(range(0, len(feats['spatial']))) mapping_idx += mapping_idx[::-1] diff --git a/mmedit/models/editors/deepfillv1/deepfillv1.py b/mmedit/models/editors/deepfillv1/deepfillv1.py index 8e9da5bfdf..8fcedc49fb 100644 --- a/mmedit/models/editors/deepfillv1/deepfillv1.py +++ b/mmedit/models/editors/deepfillv1/deepfillv1.py @@ -283,7 +283,10 @@ def train_step(self, data: List[dict], optim_wrapper): gt_img = data_samples.gt_img mask = data_samples.mask mask = mask.float() - bbox_tensor = torch.LongTensor(data_samples.mask_bbox) + + # PyTorch 2.0 could not compile 'data_samples.mask_bbox' + # bbox_tensor = torch.LongTensor(data_samples.mask_bbox) + bbox_tensor = torch.LongTensor(data_samples.metainfo['mask_bbox']) # get common output from encdec # input with ones diff --git a/mmedit/models/editors/dic/dic.py b/mmedit/models/editors/dic/dic.py index d5885e832d..e4cc027271 100644 --- a/mmedit/models/editors/dic/dic.py +++ b/mmedit/models/editors/dic/dic.py @@ -1,4 +1,10 @@ # Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List + +import torch +from mmengine.optim import OptimWrapperDict + +from mmedit.models.utils import set_requires_grad from mmedit.registry import MODELS from ..srgan import SRGAN @@ -123,26 +129,62 @@ def g_step(self, batch_outputs, batch_gt_data): return losses - def d_step_with_optim(self, batch_outputs, batch_gt_data, optim_wrapper): - """D step with optim of GAN: Calculate losses of discriminator and run - optim. + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: + """Train step of GAN-based method. Args: - batch_outputs (Tuple[Tensor]): Batch output of generator. - batch_gt_data (Tuple[Tensor]): Batch GT data. - optim_wrapper (OptimWrapper): Optim wrapper of discriminator. + data (List[dict]): Data sampled from dataloader. + optim_wrapper (OptimWrapper): OptimWrapper instance + used to update model parameters. Returns: - dict: Dict of parsed losses. + Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ - sr_list, _ = batch_outputs - gt, _ = batch_gt_data + g_optim_wrapper = optim_wrapper['generator'] + + data = self.data_preprocessor(data, True) + batch_inputs = data['inputs'] + data_samples = data['data_samples'] + batch_gt_data = self.extract_gt_data(data_samples) + + log_vars = dict() + + with g_optim_wrapper.optim_context(self): + batch_outputs = self.forward_train(batch_inputs, data_samples) + + if self.if_run_g(): + set_requires_grad(self.discriminator, False) + + log_vars_d = self.g_step_with_optim( + batch_outputs=batch_outputs, + batch_gt_data=batch_gt_data, + optim_wrapper=optim_wrapper) + + log_vars.update(log_vars_d) + + if self.if_run_d(): + set_requires_grad(self.discriminator, True) + + sr_list, _ = batch_outputs + gt, _ = batch_gt_data + + for _ in range(self.disc_repeat): + # detach before function call to resolve PyTorch2.0 compile bug + log_vars_d = self.d_step_with_optim( + batch_outputs=sr_list[-1].detach(), + batch_gt_data=gt, + optim_wrapper=optim_wrapper) + + log_vars.update(log_vars_d) + + if 'loss' in log_vars: + log_vars.pop('loss') + + self.step_counter += 1 - return super().d_step_with_optim( - batch_outputs=sr_list[-1], - batch_gt_data=gt, - optim_wrapper=optim_wrapper) + return log_vars @staticmethod def extract_gt_data(data_samples): diff --git a/mmedit/models/editors/global_local/gl_inpaintor.py b/mmedit/models/editors/global_local/gl_inpaintor.py index 72684ab495..06cfe49794 100644 --- a/mmedit/models/editors/global_local/gl_inpaintor.py +++ b/mmedit/models/editors/global_local/gl_inpaintor.py @@ -180,7 +180,9 @@ def train_step(self, data: List[dict], optim_wrapper): mask = data_samples.mask mask = mask.float() - bbox_tensor = torch.LongTensor(data_samples.mask_bbox) + # PyTorch 2.0 could not compile 'data_samples.mask_bbox' + # bbox_tensor = torch.LongTensor(data_samples.mask_bbox) + bbox_tensor = torch.LongTensor(data_samples.metainfo['mask_bbox']) input_x = torch.cat([masked_img, mask], dim=1) fake_res = self.generator(input_x) diff --git a/mmedit/models/editors/real_basicvsr/real_basicvsr.py b/mmedit/models/editors/real_basicvsr/real_basicvsr.py index 8bb6a140e5..8a924745fb 100644 --- a/mmedit/models/editors/real_basicvsr/real_basicvsr.py +++ b/mmedit/models/editors/real_basicvsr/real_basicvsr.py @@ -1,8 +1,11 @@ # Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List + import torch import torch.nn.functional as F from mmengine.optim import OptimWrapperDict +from mmedit.models.utils import set_requires_grad from mmedit.registry import MODELS from ..real_esrgan import RealESRGAN @@ -135,29 +138,63 @@ def g_step(self, batch_outputs, batch_gt_data): return losses - def d_step_with_optim(self, batch_outputs: torch.Tensor, - batch_gt_data: torch.Tensor, - optim_wrapper: OptimWrapperDict): - """D step with optim of GAN: Calculate losses of discriminator and run - optim. + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: + """Train step of GAN-based method. Args: - batch_outputs (Tensor): Batch output of generator. - batch_gt_data (Tensor): Batch GT data. - optim_wrapper (OptimWrapperDict): Optim wrapper dict. + data (List[dict]): Data sampled from dataloader. + optim_wrapper (OptimWrapper): OptimWrapper instance + used to update model parameters. Returns: - dict: Dict of parsed losses. + Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ - gt_pixel, gt_percep, gt_gan, gt_clean = batch_gt_data - fake_g_output, fake_g_lq = batch_outputs - fake_g_output = fake_g_output.view(gt_pixel.shape) + g_optim_wrapper = optim_wrapper['generator'] - return super().d_step_with_optim( - batch_outputs=fake_g_output, - batch_gt_data=(gt_pixel, gt_percep, gt_gan), - optim_wrapper=optim_wrapper) + data = self.data_preprocessor(data, True) + batch_inputs = data['inputs'] + data_samples = data['data_samples'] + batch_gt_data = self.extract_gt_data(data_samples) + + log_vars = dict() + + with g_optim_wrapper.optim_context(self): + batch_outputs = self.forward_train(batch_inputs, data_samples) + + if self.if_run_g(): + set_requires_grad(self.discriminator, False) + + log_vars_d = self.g_step_with_optim( + batch_outputs=batch_outputs, + batch_gt_data=batch_gt_data, + optim_wrapper=optim_wrapper) + + log_vars.update(log_vars_d) + + if self.if_run_d(): + set_requires_grad(self.discriminator, True) + + gt_pixel, gt_percep, gt_gan, gt_clean = batch_gt_data + fake_g_output, fake_g_lq = batch_outputs + fake_g_output = fake_g_output.view(gt_pixel.shape) + + for _ in range(self.disc_repeat): + # detach before function call to resolve PyTorch2.0 compile bug + log_vars_d = self.d_step_with_optim( + batch_outputs=fake_g_output.detach(), + batch_gt_data=(gt_pixel, gt_percep, gt_gan), + optim_wrapper=optim_wrapper) + + log_vars.update(log_vars_d) + + if 'loss' in log_vars: + log_vars.pop('loss') + + self.step_counter += 1 + + return log_vars def forward_train(self, batch_inputs, data_samples=None): """Forward Train. diff --git a/mmedit/models/editors/srgan/srgan.py b/mmedit/models/editors/srgan/srgan.py index d4af553521..168febdac1 100644 --- a/mmedit/models/editors/srgan/srgan.py +++ b/mmedit/models/editors/srgan/srgan.py @@ -308,8 +308,9 @@ def train_step(self, data: List[dict], set_requires_grad(self.discriminator, True) for _ in range(self.disc_repeat): + # detach before function call to resolve PyTorch2.0 compile bug log_vars_d = self.d_step_with_optim( - batch_outputs=batch_outputs, + batch_outputs=batch_outputs.detach(), batch_gt_data=batch_gt_data, optim_wrapper=optim_wrapper) diff --git a/mmedit/models/editors/ttsr/ttsr.py b/mmedit/models/editors/ttsr/ttsr.py index 58aaf83f0c..8094e89e0b 100644 --- a/mmedit/models/editors/ttsr/ttsr.py +++ b/mmedit/models/editors/ttsr/ttsr.py @@ -1,4 +1,6 @@ # Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List + import torch from mmengine.optim import OptimWrapperDict @@ -194,22 +196,58 @@ def g_step_with_optim(self, batch_outputs: torch.Tensor, return log_vars_g - def d_step_with_optim(self, batch_outputs, batch_gt_data, optim_wrapper): - """D step with optim of GAN: Calculate losses of discriminator and run - optim. + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapperDict) -> Dict[str, torch.Tensor]: + """Train step of GAN-based method. Args: - batch_outputs (Tuple[Tensor]): Batch output of generator. - batch_gt_data (Tensor): Batch GT data. - optim_wrapper (OptimWrapper): Optim wrapper of discriminator. + data (List[dict]): Data sampled from dataloader. + optim_wrapper (OptimWrapper): OptimWrapper instance + used to update model parameters. Returns: - dict: Dict of parsed losses. + Dict[str, torch.Tensor]: A ``dict`` of tensor for logging. """ - pred, _, _ = batch_outputs + g_optim_wrapper = optim_wrapper['generator'] + + data = self.data_preprocessor(data, True) + batch_inputs = data['inputs'] + data_samples = data['data_samples'] + batch_gt_data = self.extract_gt_data(data_samples) + + log_vars = dict() + + with g_optim_wrapper.optim_context(self): + batch_outputs = self.forward_train(batch_inputs, data_samples) + + if self.if_run_g(): + set_requires_grad(self.discriminator, False) + + log_vars_d = self.g_step_with_optim( + batch_outputs=batch_outputs, + batch_gt_data=batch_gt_data, + optim_wrapper=optim_wrapper) + + log_vars.update(log_vars_d) + + if self.if_run_d(): + set_requires_grad(self.discriminator, True) + + pred, _, _ = batch_outputs + + for _ in range(self.disc_repeat): + # detach before function call to resolve PyTorch2.0 compile bug + log_vars_d = self.d_step_with_optim( + batch_outputs=pred.detach(), + batch_gt_data=batch_gt_data, + optim_wrapper=optim_wrapper) + + log_vars.update(log_vars_d) + + if 'loss' in log_vars: + log_vars.pop('loss') + + self.step_counter += 1 - return super().d_step_with_optim( - batch_outputs=pred, - batch_gt_data=batch_gt_data, - optim_wrapper=optim_wrapper) + return log_vars diff --git a/tests/test_models/test_editors/test_deepfillv1/test_deepfillv1.py b/tests/test_models/test_editors/test_deepfillv1/test_deepfillv1.py index 50e0a249e2..3bfe7d34b3 100644 --- a/tests/test_models/test_editors/test_deepfillv1/test_deepfillv1.py +++ b/tests/test_models/test_editors/test_deepfillv1/test_deepfillv1.py @@ -65,12 +65,13 @@ def test_deepfillv1_inpaintor(): data_batch = { 'inputs': masked_img, - 'data_samples': - [EditDataSample( - mask=mask, - mask_bbox=mask_bbox, - gt_img=gt_img, - )] + 'data_samples': [ + EditDataSample( + metainfo=dict(mask_bbox=mask_bbox), + mask=mask, + gt_img=gt_img, + ) + ] } # prepare model and optimizer diff --git a/tests/test_models/test_editors/test_global_local/test_gl_inpaintor.py b/tests/test_models/test_editors/test_global_local/test_gl_inpaintor.py index 47dc6cab07..f26a05478d 100644 --- a/tests/test_models/test_editors/test_global_local/test_gl_inpaintor.py +++ b/tests/test_models/test_editors/test_global_local/test_gl_inpaintor.py @@ -30,12 +30,13 @@ def test_gl_inpaintor(): data_batch = { 'inputs': masked_img, - 'data_samples': - [EditDataSample( - mask=mask, - mask_bbox=mask_bbox, - gt_img=gt_img, - )] + 'data_samples': [ + EditDataSample( + metainfo=dict(mask_bbox=mask_bbox), + mask=mask, + gt_img=gt_img, + ) + ] } optim_g = torch.optim.SGD(gl.generator.parameters(), lr=0.1) From d7a1c876ab808cd4dbc2e66603738b002911fa7d Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Fri, 7 Apr 2023 11:23:05 +0800 Subject: [PATCH 36/39] [Release] update 1.0.0rc7 info (#1741) * [Release] update 1.0.0rc7 info * update changelog * update version * update changelog * update * update * update date --- README.md | 10 ++++++---- README_zh-CN.md | 10 ++++++---- docs/en/changelog.md | 35 +++++++++++++++++++++++++++++++++++ docs/zh_cn/changelog.md | 30 ++++++++++++++++++++++++++++++ mmedit/version.py | 2 +- 5 files changed, 78 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index da4ccae0f6..e70272008a 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,11 @@ English | [简体中文](README_zh-CN.md) ## 🚀 What's New -### New release [**MMEditing v1.0.0rc6**](https://github.com/open-mmlab/mmediting/releases/tag/v1.0.0rc6) \[02/03/2023\]: +### New release [**MMEditing v1.0.0rc7**](https://github.com/open-mmlab/mmediting/releases/tag/v1.0.0rc7) \[07/04/2023\]: -- Support Gradio gui of Inpainting inference. -- Support Colorization, Translationin and all GAN models inferencer. +- Support DiffuserWrapper +- Support ControlNet (training and inference). +- Support PyTorch 2.0 (successfully compile 33+ models on 'inductor' backend). **MMEditing** has supported all the tasks, models, metrics, and losses in [MMGeneration](https://github.com/open-mmlab/mmgeneration) and unifies interfaces of all components based on [MMEngine](https://github.com/open-mmlab/mmengine) 😍. @@ -305,6 +306,7 @@ Please see [quick run](docs/en/get_started/quick_run.md) and [inference](docs/en
    +
  • ControlNet (2023)
  • GLIDE (NeurIPS'2021)
  • Disco-Diffusion (2022)
  • Stable-Diffusion (2022)
  • @@ -332,7 +334,7 @@ MMEditing is an open source project that is contributed by researchers and engin We appreciate all the contributors who implement their methods or add new features, as well as users who give valuable feedbacks. Thank you all! - +

    🔝Back to top

    diff --git a/README_zh-CN.md b/README_zh-CN.md index 125c6e255a..8aae6a7081 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -53,10 +53,11 @@ ## 🚀 最新进展 -### 最新的 [**MMEditing v1.0.0rc6**](https://github.com/open-mmlab/mmediting/releases/tag/v1.0.0rc6) 版本已经在 \[02/03/2023\] 发布: +### 最新的 [**MMEditing v1.0.0rc7**](https://github.com/open-mmlab/mmediting/releases/tag/v1.0.0rc7) 版本已经在 \[07/04/2023\] 发布: -- 支持了 Inpainting 任务推理的 Gradio gui. -- 支持了图像上色、图像翻译和 GAN 模型的 inferencer. +- 支持了 DiffuserWrapper. +- 支持了 ControlNet 的推理与训练. +- 支持了 PyTorch 2.0 (使用 'inductor' 后端成功编译 33+ 模型). **MMEditing** 已经支持了[MMGeneration](https://github.com/open-mmlab/mmgeneration)中的全量任务、模型、优化函数和评价指标 ,并基于[MMEngine](https://github.com/open-mmlab/mmengine)统一了各组件接口 😍。 @@ -302,6 +303,7 @@ pip3 install -e .
      +
    • ControlNet (2023)
    • GLIDE (NeurIPS'2021)
    • Disco-Diffusion (2022)
    • Stable-Diffusion (2022)
    • @@ -327,7 +329,7 @@ pip3 install -e . MMEditing 是一款由不同学校和公司共同贡献的开源项目。我们感谢所有为项目提供算法复现和新功能支持的贡献者,以及提供宝贵反馈的用户。我们希望该工具箱和基准测试可以为社区提供灵活的代码工具,供用户复现现有算法并开发自己的新模型,从而不断为开源社区提供贡献。 - +

      🔝返回顶部

      diff --git a/docs/en/changelog.md b/docs/en/changelog.md index bbf2235ecb..9fab2d8b97 100644 --- a/docs/en/changelog.md +++ b/docs/en/changelog.md @@ -1,5 +1,40 @@ # Changelog +## v1.0.0rc7 (07/04/2023) + +**Highlights** + +We are excited to announce the release of MMEditing 1.0.0rc7. This release supports 51+ models, 226+ configs and 212+ checkpoints in MMGeneration and MMEditing. We highlight the following new features + +- Support DiffuserWrapper +- Support ControlNet (training and inference). +- Support PyTorch 2.0. + +**New Features & Improvements** + +- Support DiffuserWrapper. [#1692](https://github.com/open-mmlab/mmediting/pull/1692) +- Support ControlNet (training and inference). [#1744](https://github.com/open-mmlab/mmediting/pull/1744) +- Support PyTorch 2.0 (successfully compile 33+ models on 'inductor' backend). [#1742](https://github.com/open-mmlab/mmediting/pull/1742) +- Support Image Super-Resolution and Video Super-Resolution models inferencer. [#1662](https://github.com/open-mmlab/mmediting/pull/1662), [#1720](https://github.com/open-mmlab/mmediting/pull/1720) +- Refactor tools/get_flops script. [#1675](https://github.com/open-mmlab/mmediting/pull/1675) +- Refactor dataset_converters and documents for datasets. [#1690](https://github.com/open-mmlab/mmediting/pull/1690) +- Move stylegan ops to MMCV. [#1383](https://github.com/open-mmlab/mmediting/pull/1383) + +**Bug Fixes** + +- Fix disco inferencer. [#1673](https://github.com/open-mmlab/mmediting/pull/1673) +- Fix nafnet optimizer config. [#1716](https://github.com/open-mmlab/mmediting/pull/1716) +- Fix tof typo. [#1711](https://github.com/open-mmlab/mmediting/pull/1711) + +**Contributors** + +A total of 8 developers contributed to this release. +Thanks @LeoXing1996, @Z-Fran, @plyfager, @zengyh1900, @liuwenran, @ryanxingql, @HAOCHENYE, @VongolaWu + +**New Contributors** + +- @HAOCHENYE made their first contribution in https://github.com/open-mmlab/mmediting/pull/1712 + ## v1.0.0rc6 (02/03/2023) **Highlights** diff --git a/docs/zh_cn/changelog.md b/docs/zh_cn/changelog.md index 8c16e2f9bd..70b36b263f 100644 --- a/docs/zh_cn/changelog.md +++ b/docs/zh_cn/changelog.md @@ -1,5 +1,35 @@ # 变更日志 +## v1.0.0rc7 (07/04/2023) + +**主要更新** + +我们很高兴发布 MMEditing 1.0.0rc7 版本。 此版本支持了 MMEditing 和 MMGeneration 的 51+ 模型,226+ configs 和 212+ checkpoints。以下是此次版本发布的重点新功能 + +- 支持了 DiffuserWrapper. +- 支持了 ControlNet 的推理与训练. +- 支持了 PyTorch 2.0. + +**新功能和改进** + +- 支持了 DiffuserWrapper. [#1692](https://github.com/open-mmlab/mmediting/pull/1692) +- 支持了 ControlNet 的推理与训练. [#1744](https://github.com/open-mmlab/mmediting/pull/1744) +- 支持了 PyTorch 2.0 (使用 'inductor' 后端成功编译 33+ 模型) [#1742](https://github.com/open-mmlab/mmediting/pull/1742). +- 支持了图像超分和视频超分的 inferencer. [#1662](https://github.com/open-mmlab/mmediting/pull/1662), [#1720](https://github.com/open-mmlab/mmediting/pull/1720) +- 重构 get_flops 脚本. [#1675](https://github.com/open-mmlab/mmediting/pull/1675) +- 重构数据集的 dataset_converters 脚本和使用文档. [#1690](https://github.com/open-mmlab/mmediting/pull/1690) +- 迁移 stylegan 算子到 MMCV 中. [#1383](https://github.com/open-mmlab/mmediting/pull/1383) + +**Bug 修复** + +- 修复 disco inferencer. [#1673](https://github.com/open-mmlab/mmediting/pull/1673) +- 修复 nafnet optimizer 配置. [#1716](https://github.com/open-mmlab/mmediting/pull/1716) +- 修复 tof typo. [#1711](https://github.com/open-mmlab/mmediting/pull/1711) + +**贡献者** + +@LeoXing1996, @Z-Fran, @plyfager, @zengyh1900, @liuwenran, @ryanxingql, @HAOCHENYE, @VongolaWu + ## v1.0.0rc6 (02/03/2023) **主要更新** diff --git a/mmedit/version.py b/mmedit/version.py index 82f5073d32..e3b0f62e14 100644 --- a/mmedit/version.py +++ b/mmedit/version.py @@ -1,6 +1,6 @@ # Copyright (c) Open-MMLab. All rights reserved. -__version__ = '1.0.0rc6' +__version__ = '1.0.0rc7' def parse_version_info(version_str): From 4de1aad88b148fe6c6ff179068ce1cf1471556da Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Fri, 7 Apr 2023 11:38:28 +0800 Subject: [PATCH 37/39] [Fix] fix circle ci minimum gpu (#1745) --- .circleci/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/test.yml b/.circleci/test.yml index 9f7086ac1c..3fcd589743 100644 --- a/.circleci/test.yml +++ b/.circleci/test.yml @@ -174,7 +174,7 @@ workflows: torch: 1.8.1 # Use double quotation mark to explicitly specify its type # as string instead of number - cuda: "10.1" + cuda: "10.2" filters: branches: only: From 44b08951431cbb17546bc082fd6e378d44a94cd7 Mon Sep 17 00:00:00 2001 From: Z-Fran <49083766+Z-Fran@users.noreply.github.com> Date: Fri, 7 Apr 2023 12:57:14 +0800 Subject: [PATCH 38/39] [Fix] fix 1.0.0rc7ut (#1746) --- mmedit/models/editors/disco_diffusion/disco.py | 2 +- mmedit/models/editors/disco_diffusion/guider.py | 2 +- mmedit/models/editors/stylegan2/ada/upfirdn2d.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mmedit/models/editors/disco_diffusion/disco.py b/mmedit/models/editors/disco_diffusion/disco.py index 1a7b4e2be5..f46c4f2cf4 100644 --- a/mmedit/models/editors/disco_diffusion/disco.py +++ b/mmedit/models/editors/disco_diffusion/disco.py @@ -203,7 +203,7 @@ def infer(self, timesteps = tqdm(timesteps) for t in timesteps: # 1. predicted model_output - model_output = self.unet(image, t)['outputs'] + model_output = self.unet(image, t)['sample'] # 2. compute previous image: x_t -> x_t-1 cond_kwargs = dict( diff --git a/mmedit/models/editors/disco_diffusion/guider.py b/mmedit/models/editors/disco_diffusion/guider.py index 5e9535d524..c3a0183a31 100644 --- a/mmedit/models/editors/disco_diffusion/guider.py +++ b/mmedit/models/editors/disco_diffusion/guider.py @@ -440,7 +440,7 @@ def cond_fn(self, x, cosine_t[None].repeat([x.shape[0]])) pred_original_sample = model_output['pred'] else: - model_output = model(x, t)['outputs'] + model_output = model(x, t)['sample'] model_output, predicted_variance = torch.split( model_output, x.shape[1], dim=1) alpha_prod_t = 1 - beta_prod_t diff --git a/mmedit/models/editors/stylegan2/ada/upfirdn2d.py b/mmedit/models/editors/stylegan2/ada/upfirdn2d.py index 8479d713bd..0bc637738e 100644 --- a/mmedit/models/editors/stylegan2/ada/upfirdn2d.py +++ b/mmedit/models/editors/stylegan2/ada/upfirdn2d.py @@ -190,7 +190,7 @@ def downsample2d(x, f = f.flip(list(range(f.ndim))) if f.ndim == 1: x = upfirdn2d( - x, f.unsqueeze(0), down=(downx, 1), pad=(p[0], p[1], 0, 0)) + x, f.unsqueeze(0), down=(downx, 1), padding=(p[0], p[1], 0, 0)) x = upfirdn2d( - x, f.unsqueeze(1), down=(1, downy), pad=(0, 0, p[2], p[3])) + x, f.unsqueeze(1), down=(1, downy), padding=(0, 0, p[2], p[3])) return x From 677a13f94d2f92645ba76740209cca28d98c0766 Mon Sep 17 00:00:00 2001 From: LeoXing1996 Date: Fri, 7 Apr 2023 14:42:30 +0800 Subject: [PATCH 39/39] [Fix] Skip unit test of ControlNet on windows. (#1747) fix ControlNet windows UT --- .../test_editors/test_controlnet/test_controlnet.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_models/test_editors/test_controlnet/test_controlnet.py b/tests/test_models/test_editors/test_controlnet/test_controlnet.py index f078372ec5..fb8b58fb2c 100644 --- a/tests/test_models/test_editors/test_controlnet/test_controlnet.py +++ b/tests/test_models/test_editors/test_controlnet/test_controlnet.py @@ -1,8 +1,11 @@ # Copyright (c) OpenMMLab. All rights reserved. + import os.path as osp +import platform from unittest import TestCase from unittest.mock import MagicMock +import pytest import torch import torch.nn as nn from mmengine.utils import digit_version @@ -55,6 +58,9 @@ init_cfg=dict(type='init_from_unet')) +@pytest.mark.skipif( + 'win' in platform.system().lower(), + reason='skip on windows due to limited RAM.') class TestControlStableDiffusion(TestCase): def setUp(self):