From 41aaf0c530752c0eba44bf42b6a02978953294b6 Mon Sep 17 00:00:00 2001 From: zengyh1900 Date: Thu, 9 Mar 2023 11:44:29 +0800 Subject: [PATCH 1/8] register models and schedulers from diffusers --- mmedit/models/base_archs/__init__.py | 29 ++++++++++++++ .../models/diffusion_schedulers/__init__.py | 39 +++++++++++++++++++ .../ddim_scheduler.py | 0 .../ddpm_scheduler.py | 0 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 + 9 files changed, 74 insertions(+), 12 deletions(-) create mode 100644 mmedit/models/diffusion_schedulers/__init__.py rename mmedit/models/{editors/ddim => diffusion_schedulers}/ddim_scheduler.py (100%) rename mmedit/models/{editors/ddpm => diffusion_schedulers}/ddpm_scheduler.py (100%) delete mode 100644 mmedit/models/editors/ddim/__init__.py diff --git a/mmedit/models/base_archs/__init__.py b/mmedit/models/base_archs/__init__.py index 30b0ec3002..1e92d286c8 100644 --- a/mmedit/models/base_archs/__init__.py +++ b/mmedit/models/base_archs/__init__.py @@ -1,5 +1,7 @@ # Copyright (c) OpenMMLab. All rights reserved. # To register Deconv +from typing import List + from .all_gather_layer import AllGatherLayer from .aspp import ASPP from .conv import * # noqa: F401, F403 @@ -19,6 +21,31 @@ from .upsample import PixelShufflePack from .vgg import VGG16 + +def register_diffusers_models() -> List[str]: + """Register models in ``diffusers.models`` to the ``MODELS`` registry. + + Returns: + List[str]: A list of registered DIFFUSION_MODELS' name. + """ + import inspect + + import diffusers + + from mmedit.registry import MODELS + + DIFFUSERS_MODELS = [] + for module_name in dir(diffusers.models): + module = getattr(diffusers.models, module_name) + if inspect.isclass(module): + MODELS.register_module( + name='Diffusers' + 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', @@ -27,3 +54,5 @@ 'MultiLayerDiscriminator', 'PatchDiscriminator', 'VGG16', 'ResNet', 'AllGatherLayer', 'ResidualBlockNoBN' ] + +__all__.extend(REGISTERED_DIFFUSERS_MODELS) diff --git a/mmedit/models/diffusion_schedulers/__init__.py b/mmedit/models/diffusion_schedulers/__init__.py new file mode 100644 index 0000000000..8d2041316d --- /dev/null +++ b/mmedit/models/diffusion_schedulers/__init__.py @@ -0,0 +1,39 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List + +from .ddim_scheduler import DDIMScheduler +from .ddpm_scheduler import DDPMScheduler + + +def register_diffusers_schedulers() -> List[str]: + """Register schedulers in ``diffusers.schedulers`` to the + ``DIFFUSION_SCHEDULERS`` registry. + + Returns: + List[str]: A list of registered DIFFUSION_SCHEDULERS' name. + """ + + import inspect + + import diffusers + + from mmedit.registry import DIFFUSION_SCHEDULERS + + 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='Diffusers' + module_name, module=_scheduler) + DIFFUSERS_SCHEDULERS.append('Diffusers' + module_name) + return DIFFUSERS_SCHEDULERS + + +REGISTERED_DIFFUSERS_SCHEDULERS = register_diffusers_schedulers() + +__all__ = ['DDIMScheduler', 'DDPMScheduler'] + +__all__.extend(REGISTERED_DIFFUSERS_SCHEDULERS) diff --git a/mmedit/models/editors/ddim/ddim_scheduler.py b/mmedit/models/diffusion_schedulers/ddim_scheduler.py similarity index 100% rename from mmedit/models/editors/ddim/ddim_scheduler.py rename to mmedit/models/diffusion_schedulers/ddim_scheduler.py diff --git a/mmedit/models/editors/ddpm/ddpm_scheduler.py b/mmedit/models/diffusion_schedulers/ddpm_scheduler.py similarity index 100% rename from mmedit/models/editors/ddpm/ddpm_scheduler.py rename to mmedit/models/diffusion_schedulers/ddpm_scheduler.py 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 From 4b4004db059c264d8e4256f347456a5766c6e2b7 Mon Sep 17 00:00:00 2001 From: zengyh1900 Date: Thu, 9 Mar 2023 12:54:53 +0800 Subject: [PATCH 2/8] remove extension --- mmedit/models/base_archs/__init__.py | 2 -- mmedit/models/diffusion_schedulers/__init__.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/mmedit/models/base_archs/__init__.py b/mmedit/models/base_archs/__init__.py index 1e92d286c8..2712bc08e7 100644 --- a/mmedit/models/base_archs/__init__.py +++ b/mmedit/models/base_archs/__init__.py @@ -54,5 +54,3 @@ def register_diffusers_models() -> List[str]: 'MultiLayerDiscriminator', 'PatchDiscriminator', 'VGG16', 'ResNet', 'AllGatherLayer', 'ResidualBlockNoBN' ] - -__all__.extend(REGISTERED_DIFFUSERS_MODELS) diff --git a/mmedit/models/diffusion_schedulers/__init__.py b/mmedit/models/diffusion_schedulers/__init__.py index 8d2041316d..a14d559b84 100644 --- a/mmedit/models/diffusion_schedulers/__init__.py +++ b/mmedit/models/diffusion_schedulers/__init__.py @@ -35,5 +35,3 @@ def register_diffusers_schedulers() -> List[str]: REGISTERED_DIFFUSERS_SCHEDULERS = register_diffusers_schedulers() __all__ = ['DDIMScheduler', 'DDPMScheduler'] - -__all__.extend(REGISTERED_DIFFUSERS_SCHEDULERS) From a93f1731cfba63ca1bc8a50c44c3efe652c6c88a Mon Sep 17 00:00:00 2001 From: zengyh1900 Date: Thu, 9 Mar 2023 14:04:23 +0800 Subject: [PATCH 3/8] rename registered models and scheduelrs to modulename --- mmedit/models/base_archs/__init__.py | 3 +-- mmedit/models/diffusion_schedulers/__init__.py | 10 +++++----- mmedit/models/diffusion_schedulers/ddim_scheduler.py | 6 +++--- mmedit/models/diffusion_schedulers/ddpm_scheduler.py | 4 ++-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/mmedit/models/base_archs/__init__.py b/mmedit/models/base_archs/__init__.py index 2712bc08e7..7b9ca3507e 100644 --- a/mmedit/models/base_archs/__init__.py +++ b/mmedit/models/base_archs/__init__.py @@ -38,8 +38,7 @@ def register_diffusers_models() -> List[str]: for module_name in dir(diffusers.models): module = getattr(diffusers.models, module_name) if inspect.isclass(module): - MODELS.register_module( - name='Diffusers' + module_name, module=module) + MODELS.register_module(name=module_name, module=module) DIFFUSERS_MODELS.append(module_name) return DIFFUSERS_MODELS diff --git a/mmedit/models/diffusion_schedulers/__init__.py b/mmedit/models/diffusion_schedulers/__init__.py index a14d559b84..ee97b22e9a 100644 --- a/mmedit/models/diffusion_schedulers/__init__.py +++ b/mmedit/models/diffusion_schedulers/__init__.py @@ -1,8 +1,8 @@ # Copyright (c) OpenMMLab. All rights reserved. from typing import List -from .ddim_scheduler import DDIMScheduler -from .ddpm_scheduler import DDPMScheduler +from .ddim_scheduler import EditDDIMScheduler +from .ddpm_scheduler import EditDDPMScheduler def register_diffusers_schedulers() -> List[str]: @@ -27,11 +27,11 @@ def register_diffusers_schedulers() -> List[str]: _scheduler = getattr(diffusers.schedulers, module_name) if inspect.isclass(_scheduler): DIFFUSION_SCHEDULERS.register_module( - name='Diffusers' + module_name, module=_scheduler) - DIFFUSERS_SCHEDULERS.append('Diffusers' + module_name) + name=module_name, module=_scheduler) + DIFFUSERS_SCHEDULERS.append(module_name) return DIFFUSERS_SCHEDULERS REGISTERED_DIFFUSERS_SCHEDULERS = register_diffusers_schedulers() -__all__ = ['DDIMScheduler', 'DDPMScheduler'] +__all__ = ['EditDDIMScheduler', 'EditDDPMScheduler'] diff --git a/mmedit/models/diffusion_schedulers/ddim_scheduler.py b/mmedit/models/diffusion_schedulers/ddim_scheduler.py index 13dd9506d2..a4948267b9 100644 --- a/mmedit/models/diffusion_schedulers/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/diffusion_schedulers/ddpm_scheduler.py b/mmedit/models/diffusion_schedulers/ddpm_scheduler.py index b1f52da8cd..0047020c2d 100644 --- a/mmedit/models/diffusion_schedulers/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 From 3828da88844f1c857bd203418b970c014bc4d649 Mon Sep 17 00:00:00 2001 From: zengyh1900 Date: Thu, 9 Mar 2023 14:16:40 +0800 Subject: [PATCH 4/8] use try-import to register diffusers modules --- mmedit/models/base_archs/__init__.py | 11 +++++++++-- mmedit/models/diffusion_schedulers/__init__.py | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/mmedit/models/base_archs/__init__.py b/mmedit/models/base_archs/__init__.py index 7b9ca3507e..1c037d970f 100644 --- a/mmedit/models/base_archs/__init__.py +++ b/mmedit/models/base_archs/__init__.py @@ -1,7 +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 @@ -30,10 +32,15 @@ def register_diffusers_models() -> List[str]: """ import inspect - import diffusers - 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) diff --git a/mmedit/models/diffusion_schedulers/__init__.py b/mmedit/models/diffusion_schedulers/__init__.py index ee97b22e9a..3c9ab19d2c 100644 --- a/mmedit/models/diffusion_schedulers/__init__.py +++ b/mmedit/models/diffusion_schedulers/__init__.py @@ -1,6 +1,8 @@ # 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 @@ -15,10 +17,15 @@ def register_diffusers_schedulers() -> List[str]: import inspect - import diffusers - 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'): From 6f0278f8ddf3730851c672b131cad8604576a1d1 Mon Sep 17 00:00:00 2001 From: zengyh1900 Date: Thu, 9 Mar 2023 14:43:04 +0800 Subject: [PATCH 5/8] fix ut --- ...sco-diffusion_adm-u-finetuned_imagenet-256x256.py | 2 +- ...sco-diffusion_adm-u-finetuned_imagenet-512x512.py | 2 +- .../stable-diffusion_ddim_denoisingunet.py | 2 +- .../test_inferencers/test_text2image_inferencers.py | 5 +++-- .../test_ddim_scheduler.py | 2 +- .../test_editors/test_ddpm/test_ddpm_scheduler.py | 12 ++++++------ .../test_disco_diffusion/test_disco_diffusion.py | 5 +++-- 7 files changed, 16 insertions(+), 14 deletions(-) rename tests/test_models/{test_editors/test_ddim => test_diffusion_schedulers}/test_ddim_scheduler.py (94%) 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/tests/test_apis/test_inferencers/test_text2image_inferencers.py b/tests/test_apis/test_inferencers/test_text2image_inferencers.py index df0b7ae6be..3c530e2876 100644 --- a/tests/test_apis/test_inferencers/test_text2image_inferencers.py +++ b/tests/test_apis/test_inferencers/test_text2image_inferencers.py @@ -10,7 +10,8 @@ from torchvision.version import __version__ as TV_VERSION from mmedit.apis.inferencers.text2image_inferencer import Text2ImageInferencer -from mmedit.models import DDIMScheduler, DenoisingUnet, DiscoDiffusion +from mmedit.models import DenoisingUnet, DiscoDiffusion +from mmedit.models.diffusion_schedulers import EditDDIMScheduler from mmedit.utils import register_all_modules register_all_modules() @@ -66,7 +67,7 @@ def setUp(self): # mock clip self.clip_models = [clip_mock_wrapper(), clip_mock_wrapper()] # diffusion_scheduler - self.diffusion_scheduler = DDIMScheduler( + self.diffusion_scheduler = EditDDIMScheduler( variance_type='learned_range', beta_schedule='linear', clip_sample=False) diff --git a/tests/test_models/test_editors/test_ddim/test_ddim_scheduler.py b/tests/test_models/test_diffusion_schedulers/test_ddim_scheduler.py similarity index 94% rename from tests/test_models/test_editors/test_ddim/test_ddim_scheduler.py rename to tests/test_models/test_diffusion_schedulers/test_ddim_scheduler.py index ba8eb0663c..42a25c4614 100644 --- a/tests/test_models/test_editors/test_ddim/test_ddim_scheduler.py +++ b/tests/test_models/test_diffusion_schedulers/test_ddim_scheduler.py @@ -2,7 +2,7 @@ import pytest import torch -from mmedit.models.editors.ddim.ddim_scheduler import DDIMScheduler +from mmedit.models.diffusion_schedulers.ddim_scheduler import DDIMScheduler def test_ddim(): diff --git a/tests/test_models/test_editors/test_ddpm/test_ddpm_scheduler.py b/tests/test_models/test_editors/test_ddpm/test_ddpm_scheduler.py index fe4c33126b..9bda959c55 100644 --- a/tests/test_models/test_editors/test_ddpm/test_ddpm_scheduler.py +++ b/tests/test_models/test_editors/test_ddpm/test_ddpm_scheduler.py @@ -2,13 +2,13 @@ import pytest import torch -from mmedit.models.editors.ddpm.ddpm_scheduler import DDPMScheduler +from mmedit.models.diffusion_schedulers.ddpm_scheduler import EditDDPMScheduler def test_ddpm(): modelout = torch.rand((1, 8, 32, 32)) sample = torch.rand((1, 4, 32, 32)) - ddpm = DDPMScheduler( + ddpm = EditDDPMScheduler( num_train_timesteps=1000, variance_type='learned_range') result = ddpm.step(modelout, 980, sample) assert result['prev_sample'].shape == (1, 4, 32, 32) @@ -32,11 +32,11 @@ def test_ddpm(): def test_ddpm_init(): - DDPMScheduler(trained_betas=1) + EditDDPMScheduler(trained_betas=1) - DDPMScheduler(beta_schedule='scaled_linear') + EditDDPMScheduler(beta_schedule='scaled_linear') - DDPMScheduler(beta_schedule='squaredcos_cap_v2') + EditDDPMScheduler(beta_schedule='squaredcos_cap_v2') with pytest.raises(Exception): - DDPMScheduler(beta_schedule='tem') + EditDDPMScheduler(beta_schedule='tem') diff --git a/tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion.py b/tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion.py index 7a56a6603a..fa9c194d07 100644 --- a/tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion.py +++ b/tests/test_models/test_editors/test_disco_diffusion/test_disco_diffusion.py @@ -9,7 +9,8 @@ from mmengine.utils import digit_version from torchvision.version import __version__ as TV_VERSION -from mmedit.models import DDIMScheduler, DenoisingUnet, DiscoDiffusion +from mmedit.models import DenoisingUnet, DiscoDiffusion +from mmedit.models.diffusion_schedulers import EditDDIMScheduler from mmedit.utils import register_all_modules register_all_modules() @@ -66,7 +67,7 @@ def setUp(self): # mock clip self.clip_models = [clip_mock_wrapper(), clip_mock_wrapper()] # diffusion_scheduler - self.diffusion_scheduler = DDIMScheduler( + self.diffusion_scheduler = EditDDIMScheduler( variance_type='learned_range', beta_schedule='linear', clip_sample=False) From 4ee329e12ed3275430f6f30e01fd8884d0b45935 Mon Sep 17 00:00:00 2001 From: zengyh1900 Date: Thu, 9 Mar 2023 14:45:33 +0800 Subject: [PATCH 6/8] - --- .../test_ddim_scheduler.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_models/test_diffusion_schedulers/test_ddim_scheduler.py b/tests/test_models/test_diffusion_schedulers/test_ddim_scheduler.py index 42a25c4614..f149e3ec24 100644 --- a/tests/test_models/test_diffusion_schedulers/test_ddim_scheduler.py +++ b/tests/test_models/test_diffusion_schedulers/test_ddim_scheduler.py @@ -2,13 +2,13 @@ import pytest import torch -from mmedit.models.diffusion_schedulers.ddim_scheduler import DDIMScheduler +from mmedit.models.diffusion_schedulers.ddim_scheduler import EditDDIMScheduler def test_ddim(): modelout = torch.rand((1, 8, 32, 32)) sample = torch.rand((1, 4, 32, 32)) - ddim = DDIMScheduler( + ddim = EditDDIMScheduler( num_train_timesteps=1000, variance_type='learned_range') ddim.set_timesteps(10) result = ddim.step(modelout, 980, sample) @@ -22,22 +22,22 @@ def test_ddim(): def test_ddim_init(): - ddim = DDIMScheduler( + ddim = EditDDIMScheduler( num_train_timesteps=1000, beta_schedule='scaled_linear') - ddim = DDIMScheduler( + ddim = EditDDIMScheduler( num_train_timesteps=1000, beta_schedule='squaredcos_cap_v2') - assert isinstance(ddim, DDIMScheduler) + assert isinstance(ddim, EditDDIMScheduler) with pytest.raises(Exception): - DDIMScheduler(num_train_timesteps=1000, beta_schedule='fake') + EditDDIMScheduler(num_train_timesteps=1000, beta_schedule='fake') def test_ddim_step(): modelout = torch.rand((1, 8, 32, 32)) sample = torch.rand((1, 4, 32, 32)) - ddim = DDIMScheduler( + ddim = EditDDIMScheduler( num_train_timesteps=1000, variance_type='learned_range') with pytest.raises(Exception): ddim.step(modelout, 980, sample) From 6b6de9921caf9cde4d39fb6908d7785d7d6345de Mon Sep 17 00:00:00 2001 From: zengyh1900 Date: Thu, 9 Mar 2023 15:41:49 +0800 Subject: [PATCH 7/8] fix ut --- .../test_editors/test_stable_diffusion/test_stable_diffusion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f84f58a7ee..4e92650416 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 @@ -50,7 +50,7 @@ ]) diffusion_scheduler = dict( - type='DDIMScheduler', + type='EditDDIMScheduler', variance_type='learned_range', beta_end=0.012, beta_schedule='scaled_linear', From 18a49390fb3cd28a1f7445f32bdf47766405ed1e Mon Sep 17 00:00:00 2001 From: zengyh1900 Date: Thu, 9 Mar 2023 16:43:21 +0800 Subject: [PATCH 8/8] update docstring per review --- mmedit/models/base_archs/__init__.py | 3 +++ mmedit/models/diffusion_schedulers/__init__.py | 6 +++++- tests/data/video_interpolation_result.mp4 | Bin 0 -> 14050 bytes .../test_guided_diffusion/test_adm.py | 4 ++-- 4 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 tests/data/video_interpolation_result.mp4 diff --git a/mmedit/models/base_archs/__init__.py b/mmedit/models/base_archs/__init__.py index 1c037d970f..22585ee445 100644 --- a/mmedit/models/base_archs/__init__.py +++ b/mmedit/models/base_archs/__init__.py @@ -26,6 +26,9 @@ 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. diff --git a/mmedit/models/diffusion_schedulers/__init__.py b/mmedit/models/diffusion_schedulers/__init__.py index 3c9ab19d2c..8e81e1a670 100644 --- a/mmedit/models/diffusion_schedulers/__init__.py +++ b/mmedit/models/diffusion_schedulers/__init__.py @@ -9,7 +9,11 @@ def register_diffusers_schedulers() -> List[str]: """Register schedulers in ``diffusers.schedulers`` to the - ``DIFFUSION_SCHEDULERS`` registry. + ``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. 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 zcmZX52UwF!(`Z6~fCLhvG%2A=kzPdzRZ1u#kPw1GXi61CL`s0r1f+^|R6u%wBOt|s zK#(Hs(1b%#X~F>%3B8jW&-Z`#o_p^+&%QG|GdtPc*}U)W>@ENR;JY0V?B{Xc*9QQg z1N_Fcr0C+P!mjEwS%a`R&T5&%KR~Ufmgw7V0v|8&=!wW^o(@7VX&l;q02AiS%^+ddyne zeRlYkM`pA;Y`JBO)zwLCcKD#NgdBQb=Sob`2@}2yZ-fwKLiLbFOZl>;+_ILA8hw7k zS9U_}hM`Q?rX8-5gq7&?{XP| zaO7wR#LxACI+MjHd%%~}&Wx6D2R2X}JDKP-?!=&eD4zlg2*D2WGwYLiBIk}$Goe$k zMiKStn7&B*V0%!Z&og5rg6Yf$t3x5)guG`>ArqZz%JbUOfJCo3?(}l6*ur)nDZ)`C z_ZuDqCYO$;^jeW@5+XroW*7f4)|^f#q)5<&KS)rTA*b-m`<-Tcn^*Uw9(+D7jb6>} z&2?!rNh74a|LOb(8kG~dA}r3CR&*7Gtjs<7?9v+|sALMB%BHmSjh%id^s5!}ZEV^& z8{X>jzsO#_q?>!>%J|8LJFkhjuYUy42-%nzD0lPH!0B_$pM#VW6FkVEEj7n1gYZ0KU>!~& zT;135F+3b_Qh^%_g(ouz?ngALY>ttp*W? z4}!!Z_i{0RaNUVZ0RI^?e{dMJY#PPYpE!Pra%`2ry9|ylbfPz&xc^O7b|UkHN8hDn zkRS-Plas~F2*b94?E=r`^^74v80+UkQepY&^*2MOvFpRujrnL)6>=u1V2W}O#^V%w z4(IFxl8&9I&tBD9R%<8kli^VCMF+cw!cLvtEqxJGaQhc8_@yCbLH7(zxxILzLcOqM zR!%rLrlBx|gjkW#jg!Q}^W-cXKJAI|8(OpBWbdAYX=Z@XQh={=0}M*qp3)Yh6&lCM zm^uZ&<6iPyA>v?%H%fh1o}zd5d9hHv!!R+<5w4*H*poQE7mJ^#@PYb@9co($Leg$m z?!~4zY2%G6jS3$QewFhY7C1+z343{OWd|vnoZvYgv93VT{Alu29#|M87;h#zIqlT% z@)dvCBu&>@$~)wV`kqa6kFLTC^-yDa8PTxdG?+spVSK&x)`cAE7_0O6dX7&Cwp9R(*5z@P+zqK5kp#SqL zLK%WEY*!rNDa$N(v&>@hcopMIe{RMH+_j*m%U>9E6TrqB*E`5a zGjS6{jLwT`Yh47HHy|hIMT@_5U0dy}69JnT)X7*m@qNHVcI(ELvvk%k?6Jgz;Ry~^ zVDnTX4`Iurlu3#%f0a#p=B`b+=AnPx^tBL8c&@<4c$q~t3Zu<09=$_6K&)qg*41iK zU%vV1SlAw4nHB>nwr0|kKX|Y?r;9h`&n~gde7OPbxwa0t?f#3)v(YoL;XM@&&=O?G zj;-#}#v|V+=u9rXA=L#r7X5&*ou0hI=H43KQf55n>4K~w4?iR0qFQ zEZYHfx|!hIG#U!$G_`H1T+wsw;)K9wY~k5e<8D8rCFu?NMr*UdAHRR>rY{nGqiy^t zL-T;5pD-HDSyH^*le{q_D-i!PfS|z$D7}aefZ^m0RsRFYxOS|(kN(Y79)xh!aq z*;zfTQhP%jy{j{K#Ym5n={|OZ8%0T*0dW5H)%WntbA3%}Ta6?_Woz&5!%(FbYX5Du zoT5x~P8V}R1J;eQKy{CL8oCjjW?;IPlU^qx*3>Kxp6+*>dn|aieA0HDH#?--ul;># z{p&$$W>#XNwX9eyesX_v&H&2U3c@6ZA!)>F zsL6OaKeL8Nu!Lls{w#F&hMh%TQ? z>@7IVbl9w9l4mJa>wW(B4v-CN$zJ`KGJ+A<)F=HK&D8ZXOO}hUR8T` z^9=+u`Gey`2S&~s)}{k-M9yVAU5hEj&oT2!AyUa4Qg{e|lOr&Olguu0!fsSdLCcG# zM#4eqO2mls^g@WjV4U-jND9s^@<1qC8OCvfv(ym~MNrxj44%*jRJ`8{R%1E21+*n! zj6!s}d6>q~e<=(KTYH{P!5_v~hqPxo;7Pc4HDL6z-bMdSNO)h99U@zt*oQu~df>oM zs8hTrGQo_B>jhssHD8&`f(aXx&XEt)=!pdA-kngbYxI-6DmWKyZPjOy6M|dSudwPovmKkU1qEm|rm3M<(`U&>i<~F^aer}ztM`m)N zuDWK=T0UsFnecd>|NFJo$-5IHV=ZIR)R-pXU!6r_kz2aV6&)|2^PNzM zDV|~~!x$WSR=yV_ex6=ChCzSH{JKGV07!cY6$OoAl#;!SV(qrhmNExybe0s4NEn$u zPM2nS$crH1^%!#NL<5I;VWvc7SUOba2Q!?6R(@k@yM#pwxHx=aA9dG13~3^v&DrWz z=Aw{{d`*y|NXUmDD>D(YFN!_?_<_!PkSYx&J-2RJ6F#!Xgf2!uRu#$H9r0D6N2-aeSJp81sQlqD}ylO68 zH>G_K6t*us+|v|IFzK;>d0yv{Xenr|wSZpqK#SkWZ?AlW-@*MR-k4rBlHH*UBc%Ix zVxnng?TClJF2Kl@Fcm5lm&*h1acMG*tAWNi{WaQ9gO$h#3O%~&9wOrwyt8H_HB%E+ zq3yDmrub#;+tnUfqkjGj#oByXqB1hhwb{34rTI$7 zg8{X|%_rBL-|||5?0Eq}KM62BkmPjdVBC5+UPx4c!0j(auW6ilRZsoY$}7si4VQM! z*nW$=7nX@b!goSoo%j#J%bk7@TP$VejUj(S#e4Emo!B!lkm5WdxAgJncToVBy+k zHHvk^l7vk4m}h~Eh3UhYI5>Tv?ga$+Y$t#B%L$WrIsfP4?@4PV3zo+?c*N@mjn}9N zEOGBDggoxEs%8kqi08$A>gwI%@OV7&B?<5e?ep(WRGmML3 z`=Qg#jt|OAQ)ZHC2x3Eol#g`OF%+ViLSTTkTiqmGX*#&2fzzY@$V6S6(O2>sqtsOL zJJBkCj*MPq6nvD-ZGsqn)MqT3p#Nk)-@GvR8A3-xtM4jCbnYTQ$z3{so3@*gUwy!@Geds86VSDnuq^O9(ReeZIUPiua=>I3kU8GF^gv!%afVMOX->iQ@|lXY zJnTdZR61SpRz}7~tlS+1&y(d>0G!%xj-6{i(1C5%;@@%8Ys_|>m*K+y=%WOQme!~W zWr~7<%RB;Q>|?(gZk|)Fp%ZT6Ml=al%6eI^m73`u2u1@s0K>cXH_gOUYf9cWFC|@X z=&AlXaA^G?i;T(r0H2CoVDPaFFJWB{-fc)~Ufz5~xX_!JLD6v#?>6l$Q+s&P34_l zA>STn6s30!-=A7>*pQsS3jEyB;YmG#8vy6lHR{&|6kE+>QwNSG%5o#&CTd3KERrS6Z1S@~u+p64t( zMoohVUS{5JPaT7|0oro1EpJa`D>=l0H7~^i zjNFCLE_I@BjBRG5UTt1A(T(B5+`M_kLd!zK=e;uO-KVshSILl;km2m;xwt6f6YlCR zk_FN>>6D~_$&F+#!!cN%7OgxQ^PuPOux9|A0p}0Y*)}D>(9So*DbI`;LHGb;o5>y4 zhXffk5&0}!C{?z8a#OKv!K#Hx(8rP79`shkr3_84NZx^uSHZ04&*g+)?f!wNBc5u! z19^u6IbQBOZa+vtx;d~tG$MgtULZpUQlsbP?7OFp&(%IcqJ-%3ts=j7Ic;B?{3J{Q zG!Onn0GnP5zo)%-2g_dYrOq(g#X8u0Y0FDP{?MPX!Jj^gOZLFm+w}EZoAcUi#c&W% zX4Tpr1p&yrt9Ml=qm$N%Zlg?tqLowoi3GtMALsc+X0V5-6*o(-yXEvNo+n{SPJkG+M$dMqD~2KjZ1kXipr^&3eTmp*#thndzZ^|v z!se0 z>1!taJ(cj(Du!<;O&C%B4c|HE5pENHu7$cKPjbHxlqdtlRF>**GzisgGCb)%tph-g zm09mf-&j7Z`|$K+!f37adBJYggEa1s9lunsK!GucQ+@5TuuRX|53DrOo z)#dYxK3;<4_v%&F(nHZ4Rofxe9I@@B%BH62RI#rGU#vQ(1zW|}suRi{cAT4av-7`R zX(pJh{G_d%|5$%d*f72MF)r6V3d=Yj+Vpu6$^dvHZQ9>d#s8(D+P~u#jD^?dQ5+Tj zAtOmTx@jy`K`NHcXcGO?Oh#u<;>P^zD@ET6=*<}ozYPH&g&nJ0kFL%qw%;n0T~#yX zJwwYk0|t+6XVEXHt`l#`pr&z=q!%x?vdZywAC6Qbt`w8U~vU zASjWwsPFHW&!!(qNTbX6%8&6}d_z(&xerDAvXYY}?7AGdj5cSse6N{3urlr6Qlqq- zapSvL38(+$BSA9vhl(l!$uad02@mw)?bCOoZch7&iJuiVyQ>gZ-@I<9AKTf486<(v z@&u?ORcN)Nn-e8&1skKRJ)ows@b0IyWl6)R%`A$M<)S+S&*;$YF55BXb8+6%jJU0a zDYs|893(xMmK<@&(U2h4kP7lp508?3jn&(6-h%E@=OKe}uLot3_Q)QH8mXZG)wA1h zf>0pQR~?gj0(b&PQ_#&tKO$h#;Zp~rZG%px-0E_G=yOw1s4!!7cinA-H^;lynS}K0 z2u-BT@Fu!O*`cQCq)^LKLOS{>cf@A<$$e6QfBWB5kE@cKk;hl78xSPt*#?c}vqAR{ za%YUwch(o$>LHvjM-9ijU-d}k$r@MjR{qfOg!XhTV1=`#jXOS^>`mCqTrWTkjaKq` z)|gNT+>CaSfcGOUYaT-A-N$i=Ov|vyMS;>&$rk4#T=_XDy0erq*5kDF#+?kxS>HI5pFJkmem zA7Q?M)q`DV+{a$*3)V;LaUgWhQ%;%^fOEayN*=83%D+xaR&8iwILzX1;4P+O~|a@+;P+O z#7yBiP?M-9g*!pHiZ^7r44#Hx?u*G(mCrQZU&}WsIK|w2VsCR{X}xj+eiu5Pa?x0@ zwV zY0TH@9GXTa`;^{#=B$uZnwhBN27PODE4DaEesFzuh;#VV+O72lZmo7dI`j1v|I(Rh zRhJBiZ<1=Xw;V2p#kEh~*}D?RgRGz*#NY(aLs9s;_lzms@67os*p38fK1M4#~|5Y~1_seGN^W z%paB4_R*-Ps${z`!^`eS=-1Q=G*?R>8RGb2dvQf_3x8xU#TFg&n^rdFXvtNoyb*jY z?eU;S=BJw$D3r9D3NxGseC^}K;^ao*?3K!-dg=6Ba<#O3t+vL| zJ5e?+)?!!jS!VUtfIZ>ELh6-iKb?vN5yK`z3^EJO6XO`*MIJ!|3r5}`_6RaJZ7rwpT<(#&4mlp1O?`xyI z^~`G4PbXO+VxjdK>uLQrkZ`|-pyS3QU;Ao(Q;S=xwoUG%Iw^O@PEPPE-Dk`-=zj zHA+yA&){(`Flz?2j}C%v9bOs(`KxN4-K`%)K&Q-q)Tqu_Nz3|RR7JQnACFU zS#3j8^9vb^S#q}L3vaLQ)S1dT$vWaS?=Wk+99Hqli0pf|(~JwZd0;#qBBv6_hvdntqZcJp#Z{iwy?CkUS?Q$laG$Ie(X15e_XJ(cGZRK=X8l#q zgI;!4Vdu?bbGEik>U2`c-Zhgw@omrXQq;K**#y>aookfW3UckE73~=gY;uaDCGSSd zraJ2+1H7hc=6J!;#9K{9Qg$_TQu#z5CFTX)vy{=pqL2E+Zg67n!*6^FoNM`qFQnZ4 zpONbF@@KtfTD^78Dy-DItk(`+0i1DveW%`+#$12!O2W=?;KpvaRlf$L;V5yB6y|7Z zBs}qV``xvs03-g*GCAbadCJO#Q`d+*0rBVoSlFEE^Q^5hklT7=LVjIYY}KVtf{Il~ z(@h`e$7II2yGgELl#|A`)Td3hhr4Et57(kMFr5V+cRz96!XU2~$C@41t;2Dj`x1-I zFL{R@TbEe$L+Gk_F*hsTN|79H1-!W*9jknmQT`T2@wG?(QA8Q&)|=jkm7b|lwWg1s z8ZP=F_gjlf?WfgEj!LC<>R))>|2YC|YT$Uj>4GZeO7`L-i8yVCF3%VYb9GF=R|i3! z^ZA|)>3_wHKDxca?M#9E0)`#srtyTXOb=8I4zSEryUe`)d||PB8+-kk&0pgscLr0Z zjMZ&Eq9~!?KL_^SH;b1!Y&!}4PQAV}sl|Bj-Z8>LOzqhYs%mn!dsoj;#qlAvx+@5w zoYuU~Hf@n}A7{aoW;#7n+`(4e(ROKI{0cp6OO@edM$7Z~o7|8@!UK&5#?$WiFF{Nr zNRj6kmv~pL<#T02I1Sq>iW#TA0pGO|$ZF&Tl&W}~-*x(AtbE~a)V??Jj zMOf>f=R9{%NN$`>g&%y7x z-euO;c1fm#8l*dviRU>@xj)1GL<#oxks3>L_TuTCReN-PbmGS3E8RB_CFNI`S-gO3Z{ za+6Y}_W;_s~E!!Z-ram6I7t+x$C%cc$cgveze8Tu` z``u7#?g7L`psHZ6YNyiXL42{@kMr9sN~f>?3Oo6l{PTJsVfzmF1^@a8MezxByWR7^ zV5f`wxMaTb_Eqhe*w0O6xn#A4jkv++NY}a$?{RO^f%Jv#$ycM@_uupe z2d1#Jar23LG-`VboC9Y0Qtp)VgZbD2xpCzsktZJa<( z>^`?`KUE5v?Z3ZDb|n=AYZgEMR(ZKb+#|lb(FzmX`Ng~Oy6(p{b;esdigTT}h_3g$ z(J}?yb+HTu`QP!?*8O1ykX{kKXNCLKl3i$VY7rlZwQ|n@Cw% zAG8NHy_3N*3v5J$kuyLN#~x!*@Z0DF)-VYw2b98N*u43zl%COm;DeQl1iTUAiZ{uz z=qPozvyFWB;#8h;VVM@~$(FVdagPR@ugFKGv7ON~!bL6q3{TNxO3QUjPniZSeuIwx zaIk?gP^E70SUC-YRT(phokpmISE=@H+A(6f0Ny0A`8x!WQ|zN>`s|$n3tTzg+&V{r z55K^%uo#)gi9Ks|)(ngDD>sv+O$%JPuer9chDoaw%oqUI8eNu^nm-oQZJsUUF58Y|Ut7$%fW;vx&ssq>xZ*f(1Efho#agFb zrVcal)IDt!ljniW>Wlo!J_;qnLbOnyD7?w_f01DX2a%?n;3w8*Y(0y6bi6)C*`6f{ zR?$~eN4Z9hZZHLvlO}C)LL4AhEX1NE*vsR@W{JdCF%H`3IVT3iy2}Aq z`I%+fo$%|zg~TWI%aa&dkDyAbYtIRNn*ipsk5##)=`(rcCuD;B*y)8g=Xkdfj8Y8h z6rrJ1u(Op-0RuOyp1km_VA2OYmt>HQbRnNMZ{xLLvLRRXDz7!eo!`4xRj z7=3IIlYob9I$O`tuzX!Jk5hWpL!B}7D`~GY=jQodC$Dq)-mKT#ord1lN!?av=LVV8 zcQ>#oL{X(Ip4)2_vNojGE$e1k=Lp7~Mg9oIIoammksiqyb&o&3$VlCHiDYr#(MRtP z`KIxzxz_p{2PoLIN3E}vK>azdO-P8w*`Y%UQQojSA23UbWUUkDlGl*+P*;aJ=os-c z+r6Mhnkzp5UkEHPsJ&)f@mAu*@aUar-TYVc?+ZFH*|c~>ZDkRE(oxezIT$&WIp>bv z`O6@AEm=H|AryT1##$*5U^FB}?Wsi8sPCAViE%NT1l9{yjT~88OYnmSqXa485SFVZ z#S^^nTn`OP{833lzH6i64T(^y!4X0gf=x3?2+-%RVqCL?LO*Cek!rlfU=MkrbGP(P z-)GAp35HD}=j-x+M!wwKTfGjWW=#=ZmlLtBG;jESVJuapTGTkFz^M zRW(qSZ6L-0$zP9z!*$0kv{5;N^~jO-13o0>R6DVmzVHr*n_!mMFHt$CG_-PGC>2CJ zIY@`a4aE2PnGC)(y?0e-PQPPobd&Y6#Z7GimGe@r@B5w-4OE|_N@^VG64!Wa4O-xo z4-zZ70$#%B0`01Uf}R5A9(B}ju3L?}m5rsIbwkIGb)$}pKS!5*{4l!g&!h`6oVaK) z+GxVT878m8WO9E{-2GwBY-h5MV$tkc*@tC$cE6zK^75=#Yoagb3OjX0rD#!Z5YfOoF`Oel26;QdQ{EVpDH&351=1P!aHaYtP<*{K}& zIyYXiDuWt+?&QsfWNqhc@4gTqX_$Hn--R_xrUxsi8AU5FyyoJJ5sB>R3ZnCqGnBS_f_j3B;AB;51ZfvwNdSdmOle% zQIt|f>B};39_NFg$}1s7mkA#^um`Ljek(%23Gh2?c9@Z8+_joZfTzyJlndGd@;L$R zyVi8rwd@5Cozak2;J&j;;RrFg%U-jCvhFaQzdLUO-#M@`FlFTm3O6@kZ$?DvUB8rr zG!sdZVIu@M{^L42&pVLva%$Ra_=AGes3 zUy?Rcd^)asw<0;zh_&j(0--`JcQTHeO{c2|mfAZL-;+UifM$%#ml6_z7B)A}c>ptL zA>AsePcvr0s&RceE0gifeV?hx6Ha-(78nq;VGyvU zwKKp~&qgofs)wHE3jhu_}KAIEAPDE&DhTRH;9b)oWPYZ=OcM;e>`$H7JbPTnynKvdQUKTVV>DBU5N)#f~d4{Xcf`C(iV^Bl%+@T0WSxiw-qOV#=IV~t7APt4Ck$-05)lP}n&5C}2 zc9%060N~Z^&0dsQd^&uBus;qTk&z=(ek@$orku3U4(z-kRJJ73cIIvaOO_HoGlj#( zb^I=8yu`*5t6W3GNO{Of5mLv(=1+Ly$upQA%xKU(E9=B?TDu)ef7wi^;g-PzNdwgm z@aIN9Zbq($3N04H5si<#SDmjvXz@w&H=HAM9fn(GmhB zAkq_)8$(_-oOO8i{PVE9+F5i0r(>E5Km81%Vsw`@-2l_B_JNy3pxjqO^(^!nDz0V*O zFTW)CogJuG9Wm!7QoZfc1a6eb5@BM-wlZ<3&G<+>a`==b#@T+c^~7+mL{5(X#CSF= z4T9d99}P4;`vYo&){_@@&wis}F{g@&!=Z?oopvE z_VZc@mRpuacGnK?Z)(~WbT0KZ8vuLas;#;|^Ne5eRg{E9lv4RZ!yaIgPm5PKerQzJ zV5HrUDvzT#lo|76UF%os8o-u9o)r$-1!j!-&d~J8S6uy>F|%jP5Ub@eHhQ8Hu;g8J zkk~!U-(x?#rHdfA+RZxdpc&Vh-IA_)pLyu0gab3`J9-TzjTNn zh$gQ5BtWnlcLq{hAXu3Gaxn2z&bBTf=w?Sl2RGQ@^6G}FJSEnBPJ zI(o)kKh*uhk^d;3b@msDLS*ESuErRFo^>uI1*0AS{=D^gGimEh(N*kU5t)tWc=G|% zW?pAE)~A5DEPuuBds)RC>m}MujsmG@SN0QacOK)Fz;BY*H=sC-1I*rZe&n8i;5a_j zsQn8*B)eBd%s9ssK|TzSV?W{Il(k@r1m|V<^_ZA`Ao5L+5X>NoTFu#_p4#Vwpl61R zP~xubG{o+4Wb~Z+l%G`p=t=mtVEbc;ee4dmE_*I}W}{K;+G(pCm@e_>@TPX_*!?ql zx>KK`gOeaw&q02N4lk@Fv*~FNH?}QCVfggD(Xb(dhM_@I=I1kk7%|I`NyWzyK`6JG zBg<~ujmYt!3}eK^`Rt9v{z;H|i~{9^01TQ(lHL^lQDIYqU1)p*X$oA9%jVg7l!1X=jbpLB{mGwFt#Q_~ch#(}lt)p+%{2u6UQ_85j>d_7N6AI#@0A z6FekpX0*J=!OpJ8MKOx|$m_YAyy#3I+vJ~FXw&N+NQ`DfJ72{Eftqp*^1Q%DwIPf- zAn(W{v6MKs1Kc0vA1<>&uudTv2PXYF44u@=-D{(4_Wbpl7VTRkADqEASy(NnXBm6H zHIt;#8wc%Omvy2)UTgCQD`{ilh9IF`J{s$zB5+!f6VCK@NspJ4S<*V1tYbK@j;udb zTP653P1{T-$-%Xg8ga7Mm$j&N0~Vi-dC|M(!>1A%A0s*@G-Z@rLQ5BSnvc=~5K!xr zdmALnKN^2}%^Xc;u$j^oR zA%#xj66X)6i$r#rWJU=-Q4UOFWp`hNC1(y-p2O+kX+Qmu2&%W z$#eSfd~aj{3Jg8~>%PN&k{nAJuY|{B&3F^4=D4rI#+jXAD=0=_LJU9$4(>&Y#W3i> zvkYEw(cTD!Z>{QvS6Y=wD=Aa{1SWh0nhDa~GHuh>_TB}w8*;^!)240U(5jZY7<2Gx z``gH=PpN*!`ZcrQCSBMYT}HkozVA=l?SOAHG`$7tzXf+ zHL3;59}2IvZZ+AO7n~{LAgY5FK%b3?o;HD-@Q1y*N!iD%_ml(+X{TG_1qp@%sRYKJ zk0UZ#jFynb+tI|oGnF+xELYy!Olo_zHGYeQJp~F5# zul$j!vP?S;`I>42!KHmja#?IRyVKj>0Z`{e-K}Cj`IMn0kR8og<`M~%&;=DZWm!Y- z;oQ7u=B4%L*Ki#-g!0mrOQ5Qs($y^-b2J$lo;(qKqtDMA(gibe7?CW*tF+$X$X2NY zvKL9_Yu-wTshdl?DiFij0aGS+`Ro>Tpr(QZ_*pJObIrT+NgLA$F}zOY1<^NME_PJf z&4)@72Z1%Xdg7wTpelJQ$6|nzf{*^ZMB8fGzfff}c@hq@V)h&-ZXy0w&N!s;gIZc9g3x)K)dLsT#7Dw z$+oYSFq`8czaw|k6p^h8+j(QmN4U_J*isoO*Iq>raB7z)K+2erJB-Dh(;aQ4HBCYZ zPKUlSE(;eQH85V(w0Mf!R>>HMb7GL=F`J|XPYyShFoFZgaRYeDz2rweFEKGY4~3NTA^h$0YF;R>R;UdJ3|xvUqS#t=ij>jKTSuw3*;W)@8m@j-3;*h z=QlzBQv0tp&42O!L;hFtU%~&A*ZIx={rH^#08uyBfcrGe=jMH%cE9K!_+8>ZcK<00 zobz$@aH8=9eO&+Fwky)uAOO1apK>zpuHOFtP_##&hb!&g(*FSrE$?gWbl26}?Y9mv z(Z}QNZ5nYQ(B~hc|E{K}>wjc?uKsSnb$-KdIpl%Ax8Q$hpy~YpXKxxkb3fqze;x8$ zr=NCl>bIkQ!@q6*hoeJlwlR(Toqogrukj!L|9Ns#skDrf+kMyH-2?y;i9}0UF?t%- z6J-C*y7(vYcVeJ%lR`2VN>|HmAS$9+HGAK%c(e=17z|3CHRqcxdk>mT^d_?>=_jo(<1 zCJUkA{{oExrL4f50Or~Nka+bDq6$lJ6=s;T~N