InvokeAI 2.2.4.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- backend/__init__.py +0 -0
- backend/invoke_ai_web_server.py +1724 -0
- backend/modules/__init__.py +0 -0
- backend/modules/create_cmd_parser.py +55 -0
- backend/modules/get_canvas_generation_mode.py +117 -0
- backend/modules/parameters.py +71 -0
- backend/modules/parse_seed_weights.py +47 -0
- configs/INITIAL_MODELS.yaml +80 -0
- configs/models.yaml.example +29 -0
- configs/sd-concepts.txt +803 -0
- configs/stable-diffusion/v1-finetune.yaml +110 -0
- configs/stable-diffusion/v1-finetune_style.yaml +103 -0
- configs/stable-diffusion/v1-inference.yaml +79 -0
- configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
- configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
- docs/assets/invoke-web-server-1.png +0 -0
- docs/assets/invoke_ai_banner.png +0 -0
- invokeai-2.2.4.5.data/data/assets/caution.png +0 -0
- invokeai-2.2.4.5.data/data/configs/INITIAL_MODELS.yaml +80 -0
- invokeai-2.2.4.5.data/data/configs/models.yaml.example +29 -0
- invokeai-2.2.4.5.data/data/configs/sd-concepts.txt +803 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune.yaml +110 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune_style.yaml +103 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inference.yaml +79 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter-Bold.790c108b.ttf +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter.b9a8e5e2.ttf +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/favicon.0d253ced.ico +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/index-legacy-b741077f.js +48 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/index.0dadf5d0.css +1 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/index.21ff81eb.js +625 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/logo.13003d72.png +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills-legacy-dde3a68a.js +4 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills.1ff60148.js +1 -0
- invokeai-2.2.4.5.data/data/frontend/dist/index.html +23 -0
- invokeai-2.2.4.5.data/data/scripts/configure_invokeai.py +797 -0
- invokeai-2.2.4.5.data/data/scripts/create_root.py +43 -0
- invokeai-2.2.4.5.data/data/scripts/dream.py +10 -0
- invokeai-2.2.4.5.data/data/scripts/images2prompt.py +30 -0
- invokeai-2.2.4.5.data/data/scripts/invoke.py +5 -0
- invokeai-2.2.4.5.data/data/scripts/legacy_api.py +681 -0
- invokeai-2.2.4.5.data/data/scripts/load_models.py +12 -0
- invokeai-2.2.4.5.data/data/scripts/merge_embeddings.py +124 -0
- invokeai-2.2.4.5.data/data/scripts/preload_models.py +12 -0
- invokeai-2.2.4.5.data/data/scripts/sd-metadata.py +22 -0
- invokeai-2.2.4.5.dist-info/LICENSE +21 -0
- invokeai-2.2.4.5.dist-info/LICENSE-ModelWeights.txt +294 -0
- invokeai-2.2.4.5.dist-info/METADATA +288 -0
- invokeai-2.2.4.5.dist-info/RECORD +169 -0
- invokeai-2.2.4.5.dist-info/WHEEL +5 -0
- invokeai-2.2.4.5.dist-info/entry_points.txt +4 -0
- invokeai-2.2.4.5.dist-info/top_level.txt +6 -0
- invokeai-2.2.4.5.dist-info/zip-safe +1 -0
- ldm/__init__.py +0 -0
- ldm/data/__init__.py +0 -0
- ldm/data/base.py +31 -0
- ldm/data/imagenet.py +466 -0
- ldm/data/lsun.py +126 -0
- ldm/data/personalized.py +202 -0
- ldm/data/personalized_style.py +169 -0
- ldm/generate.py +1159 -0
- ldm/invoke/CLI.py +960 -0
- ldm/invoke/__init__.py +3 -0
- ldm/invoke/args.py +1257 -0
- ldm/invoke/concepts_lib.py +169 -0
- ldm/invoke/conditioning.py +289 -0
- ldm/invoke/devices.py +27 -0
- ldm/invoke/generator/__init__.py +4 -0
- ldm/invoke/generator/base.py +335 -0
- ldm/invoke/generator/embiggen.py +501 -0
- ldm/invoke/generator/img2img.py +97 -0
- ldm/invoke/generator/inpaint.py +358 -0
- ldm/invoke/generator/omnibus.py +175 -0
- ldm/invoke/generator/txt2img.py +88 -0
- ldm/invoke/generator/txt2img2img.py +182 -0
- ldm/invoke/globals.py +31 -0
- ldm/invoke/image_util.py +70 -0
- ldm/invoke/log.py +66 -0
- ldm/invoke/model_cache.py +449 -0
- ldm/invoke/patchmatch.py +44 -0
- ldm/invoke/pngwriter.py +113 -0
- ldm/invoke/prompt_parser.py +655 -0
- ldm/invoke/readline.py +442 -0
- ldm/invoke/restoration/__init__.py +4 -0
- ldm/invoke/restoration/base.py +38 -0
- ldm/invoke/restoration/codeformer.py +103 -0
- ldm/invoke/restoration/codeformer_arch.py +276 -0
- ldm/invoke/restoration/gfpgan.py +84 -0
- ldm/invoke/restoration/outcrop.py +108 -0
- ldm/invoke/restoration/outpaint.py +92 -0
- ldm/invoke/restoration/realesrgan.py +90 -0
- ldm/invoke/restoration/vqgan_arch.py +435 -0
- ldm/invoke/seamless.py +30 -0
- ldm/invoke/server.py +282 -0
- ldm/invoke/server_legacy.py +246 -0
- ldm/invoke/txt2mask.py +136 -0
- ldm/lr_scheduler.py +143 -0
- ldm/models/__init__.py +0 -0
- ldm/models/autoencoder.py +596 -0
- ldm/models/diffusion/__init__.py +0 -0
- ldm/models/diffusion/classifier.py +355 -0
- ldm/models/diffusion/cross_attention_control.py +443 -0
- ldm/models/diffusion/cross_attention_map_saving.py +95 -0
- ldm/models/diffusion/ddim.py +111 -0
- ldm/models/diffusion/ddpm.py +2263 -0
- ldm/models/diffusion/ksampler.py +312 -0
- ldm/models/diffusion/plms.py +146 -0
- ldm/models/diffusion/sampler.py +450 -0
- ldm/models/diffusion/shared_invokeai_diffusion.py +244 -0
- ldm/modules/__init__.py +0 -0
- ldm/modules/attention.py +274 -0
- ldm/modules/diffusionmodules/__init__.py +0 -0
- ldm/modules/diffusionmodules/model.py +894 -0
- ldm/modules/diffusionmodules/openaimodel.py +1036 -0
- ldm/modules/diffusionmodules/util.py +314 -0
- ldm/modules/distributions/__init__.py +0 -0
- ldm/modules/distributions/distributions.py +104 -0
- ldm/modules/ema.py +88 -0
- ldm/modules/embedding_manager.py +413 -0
- ldm/modules/encoders/__init__.py +0 -0
- ldm/modules/encoders/modules.py +772 -0
- ldm/modules/image_degradation/__init__.py +6 -0
- ldm/modules/image_degradation/bsrgan.py +846 -0
- ldm/modules/image_degradation/bsrgan_light.py +751 -0
- ldm/modules/image_degradation/utils_image.py +1024 -0
- ldm/modules/losses/__init__.py +1 -0
- ldm/modules/losses/contperceptual.py +175 -0
- ldm/modules/losses/vqperceptual.py +240 -0
- ldm/modules/x_transformer.py +752 -0
- ldm/simplet2i.py +13 -0
- ldm/util.py +264 -0
- scripts/configure_invokeai.py +797 -0
- scripts/create_root.py +43 -0
- scripts/dream.py +10 -0
- scripts/images2prompt.py +30 -0
- scripts/invoke.py +5 -0
- scripts/legacy_api.py +681 -0
- scripts/load_models.py +12 -0
- scripts/merge_embeddings.py +124 -0
- scripts/orig_scripts/img2img.py +296 -0
- scripts/orig_scripts/inpaint.py +98 -0
- scripts/orig_scripts/knn2img.py +397 -0
- scripts/orig_scripts/sample_diffusion.py +313 -0
- scripts/orig_scripts/train_searcher.py +147 -0
- scripts/orig_scripts/txt2img.py +324 -0
- scripts/preload_models.py +12 -0
- scripts/sd-metadata.py +22 -0
- vendored/clip/clip/__init__.py +1 -0
- vendored/clip/clip/bpe_simple_vocab_16e6.txt.gz +0 -0
- vendored/clip/clip/clip.py +237 -0
- vendored/clip/clip/model.py +436 -0
- vendored/clip/clip/simple_tokenizer.py +132 -0
- vendored/clip/hubconf.py +42 -0
- vendored/clip/setup.py +21 -0
- vendored/clip/tests/test_consistency.py +25 -0
- vendored/clipseg/datasets/coco_wrapper.py +99 -0
- vendored/clipseg/datasets/pascal_zeroshot.py +60 -0
- vendored/clipseg/datasets/pfe_dataset.py +129 -0
- vendored/clipseg/datasets/phrasecut.py +380 -0
- vendored/clipseg/datasets/utils.py +68 -0
- vendored/clipseg/evaluation_utils.py +292 -0
- vendored/clipseg/general_utils.py +272 -0
- vendored/clipseg/metrics.py +271 -0
- vendored/clipseg/models/clipseg.py +538 -0
- vendored/clipseg/models/vitseg.py +286 -0
- vendored/clipseg/score.py +453 -0
- vendored/clipseg/setup.py +30 -0
- vendored/clipseg/training.py +266 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
'''
|
|
2
|
+
ldm.models.diffusion.sampler
|
|
3
|
+
|
|
4
|
+
Base class for ldm.models.diffusion.ddim, ldm.models.diffusion.ksampler, etc
|
|
5
|
+
'''
|
|
6
|
+
import torch
|
|
7
|
+
import numpy as np
|
|
8
|
+
from tqdm import tqdm
|
|
9
|
+
from functools import partial
|
|
10
|
+
from ldm.invoke.devices import choose_torch_device
|
|
11
|
+
from ldm.models.diffusion.shared_invokeai_diffusion import InvokeAIDiffuserComponent
|
|
12
|
+
|
|
13
|
+
from ldm.modules.diffusionmodules.util import (
|
|
14
|
+
make_ddim_sampling_parameters,
|
|
15
|
+
make_ddim_timesteps,
|
|
16
|
+
noise_like,
|
|
17
|
+
extract_into_tensor,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
class Sampler(object):
|
|
21
|
+
def __init__(self, model, schedule='linear', steps=None, device=None, **kwargs):
|
|
22
|
+
self.model = model
|
|
23
|
+
self.ddim_timesteps = None
|
|
24
|
+
self.ddpm_num_timesteps = steps
|
|
25
|
+
self.schedule = schedule
|
|
26
|
+
self.device = device or choose_torch_device()
|
|
27
|
+
self.invokeai_diffuser = InvokeAIDiffuserComponent(self.model,
|
|
28
|
+
model_forward_callback = lambda x, sigma, cond: self.model.apply_model(x, sigma, cond))
|
|
29
|
+
|
|
30
|
+
def register_buffer(self, name, attr):
|
|
31
|
+
if type(attr) == torch.Tensor:
|
|
32
|
+
if attr.device != torch.device(self.device):
|
|
33
|
+
attr = attr.to(torch.float32).to(torch.device(self.device))
|
|
34
|
+
setattr(self, name, attr)
|
|
35
|
+
|
|
36
|
+
# This method was copied over from ddim.py and probably does stuff that is
|
|
37
|
+
# ddim-specific. Disentangle at some point.
|
|
38
|
+
def make_schedule(
|
|
39
|
+
self,
|
|
40
|
+
ddim_num_steps,
|
|
41
|
+
ddim_discretize='uniform',
|
|
42
|
+
ddim_eta=0.0,
|
|
43
|
+
verbose=False,
|
|
44
|
+
):
|
|
45
|
+
self.total_steps = ddim_num_steps
|
|
46
|
+
self.ddim_timesteps = make_ddim_timesteps(
|
|
47
|
+
ddim_discr_method=ddim_discretize,
|
|
48
|
+
num_ddim_timesteps=ddim_num_steps,
|
|
49
|
+
num_ddpm_timesteps=self.ddpm_num_timesteps,
|
|
50
|
+
verbose=verbose,
|
|
51
|
+
)
|
|
52
|
+
alphas_cumprod = self.model.alphas_cumprod
|
|
53
|
+
assert (
|
|
54
|
+
alphas_cumprod.shape[0] == self.ddpm_num_timesteps
|
|
55
|
+
), 'alphas have to be defined for each timestep'
|
|
56
|
+
to_torch = (
|
|
57
|
+
lambda x: x.clone()
|
|
58
|
+
.detach()
|
|
59
|
+
.to(torch.float32)
|
|
60
|
+
.to(self.model.device)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
self.register_buffer('betas', to_torch(self.model.betas))
|
|
64
|
+
self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod))
|
|
65
|
+
self.register_buffer(
|
|
66
|
+
'alphas_cumprod_prev', to_torch(self.model.alphas_cumprod_prev)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# calculations for diffusion q(x_t | x_{t-1}) and others
|
|
70
|
+
self.register_buffer(
|
|
71
|
+
'sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod.cpu()))
|
|
72
|
+
)
|
|
73
|
+
self.register_buffer(
|
|
74
|
+
'sqrt_one_minus_alphas_cumprod',
|
|
75
|
+
to_torch(np.sqrt(1.0 - alphas_cumprod.cpu())),
|
|
76
|
+
)
|
|
77
|
+
self.register_buffer(
|
|
78
|
+
'log_one_minus_alphas_cumprod',
|
|
79
|
+
to_torch(np.log(1.0 - alphas_cumprod.cpu())),
|
|
80
|
+
)
|
|
81
|
+
self.register_buffer(
|
|
82
|
+
'sqrt_recip_alphas_cumprod',
|
|
83
|
+
to_torch(np.sqrt(1.0 / alphas_cumprod.cpu())),
|
|
84
|
+
)
|
|
85
|
+
self.register_buffer(
|
|
86
|
+
'sqrt_recipm1_alphas_cumprod',
|
|
87
|
+
to_torch(np.sqrt(1.0 / alphas_cumprod.cpu() - 1)),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# ddim sampling parameters
|
|
91
|
+
(
|
|
92
|
+
ddim_sigmas,
|
|
93
|
+
ddim_alphas,
|
|
94
|
+
ddim_alphas_prev,
|
|
95
|
+
) = make_ddim_sampling_parameters(
|
|
96
|
+
alphacums=alphas_cumprod.cpu(),
|
|
97
|
+
ddim_timesteps=self.ddim_timesteps,
|
|
98
|
+
eta=ddim_eta,
|
|
99
|
+
verbose=verbose,
|
|
100
|
+
)
|
|
101
|
+
self.register_buffer('ddim_sigmas', ddim_sigmas)
|
|
102
|
+
self.register_buffer('ddim_alphas', ddim_alphas)
|
|
103
|
+
self.register_buffer('ddim_alphas_prev', ddim_alphas_prev)
|
|
104
|
+
self.register_buffer(
|
|
105
|
+
'ddim_sqrt_one_minus_alphas', np.sqrt(1.0 - ddim_alphas)
|
|
106
|
+
)
|
|
107
|
+
sigmas_for_original_sampling_steps = ddim_eta * torch.sqrt(
|
|
108
|
+
(1 - self.alphas_cumprod_prev)
|
|
109
|
+
/ (1 - self.alphas_cumprod)
|
|
110
|
+
* (1 - self.alphas_cumprod / self.alphas_cumprod_prev)
|
|
111
|
+
)
|
|
112
|
+
self.register_buffer(
|
|
113
|
+
'ddim_sigmas_for_original_num_steps',
|
|
114
|
+
sigmas_for_original_sampling_steps,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
@torch.no_grad()
|
|
118
|
+
def stochastic_encode(self, x0, t, use_original_steps=False, noise=None):
|
|
119
|
+
# fast, but does not allow for exact reconstruction
|
|
120
|
+
# t serves as an index to gather the correct alphas
|
|
121
|
+
if use_original_steps:
|
|
122
|
+
sqrt_alphas_cumprod = self.sqrt_alphas_cumprod
|
|
123
|
+
sqrt_one_minus_alphas_cumprod = self.sqrt_one_minus_alphas_cumprod
|
|
124
|
+
else:
|
|
125
|
+
sqrt_alphas_cumprod = torch.sqrt(self.ddim_alphas)
|
|
126
|
+
sqrt_one_minus_alphas_cumprod = self.ddim_sqrt_one_minus_alphas
|
|
127
|
+
|
|
128
|
+
if noise is None:
|
|
129
|
+
noise = torch.randn_like(x0)
|
|
130
|
+
return (
|
|
131
|
+
extract_into_tensor(sqrt_alphas_cumprod, t, x0.shape) * x0
|
|
132
|
+
+ extract_into_tensor(sqrt_one_minus_alphas_cumprod, t, x0.shape)
|
|
133
|
+
* noise
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
@torch.no_grad()
|
|
137
|
+
def sample(
|
|
138
|
+
self,
|
|
139
|
+
S, # S is steps
|
|
140
|
+
batch_size,
|
|
141
|
+
shape,
|
|
142
|
+
conditioning=None,
|
|
143
|
+
callback=None,
|
|
144
|
+
normals_sequence=None,
|
|
145
|
+
img_callback=None, # TODO: this is very confusing because it is called "step_callback" elsewhere. Change.
|
|
146
|
+
quantize_x0=False,
|
|
147
|
+
eta=0.0,
|
|
148
|
+
mask=None,
|
|
149
|
+
x0=None,
|
|
150
|
+
temperature=1.0,
|
|
151
|
+
noise_dropout=0.0,
|
|
152
|
+
score_corrector=None,
|
|
153
|
+
corrector_kwargs=None,
|
|
154
|
+
verbose=False,
|
|
155
|
+
x_T=None,
|
|
156
|
+
log_every_t=100,
|
|
157
|
+
unconditional_guidance_scale=1.0,
|
|
158
|
+
unconditional_conditioning=None,
|
|
159
|
+
# this has to come in the same format as the conditioning, # e.g. as encoded tokens, ...
|
|
160
|
+
**kwargs,
|
|
161
|
+
):
|
|
162
|
+
|
|
163
|
+
if conditioning is not None:
|
|
164
|
+
if isinstance(conditioning, dict):
|
|
165
|
+
ctmp = conditioning[list(conditioning.keys())[0]]
|
|
166
|
+
while isinstance(ctmp, list):
|
|
167
|
+
ctmp = ctmp[0]
|
|
168
|
+
cbs = ctmp.shape[0]
|
|
169
|
+
if cbs != batch_size:
|
|
170
|
+
print(f"Warning: Got {cbs} conditionings but batch-size is {batch_size}")
|
|
171
|
+
else:
|
|
172
|
+
if conditioning.shape[0] != batch_size:
|
|
173
|
+
print(f"Warning: Got {conditioning.shape[0]} conditionings but batch-size is {batch_size}")
|
|
174
|
+
|
|
175
|
+
# check to see if make_schedule() has run, and if not, run it
|
|
176
|
+
if self.ddim_timesteps is None:
|
|
177
|
+
self.make_schedule(
|
|
178
|
+
ddim_num_steps=S,
|
|
179
|
+
ddim_eta = eta,
|
|
180
|
+
verbose = False,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
ts = self.get_timesteps(S)
|
|
184
|
+
|
|
185
|
+
# sampling
|
|
186
|
+
C, H, W = shape
|
|
187
|
+
shape = (batch_size, C, H, W)
|
|
188
|
+
samples, intermediates = self.do_sampling(
|
|
189
|
+
conditioning,
|
|
190
|
+
shape,
|
|
191
|
+
timesteps=ts,
|
|
192
|
+
callback=callback,
|
|
193
|
+
img_callback=img_callback,
|
|
194
|
+
quantize_denoised=quantize_x0,
|
|
195
|
+
mask=mask,
|
|
196
|
+
x0=x0,
|
|
197
|
+
ddim_use_original_steps=False,
|
|
198
|
+
noise_dropout=noise_dropout,
|
|
199
|
+
temperature=temperature,
|
|
200
|
+
score_corrector=score_corrector,
|
|
201
|
+
corrector_kwargs=corrector_kwargs,
|
|
202
|
+
x_T=x_T,
|
|
203
|
+
log_every_t=log_every_t,
|
|
204
|
+
unconditional_guidance_scale=unconditional_guidance_scale,
|
|
205
|
+
unconditional_conditioning=unconditional_conditioning,
|
|
206
|
+
steps=S,
|
|
207
|
+
**kwargs
|
|
208
|
+
)
|
|
209
|
+
return samples, intermediates
|
|
210
|
+
|
|
211
|
+
@torch.no_grad()
|
|
212
|
+
def do_sampling(
|
|
213
|
+
self,
|
|
214
|
+
cond,
|
|
215
|
+
shape,
|
|
216
|
+
timesteps=None,
|
|
217
|
+
x_T=None,
|
|
218
|
+
ddim_use_original_steps=False,
|
|
219
|
+
callback=None,
|
|
220
|
+
quantize_denoised=False,
|
|
221
|
+
mask=None,
|
|
222
|
+
x0=None,
|
|
223
|
+
img_callback=None,
|
|
224
|
+
log_every_t=100,
|
|
225
|
+
temperature=1.0,
|
|
226
|
+
noise_dropout=0.0,
|
|
227
|
+
score_corrector=None,
|
|
228
|
+
corrector_kwargs=None,
|
|
229
|
+
unconditional_guidance_scale=1.0,
|
|
230
|
+
unconditional_conditioning=None,
|
|
231
|
+
steps=None,
|
|
232
|
+
**kwargs
|
|
233
|
+
):
|
|
234
|
+
b = shape[0]
|
|
235
|
+
time_range = (
|
|
236
|
+
list(reversed(range(0, timesteps)))
|
|
237
|
+
if ddim_use_original_steps
|
|
238
|
+
else np.flip(timesteps)
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
total_steps=steps
|
|
242
|
+
|
|
243
|
+
iterator = tqdm(
|
|
244
|
+
time_range,
|
|
245
|
+
desc=f'{self.__class__.__name__}',
|
|
246
|
+
total=total_steps,
|
|
247
|
+
dynamic_ncols=True,
|
|
248
|
+
)
|
|
249
|
+
old_eps = []
|
|
250
|
+
self.prepare_to_sample(t_enc=total_steps,all_timesteps_count=steps,**kwargs)
|
|
251
|
+
img = self.get_initial_image(x_T,shape,total_steps)
|
|
252
|
+
|
|
253
|
+
# probably don't need this at all
|
|
254
|
+
intermediates = {'x_inter': [img], 'pred_x0': [img]}
|
|
255
|
+
|
|
256
|
+
for i, step in enumerate(iterator):
|
|
257
|
+
index = total_steps - i - 1
|
|
258
|
+
ts = torch.full(
|
|
259
|
+
(b,),
|
|
260
|
+
step,
|
|
261
|
+
device=self.device,
|
|
262
|
+
dtype=torch.long
|
|
263
|
+
)
|
|
264
|
+
ts_next = torch.full(
|
|
265
|
+
(b,),
|
|
266
|
+
time_range[min(i + 1, len(time_range) - 1)],
|
|
267
|
+
device=self.device,
|
|
268
|
+
dtype=torch.long,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
if mask is not None:
|
|
272
|
+
assert x0 is not None
|
|
273
|
+
img_orig = self.model.q_sample(
|
|
274
|
+
x0, ts
|
|
275
|
+
) # TODO: deterministic forward pass?
|
|
276
|
+
img = img_orig * mask + (1.0 - mask) * img
|
|
277
|
+
|
|
278
|
+
outs = self.p_sample(
|
|
279
|
+
img,
|
|
280
|
+
cond,
|
|
281
|
+
ts,
|
|
282
|
+
index=index,
|
|
283
|
+
use_original_steps=ddim_use_original_steps,
|
|
284
|
+
quantize_denoised=quantize_denoised,
|
|
285
|
+
temperature=temperature,
|
|
286
|
+
noise_dropout=noise_dropout,
|
|
287
|
+
score_corrector=score_corrector,
|
|
288
|
+
corrector_kwargs=corrector_kwargs,
|
|
289
|
+
unconditional_guidance_scale=unconditional_guidance_scale,
|
|
290
|
+
unconditional_conditioning=unconditional_conditioning,
|
|
291
|
+
old_eps=old_eps,
|
|
292
|
+
t_next=ts_next,
|
|
293
|
+
step_count=steps
|
|
294
|
+
)
|
|
295
|
+
img, pred_x0, e_t = outs
|
|
296
|
+
|
|
297
|
+
old_eps.append(e_t)
|
|
298
|
+
if len(old_eps) >= 4:
|
|
299
|
+
old_eps.pop(0)
|
|
300
|
+
if callback:
|
|
301
|
+
callback(i)
|
|
302
|
+
if img_callback:
|
|
303
|
+
img_callback(img,i)
|
|
304
|
+
|
|
305
|
+
if index % log_every_t == 0 or index == total_steps - 1:
|
|
306
|
+
intermediates['x_inter'].append(img)
|
|
307
|
+
intermediates['pred_x0'].append(pred_x0)
|
|
308
|
+
|
|
309
|
+
return img, intermediates
|
|
310
|
+
|
|
311
|
+
# NOTE that decode() and sample() are almost the same code, and do the same thing.
|
|
312
|
+
# The variable names are changed in order to be confusing.
|
|
313
|
+
@torch.no_grad()
|
|
314
|
+
def decode(
|
|
315
|
+
self,
|
|
316
|
+
x_latent,
|
|
317
|
+
cond,
|
|
318
|
+
t_start,
|
|
319
|
+
img_callback=None,
|
|
320
|
+
unconditional_guidance_scale=1.0,
|
|
321
|
+
unconditional_conditioning=None,
|
|
322
|
+
use_original_steps=False,
|
|
323
|
+
init_latent = None,
|
|
324
|
+
mask = None,
|
|
325
|
+
all_timesteps_count = None,
|
|
326
|
+
**kwargs
|
|
327
|
+
):
|
|
328
|
+
timesteps = (
|
|
329
|
+
np.arange(self.ddpm_num_timesteps)
|
|
330
|
+
if use_original_steps
|
|
331
|
+
else self.ddim_timesteps
|
|
332
|
+
)
|
|
333
|
+
timesteps = timesteps[:t_start]
|
|
334
|
+
|
|
335
|
+
time_range = np.flip(timesteps)
|
|
336
|
+
total_steps = timesteps.shape[0]
|
|
337
|
+
print(f'>> Running {self.__class__.__name__} sampling starting at step {self.total_steps - t_start} of {self.total_steps} ({total_steps} new sampling steps)')
|
|
338
|
+
|
|
339
|
+
iterator = tqdm(time_range, desc='Decoding image', total=total_steps)
|
|
340
|
+
x_dec = x_latent
|
|
341
|
+
x0 = init_latent
|
|
342
|
+
self.prepare_to_sample(t_enc=total_steps, all_timesteps_count=all_timesteps_count, **kwargs)
|
|
343
|
+
|
|
344
|
+
for i, step in enumerate(iterator):
|
|
345
|
+
index = total_steps - i - 1
|
|
346
|
+
ts = torch.full(
|
|
347
|
+
(x_latent.shape[0],),
|
|
348
|
+
step,
|
|
349
|
+
device=x_latent.device,
|
|
350
|
+
dtype=torch.long,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
ts_next = torch.full(
|
|
354
|
+
(x_latent.shape[0],),
|
|
355
|
+
time_range[min(i + 1, len(time_range) - 1)],
|
|
356
|
+
device=self.device,
|
|
357
|
+
dtype=torch.long,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
if mask is not None:
|
|
361
|
+
assert x0 is not None
|
|
362
|
+
xdec_orig = self.q_sample(x0, ts) # TODO: deterministic forward pass?
|
|
363
|
+
x_dec = xdec_orig * mask + (1.0 - mask) * x_dec
|
|
364
|
+
|
|
365
|
+
outs = self.p_sample(
|
|
366
|
+
x_dec,
|
|
367
|
+
cond,
|
|
368
|
+
ts,
|
|
369
|
+
index=index,
|
|
370
|
+
use_original_steps=use_original_steps,
|
|
371
|
+
unconditional_guidance_scale=unconditional_guidance_scale,
|
|
372
|
+
unconditional_conditioning=unconditional_conditioning,
|
|
373
|
+
t_next = ts_next,
|
|
374
|
+
step_count=len(self.ddim_timesteps)
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
x_dec, pred_x0, e_t = outs
|
|
378
|
+
if img_callback:
|
|
379
|
+
img_callback(x_dec,i)
|
|
380
|
+
|
|
381
|
+
return x_dec
|
|
382
|
+
|
|
383
|
+
def get_initial_image(self,x_T,shape,timesteps=None):
|
|
384
|
+
if x_T is None:
|
|
385
|
+
return torch.randn(shape, device=self.device)
|
|
386
|
+
else:
|
|
387
|
+
return x_T
|
|
388
|
+
|
|
389
|
+
def p_sample(
|
|
390
|
+
self,
|
|
391
|
+
img,
|
|
392
|
+
cond,
|
|
393
|
+
ts,
|
|
394
|
+
index,
|
|
395
|
+
repeat_noise=False,
|
|
396
|
+
use_original_steps=False,
|
|
397
|
+
quantize_denoised=False,
|
|
398
|
+
temperature=1.0,
|
|
399
|
+
noise_dropout=0.0,
|
|
400
|
+
score_corrector=None,
|
|
401
|
+
corrector_kwargs=None,
|
|
402
|
+
unconditional_guidance_scale=1.0,
|
|
403
|
+
unconditional_conditioning=None,
|
|
404
|
+
old_eps=None,
|
|
405
|
+
t_next=None,
|
|
406
|
+
steps=None,
|
|
407
|
+
):
|
|
408
|
+
raise NotImplementedError("p_sample() must be implemented in a descendent class")
|
|
409
|
+
|
|
410
|
+
def prepare_to_sample(self,t_enc,**kwargs):
|
|
411
|
+
'''
|
|
412
|
+
Hook that will be called right before the very first invocation of p_sample()
|
|
413
|
+
to allow subclass to do additional initialization. t_enc corresponds to the actual
|
|
414
|
+
number of steps that will be run, and may be less than total steps if img2img is
|
|
415
|
+
active.
|
|
416
|
+
'''
|
|
417
|
+
pass
|
|
418
|
+
|
|
419
|
+
def get_timesteps(self,ddim_steps):
|
|
420
|
+
'''
|
|
421
|
+
The ddim and plms samplers work on timesteps. This method is called after
|
|
422
|
+
ddim_timesteps are created in make_schedule(), and selects the portion of
|
|
423
|
+
timesteps that will be used for sampling, depending on the t_enc in img2img.
|
|
424
|
+
'''
|
|
425
|
+
return self.ddim_timesteps[:ddim_steps]
|
|
426
|
+
|
|
427
|
+
def q_sample(self,x0,ts):
|
|
428
|
+
'''
|
|
429
|
+
Returns self.model.q_sample(x0,ts). Is overridden in the k* samplers to
|
|
430
|
+
return self.model.inner_model.q_sample(x0,ts)
|
|
431
|
+
'''
|
|
432
|
+
return self.model.q_sample(x0,ts)
|
|
433
|
+
|
|
434
|
+
def conditioning_key(self)->str:
|
|
435
|
+
return self.model.model.conditioning_key
|
|
436
|
+
|
|
437
|
+
def uses_inpainting_model(self)->bool:
|
|
438
|
+
return self.conditioning_key() in ('hybrid','concat')
|
|
439
|
+
|
|
440
|
+
def adjust_settings(self,**kwargs):
|
|
441
|
+
'''
|
|
442
|
+
This is a catch-all method for adjusting any instance variables
|
|
443
|
+
after the sampler is instantiated. No type-checking performed
|
|
444
|
+
here, so use with care!
|
|
445
|
+
'''
|
|
446
|
+
for k in kwargs.keys():
|
|
447
|
+
try:
|
|
448
|
+
setattr(self,k,kwargs[k])
|
|
449
|
+
except AttributeError:
|
|
450
|
+
print(f'** Warning: attempt to set unknown attribute {k} in sampler of type {type(self)}')
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import traceback
|
|
2
|
+
from math import ceil
|
|
3
|
+
from typing import Callable, Optional, Union
|
|
4
|
+
|
|
5
|
+
import torch
|
|
6
|
+
|
|
7
|
+
from ldm.models.diffusion.cross_attention_control import Arguments, \
|
|
8
|
+
remove_cross_attention_control, setup_cross_attention_control, Context, get_cross_attention_modules, CrossAttentionType
|
|
9
|
+
from ldm.models.diffusion.cross_attention_map_saving import AttentionMapSaver
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class InvokeAIDiffuserComponent:
|
|
13
|
+
'''
|
|
14
|
+
The aim of this component is to provide a single place for code that can be applied identically to
|
|
15
|
+
all InvokeAI diffusion procedures.
|
|
16
|
+
|
|
17
|
+
At the moment it includes the following features:
|
|
18
|
+
* Cross attention control ("prompt2prompt")
|
|
19
|
+
* Hybrid conditioning (used for inpainting)
|
|
20
|
+
'''
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ExtraConditioningInfo:
|
|
24
|
+
def __init__(self, tokens_count_including_eos_bos:int, cross_attention_control_args: Optional[Arguments]):
|
|
25
|
+
self.tokens_count_including_eos_bos = tokens_count_including_eos_bos
|
|
26
|
+
self.cross_attention_control_args = cross_attention_control_args
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def wants_cross_attention_control(self):
|
|
30
|
+
return self.cross_attention_control_args is not None
|
|
31
|
+
|
|
32
|
+
def __init__(self, model, model_forward_callback:
|
|
33
|
+
Callable[[torch.Tensor, torch.Tensor, torch.Tensor], torch.Tensor]
|
|
34
|
+
):
|
|
35
|
+
"""
|
|
36
|
+
:param model: the unet model to pass through to cross attention control
|
|
37
|
+
:param model_forward_callback: a lambda with arguments (x, sigma, conditioning_to_apply). will be called repeatedly. most likely, this should simply call model.forward(x, sigma, conditioning)
|
|
38
|
+
"""
|
|
39
|
+
self.model = model
|
|
40
|
+
self.model_forward_callback = model_forward_callback
|
|
41
|
+
self.cross_attention_control_context = None
|
|
42
|
+
|
|
43
|
+
def setup_cross_attention_control(self, conditioning: ExtraConditioningInfo, step_count: int):
|
|
44
|
+
self.conditioning = conditioning
|
|
45
|
+
self.cross_attention_control_context = Context(
|
|
46
|
+
arguments=self.conditioning.cross_attention_control_args,
|
|
47
|
+
step_count=step_count
|
|
48
|
+
)
|
|
49
|
+
setup_cross_attention_control(self.model, self.cross_attention_control_context)
|
|
50
|
+
|
|
51
|
+
def remove_cross_attention_control(self):
|
|
52
|
+
self.conditioning = None
|
|
53
|
+
self.cross_attention_control_context = None
|
|
54
|
+
remove_cross_attention_control(self.model)
|
|
55
|
+
|
|
56
|
+
def setup_attention_map_saving(self, saver: AttentionMapSaver):
|
|
57
|
+
def callback(slice, dim, offset, slice_size, key):
|
|
58
|
+
if dim is not None:
|
|
59
|
+
# sliced tokens attention map saving is not implemented
|
|
60
|
+
return
|
|
61
|
+
saver.add_attention_maps(slice, key)
|
|
62
|
+
|
|
63
|
+
tokens_cross_attention_modules = get_cross_attention_modules(self.model, CrossAttentionType.TOKENS)
|
|
64
|
+
for identifier, module in tokens_cross_attention_modules:
|
|
65
|
+
key = ('down' if identifier.startswith('down') else
|
|
66
|
+
'up' if identifier.startswith('up') else
|
|
67
|
+
'mid')
|
|
68
|
+
module.set_attention_slice_calculated_callback(
|
|
69
|
+
lambda slice, dim, offset, slice_size, key=key: callback(slice, dim, offset, slice_size, key))
|
|
70
|
+
|
|
71
|
+
def remove_attention_map_saving(self):
|
|
72
|
+
tokens_cross_attention_modules = get_cross_attention_modules(self.model, CrossAttentionType.TOKENS)
|
|
73
|
+
for _, module in tokens_cross_attention_modules:
|
|
74
|
+
module.set_attention_slice_calculated_callback(None)
|
|
75
|
+
|
|
76
|
+
def do_diffusion_step(self, x: torch.Tensor, sigma: torch.Tensor,
|
|
77
|
+
unconditioning: Union[torch.Tensor,dict],
|
|
78
|
+
conditioning: Union[torch.Tensor,dict],
|
|
79
|
+
unconditional_guidance_scale: float,
|
|
80
|
+
step_index: Optional[int]=None
|
|
81
|
+
):
|
|
82
|
+
"""
|
|
83
|
+
:param x: current latents
|
|
84
|
+
:param sigma: aka t, passed to the internal model to control how much denoising will occur
|
|
85
|
+
:param unconditioning: embeddings for unconditioned output. for hybrid conditioning this is a dict of tensors [B x 77 x 768], otherwise a single tensor [B x 77 x 768]
|
|
86
|
+
:param conditioning: embeddings for conditioned output. for hybrid conditioning this is a dict of tensors [B x 77 x 768], otherwise a single tensor [B x 77 x 768]
|
|
87
|
+
:param unconditional_guidance_scale: aka CFG scale, controls how much effect the conditioning tensor has
|
|
88
|
+
:param step_index: counts upwards from 0 to (step_count-1) (as passed to setup_cross_attention_control, if using). May be called multiple times for a single step, therefore do not assume that its value will monotically increase. If None, will be estimated by comparing sigma against self.model.sigmas .
|
|
89
|
+
:return: the new latents after applying the model to x using unscaled unconditioning and CFG-scaled conditioning.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
cross_attention_control_types_to_do = []
|
|
94
|
+
context: Context = self.cross_attention_control_context
|
|
95
|
+
if self.cross_attention_control_context is not None:
|
|
96
|
+
percent_through = self.estimate_percent_through(step_index, sigma)
|
|
97
|
+
cross_attention_control_types_to_do = context.get_active_cross_attention_control_types_for_step(percent_through)
|
|
98
|
+
|
|
99
|
+
wants_cross_attention_control = (len(cross_attention_control_types_to_do) > 0)
|
|
100
|
+
wants_hybrid_conditioning = isinstance(conditioning, dict)
|
|
101
|
+
|
|
102
|
+
if wants_hybrid_conditioning:
|
|
103
|
+
unconditioned_next_x, conditioned_next_x = self.apply_hybrid_conditioning(x, sigma, unconditioning, conditioning)
|
|
104
|
+
elif wants_cross_attention_control:
|
|
105
|
+
unconditioned_next_x, conditioned_next_x = self.apply_cross_attention_controlled_conditioning(x, sigma, unconditioning, conditioning, cross_attention_control_types_to_do)
|
|
106
|
+
else:
|
|
107
|
+
unconditioned_next_x, conditioned_next_x = self.apply_standard_conditioning(x, sigma, unconditioning, conditioning)
|
|
108
|
+
|
|
109
|
+
# to scale how much effect conditioning has, calculate the changes it does and then scale that
|
|
110
|
+
scaled_delta = (conditioned_next_x - unconditioned_next_x) * unconditional_guidance_scale
|
|
111
|
+
combined_next_x = unconditioned_next_x + scaled_delta
|
|
112
|
+
|
|
113
|
+
return combined_next_x
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# methods below are called from do_diffusion_step and should be considered private to this class.
|
|
117
|
+
|
|
118
|
+
def apply_standard_conditioning(self, x, sigma, unconditioning, conditioning):
|
|
119
|
+
# fast batched path
|
|
120
|
+
x_twice = torch.cat([x] * 2)
|
|
121
|
+
sigma_twice = torch.cat([sigma] * 2)
|
|
122
|
+
both_conditionings = torch.cat([unconditioning, conditioning])
|
|
123
|
+
unconditioned_next_x, conditioned_next_x = self.model_forward_callback(x_twice, sigma_twice,
|
|
124
|
+
both_conditionings).chunk(2)
|
|
125
|
+
return unconditioned_next_x, conditioned_next_x
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def apply_hybrid_conditioning(self, x, sigma, unconditioning, conditioning):
|
|
129
|
+
assert isinstance(conditioning, dict)
|
|
130
|
+
assert isinstance(unconditioning, dict)
|
|
131
|
+
x_twice = torch.cat([x] * 2)
|
|
132
|
+
sigma_twice = torch.cat([sigma] * 2)
|
|
133
|
+
both_conditionings = dict()
|
|
134
|
+
for k in conditioning:
|
|
135
|
+
if isinstance(conditioning[k], list):
|
|
136
|
+
both_conditionings[k] = [
|
|
137
|
+
torch.cat([unconditioning[k][i], conditioning[k][i]])
|
|
138
|
+
for i in range(len(conditioning[k]))
|
|
139
|
+
]
|
|
140
|
+
else:
|
|
141
|
+
both_conditionings[k] = torch.cat([unconditioning[k], conditioning[k]])
|
|
142
|
+
unconditioned_next_x, conditioned_next_x = self.model_forward_callback(x_twice, sigma_twice, both_conditionings).chunk(2)
|
|
143
|
+
return unconditioned_next_x, conditioned_next_x
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def apply_cross_attention_controlled_conditioning(self, x:torch.Tensor, sigma, unconditioning, conditioning, cross_attention_control_types_to_do):
|
|
147
|
+
# print('pct', percent_through, ': doing cross attention control on', cross_attention_control_types_to_do)
|
|
148
|
+
# slower non-batched path (20% slower on mac MPS)
|
|
149
|
+
# We are only interested in using attention maps for conditioned_next_x, but batching them with generation of
|
|
150
|
+
# unconditioned_next_x causes attention maps to *also* be saved for the unconditioned_next_x.
|
|
151
|
+
# This messes app their application later, due to mismatched shape of dim 0 (seems to be 16 for batched vs. 8)
|
|
152
|
+
# (For the batched invocation the `wrangler` function gets attention tensor with shape[0]=16,
|
|
153
|
+
# representing batched uncond + cond, but then when it comes to applying the saved attention, the
|
|
154
|
+
# wrangler gets an attention tensor which only has shape[0]=8, representing just self.edited_conditionings.)
|
|
155
|
+
# todo: give CrossAttentionControl's `wrangler` function more info so it can work with a batched call as well.
|
|
156
|
+
context:Context = self.cross_attention_control_context
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
unconditioned_next_x = self.model_forward_callback(x, sigma, unconditioning)
|
|
160
|
+
|
|
161
|
+
# process x using the original prompt, saving the attention maps
|
|
162
|
+
#print("saving attention maps for", cross_attention_control_types_to_do)
|
|
163
|
+
for ca_type in cross_attention_control_types_to_do:
|
|
164
|
+
context.request_save_attention_maps(ca_type)
|
|
165
|
+
_ = self.model_forward_callback(x, sigma, conditioning)
|
|
166
|
+
context.clear_requests(cleanup=False)
|
|
167
|
+
|
|
168
|
+
# process x again, using the saved attention maps to control where self.edited_conditioning will be applied
|
|
169
|
+
#print("applying saved attention maps for", cross_attention_control_types_to_do)
|
|
170
|
+
for ca_type in cross_attention_control_types_to_do:
|
|
171
|
+
context.request_apply_saved_attention_maps(ca_type)
|
|
172
|
+
edited_conditioning = self.conditioning.cross_attention_control_args.edited_conditioning
|
|
173
|
+
conditioned_next_x = self.model_forward_callback(x, sigma, edited_conditioning)
|
|
174
|
+
context.clear_requests(cleanup=True)
|
|
175
|
+
|
|
176
|
+
except:
|
|
177
|
+
context.clear_requests(cleanup=True)
|
|
178
|
+
raise
|
|
179
|
+
|
|
180
|
+
return unconditioned_next_x, conditioned_next_x
|
|
181
|
+
|
|
182
|
+
def estimate_percent_through(self, step_index, sigma):
|
|
183
|
+
if step_index is not None and self.cross_attention_control_context is not None:
|
|
184
|
+
# percent_through will never reach 1.0 (but this is intended)
|
|
185
|
+
return float(step_index) / float(self.cross_attention_control_context.step_count)
|
|
186
|
+
# find the best possible index of the current sigma in the sigma sequence
|
|
187
|
+
smaller_sigmas = torch.nonzero(self.model.sigmas <= sigma)
|
|
188
|
+
sigma_index = smaller_sigmas[-1].item() if smaller_sigmas.shape[0] > 0 else 0
|
|
189
|
+
# flip because sigmas[0] is for the fully denoised image
|
|
190
|
+
# percent_through must be <1
|
|
191
|
+
return 1.0 - float(sigma_index + 1) / float(self.model.sigmas.shape[0])
|
|
192
|
+
# print('estimated percent_through', percent_through, 'from sigma', sigma.item())
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# todo: make this work
|
|
196
|
+
@classmethod
|
|
197
|
+
def apply_conjunction(cls, x, t, forward_func, uc, c_or_weighted_c_list, global_guidance_scale):
|
|
198
|
+
x_in = torch.cat([x] * 2)
|
|
199
|
+
t_in = torch.cat([t] * 2) # aka sigmas
|
|
200
|
+
|
|
201
|
+
deltas = None
|
|
202
|
+
uncond_latents = None
|
|
203
|
+
weighted_cond_list = c_or_weighted_c_list if type(c_or_weighted_c_list) is list else [(c_or_weighted_c_list, 1)]
|
|
204
|
+
|
|
205
|
+
# below is fugly omg
|
|
206
|
+
num_actual_conditionings = len(c_or_weighted_c_list)
|
|
207
|
+
conditionings = [uc] + [c for c,weight in weighted_cond_list]
|
|
208
|
+
weights = [1] + [weight for c,weight in weighted_cond_list]
|
|
209
|
+
chunk_count = ceil(len(conditionings)/2)
|
|
210
|
+
deltas = None
|
|
211
|
+
for chunk_index in range(chunk_count):
|
|
212
|
+
offset = chunk_index*2
|
|
213
|
+
chunk_size = min(2, len(conditionings)-offset)
|
|
214
|
+
|
|
215
|
+
if chunk_size == 1:
|
|
216
|
+
c_in = conditionings[offset]
|
|
217
|
+
latents_a = forward_func(x_in[:-1], t_in[:-1], c_in)
|
|
218
|
+
latents_b = None
|
|
219
|
+
else:
|
|
220
|
+
c_in = torch.cat(conditionings[offset:offset+2])
|
|
221
|
+
latents_a, latents_b = forward_func(x_in, t_in, c_in).chunk(2)
|
|
222
|
+
|
|
223
|
+
# first chunk is guaranteed to be 2 entries: uncond_latents + first conditioining
|
|
224
|
+
if chunk_index == 0:
|
|
225
|
+
uncond_latents = latents_a
|
|
226
|
+
deltas = latents_b - uncond_latents
|
|
227
|
+
else:
|
|
228
|
+
deltas = torch.cat((deltas, latents_a - uncond_latents))
|
|
229
|
+
if latents_b is not None:
|
|
230
|
+
deltas = torch.cat((deltas, latents_b - uncond_latents))
|
|
231
|
+
|
|
232
|
+
# merge the weighted deltas together into a single merged delta
|
|
233
|
+
per_delta_weights = torch.tensor(weights[1:], dtype=deltas.dtype, device=deltas.device)
|
|
234
|
+
normalize = False
|
|
235
|
+
if normalize:
|
|
236
|
+
per_delta_weights /= torch.sum(per_delta_weights)
|
|
237
|
+
reshaped_weights = per_delta_weights.reshape(per_delta_weights.shape + (1, 1, 1))
|
|
238
|
+
deltas_merged = torch.sum(deltas * reshaped_weights, dim=0, keepdim=True)
|
|
239
|
+
|
|
240
|
+
# old_return_value = super().forward(x, sigma, uncond, cond, cond_scale)
|
|
241
|
+
# assert(0 == len(torch.nonzero(old_return_value - (uncond_latents + deltas_merged * cond_scale))))
|
|
242
|
+
|
|
243
|
+
return uncond_latents + deltas_merged * global_guidance_scale
|
|
244
|
+
|
ldm/modules/__init__.py
ADDED
|
File without changes
|