diff --git a/CHANGELOG.md b/CHANGELOG.md index bdacba68d..2ea4310b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,12 +21,24 @@ Upgrades are still possible and supported, but above is recommended for best exp - faster search, ability to show/hide/sort networks - refactored subfolder handling *note*: this will trigger model hash recaclulation on first model use -- **Refiner**: - - You can now use *SD Latent Upscale* models as refiner - this is a bit experimental, but it works quite well! - Simply go to *Models -> Huggingface* and download: - - `stabilityai/sd-x2-latent-upscaler` - - `stabilityai/stable-diffusion-x4-upscaler` +- **Diffusers**: + - **SDXL Inpaint** + - Although any model can be used for inpainiting, there is a case to be made for + dedicated inpainting models as they are tuned to inpaint and not generate + - Model can be used as base model for **img2img** or refiner model for **txt2img** + To download go to *Models -> Huggingface*: + - `diffusers/stable-diffusion-xl-1.0-inpainting-0.1` *(6.7GB)* + - **SDXL Instruct-Pix2Pix** + - Model can be used as base model for **img2img** or refiner model for **txt2img** + This model is massive and requires a lot of resources! + To download go to *Models -> Huggingface*: + - `diffusers/sdxl-instructpix2pix-768` *(11.9GB)* + - **SD Latent Upscale** + - You can use *SD Latent Upscale* models as **refiner models** + This is a bit experimental, but it works quite well! + To download go to *Models -> Huggingface*: + - `stabilityai/sd-x2-latent-upscaler` *(2.2GB)* + - `stabilityai/stable-diffusion-x4-upscaler` *(1.7GB)* - **Upscalers**: - more high quality upscalers available by default *SwinIR:2, ESRGAN:12, RealESRGAN:6, SCUNet:2* diff --git a/installer.py b/installer.py index 1a805499d..41ec5b442 100644 --- a/installer.py +++ b/installer.py @@ -578,7 +578,8 @@ def install_repositories(): clone(taming_transformers_repo, d('taming-transformers'), taming_transformers_commit) k_diffusion_repo = os.environ.get('K_DIFFUSION_REPO', 'https://github.com/crowsonkb/k-diffusion.git') # k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', "b43db16749d51055f813255eea2fdf1def801919") - k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', 'ab527a9') + # k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', 'ab527a9') + k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', 'f4a74f1ec906cb62916f58288ec73ef0330ba446') clone(k_diffusion_repo, d('k-diffusion'), k_diffusion_commit) codeformer_repo = os.environ.get('CODEFORMER_REPO', 'https://github.com/sczhou/CodeFormer.git') # codeformer_commit = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af") diff --git a/modules/processing.py b/modules/processing.py index f1fda1941..cd049f9d0 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -1096,11 +1096,11 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): self.sampler = None def init(self, all_prompts, all_seeds, all_subseeds): - if shared.backend == shared.Backend.DIFFUSERS and self.image_mask is None: - modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.IMAGE_2_IMAGE) - elif shared.backend == shared.Backend.DIFFUSERS and self.image_mask is not None: + if shared.backend == shared.Backend.DIFFUSERS and self.image_mask is not None: modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.INPAINTING) self.sd_model.dtype = self.sd_model.unet.dtype + elif shared.backend == shared.Backend.DIFFUSERS and self.image_mask is None: + modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.IMAGE_2_IMAGE) if self.sampler_name == "PLMS": self.sampler_name = 'UniPC' @@ -1213,12 +1213,11 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): self.image_conditioning = self.img2img_image_conditioning(image, self.init_latent, image_mask) def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts): - if shared.backend == shared.Backend.DIFFUSERS: - if self.init_mask is None: # pylint: disable=no-member - modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.IMAGE_2_IMAGE) - else: - modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.INPAINTING) - self.sd_model.dtype = self.sd_model.unet.dtype + if shared.backend == shared.Backend.DIFFUSERS and self.image_mask is not None: + modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.INPAINTING) + self.sd_model.dtype = self.sd_model.unet.dtype + elif shared.backend == shared.Backend.DIFFUSERS and self.image_mask is None: + modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.IMAGE_2_IMAGE) x = create_random_tensors([4, self.height // 8, self.width // 8], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self) x *= self.initial_noise_multiplier diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index b099fe195..46205656b 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -23,6 +23,16 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro p.is_hr_pass = True is_refiner_enabled = p.enable_hr and p.refiner_steps > 0 and p.refiner_start > 0 and p.refiner_start < 1 and shared.sd_refiner is not None + if len(p.init_images) > 0: + tgt_width, tgt_height = 8 * math.ceil(p.init_images[0].width / 8), 8 * math.ceil(p.init_images[0].height / 8) + if p.init_images[0].width != tgt_width or p.init_images[0].height != tgt_height: + shared.log.debug(f'Resizing init images: original={p.init_images[0].width}x{p.init_images[0].height} target={tgt_width}x{tgt_height}') + p.init_images = [images.resize_image(1, image, tgt_width, tgt_height, upscaler_name=None) for image in p.init_images] + if p.mask is not None: + p.mask = images.resize_image(1, p.mask, tgt_width, tgt_height, upscaler_name=None) + if p.mask_for_overlay is not None: + p.mask_for_overlay = images.resize_image(1, p.mask_for_overlay, tgt_width, tgt_height, upscaler_name=None) + def hires_resize(latents): # input=latents output=pil latent_upscaler = shared.latent_upscale_modes.get(p.hr_upscaler, None) shared.log.info(f'Hires: upscaler={p.hr_upscaler} width={p.hr_upscale_to_x} height={p.hr_upscale_to_y} images={latents.shape[0]}') @@ -310,8 +320,13 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro elif sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.IMAGE_2_IMAGE: p.ops.append('img2img') task_specific_kwargs = {"image": p.init_images, "strength": p.denoising_strength} + elif sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.INSTRUCT: + p.ops.append('instruct') + task_specific_kwargs = {"height": 8 * math.ceil(p.height / 8), "width": 8 * math.ceil(p.width / 8), "image": p.init_images, "strength": p.denoising_strength} elif sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.INPAINTING: p.ops.append('inpaint') + if p.mask is None: + p.mask = TF.to_pil_image(torch.ones_like(TF.to_tensor(p.init_images[0]))).convert("L") task_specific_kwargs = {"image": p.init_images, "mask_image": p.mask, "strength": p.denoising_strength, "height": 8 * math.ceil(p.height / 8), "width": 8 * math.ceil(p.width / 8)} if shared.state.interrupted or shared.state.skipped: @@ -360,7 +375,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro shared.log.info(e) except ValueError as e: shared.state.interrupted = True - shared.log.error(e) + shared.log.error(f'Processing: {e}') if hasattr(shared.sd_model, 'embedding_db') and len(shared.sd_model.embedding_db.embeddings_used) > 0: p.extra_generation_params['Embeddings'] = ', '.join(shared.sd_model.embedding_db.embeddings_used) diff --git a/modules/sd_models.py b/modules/sd_models.py index ed9934d20..9005d412a 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -956,6 +956,7 @@ class DiffusersTaskType(Enum): TEXT_2_IMAGE = 1 IMAGE_2_IMAGE = 2 INPAINTING = 3 + INSTRUCT = 4 def set_diffuser_pipe(pipe, new_pipe_type): sd_checkpoint_info = getattr(pipe, "sd_checkpoint_info", None) @@ -963,12 +964,19 @@ def set_diffuser_pipe(pipe, new_pipe_type): sd_model_hash = getattr(pipe, "sd_model_hash", None) has_accelerate = getattr(pipe, "has_accelerate", None) - if new_pipe_type == DiffusersTaskType.TEXT_2_IMAGE: - new_pipe = diffusers.AutoPipelineForText2Image.from_pipe(pipe) - elif new_pipe_type == DiffusersTaskType.IMAGE_2_IMAGE: - new_pipe = diffusers.AutoPipelineForImage2Image.from_pipe(pipe) - elif new_pipe_type == DiffusersTaskType.INPAINTING: - new_pipe = diffusers.AutoPipelineForInpainting.from_pipe(pipe) + if pipe.__class__.__name__ == "StableDiffusionXLPipeline" or pipe.__class__.__name__ == 'StableDiffusionXLImg2ImgPipeline': + new_pipe_type = DiffusersTaskType.INPAINTING # sdxl works better with init mask + try: + if new_pipe_type == DiffusersTaskType.TEXT_2_IMAGE: + new_pipe = diffusers.AutoPipelineForText2Image.from_pipe(pipe) + elif new_pipe_type == DiffusersTaskType.IMAGE_2_IMAGE: + new_pipe = diffusers.AutoPipelineForImage2Image.from_pipe(pipe) + elif new_pipe_type == DiffusersTaskType.INPAINTING: + new_pipe = diffusers.AutoPipelineForInpainting.from_pipe(pipe) + except Exception as e: # pylint: disable=unused-variable + # shared.log.error(f'Failed to change: type={new_pipe_type} pipeline={pipe.__class__.__name__} {e}') + return + if pipe.__class__ == new_pipe.__class__: return @@ -977,7 +985,7 @@ def set_diffuser_pipe(pipe, new_pipe_type): new_pipe.sd_model_hash = sd_model_hash new_pipe.has_accelerate = has_accelerate model_data.sd_model = new_pipe - shared.log.info(f"Pipeline class changed from {pipe.__class__.__name__} to {new_pipe.__class__.__name__}") + shared.log.debug(f"Pipeline class changed from {pipe.__class__.__name__} to {new_pipe.__class__.__name__}") def get_native(pipe: diffusers.DiffusionPipeline): @@ -995,11 +1003,14 @@ def get_native(pipe: diffusers.DiffusionPipeline): def get_diffusers_task(pipe: diffusers.DiffusionPipeline) -> DiffusersTaskType: - if pipe.__class__ in diffusers.pipelines.auto_pipeline.AUTO_IMAGE2IMAGE_PIPELINES_MAPPING.values(): + if pipe.__class__.__name__ == "StableDiffusionXLInstructPix2PixPipeline": + return DiffusersTaskType.INSTRUCT + elif pipe.__class__ in diffusers.pipelines.auto_pipeline.AUTO_IMAGE2IMAGE_PIPELINES_MAPPING.values(): return DiffusersTaskType.IMAGE_2_IMAGE elif pipe.__class__ in diffusers.pipelines.auto_pipeline.AUTO_INPAINT_PIPELINES_MAPPING.values(): return DiffusersTaskType.INPAINTING - return DiffusersTaskType.TEXT_2_IMAGE + else: + return DiffusersTaskType.TEXT_2_IMAGE def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None, op='model'): diff --git a/requirements.txt b/requirements.txt index 3fc7a4336..6aa29a15d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -40,6 +40,7 @@ scikit-image basicsr compel==2.0.2 fasteners +dctorch typing-extensions==4.7.1 antlr4-python3-runtime==4.9.3 requests==2.31.0