From d6773d8b986653d42995d8c266c8267135701329 Mon Sep 17 00:00:00 2001 From: smthem <2102561739@qq.com> Date: Fri, 2 Aug 2024 21:35:27 +0800 Subject: [PATCH] new --- Diffree_node.py | 463 +++++ __init__.py | 4 + app.py | 401 ++++ config/generate.yaml | 112 ++ no_need_requirements.txt | 18 + .../autoencoder/autoencoder_kl_16x16x16.yaml | 54 + .../autoencoder/autoencoder_kl_32x32x4.yaml | 53 + .../autoencoder/autoencoder_kl_64x64x3.yaml | 54 + .../autoencoder/autoencoder_kl_8x8x64.yaml | 53 + .../latent-diffusion/celebahq-ldm-vq-4.yaml | 86 + .../latent-diffusion/cin-ldm-vq-f8.yaml | 98 + .../configs/latent-diffusion/cin256-v2.yaml | 68 + .../latent-diffusion/ffhq-ldm-vq-4.yaml | 85 + .../lsun_bedrooms-ldm-vq-4.yaml | 85 + .../lsun_churches-ldm-kl-8.yaml | 91 + .../latent-diffusion/txt2img-1p4B-eval.yaml | 71 + .../768x768.yaml | 68 + .../stable-diffusion/v1-inference.yaml | 70 + .../data/imagenet_clsidx_to_label.txt | 1000 ++++++++++ ...imagenet_train_hr_indices.p.REMOVED.git-id | 1 + .../data/imagenet_val_hr_indices.p | Bin 0 -> 145756 bytes stable_diffusion/data/index_synset.yaml | 1000 ++++++++++ stable_diffusion/environment.yaml | 31 + stable_diffusion/ldmx/data/__init__.py | 0 stable_diffusion/ldmx/data/base.py | 23 + stable_diffusion/ldmx/data/imagenet.py | 394 ++++ stable_diffusion/ldmx/data/lsun.py | 92 + stable_diffusion/ldmx/lr_scheduler.py | 98 + stable_diffusion/ldmx/models/autoencoder.py | 449 +++++ .../ldmx/models/diffusion/__init__.py | 0 .../ldmx/models/diffusion/classifier.py | 267 +++ .../ldmx/models/diffusion/ddim.py | 241 +++ .../ldmx/models/diffusion/ddpm.py | 1451 +++++++++++++++ .../ldmx/models/diffusion/ddpm_diffree.py | 1611 +++++++++++++++++ .../ldmx/models/diffusion/ddpm_edit.py | 1465 +++++++++++++++ .../models/diffusion/dpm_solver/__init__.py | 1 + .../models/diffusion/dpm_solver/dpm_solver.py | 1184 ++++++++++++ .../models/diffusion/dpm_solver/sampler.py | 82 + .../ldmx/models/diffusion/plms.py | 236 +++ stable_diffusion/ldmx/modules/attention.py | 272 +++ .../ldmx/modules/diffusionmodules/__init__.py | 0 .../ldmx/modules/diffusionmodules/model.py | 834 +++++++++ .../modules/diffusionmodules/openaimodel.py | 961 ++++++++++ .../diffusionmodules/openaimodel_diffree.py | 1200 ++++++++++++ .../ldmx/modules/diffusionmodules/util.py | 267 +++ .../ldmx/modules/distributions/__init__.py | 0 .../modules/distributions/distributions.py | 92 + stable_diffusion/ldmx/modules/ema.py | 76 + .../ldmx/modules/encoders/__init__.py | 0 .../ldmx/modules/encoders/modules.py | 322 ++++ .../modules/image_degradation/__init__.py | 2 + .../ldmx/modules/image_degradation/bsrgan.py | 730 ++++++++ .../modules/image_degradation/bsrgan_light.py | 650 +++++++ .../modules/image_degradation/utils_image.py | 916 ++++++++++ .../ldmx/modules/losses/__init__.py | 1 + .../ldmx/modules/losses/contperceptual.py | 111 ++ .../ldmx/modules/losses/vqperceptual.py | 167 ++ .../ldmx/modules/x_transformer.py | 641 +++++++ stable_diffusion/ldmx/util.py | 203 +++ stable_diffusion/main.py | 748 ++++++++ .../first_stage_models/kl-f16/config.yaml | 44 + .../first_stage_models/kl-f32/config.yaml | 46 + .../first_stage_models/kl-f4/config.yaml | 41 + .../first_stage_models/kl-f8/config.yaml | 42 + .../first_stage_models/vq-f16/config.yaml | 49 + .../vq-f4-noattn/config.yaml | 46 + .../first_stage_models/vq-f4/config.yaml | 45 + .../first_stage_models/vq-f8-n256/config.yaml | 48 + .../first_stage_models/vq-f8/config.yaml | 48 + .../models/ldm/bsr_sr/config.yaml | 80 + .../models/ldm/celeba256/config.yaml | 70 + .../models/ldm/cin256/config.yaml | 80 + .../models/ldm/ffhq256/config.yaml | 70 + .../models/ldm/inpainting_big/config.yaml | 67 + .../ldm/layout2img-openimages256/config.yaml | 81 + .../models/ldm/lsun_beds256/config.yaml | 70 + .../models/ldm/lsun_churches256/config.yaml | 92 + .../ldm/semantic_synthesis256/config.yaml | 59 + .../ldm/semantic_synthesis512/config.yaml | 78 + .../models/ldm/text2img256/config.yaml | 77 + stable_diffusion/notebook_helpers.py | 270 +++ stable_diffusion/scripts/img2img.py | 293 +++ stable_diffusion/scripts/inpaint.py | 98 + stable_diffusion/scripts/knn2img.py | 398 ++++ stable_diffusion/scripts/sample_diffusion.py | 313 ++++ .../scripts/tests/test_watermark.py | 18 + stable_diffusion/scripts/train_searcher.py | 147 ++ stable_diffusion/scripts/txt2img.py | 352 ++++ stable_diffusion/setup.py | 13 + 89 files changed, 22888 insertions(+) create mode 100644 Diffree_node.py create mode 100644 __init__.py create mode 100644 app.py create mode 100644 config/generate.yaml create mode 100644 no_need_requirements.txt create mode 100644 stable_diffusion/configs/autoencoder/autoencoder_kl_16x16x16.yaml create mode 100644 stable_diffusion/configs/autoencoder/autoencoder_kl_32x32x4.yaml create mode 100644 stable_diffusion/configs/autoencoder/autoencoder_kl_64x64x3.yaml create mode 100644 stable_diffusion/configs/autoencoder/autoencoder_kl_8x8x64.yaml create mode 100644 stable_diffusion/configs/latent-diffusion/celebahq-ldm-vq-4.yaml create mode 100644 stable_diffusion/configs/latent-diffusion/cin-ldm-vq-f8.yaml create mode 100644 stable_diffusion/configs/latent-diffusion/cin256-v2.yaml create mode 100644 stable_diffusion/configs/latent-diffusion/ffhq-ldm-vq-4.yaml create mode 100644 stable_diffusion/configs/latent-diffusion/lsun_bedrooms-ldm-vq-4.yaml create mode 100644 stable_diffusion/configs/latent-diffusion/lsun_churches-ldm-kl-8.yaml create mode 100644 stable_diffusion/configs/latent-diffusion/txt2img-1p4B-eval.yaml create mode 100644 stable_diffusion/configs/retrieval-augmented-diffusion/768x768.yaml create mode 100644 stable_diffusion/configs/stable-diffusion/v1-inference.yaml create mode 100644 stable_diffusion/data/imagenet_clsidx_to_label.txt create mode 100644 stable_diffusion/data/imagenet_train_hr_indices.p.REMOVED.git-id create mode 100644 stable_diffusion/data/imagenet_val_hr_indices.p create mode 100644 stable_diffusion/data/index_synset.yaml create mode 100644 stable_diffusion/environment.yaml create mode 100644 stable_diffusion/ldmx/data/__init__.py create mode 100644 stable_diffusion/ldmx/data/base.py create mode 100644 stable_diffusion/ldmx/data/imagenet.py create mode 100644 stable_diffusion/ldmx/data/lsun.py create mode 100644 stable_diffusion/ldmx/lr_scheduler.py create mode 100644 stable_diffusion/ldmx/models/autoencoder.py create mode 100644 stable_diffusion/ldmx/models/diffusion/__init__.py create mode 100644 stable_diffusion/ldmx/models/diffusion/classifier.py create mode 100644 stable_diffusion/ldmx/models/diffusion/ddim.py create mode 100644 stable_diffusion/ldmx/models/diffusion/ddpm.py create mode 100644 stable_diffusion/ldmx/models/diffusion/ddpm_diffree.py create mode 100644 stable_diffusion/ldmx/models/diffusion/ddpm_edit.py create mode 100644 stable_diffusion/ldmx/models/diffusion/dpm_solver/__init__.py create mode 100644 stable_diffusion/ldmx/models/diffusion/dpm_solver/dpm_solver.py create mode 100644 stable_diffusion/ldmx/models/diffusion/dpm_solver/sampler.py create mode 100644 stable_diffusion/ldmx/models/diffusion/plms.py create mode 100644 stable_diffusion/ldmx/modules/attention.py create mode 100644 stable_diffusion/ldmx/modules/diffusionmodules/__init__.py create mode 100644 stable_diffusion/ldmx/modules/diffusionmodules/model.py create mode 100644 stable_diffusion/ldmx/modules/diffusionmodules/openaimodel.py create mode 100644 stable_diffusion/ldmx/modules/diffusionmodules/openaimodel_diffree.py create mode 100644 stable_diffusion/ldmx/modules/diffusionmodules/util.py create mode 100644 stable_diffusion/ldmx/modules/distributions/__init__.py create mode 100644 stable_diffusion/ldmx/modules/distributions/distributions.py create mode 100644 stable_diffusion/ldmx/modules/ema.py create mode 100644 stable_diffusion/ldmx/modules/encoders/__init__.py create mode 100644 stable_diffusion/ldmx/modules/encoders/modules.py create mode 100644 stable_diffusion/ldmx/modules/image_degradation/__init__.py create mode 100644 stable_diffusion/ldmx/modules/image_degradation/bsrgan.py create mode 100644 stable_diffusion/ldmx/modules/image_degradation/bsrgan_light.py create mode 100644 stable_diffusion/ldmx/modules/image_degradation/utils_image.py create mode 100644 stable_diffusion/ldmx/modules/losses/__init__.py create mode 100644 stable_diffusion/ldmx/modules/losses/contperceptual.py create mode 100644 stable_diffusion/ldmx/modules/losses/vqperceptual.py create mode 100644 stable_diffusion/ldmx/modules/x_transformer.py create mode 100644 stable_diffusion/ldmx/util.py create mode 100644 stable_diffusion/main.py create mode 100644 stable_diffusion/models/first_stage_models/kl-f16/config.yaml create mode 100644 stable_diffusion/models/first_stage_models/kl-f32/config.yaml create mode 100644 stable_diffusion/models/first_stage_models/kl-f4/config.yaml create mode 100644 stable_diffusion/models/first_stage_models/kl-f8/config.yaml create mode 100644 stable_diffusion/models/first_stage_models/vq-f16/config.yaml create mode 100644 stable_diffusion/models/first_stage_models/vq-f4-noattn/config.yaml create mode 100644 stable_diffusion/models/first_stage_models/vq-f4/config.yaml create mode 100644 stable_diffusion/models/first_stage_models/vq-f8-n256/config.yaml create mode 100644 stable_diffusion/models/first_stage_models/vq-f8/config.yaml create mode 100644 stable_diffusion/models/ldm/bsr_sr/config.yaml create mode 100644 stable_diffusion/models/ldm/celeba256/config.yaml create mode 100644 stable_diffusion/models/ldm/cin256/config.yaml create mode 100644 stable_diffusion/models/ldm/ffhq256/config.yaml create mode 100644 stable_diffusion/models/ldm/inpainting_big/config.yaml create mode 100644 stable_diffusion/models/ldm/layout2img-openimages256/config.yaml create mode 100644 stable_diffusion/models/ldm/lsun_beds256/config.yaml create mode 100644 stable_diffusion/models/ldm/lsun_churches256/config.yaml create mode 100644 stable_diffusion/models/ldm/semantic_synthesis256/config.yaml create mode 100644 stable_diffusion/models/ldm/semantic_synthesis512/config.yaml create mode 100644 stable_diffusion/models/ldm/text2img256/config.yaml create mode 100644 stable_diffusion/notebook_helpers.py create mode 100644 stable_diffusion/scripts/img2img.py create mode 100644 stable_diffusion/scripts/inpaint.py create mode 100644 stable_diffusion/scripts/knn2img.py create mode 100644 stable_diffusion/scripts/sample_diffusion.py create mode 100644 stable_diffusion/scripts/tests/test_watermark.py create mode 100644 stable_diffusion/scripts/train_searcher.py create mode 100644 stable_diffusion/scripts/txt2img.py create mode 100644 stable_diffusion/setup.py diff --git a/Diffree_node.py b/Diffree_node.py new file mode 100644 index 0000000..485d467 --- /dev/null +++ b/Diffree_node.py @@ -0,0 +1,463 @@ +# !/usr/bin/env python +# -*- coding: UTF-8 -*- + +import math +import random +import sys +import os +from tqdm.auto import trange +import einops +import k_diffusion as K +import numpy as np +import torch +import torch.nn as nn +from einops import rearrange +from omegaconf import OmegaConf +from PIL import Image, ImageOps, ImageFilter +from torch import autocast +import cv2 + +from .stable_diffusion.ldmx.util import instantiate_from_config +import folder_paths +from comfy.utils import common_upscale + +cur_path = os.path.dirname(os.path.abspath(__file__)) +MAX_SEED = np.iinfo(np.int32).max +device = ( + "cuda" + if torch.cuda.is_available() + else "mps" if torch.backends.mps.is_available() else "cpu" +) + +def get_instance_path(path): + instance_path = os.path.normpath(path) + if sys.platform == 'win32': + instance_path = instance_path.replace('\\', "/") + return instance_path + +def pil2tensor(pil_img): + tensor = torch.from_numpy(np.array(pil_img).astype(np.float32) / 255.0).unsqueeze(0) + return tensor + +def tensor2phi(tensor): + image_np = tensor.squeeze().mul(255).clamp(0, 255).byte().numpy() + pil_img = Image.fromarray(image_np, mode='RGB') + return pil_img + +def nomarl_upscale(img_tensor, width, height): + samples = img_tensor.movedim(-1, 1) + img = common_upscale(samples, width, height, "nearest-exact", "center") + samples = img.movedim(1, -1) + return samples + +def nomarl_upscale_to_pil(img_tensor, width, height): + samples = img_tensor.movedim(-1, 1) + img = common_upscale(samples, width, height, "nearest-exact", "center") + samples = img.movedim(1, -1) + img_pil = tensor2phi(samples) + return img_pil + +def narry_list_to_pill_ist(narry_list_in): + for i in range(len(narry_list_in)): + value = narry_list_in[i] + modified_value = pil2tensor(value) + narry_list_in[i] = modified_value + return narry_list_in + +def narry_list(list_in): + for i in range(len(list_in)): + value = list_in[i] + modified_value = pil2tensor(value) + list_in[i] = modified_value + return list_in + +def phi_list(list_in): + for i in range(len(list_in)): + value = list_in[i] + list_in[i] = value + return list_in + +def get_local_path(file_path, model_name,model_dir): + path = os.path.join(file_path, "models", model_name, model_dir) + model_path = os.path.normpath(path) + if sys.platform.startswith('win32'): + model_path = model_path.replace('\\', "/") + return model_path + +def get_image_path_list(folder_name): + image_basename_list = os.listdir(folder_name) + image_path_list = sorted( + [os.path.join(folder_name, basename) for basename in image_basename_list] + ) + return image_path_list + +class CFGDenoiser(nn.Module): + def __init__(self, model): + super().__init__() + self.inner_model = model + + def forward(self, z_0, z_1, sigma, cond, uncond, text_cfg_scale, image_cfg_scale): + cfg_z_0 = einops.repeat(z_0, "1 ... -> n ...", n=3) + cfg_z_1 = einops.repeat(z_1, "1 ... -> n ...", n=3) + cfg_sigma = einops.repeat(sigma, "1 ... -> n ...", n=3) + cfg_cond = { + "c_crossattn": [torch.cat([cond["c_crossattn"][0], uncond["c_crossattn"][0], uncond["c_crossattn"][0]])], + "c_concat": [torch.cat([cond["c_concat"][0], cond["c_concat"][0], uncond["c_concat"][0]])], + } + output_0, output_1 = self.inner_model(cfg_z_0, cfg_z_1, cfg_sigma, cond=cfg_cond) + out_cond_0, out_img_cond_0, out_uncond_0 = output_0.chunk(3) + out_cond_1, _, _ = output_1.chunk(3) + return out_uncond_0 + text_cfg_scale * (out_cond_0 - out_img_cond_0) + image_cfg_scale * (out_img_cond_0 - out_uncond_0), \ + out_cond_1 + +def load_model_from_config(config, ckpt, vae_ckpt=None, verbose=False): + print(f"Loading model from {ckpt}") + pl_sd = torch.load(ckpt, map_location="cpu") + if "global_step" in pl_sd: + print(f"Global Step: {pl_sd['global_step']}") + sd = pl_sd["state_dict"] + if vae_ckpt is not None: + print(f"Loading VAE from {vae_ckpt}") + vae_sd = torch.load(vae_ckpt, map_location="cpu")["state_dict"] + sd = { + k: vae_sd[k[len("first_stage_model.") :]] if k.startswith("first_stage_model.") else v + for k, v in sd.items() + } + model = instantiate_from_config(config.model) + m, u = model.load_state_dict(sd, strict=False) + if len(m) > 0 and verbose: + print("missing keys:") + print(m) + if len(u) > 0 and verbose: + print("unexpected keys:") + print(u) + return model + +def append_dims(x, target_dims): + """Appends dimensions to the end of a tensor until it has target_dims dimensions.""" + dims_to_append = target_dims - x.ndim + if dims_to_append < 0: + raise ValueError(f'input has {x.ndim} dims but target_dims is {target_dims}, which is less') + return x[(...,) + (None,) * dims_to_append] + + +class CompVisDenoiser(K.external.CompVisDenoiser): + def __init__(self, model, quantize=False, device='cpu'): + super().__init__(model, quantize, device) + + def get_eps(self, *args, **kwargs): + return self.inner_model.apply_model(*args, **kwargs) + + def forward(self, input_0, input_1, sigma, **kwargs): + c_out, c_in = [append_dims(x, input_0.ndim) for x in self.get_scalings(sigma)] + # eps_0, eps_1 = self.get_eps(input_0 * c_in, input_1 * c_in, self.sigma_to_t(sigma), **kwargs) + eps_0, eps_1 = self.get_eps(input_0 * c_in, self.sigma_to_t(sigma).cuda(), **kwargs) + + return input_0 + eps_0 * c_out, eps_1 + + +def to_d(x, sigma, denoised): + """Converts a denoiser output to a Karras ODE derivative.""" + return (x - denoised) / append_dims(sigma, x.ndim) + + +def default_noise_sampler(x): + return lambda sigma, sigma_next: torch.randn_like(x) + + +def get_ancestral_step(sigma_from, sigma_to, eta=1.): + """Calculates the noise level (sigma_down) to step down to and the amount + of noise to add (sigma_up) when doing an ancestral sampling step.""" + if not eta: + return sigma_to, 0. + sigma_up = min(sigma_to, eta * (sigma_to ** 2 * (sigma_from ** 2 - sigma_to ** 2) / sigma_from ** 2) ** 0.5) + sigma_down = (sigma_to ** 2 - sigma_up ** 2) ** 0.5 + return sigma_down, sigma_up + + +def decode_mask(mask, height=256, width=256): + mask = nn.functional.interpolate(mask, size=(height, width), mode="bilinear", align_corners=False) + mask = torch.where(mask > 0, 1, -1) # Thresholding step + mask = torch.clamp((mask + 1.0) / 2.0, min=0.0, max=1.0) + mask = 255.0 * rearrange(mask, "1 c h w -> h w c") + mask = torch.cat([mask, mask, mask], dim=-1) + mask = mask.type(torch.uint8).cpu().numpy() + return mask + + +def sample_euler_ancestral(model, x_0, x_1, sigmas, height, width, extra_args=None, disable=None, eta=1., s_noise=1., + noise_sampler=None): + """Ancestral sampling with Euler method steps.""" + extra_args = {} if extra_args is None else extra_args + noise_sampler = default_noise_sampler(x_0) if noise_sampler is None else noise_sampler + s_in = x_0.new_ones([x_0.shape[0]]) + + mask_list = [] + image_list = [] + for i in trange(len(sigmas) - 1, disable=disable): + denoised_0, denoised_1 = model(x_0, x_1, sigmas[i] * s_in, **extra_args) + image_list.append(denoised_0) + + sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta) + d_0 = to_d(x_0, sigmas[i], denoised_0) + + # Euler method + dt = sigma_down - sigmas[i] + x_0 = x_0 + d_0 * dt + + if sigmas[i + 1] > 0: + x_0 = x_0 + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up + + x_1 = denoised_1 + mask_list.append(decode_mask(x_1, height, width)) + + image_list = torch.cat(image_list, dim=0) + + return x_0, x_1, image_list, mask_list + + +class Diffree_Model_Loader: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "ckpt_name": (["none"] + folder_paths.get_filename_list("checkpoints"),), + "vae": (["none"] + folder_paths.get_filename_list("vae"),), + } + } + + RETURN_TYPES = ("MODEL", "MODEL","MODEL",) + RETURN_NAMES = ("model", "model_wrap","model_wrap_cfg",) + FUNCTION = "main_loader" + CATEGORY = "Diffree" + + def main_loader(self, ckpt_name, vae,): + if vae != "none": + vae_ckpt = folder_paths.get_full_path("vae", vae) + else: + vae_ckpt = None + ckpt = folder_paths.get_full_path("checkpoints", ckpt_name) + config_path = os.path.join(cur_path, "config", "generate.yaml") + config = OmegaConf.load(config_path) + model = load_model_from_config(config, ckpt, vae_ckpt) + model.eval().cuda() + model_wrap = CompVisDenoiser(model) + model_wrap_cfg = CFGDenoiser(model_wrap) + return (model, model_wrap,model_wrap_cfg) + + +def generate( + model, + model_wrap, + model_wrap_cfg, + image: Image.Image, + instruction: str, + width: int, + height: int, + steps: int, + randomize_seed: bool, + seed: int, + randomize_cfg: bool, + text_cfg_scale: float, + image_cfg_scale: float, + rgb_mode: str, +): + + null_token = model.get_learned_conditioning([""]) + seed = random.randint(0, 100000) if randomize_seed else seed + text_cfg_scale = round(random.uniform(6.0, 9.0), ndigits=2) if randomize_cfg else text_cfg_scale + image_cfg_scale = round(random.uniform(1.2, 1.8), ndigits=2) if randomize_cfg else image_cfg_scale + + #width, height = input_image.size #图片裁切,已用其他功能替换 + # factor = resolution / max(width, height) + # factor = math.ceil(min(width, height) * factor / 64) * 64 / min(width, height) + # width = int((width * factor) // 64) * 64 + # height = int((height * factor) // 64) * 64 + #input_image = ImageOps.fit(image, (width, height), method=Image.Resampling.LANCZOS) + input_image_copy = image + + if instruction == "": + instruction="reflective sunglasses" # prompt为空时,返回默认prompt + + model.cuda() + with torch.no_grad(), autocast("cuda"), model.ema_scope(): + cond = {} + cond["c_crossattn"] = [model.get_learned_conditioning([instruction]).to(model.device)] + input_image = 2 * torch.tensor(np.array(image)).float() / 255 - 1 + input_image = rearrange(input_image, "h w c -> 1 c h w").to(model.device) + cond["c_concat"] = [model.encode_first_stage(input_image).mode().to(model.device)] + + uncond = {} + uncond["c_crossattn"] = [null_token.to(model.device)] + uncond["c_concat"] = [torch.zeros_like(cond["c_concat"][0])] + + sigmas = model_wrap.get_sigmas(steps).to(model.device) + + extra_args = { + "cond": cond, + "uncond": uncond, + "text_cfg_scale": text_cfg_scale, + "image_cfg_scale": image_cfg_scale, + } + torch.manual_seed(seed) + z_0 = torch.randn_like(cond["c_concat"][0]).to(model.device) * sigmas[0] + z_1 = torch.randn_like(cond["c_concat"][0]).to(model.device) * sigmas[0] + + z_0, z_1, image_list, mask_list = sample_euler_ancestral(model_wrap_cfg, z_0, z_1, sigmas, height, width, + extra_args=extra_args) + + x_0 = model.decode_first_stage(z_0) + + if model.first_stage_downsample: + x_1 = nn.functional.interpolate(z_1, size=(height, width), mode="bilinear", align_corners=False) + x_1 = torch.where(x_1 > 0, 1, -1) # Thresholding step + else: + x_1 = model.decode_first_stage(z_1) + + x_0 = torch.clamp((x_0 + 1.0) / 2.0, min=0.0, max=1.0) + x_1 = torch.clamp((x_1 + 1.0) / 2.0, min=0.0, max=1.0) + x_0 = 255.0 * rearrange(x_0, "1 c h w -> h w c") + x_1 = 255.0 * rearrange(x_1, "1 c h w -> h w c") + x_1 = torch.cat([x_1, x_1, x_1], dim=-1) + edited_image = Image.fromarray(x_0.type(torch.uint8).cpu().numpy()) + edited_mask = Image.fromarray(x_1.type(torch.uint8).cpu().numpy()) + + # image_video_path = None #no need + # if not weather_close_video: + # image_video = [] + # + # for i in range(0, len(image_list), decode_image_batch): + # if i + decode_image_batch < len(image_list): + # tmp_image_list = image_list[i:i + decode_image_batch] + # else: + # tmp_image_list = image_list[i:] + # tmp_image_list = model.decode_first_stage(tmp_image_list) + # tmp_image_list = torch.clamp((tmp_image_list + 1.0) / 2.0, min=0.0, max=1.0) + # tmp_image_list = 255.0 * rearrange(tmp_image_list, "b c h w -> b h w c") + # tmp_image_list = tmp_image_list.type(torch.uint8).cpu().numpy() + # # image list to image + # for image in tmp_image_list: + # image_video.append(image) + + # image_file_prefix = ''.join(random.choice("0123456789") for _ in range(6)) #图像生成过程的渐变视频,做demo可以,实际好像用处不大,先取消 + # image_video_path = os.path.join(folder_paths.input_directory, f"image_{image_file_prefix}_temp.mp4") + # #image_video_path = "image.mp4" + # fps = 30 + # with imageio.get_writer(image_video_path, fps=fps) as video: + # for image in image_video: + # video.append_data(image) + + # 对edited_mask做膨胀 + edited_mask_copy = edited_mask.copy() + kernel = np.ones((3, 3), np.uint8) + edited_mask = cv2.dilate(np.array(edited_mask), kernel, iterations=3) + edited_mask = Image.fromarray(edited_mask) + + m_img = edited_mask.filter(ImageFilter.GaussianBlur(radius=3)) + m_img = np.asarray(m_img).astype('float') / 255.0 + img_np = np.asarray(input_image_copy).astype('float') / 255.0 + ours_np = np.asarray(edited_image).astype('float') / 255.0 + #print(ours_np) + mix_image_np = m_img * ours_np + (1 - m_img) * img_np + mix_image = Image.fromarray((mix_image_np * 255).astype(np.uint8)).convert('RGB') + + rgb_choice = np.array(mix_image).astype('float') * 1 + if rgb_mode=="red": + rgb_choice[:, :, 0] = 180.0 + rgb_choice[:, :, 2] = 0 + rgb_choice[:, :, 1] = 0 + elif rgb_mode=="blue": + rgb_choice[:, :, 0] = 0 + rgb_choice[:, :, 2] = 180.0 + rgb_choice[:, :, 1] = 0 + else:# green + rgb_choice[:, :, 0] = 0 + rgb_choice[:, :, 2] = 0 + rgb_choice[:, :, 1] = 180.0 + + + mix_result_with_rgb_mask = np.array(mix_image) + mix_result_with_rgb_mask = Image.fromarray( + (mix_result_with_rgb_mask.astype('float') * (1 - m_img.astype('float') / 2.0) + + m_img.astype('float') / 2.0 * rgb_choice).astype('uint8')) + + mask_img=Image.fromarray((m_img * 255).astype(np.uint8)).convert('RGB') + + #print(mix_image,mask_img,mix_result_with_rgb_mask) + + # #mask_video_path = "mask.mp4" # no need + # fps = 30 + # with imageio.get_writer(mask_video_path, fps=fps) as video: + # for image in mask_list: + # video.append_data(image) + + # return [int(seed), text_cfg_scale, image_cfg_scale, edited_image, mix_image, edited_mask_copy, mask_video_path, + # image_video_path, input_image_copy, mix_result_with_red_mask] + + return mix_image, mask_img,mix_result_with_rgb_mask + + +class Diffree_Sampler: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "image": ("IMAGE",), + "model": ("MODEL",), + "model_wrap": ("MODEL",), + "model_wrap_cfg": ("MODEL",), + "prompt": ("STRING", {"multiline": True, "default": "reflective sunglasses"}), + "randomize_seed":("BOOLEAN", {"default": False},), + "seed": ("INT", {"default": 100, "min": 0, "max": MAX_SEED}), + "steps": ("INT", {"default": 20, "min": 1, "max": 100}), + "randomize_cfg": ("BOOLEAN", {"default": False},), + "text_cfg": ("FLOAT", {"default": 7.5, "min": 0.1, "max": 10.0, "step": 0.1, "round": 0.01}), + "img_cfg": ("FLOAT", {"default": 1.5, "min": 0.1, "max": 10.0, "step": 0.1, "round": 0.01}), + "width": ("INT", {"default": 512, "min": 256, "max": 2048, "step": 64, "display": "number"}), + "height": ("INT", {"default": 512, "min": 256, "max": 2048, "step": 64, "display": "number"}), + "rgb_mode":(["red","green","blue",],), + "batch_size": ("INT", {"default": 1, "min": 1, "max": 100, "step": 1, }),} + } + + RETURN_TYPES = ("IMAGE","IMAGE","IMAGE",) + RETURN_NAMES = ("image","mask","rgb_mask",) + FUNCTION = "df_sampler" + CATEGORY = "Diffree" + + def df_sampler(self, image, model, model_wrap,model_wrap_cfg, prompt, randomize_seed,seed, steps,randomize_cfg, text_cfg,img_cfg,width,height,rgb_mode,batch_size,): + image=nomarl_upscale_to_pil(image,width,height) + mix_image_list,mask_img_list,mix_result_with_rgb_mask_list=[],[],[] + for i in range(batch_size): + mix_image,mask_img,mix_result_with_rgb_mask=generate(model,model_wrap,model_wrap_cfg,image,prompt,width,height,steps,randomize_seed,seed,randomize_cfg,text_cfg,img_cfg,rgb_mode) + mix_image_list.append(mix_image) + mask_img_list.append(mask_img) + mix_result_with_rgb_mask_list.append(mix_result_with_rgb_mask) + + mix_image=narry_list(mix_image_list) + mask_img = narry_list(mask_img_list) + mix_result_with_rgb_mask = narry_list(mix_result_with_rgb_mask_list) + + image=torch.from_numpy(np.fromiter(mix_image, np.dtype((np.float32, (height, width, 3))))) + mask = torch.from_numpy(np.fromiter(mask_img, np.dtype((np.float32, (height, width, 3))))) + rgb_mask=torch.from_numpy(np.fromiter(mix_result_with_rgb_mask, np.dtype((np.float32, (height, width, 3))))) + + return (image,mask,rgb_mask) + + +NODE_CLASS_MAPPINGS = { + "Diffree_Model_Loader": Diffree_Model_Loader, + "Diffree_Sampler": Diffree_Sampler, + +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "Diffree_Model_Loader": "Diffree_Model_Loader", + "Diffree_Sampler": "Diffree_Sampler", + +} diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..601da81 --- /dev/null +++ b/__init__.py @@ -0,0 +1,4 @@ + +from .Diffree_node import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS + +__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] diff --git a/app.py b/app.py new file mode 100644 index 0000000..0046f55 --- /dev/null +++ b/app.py @@ -0,0 +1,401 @@ +from __future__ import annotations + +import math +import random +import sys +from argparse import ArgumentParser + +from tqdm.auto import trange +import einops +import gradio as gr +import k_diffusion as K +import numpy as np +import torch +import torch.nn as nn +from einops import rearrange +from omegaconf import OmegaConf +from PIL import Image, ImageOps, ImageFilter +from torch import autocast +import cv2 +import imageio + +sys.path.append("./stable_diffusion") + +from stable_diffusion.ldm.util import instantiate_from_config + +class CFGDenoiser(nn.Module): + def __init__(self, model): + super().__init__() + self.inner_model = model + + def forward(self, z_0, z_1, sigma, cond, uncond, text_cfg_scale, image_cfg_scale): + cfg_z_0 = einops.repeat(z_0, "1 ... -> n ...", n=3) + cfg_z_1 = einops.repeat(z_1, "1 ... -> n ...", n=3) + cfg_sigma = einops.repeat(sigma, "1 ... -> n ...", n=3) + cfg_cond = { + "c_crossattn": [torch.cat([cond["c_crossattn"][0], uncond["c_crossattn"][0], uncond["c_crossattn"][0]])], + "c_concat": [torch.cat([cond["c_concat"][0], cond["c_concat"][0], uncond["c_concat"][0]])], + } + output_0, output_1 = self.inner_model(cfg_z_0, cfg_z_1, cfg_sigma, cond=cfg_cond) + out_cond_0, out_img_cond_0, out_uncond_0 = output_0.chunk(3) + out_cond_1, _, _ = output_1.chunk(3) + return out_uncond_0 + text_cfg_scale * (out_cond_0 - out_img_cond_0) + image_cfg_scale * (out_img_cond_0 - out_uncond_0), \ + out_cond_1 + +def load_model_from_config(config, ckpt, vae_ckpt=None, verbose=False): + print(f"Loading model from {ckpt}") + pl_sd = torch.load(ckpt, map_location="cpu") + if "global_step" in pl_sd: + print(f"Global Step: {pl_sd['global_step']}") + sd = pl_sd["state_dict"] + if vae_ckpt is not None: + print(f"Loading VAE from {vae_ckpt}") + vae_sd = torch.load(vae_ckpt, map_location="cpu")["state_dict"] + sd = { + k: vae_sd[k[len("first_stage_model.") :]] if k.startswith("first_stage_model.") else v + for k, v in sd.items() + } + model = instantiate_from_config(config.model) + m, u = model.load_state_dict(sd, strict=True) + if len(m) > 0 and verbose: + print("missing keys:") + print(m) + if len(u) > 0 and verbose: + print("unexpected keys:") + print(u) + return model + +def append_dims(x, target_dims): + """Appends dimensions to the end of a tensor until it has target_dims dimensions.""" + dims_to_append = target_dims - x.ndim + if dims_to_append < 0: + raise ValueError(f'input has {x.ndim} dims but target_dims is {target_dims}, which is less') + return x[(...,) + (None,) * dims_to_append] + +class CompVisDenoiser(K.external.CompVisDenoiser): + def __init__(self, model, quantize=False, device='cpu'): + super().__init__(model, quantize, device) + + def get_eps(self, *args, **kwargs): + return self.inner_model.apply_model(*args, **kwargs) + + def forward(self, input_0, input_1, sigma, **kwargs): + c_out, c_in = [append_dims(x, input_0.ndim) for x in self.get_scalings(sigma)] + # eps_0, eps_1 = self.get_eps(input_0 * c_in, input_1 * c_in, self.sigma_to_t(sigma), **kwargs) + eps_0, eps_1 = self.get_eps(input_0 * c_in, self.sigma_to_t(sigma).cuda(), **kwargs) + + return input_0 + eps_0 * c_out, eps_1 + +def to_d(x, sigma, denoised): + """Converts a denoiser output to a Karras ODE derivative.""" + return (x - denoised) / append_dims(sigma, x.ndim) + +def default_noise_sampler(x): + return lambda sigma, sigma_next: torch.randn_like(x) + +def get_ancestral_step(sigma_from, sigma_to, eta=1.): + """Calculates the noise level (sigma_down) to step down to and the amount + of noise to add (sigma_up) when doing an ancestral sampling step.""" + if not eta: + return sigma_to, 0. + sigma_up = min(sigma_to, eta * (sigma_to ** 2 * (sigma_from ** 2 - sigma_to ** 2) / sigma_from ** 2) ** 0.5) + sigma_down = (sigma_to ** 2 - sigma_up ** 2) ** 0.5 + return sigma_down, sigma_up + +def decode_mask(mask, height = 256, width = 256): + mask = nn.functional.interpolate(mask, size=(height, width), mode="bilinear", align_corners=False) + mask = torch.where(mask > 0, 1, -1) # Thresholding step + mask = torch.clamp((mask + 1.0) / 2.0, min=0.0, max=1.0) + mask = 255.0 * rearrange(mask, "1 c h w -> h w c") + mask = torch.cat([mask, mask, mask], dim=-1) + mask = mask.type(torch.uint8).cpu().numpy() + return mask + +def sample_euler_ancestral(model, x_0, x_1, sigmas, height, width, extra_args=None, disable=None, eta=1., s_noise=1., noise_sampler=None): + """Ancestral sampling with Euler method steps.""" + extra_args = {} if extra_args is None else extra_args + noise_sampler = default_noise_sampler(x_0) if noise_sampler is None else noise_sampler + s_in = x_0.new_ones([x_0.shape[0]]) + + mask_list = [] + image_list = [] + for i in trange(len(sigmas) - 1, disable=disable): + denoised_0, denoised_1 = model(x_0, x_1, sigmas[i] * s_in, **extra_args) + image_list.append(denoised_0) + + sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta) + d_0 = to_d(x_0, sigmas[i], denoised_0) + + # Euler method + dt = sigma_down - sigmas[i] + x_0 = x_0 + d_0 * dt + + if sigmas[i + 1] > 0: + x_0 = x_0 + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up + + x_1 = denoised_1 + mask_list.append(decode_mask(x_1, height, width)) + + image_list = torch.cat(image_list, dim=0) + + return x_0, x_1, image_list, mask_list + +parser = ArgumentParser() +parser.add_argument("--resolution", default=512, type=int) +parser.add_argument("--config", default="config/generate.yaml", type=str) +parser.add_argument("--ckpt", default="checkpoints/diffree-step=000010999.ckpt", type=str) +parser.add_argument("--vae-ckpt", default=None, type=str) +args = parser.parse_args() + +config = OmegaConf.load(args.config) +model = load_model_from_config(config, args.ckpt, args.vae_ckpt) +model.eval().cuda() +model_wrap = CompVisDenoiser(model) +model_wrap_cfg = CFGDenoiser(model_wrap) +null_token = model.get_learned_conditioning([""]) + +def generate( + input_image: Image.Image, + instruction: str, + steps: int, + randomize_seed: bool, + seed: int, + randomize_cfg: bool, + text_cfg_scale: float, + image_cfg_scale: float, + weather_close_video: bool, + decode_image_batch: int +): + seed = random.randint(0, 100000) if randomize_seed else seed + text_cfg_scale = round(random.uniform(6.0, 9.0), ndigits=2) if randomize_cfg else text_cfg_scale + image_cfg_scale = round(random.uniform(1.2, 1.8), ndigits=2) if randomize_cfg else image_cfg_scale + + width, height = input_image.size + factor = args.resolution / max(width, height) + factor = math.ceil(min(width, height) * factor / 64) * 64 / min(width, height) + width = int((width * factor) // 64) * 64 + height = int((height * factor) // 64) * 64 + input_image = ImageOps.fit(input_image, (width, height), method=Image.Resampling.LANCZOS) + input_image_copy = input_image.convert("RGB") + + if instruction == "": + return [input_image, seed] + + model.cuda() + with torch.no_grad(), autocast("cuda"), model.ema_scope(): + cond = {} + cond["c_crossattn"] = [model.get_learned_conditioning([instruction]).to(model.device)] + input_image = 2 * torch.tensor(np.array(input_image)).float() / 255 - 1 + input_image = rearrange(input_image, "h w c -> 1 c h w").to(model.device) + cond["c_concat"] = [model.encode_first_stage(input_image).mode().to(model.device)] + + uncond = {} + uncond["c_crossattn"] = [null_token.to(model.device)] + uncond["c_concat"] = [torch.zeros_like(cond["c_concat"][0])] + + + sigmas = model_wrap.get_sigmas(steps).to(model.device) + + extra_args = { + "cond": cond, + "uncond": uncond, + "text_cfg_scale": text_cfg_scale, + "image_cfg_scale": image_cfg_scale, + } + torch.manual_seed(seed) + z_0 = torch.randn_like(cond["c_concat"][0]).to(model.device) * sigmas[0] + z_1 = torch.randn_like(cond["c_concat"][0]).to(model.device) * sigmas[0] + + z_0, z_1, image_list, mask_list = sample_euler_ancestral(model_wrap_cfg, z_0, z_1, sigmas, height, width, extra_args=extra_args) + + x_0 = model.decode_first_stage(z_0) + + if model.first_stage_downsample: + x_1 = nn.functional.interpolate(z_1, size=(height, width), mode="bilinear", align_corners=False) + x_1 = torch.where(x_1 > 0, 1, -1) # Thresholding step + else: + x_1 = model.decode_first_stage(z_1) + + x_0 = torch.clamp((x_0 + 1.0) / 2.0, min=0.0, max=1.0) + x_1 = torch.clamp((x_1 + 1.0) / 2.0, min=0.0, max=1.0) + x_0 = 255.0 * rearrange(x_0, "1 c h w -> h w c") + x_1 = 255.0 * rearrange(x_1, "1 c h w -> h w c") + x_1 = torch.cat([x_1, x_1, x_1], dim=-1) + edited_image = Image.fromarray(x_0.type(torch.uint8).cpu().numpy()) + edited_mask = Image.fromarray(x_1.type(torch.uint8).cpu().numpy()) + + image_video_path = None + if not weather_close_video: + image_video = [] + + for i in range(0, len(image_list), decode_image_batch): + if i + decode_image_batch < len(image_list): + tmp_image_list = image_list[i:i+decode_image_batch] + else: + tmp_image_list = image_list[i:] + tmp_image_list = model.decode_first_stage(tmp_image_list) + tmp_image_list = torch.clamp((tmp_image_list + 1.0) / 2.0, min=0.0, max=1.0) + tmp_image_list = 255.0 * rearrange(tmp_image_list, "b c h w -> b h w c") + tmp_image_list = tmp_image_list.type(torch.uint8).cpu().numpy() + # image list to image + for image in tmp_image_list: + image_video.append(image) + + image_video_path = "image.mp4" + fps = 30 + with imageio.get_writer(image_video_path, fps=fps) as video: + for image in image_video: + video.append_data(image) + + # 对edited_mask做膨胀 + edited_mask_copy = edited_mask.copy() + kernel = np.ones((3, 3), np.uint8) + edited_mask = cv2.dilate(np.array(edited_mask), kernel, iterations=3) + edited_mask = Image.fromarray(edited_mask) + + + m_img = edited_mask.filter(ImageFilter.GaussianBlur(radius=3)) + m_img = np.asarray(m_img).astype('float') / 255.0 + img_np = np.asarray(input_image_copy).astype('float') / 255.0 + ours_np = np.asarray(edited_image).astype('float') / 255.0 + + mix_image_np = m_img * ours_np + (1 - m_img) * img_np + mix_image = Image.fromarray((mix_image_np * 255).astype(np.uint8)).convert('RGB') + + + red = np.array(mix_image).astype('float') * 1 + red[:, :, 0] = 180.0 + red[:, :, 2] = 0 + red[:, :, 1] = 0 + mix_result_with_red_mask = np.array(mix_image) + mix_result_with_red_mask = Image.fromarray( + (mix_result_with_red_mask.astype('float') * (1 - m_img.astype('float') / 2.0) + + m_img.astype('float') / 2.0 * red).astype('uint8')) + + + + mask_video_path = "mask.mp4" + fps = 30 + with imageio.get_writer(mask_video_path, fps=fps) as video: + for image in mask_list: + video.append_data(image) + + return [int(seed), text_cfg_scale, image_cfg_scale, edited_image, mix_image, edited_mask_copy, mask_video_path, image_video_path, input_image_copy, mix_result_with_red_mask] + +def reset(): + return [100, "Randomize Seed", 1372, "Fix CFG", 7.5, 1.5, None, None, None, None, None, None, None, "Close Image Video", 10] + +def get_example(): + return [ + ["example_images/dufu.png", "black and white suit", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/girl.jpeg", "reflective sunglasses", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/road_sign.png", "stop sign", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/dufu.png", "blue medical mask", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/people_standing.png", "dark green pleated skirt", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/girl.jpeg", "shiny golden crown", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/dufu.png", "sunglasses", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/girl.jpeg", "diamond necklace", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/iron_man.jpg", "sunglasses", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/girl.jpeg", "the queen's crown", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ["example_images/girl.jpeg", "gorgeous yellow gown", 100, "Fix Seed", 1372, "Fix CFG", 7.5, 1.5], + ] + +with gr.Blocks(css="footer {visibility: hidden}") as demo: + with gr.Row(): + gr.Markdown( + "
Bvd
z*rM@=##W7O8rwB?XzbM3rLkLMkH%h&eH!~U4rm >H6eGn<<*qeQb?(s@ dIQ0pA9E7tlDMNkG$p<^e4NS_ZTVXdUolK%0QJ0qp|X2XqMdHK1ca=YTE&T?4uW
zbPwne&@-S{K<|J)0eu7d1@sRX5HK)cP{81TApt`Jh6M}{7!fcs;E#Y&0iy%P1dI(B
z7cf3xLcqj;Ndc1srUXn4m=-WSU`D{qfLQ^v1Lg$G4VV`&KVU(?!hl5qe+DcLSQ7A8
zz|w$a0m}nc1gs2L6|g#BO~BfKbph)GHUw-8*c7liU`xQ(fNcTW19k-L4A>R0JK*nt
zJpp?I_66(@I1q3!;84KffFl7%1C9k85BMkG-+&VVCj(9eoDMh>a5msv!1;g+0T%-<
z1zZle67XNZ)qraO*8^?@+zhxCa68~mz} 3~q=ZOGky0Y1
zMaqbj6)7iDUZjFZMUhG(l|`zER28WvQeC8mNG*}tBF~D{5qVCeu1GzR`XUWPo)>vR
zMvSofLIb)Jsu6MS~O#Q}6s=
zJt>-`Xquu~ismU=q-dF
7P^ILVOiJ~j)iOC
zTZ9&oMPiXz
{1X
zQp%>3ODUi7Y|3*f&!_*FdxaDsMNE-W
@wMH^0&zzlf5SUO!k``Fga*)$mFoe5tE}P$4ri!{A2R3
z$qAE_CZ|kJo18H@YjV!yyvYTVizb&$E}L92`OoC4$u*PfCO1rOn%pwEZF0xtuE{-<
z`z8-e9-2Hd$zbu6MMjHE7MU%wSY)-xW|7?@heb|{r!8_>2HBeGXypU44`gCd7S4vQQSIVy5Y