diffusers icon indicating copy to clipboard operation
diffusers copied to clipboard

Expanded init fields in StableDiffusionPipeline cause incompatibilities with many/most inherited pipelines

Open vladmandic opened this issue 2 years ago • 11 comments

Describe the bug

class StableDiffusionPipeline has its init section as:

    def __init__(
        self,
        vae: AutoencoderKL,
        text_encoder: CLIPTextModel,
        tokenizer: CLIPTokenizer,
        unet: UNet2DConditionModel,
        scheduler: KarrasDiffusionSchedulers,
        safety_checker: StableDiffusionSafetyChecker,
        feature_extractor: CLIPImageProcessor,
        image_encoder: CLIPVisionModelWithProjection = None,
        requires_safety_checker: bool = True,
    ):

and here image_encoder was recently introduced thus changing the class signature
but most community pipelines do not include init field for recently included image_encoder and thus order or params is wrong

for example, examples/community/regional_prompting_stable_diffusion.py has this in its init:

        super().__init__(
            vae,
            text_encoder,
            tokenizer,
            unet,
            scheduler,
            safety_checker,
            feature_extractor,
            requires_safety_checker,
        )

which means bool value from requires_safety_checker is going to be passed as image_encoder and pipeline will fail during initialization like this:

> diffusers/pipelines/pipeline_utils.py:546 in _fetch_class_library_tuple
AttributeError: 'bool' object has no attribute '__module__'

this is a conceptual problem with changing master class signature while all inherited classes pass args list as simple list.
i don't see a simple solution as going back is bad and going forward requires updates to a lot of pipelines.

but at the very basic, at least add error handling to _fetch_class_library_tuple so invalid type does not cause entire solution to crash.

Reproduction

load nearly any community pipeline or any pipeline inherited from StableDiffusionPipeline, but not updated to use new signature in its super().__init__ call

Logs

No response

System Info

diffusers==0.26.3

Who can help?

@yiyixuxu @DN6 @sayakpaul @patrickvonplaten

vladmandic avatar Feb 13 '24 20:02 vladmandic

Cc: @yiyixuxu

sayakpaul avatar Feb 14 '24 01:02 sayakpaul

Hi @vladmandic It only breaks pipelines that inherit from StableDiffusionPipeline instead of DiffusionPipeine - all our pipelines should inherit from DiffusionPipeline.

I don't consider this a breaking change for this reason. However would very much like to make the community pipelines work correctly again. We can ask the community to help refactor these PRs to use DiffusionPipeline as a base class instead - does this plan work for you?

cc @sayakpaul @DN6 here do you guys have any good ideas?

I think we should start to check the base classes for community pipeline PRs and don't merging in unless they use DiffusionPipeline

yiyixuxu avatar Feb 14 '24 06:02 yiyixuxu

What you suggested is the best case here as it's the simplest.

sayakpaul avatar Feb 14 '24 06:02 sayakpaul

@vladmandic

Is this something can be done in SD.Next for a temporary solution while we trying to update all the community pipelines to use DiffusionPipeline?

but at the very basic, at least add error handling to _fetch_class_library_tuple so invalid type does not cause entire solution to crash.

yiyixuxu avatar Feb 14 '24 06:02 yiyixuxu

thanks - i agree with action plan. i'll try monkey-patching _fetch_class_library_tuple from sdnext in the meantime.

vladmandic avatar Feb 14 '24 15:02 vladmandic

i confirm that monkey-patching works as as stop-gap solution

from diffusers.pipelines import pipeline_utils

def hijack_register_modules(self, **kwargs):
    for name, module in kwargs.items():
        if module is None or isinstance(module, (tuple, list)) and module[0] is None:
            register_dict = {name: (None, None)}
        elif isinstance(module, bool):
            pass
        else:
            library, class_name = pipeline_utils._fetch_class_library_tuple(module)
            register_dict = {name: (library, class_name)}
        self.register_to_config(**register_dict)
        setattr(self, name, module)

pipeline_utils.DiffusionPipeline.register_modules = hijack_register_modules

vladmandic avatar Feb 14 '24 16:02 vladmandic

This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.

Please note that issues that do not follow the contributing guidelines are likely to be ignored.

github-actions[bot] avatar Mar 15 '24 15:03 github-actions[bot]

I think this is not stale. @yiyixuxu can you confirm?

sayakpaul avatar Mar 15 '24 15:03 sayakpaul

This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.

Please note that issues that do not follow the contributing guidelines are likely to be ignored.

github-actions[bot] avatar Apr 09 '24 15:04 github-actions[bot]

ping.

vladmandic avatar Apr 09 '24 18:04 vladmandic

This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.

Please note that issues that do not follow the contributing guidelines are likely to be ignored.

github-actions[bot] avatar May 04 '24 15:05 github-actions[bot]

ping.

vladmandic avatar Oct 03 '24 12:10 vladmandic

@vladmandic do yo maybe have a list of the community pipelines that are you interested in fixing? Probably will be better if we open an issue with a specific list than a generic one.

Regional prompting is the main one right? For some time I wanted to take a look into it and maybe do a new one with the same for controlnet.

asomoza avatar Oct 04 '24 01:10 asomoza

i'd need to go over the list of community pipelines to see which ones are most useful. regional prompting was a great idea a long time ago, but original pipeline was never ported to sdxl so its value has diminished.

vladmandic avatar Oct 04 '24 02:10 vladmandic

yeah, I'll probably take that one, I mean the SDXL one, I don't use SD 1.5 anymore but I can still fix it as a bonus while making the SDXL one.

asomoza avatar Oct 04 '24 02:10 asomoza