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,443 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
import math
|
|
3
|
+
from typing import Optional, Callable
|
|
4
|
+
|
|
5
|
+
import psutil
|
|
6
|
+
import torch
|
|
7
|
+
from torch import nn
|
|
8
|
+
|
|
9
|
+
# adapted from bloc97's CrossAttentionControl colab
|
|
10
|
+
# https://github.com/bloc97/CrossAttentionControl
|
|
11
|
+
|
|
12
|
+
class Arguments:
|
|
13
|
+
def __init__(self, edited_conditioning: torch.Tensor, edit_opcodes: list[tuple], edit_options: dict):
|
|
14
|
+
"""
|
|
15
|
+
:param edited_conditioning: if doing cross-attention control, the edited conditioning [1 x 77 x 768]
|
|
16
|
+
:param edit_opcodes: if doing cross-attention control, a list of difflib.SequenceMatcher-like opcodes describing how to map original conditioning tokens to edited conditioning tokens (only the 'equal' opcode is required)
|
|
17
|
+
:param edit_options: if doing cross-attention control, per-edit options. there should be 1 item in edit_options for each item in edit_opcodes.
|
|
18
|
+
"""
|
|
19
|
+
# todo: rewrite this to take embedding fragments rather than a single edited_conditioning vector
|
|
20
|
+
self.edited_conditioning = edited_conditioning
|
|
21
|
+
self.edit_opcodes = edit_opcodes
|
|
22
|
+
|
|
23
|
+
if edited_conditioning is not None:
|
|
24
|
+
assert len(edit_opcodes) == len(edit_options), \
|
|
25
|
+
"there must be 1 edit_options dict for each edit_opcodes tuple"
|
|
26
|
+
non_none_edit_options = [x for x in edit_options if x is not None]
|
|
27
|
+
assert len(non_none_edit_options)>0, "missing edit_options"
|
|
28
|
+
if len(non_none_edit_options)>1:
|
|
29
|
+
print('warning: cross-attention control options are not working properly for >1 edit')
|
|
30
|
+
self.edit_options = non_none_edit_options[0]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class CrossAttentionType(enum.Enum):
|
|
34
|
+
SELF = 1
|
|
35
|
+
TOKENS = 2
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Context:
|
|
39
|
+
|
|
40
|
+
cross_attention_mask: Optional[torch.Tensor]
|
|
41
|
+
cross_attention_index_map: Optional[torch.Tensor]
|
|
42
|
+
|
|
43
|
+
class Action(enum.Enum):
|
|
44
|
+
NONE = 0
|
|
45
|
+
SAVE = 1,
|
|
46
|
+
APPLY = 2
|
|
47
|
+
|
|
48
|
+
def __init__(self, arguments: Arguments, step_count: int):
|
|
49
|
+
"""
|
|
50
|
+
:param arguments: Arguments for the cross-attention control process
|
|
51
|
+
:param step_count: The absolute total number of steps of diffusion (for img2img this is likely larger than the number of steps that will actually run)
|
|
52
|
+
"""
|
|
53
|
+
self.cross_attention_mask = None
|
|
54
|
+
self.cross_attention_index_map = None
|
|
55
|
+
self.self_cross_attention_action = Context.Action.NONE
|
|
56
|
+
self.tokens_cross_attention_action = Context.Action.NONE
|
|
57
|
+
self.arguments = arguments
|
|
58
|
+
self.step_count = step_count
|
|
59
|
+
|
|
60
|
+
self.self_cross_attention_module_identifiers = []
|
|
61
|
+
self.tokens_cross_attention_module_identifiers = []
|
|
62
|
+
|
|
63
|
+
self.saved_cross_attention_maps = {}
|
|
64
|
+
|
|
65
|
+
self.clear_requests(cleanup=True)
|
|
66
|
+
|
|
67
|
+
def register_cross_attention_modules(self, model):
|
|
68
|
+
for name,module in get_cross_attention_modules(model, CrossAttentionType.SELF):
|
|
69
|
+
if name in self.self_cross_attention_module_identifiers:
|
|
70
|
+
assert False, f"name {name} cannot appear more than once"
|
|
71
|
+
self.self_cross_attention_module_identifiers.append(name)
|
|
72
|
+
for name,module in get_cross_attention_modules(model, CrossAttentionType.TOKENS):
|
|
73
|
+
if name in self.tokens_cross_attention_module_identifiers:
|
|
74
|
+
assert False, f"name {name} cannot appear more than once"
|
|
75
|
+
self.tokens_cross_attention_module_identifiers.append(name)
|
|
76
|
+
|
|
77
|
+
def request_save_attention_maps(self, cross_attention_type: CrossAttentionType):
|
|
78
|
+
if cross_attention_type == CrossAttentionType.SELF:
|
|
79
|
+
self.self_cross_attention_action = Context.Action.SAVE
|
|
80
|
+
else:
|
|
81
|
+
self.tokens_cross_attention_action = Context.Action.SAVE
|
|
82
|
+
|
|
83
|
+
def request_apply_saved_attention_maps(self, cross_attention_type: CrossAttentionType):
|
|
84
|
+
if cross_attention_type == CrossAttentionType.SELF:
|
|
85
|
+
self.self_cross_attention_action = Context.Action.APPLY
|
|
86
|
+
else:
|
|
87
|
+
self.tokens_cross_attention_action = Context.Action.APPLY
|
|
88
|
+
|
|
89
|
+
def is_tokens_cross_attention(self, module_identifier) -> bool:
|
|
90
|
+
return module_identifier in self.tokens_cross_attention_module_identifiers
|
|
91
|
+
|
|
92
|
+
def get_should_save_maps(self, module_identifier: str) -> bool:
|
|
93
|
+
if module_identifier in self.self_cross_attention_module_identifiers:
|
|
94
|
+
return self.self_cross_attention_action == Context.Action.SAVE
|
|
95
|
+
elif module_identifier in self.tokens_cross_attention_module_identifiers:
|
|
96
|
+
return self.tokens_cross_attention_action == Context.Action.SAVE
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
def get_should_apply_saved_maps(self, module_identifier: str) -> bool:
|
|
100
|
+
if module_identifier in self.self_cross_attention_module_identifiers:
|
|
101
|
+
return self.self_cross_attention_action == Context.Action.APPLY
|
|
102
|
+
elif module_identifier in self.tokens_cross_attention_module_identifiers:
|
|
103
|
+
return self.tokens_cross_attention_action == Context.Action.APPLY
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
def get_active_cross_attention_control_types_for_step(self, percent_through:float=None)\
|
|
107
|
+
-> list[CrossAttentionType]:
|
|
108
|
+
"""
|
|
109
|
+
Should cross-attention control be applied on the given step?
|
|
110
|
+
:param percent_through: How far through the step sequence are we (0.0=pure noise, 1.0=completely denoised image). Expected range 0.0..<1.0.
|
|
111
|
+
:return: A list of attention types that cross-attention control should be performed for on the given step. May be [].
|
|
112
|
+
"""
|
|
113
|
+
if percent_through is None:
|
|
114
|
+
return [CrossAttentionType.SELF, CrossAttentionType.TOKENS]
|
|
115
|
+
|
|
116
|
+
opts = self.arguments.edit_options
|
|
117
|
+
to_control = []
|
|
118
|
+
if opts['s_start'] <= percent_through < opts['s_end']:
|
|
119
|
+
to_control.append(CrossAttentionType.SELF)
|
|
120
|
+
if opts['t_start'] <= percent_through < opts['t_end']:
|
|
121
|
+
to_control.append(CrossAttentionType.TOKENS)
|
|
122
|
+
return to_control
|
|
123
|
+
|
|
124
|
+
def save_slice(self, identifier: str, slice: torch.Tensor, dim: Optional[int], offset: int,
|
|
125
|
+
slice_size: Optional[int]):
|
|
126
|
+
if identifier not in self.saved_cross_attention_maps:
|
|
127
|
+
self.saved_cross_attention_maps[identifier] = {
|
|
128
|
+
'dim': dim,
|
|
129
|
+
'slice_size': slice_size,
|
|
130
|
+
'slices': {offset or 0: slice}
|
|
131
|
+
}
|
|
132
|
+
else:
|
|
133
|
+
self.saved_cross_attention_maps[identifier]['slices'][offset or 0] = slice
|
|
134
|
+
|
|
135
|
+
def get_slice(self, identifier: str, requested_dim: Optional[int], requested_offset: int, slice_size: int):
|
|
136
|
+
saved_attention_dict = self.saved_cross_attention_maps[identifier]
|
|
137
|
+
if requested_dim is None:
|
|
138
|
+
if saved_attention_dict['dim'] is not None:
|
|
139
|
+
raise RuntimeError(f"dim mismatch: expected dim=None, have {saved_attention_dict['dim']}")
|
|
140
|
+
return saved_attention_dict['slices'][0]
|
|
141
|
+
|
|
142
|
+
if saved_attention_dict['dim'] == requested_dim:
|
|
143
|
+
if slice_size != saved_attention_dict['slice_size']:
|
|
144
|
+
raise RuntimeError(
|
|
145
|
+
f"slice_size mismatch: expected slice_size={slice_size}, have {saved_attention_dict['slice_size']}")
|
|
146
|
+
return saved_attention_dict['slices'][requested_offset]
|
|
147
|
+
|
|
148
|
+
if saved_attention_dict['dim'] is None:
|
|
149
|
+
whole_saved_attention = saved_attention_dict['slices'][0]
|
|
150
|
+
if requested_dim == 0:
|
|
151
|
+
return whole_saved_attention[requested_offset:requested_offset + slice_size]
|
|
152
|
+
elif requested_dim == 1:
|
|
153
|
+
return whole_saved_attention[:, requested_offset:requested_offset + slice_size]
|
|
154
|
+
|
|
155
|
+
raise RuntimeError(f"Cannot convert dim {saved_attention_dict['dim']} to requested dim {requested_dim}")
|
|
156
|
+
|
|
157
|
+
def get_slicing_strategy(self, identifier: str) -> tuple[Optional[int], Optional[int]]:
|
|
158
|
+
saved_attention = self.saved_cross_attention_maps.get(identifier, None)
|
|
159
|
+
if saved_attention is None:
|
|
160
|
+
return None, None
|
|
161
|
+
return saved_attention['dim'], saved_attention['slice_size']
|
|
162
|
+
|
|
163
|
+
def clear_requests(self, cleanup=True):
|
|
164
|
+
self.tokens_cross_attention_action = Context.Action.NONE
|
|
165
|
+
self.self_cross_attention_action = Context.Action.NONE
|
|
166
|
+
if cleanup:
|
|
167
|
+
self.saved_cross_attention_maps = {}
|
|
168
|
+
|
|
169
|
+
def offload_saved_attention_slices_to_cpu(self):
|
|
170
|
+
for key, map_dict in self.saved_cross_attention_maps.items():
|
|
171
|
+
for offset, slice in map_dict['slices'].items():
|
|
172
|
+
map_dict[offset] = slice.to('cpu')
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class InvokeAICrossAttentionMixin:
|
|
177
|
+
"""
|
|
178
|
+
Enable InvokeAI-flavoured CrossAttention calculation, which does aggressive low-memory slicing and calls
|
|
179
|
+
through both to an attention_slice_wrangler and a slicing_strategy_getter for custom attention map wrangling
|
|
180
|
+
and dymamic slicing strategy selection.
|
|
181
|
+
"""
|
|
182
|
+
def __init__(self):
|
|
183
|
+
self.mem_total_gb = psutil.virtual_memory().total // (1 << 30)
|
|
184
|
+
self.attention_slice_wrangler = None
|
|
185
|
+
self.slicing_strategy_getter = None
|
|
186
|
+
self.attention_slice_calculated_callback = None
|
|
187
|
+
|
|
188
|
+
def set_attention_slice_wrangler(self, wrangler: Optional[Callable[[nn.Module, torch.Tensor, int, int, int], torch.Tensor]]):
|
|
189
|
+
'''
|
|
190
|
+
Set custom attention calculator to be called when attention is calculated
|
|
191
|
+
:param wrangler: Callback, with args (module, suggested_attention_slice, dim, offset, slice_size),
|
|
192
|
+
which returns either the suggested_attention_slice or an adjusted equivalent.
|
|
193
|
+
`module` is the current CrossAttention module for which the callback is being invoked.
|
|
194
|
+
`suggested_attention_slice` is the default-calculated attention slice
|
|
195
|
+
`dim` is -1 if the attenion map has not been sliced, or 0 or 1 for dimension-0 or dimension-1 slicing.
|
|
196
|
+
If `dim` is >= 0, `offset` and `slice_size` specify the slice start and length.
|
|
197
|
+
|
|
198
|
+
Pass None to use the default attention calculation.
|
|
199
|
+
:return:
|
|
200
|
+
'''
|
|
201
|
+
self.attention_slice_wrangler = wrangler
|
|
202
|
+
|
|
203
|
+
def set_slicing_strategy_getter(self, getter: Optional[Callable[[nn.Module], tuple[int,int]]]):
|
|
204
|
+
self.slicing_strategy_getter = getter
|
|
205
|
+
|
|
206
|
+
def set_attention_slice_calculated_callback(self, callback: Optional[Callable[[torch.Tensor], None]]):
|
|
207
|
+
self.attention_slice_calculated_callback = callback
|
|
208
|
+
|
|
209
|
+
def einsum_lowest_level(self, query, key, value, dim, offset, slice_size):
|
|
210
|
+
# calculate attention scores
|
|
211
|
+
#attention_scores = torch.einsum('b i d, b j d -> b i j', q, k)
|
|
212
|
+
attention_scores = torch.baddbmm(
|
|
213
|
+
torch.empty(query.shape[0], query.shape[1], key.shape[1], dtype=query.dtype, device=query.device),
|
|
214
|
+
query,
|
|
215
|
+
key.transpose(-1, -2),
|
|
216
|
+
beta=0,
|
|
217
|
+
alpha=self.scale,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# calculate attention slice by taking the best scores for each latent pixel
|
|
221
|
+
default_attention_slice = attention_scores.softmax(dim=-1, dtype=attention_scores.dtype)
|
|
222
|
+
attention_slice_wrangler = self.attention_slice_wrangler
|
|
223
|
+
if attention_slice_wrangler is not None:
|
|
224
|
+
attention_slice = attention_slice_wrangler(self, default_attention_slice, dim, offset, slice_size)
|
|
225
|
+
else:
|
|
226
|
+
attention_slice = default_attention_slice
|
|
227
|
+
|
|
228
|
+
if self.attention_slice_calculated_callback is not None:
|
|
229
|
+
self.attention_slice_calculated_callback(attention_slice, dim, offset, slice_size)
|
|
230
|
+
|
|
231
|
+
hidden_states = torch.bmm(attention_slice, value)
|
|
232
|
+
return hidden_states
|
|
233
|
+
|
|
234
|
+
def einsum_op_slice_dim0(self, q, k, v, slice_size):
|
|
235
|
+
r = torch.zeros(q.shape[0], q.shape[1], v.shape[2], device=q.device, dtype=q.dtype)
|
|
236
|
+
for i in range(0, q.shape[0], slice_size):
|
|
237
|
+
end = i + slice_size
|
|
238
|
+
r[i:end] = self.einsum_lowest_level(q[i:end], k[i:end], v[i:end], dim=0, offset=i, slice_size=slice_size)
|
|
239
|
+
return r
|
|
240
|
+
|
|
241
|
+
def einsum_op_slice_dim1(self, q, k, v, slice_size):
|
|
242
|
+
r = torch.zeros(q.shape[0], q.shape[1], v.shape[2], device=q.device, dtype=q.dtype)
|
|
243
|
+
for i in range(0, q.shape[1], slice_size):
|
|
244
|
+
end = i + slice_size
|
|
245
|
+
r[:, i:end] = self.einsum_lowest_level(q[:, i:end], k, v, dim=1, offset=i, slice_size=slice_size)
|
|
246
|
+
return r
|
|
247
|
+
|
|
248
|
+
def einsum_op_mps_v1(self, q, k, v):
|
|
249
|
+
if q.shape[1] <= 4096: # (512x512) max q.shape[1]: 4096
|
|
250
|
+
return self.einsum_lowest_level(q, k, v, None, None, None)
|
|
251
|
+
else:
|
|
252
|
+
slice_size = math.floor(2**30 / (q.shape[0] * q.shape[1]))
|
|
253
|
+
return self.einsum_op_slice_dim1(q, k, v, slice_size)
|
|
254
|
+
|
|
255
|
+
def einsum_op_mps_v2(self, q, k, v):
|
|
256
|
+
if self.mem_total_gb > 8 and q.shape[1] <= 4096:
|
|
257
|
+
return self.einsum_lowest_level(q, k, v, None, None, None)
|
|
258
|
+
else:
|
|
259
|
+
return self.einsum_op_slice_dim0(q, k, v, 1)
|
|
260
|
+
|
|
261
|
+
def einsum_op_tensor_mem(self, q, k, v, max_tensor_mb):
|
|
262
|
+
size_mb = q.shape[0] * q.shape[1] * k.shape[1] * q.element_size() // (1 << 20)
|
|
263
|
+
if size_mb <= max_tensor_mb:
|
|
264
|
+
return self.einsum_lowest_level(q, k, v, None, None, None)
|
|
265
|
+
div = 1 << int((size_mb - 1) / max_tensor_mb).bit_length()
|
|
266
|
+
if div <= q.shape[0]:
|
|
267
|
+
return self.einsum_op_slice_dim0(q, k, v, q.shape[0] // div)
|
|
268
|
+
return self.einsum_op_slice_dim1(q, k, v, max(q.shape[1] // div, 1))
|
|
269
|
+
|
|
270
|
+
def einsum_op_cuda(self, q, k, v):
|
|
271
|
+
# check if we already have a slicing strategy (this should only happen during cross-attention controlled generation)
|
|
272
|
+
slicing_strategy_getter = self.slicing_strategy_getter
|
|
273
|
+
if slicing_strategy_getter is not None:
|
|
274
|
+
(dim, slice_size) = slicing_strategy_getter(self)
|
|
275
|
+
if dim is not None:
|
|
276
|
+
# print("using saved slicing strategy with dim", dim, "slice size", slice_size)
|
|
277
|
+
if dim == 0:
|
|
278
|
+
return self.einsum_op_slice_dim0(q, k, v, slice_size)
|
|
279
|
+
elif dim == 1:
|
|
280
|
+
return self.einsum_op_slice_dim1(q, k, v, slice_size)
|
|
281
|
+
|
|
282
|
+
# fallback for when there is no saved strategy, or saved strategy does not slice
|
|
283
|
+
mem_free_total = get_mem_free_total(q.device)
|
|
284
|
+
# Divide factor of safety as there's copying and fragmentation
|
|
285
|
+
return self.einsum_op_tensor_mem(q, k, v, mem_free_total / 3.3 / (1 << 20))
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def get_invokeai_attention_mem_efficient(self, q, k, v):
|
|
289
|
+
if q.device.type == 'cuda':
|
|
290
|
+
#print("in get_attention_mem_efficient with q shape", q.shape, ", k shape", k.shape, ", free memory is", get_mem_free_total(q.device))
|
|
291
|
+
return self.einsum_op_cuda(q, k, v)
|
|
292
|
+
|
|
293
|
+
if q.device.type == 'mps' or q.device.type == 'cpu':
|
|
294
|
+
if self.mem_total_gb >= 32:
|
|
295
|
+
return self.einsum_op_mps_v1(q, k, v)
|
|
296
|
+
return self.einsum_op_mps_v2(q, k, v)
|
|
297
|
+
|
|
298
|
+
# Smaller slices are faster due to L2/L3/SLC caches.
|
|
299
|
+
# Tested on i7 with 8MB L3 cache.
|
|
300
|
+
return self.einsum_op_tensor_mem(q, k, v, 32)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def remove_cross_attention_control(model):
|
|
305
|
+
remove_attention_function(model)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def setup_cross_attention_control(model, context: Context):
|
|
309
|
+
"""
|
|
310
|
+
Inject attention parameters and functions into the passed in model to enable cross attention editing.
|
|
311
|
+
|
|
312
|
+
:param model: The unet model to inject into.
|
|
313
|
+
:param cross_attention_control_args: Arugments passeed to the CrossAttentionControl implementations
|
|
314
|
+
:return: None
|
|
315
|
+
"""
|
|
316
|
+
|
|
317
|
+
# adapted from init_attention_edit
|
|
318
|
+
device = context.arguments.edited_conditioning.device
|
|
319
|
+
|
|
320
|
+
# urgh. should this be hardcoded?
|
|
321
|
+
max_length = 77
|
|
322
|
+
# mask=1 means use base prompt attention, mask=0 means use edited prompt attention
|
|
323
|
+
mask = torch.zeros(max_length)
|
|
324
|
+
indices_target = torch.arange(max_length, dtype=torch.long)
|
|
325
|
+
indices = torch.arange(max_length, dtype=torch.long)
|
|
326
|
+
for name, a0, a1, b0, b1 in context.arguments.edit_opcodes:
|
|
327
|
+
if b0 < max_length:
|
|
328
|
+
if name == "equal":# or (name == "replace" and a1 - a0 == b1 - b0):
|
|
329
|
+
# these tokens have not been edited
|
|
330
|
+
indices[b0:b1] = indices_target[a0:a1]
|
|
331
|
+
mask[b0:b1] = 1
|
|
332
|
+
|
|
333
|
+
context.register_cross_attention_modules(model)
|
|
334
|
+
context.cross_attention_mask = mask.to(device)
|
|
335
|
+
context.cross_attention_index_map = indices.to(device)
|
|
336
|
+
inject_attention_function(model, context)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def get_cross_attention_modules(model, which: CrossAttentionType) -> list[tuple[str, InvokeAICrossAttentionMixin]]:
|
|
340
|
+
cross_attention_class: type = InvokeAICrossAttentionMixin
|
|
341
|
+
# cross_attention_class: type = InvokeAIDiffusersCrossAttention
|
|
342
|
+
which_attn = "attn1" if which is CrossAttentionType.SELF else "attn2"
|
|
343
|
+
attention_module_tuples = [(name,module) for name, module in model.named_modules() if
|
|
344
|
+
isinstance(module, cross_attention_class) and which_attn in name]
|
|
345
|
+
cross_attention_modules_in_model_count = len(attention_module_tuples)
|
|
346
|
+
expected_count = 16
|
|
347
|
+
if cross_attention_modules_in_model_count != expected_count:
|
|
348
|
+
# non-fatal error but .swap() won't work.
|
|
349
|
+
print(f"Error! CrossAttentionControl found an unexpected number of {cross_attention_class} modules in the model " +
|
|
350
|
+
f"(expected {expected_count}, found {cross_attention_modules_in_model_count}). Either monkey-patching failed " +
|
|
351
|
+
f"or some assumption has changed about the structure of the model itself. Please fix the monkey-patching, " +
|
|
352
|
+
f"and/or update the {expected_count} above to an appropriate number, and/or find and inform someone who knows " +
|
|
353
|
+
f"what it means. This error is non-fatal, but it is likely that .swap() and attention map display will not " +
|
|
354
|
+
f"work properly until it is fixed.")
|
|
355
|
+
return attention_module_tuples
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def inject_attention_function(unet, context: Context):
|
|
359
|
+
# ORIGINAL SOURCE CODE: https://github.com/huggingface/diffusers/blob/91ddd2a25b848df0fa1262d4f1cd98c7ccb87750/src/diffusers/models/attention.py#L276
|
|
360
|
+
|
|
361
|
+
def attention_slice_wrangler(module, suggested_attention_slice:torch.Tensor, dim, offset, slice_size):
|
|
362
|
+
|
|
363
|
+
#memory_usage = suggested_attention_slice.element_size() * suggested_attention_slice.nelement()
|
|
364
|
+
|
|
365
|
+
attention_slice = suggested_attention_slice
|
|
366
|
+
|
|
367
|
+
if context.get_should_save_maps(module.identifier):
|
|
368
|
+
#print(module.identifier, "saving suggested_attention_slice of shape",
|
|
369
|
+
# suggested_attention_slice.shape, "dim", dim, "offset", offset)
|
|
370
|
+
slice_to_save = attention_slice.to('cpu') if dim is not None else attention_slice
|
|
371
|
+
context.save_slice(module.identifier, slice_to_save, dim=dim, offset=offset, slice_size=slice_size)
|
|
372
|
+
elif context.get_should_apply_saved_maps(module.identifier):
|
|
373
|
+
#print(module.identifier, "applying saved attention slice for dim", dim, "offset", offset)
|
|
374
|
+
saved_attention_slice = context.get_slice(module.identifier, dim, offset, slice_size)
|
|
375
|
+
|
|
376
|
+
# slice may have been offloaded to CPU
|
|
377
|
+
saved_attention_slice = saved_attention_slice.to(suggested_attention_slice.device)
|
|
378
|
+
|
|
379
|
+
if context.is_tokens_cross_attention(module.identifier):
|
|
380
|
+
index_map = context.cross_attention_index_map
|
|
381
|
+
remapped_saved_attention_slice = torch.index_select(saved_attention_slice, -1, index_map)
|
|
382
|
+
this_attention_slice = suggested_attention_slice
|
|
383
|
+
|
|
384
|
+
mask = context.cross_attention_mask
|
|
385
|
+
saved_mask = mask
|
|
386
|
+
this_mask = 1 - mask
|
|
387
|
+
attention_slice = remapped_saved_attention_slice * saved_mask + \
|
|
388
|
+
this_attention_slice * this_mask
|
|
389
|
+
else:
|
|
390
|
+
# just use everything
|
|
391
|
+
attention_slice = saved_attention_slice
|
|
392
|
+
|
|
393
|
+
return attention_slice
|
|
394
|
+
|
|
395
|
+
cross_attention_modules = get_cross_attention_modules(unet, CrossAttentionType.TOKENS) + get_cross_attention_modules(unet, CrossAttentionType.SELF)
|
|
396
|
+
for identifier, module in cross_attention_modules:
|
|
397
|
+
module.identifier = identifier
|
|
398
|
+
try:
|
|
399
|
+
module.set_attention_slice_wrangler(attention_slice_wrangler)
|
|
400
|
+
module.set_slicing_strategy_getter(
|
|
401
|
+
lambda module: context.get_slicing_strategy(identifier)
|
|
402
|
+
)
|
|
403
|
+
except AttributeError as e:
|
|
404
|
+
if is_attribute_error_about(e, 'set_attention_slice_wrangler'):
|
|
405
|
+
print(f"TODO: implement set_attention_slice_wrangler for {type(module)}") # TODO
|
|
406
|
+
else:
|
|
407
|
+
raise
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def remove_attention_function(unet):
|
|
411
|
+
cross_attention_modules = get_cross_attention_modules(unet, CrossAttentionType.TOKENS) + get_cross_attention_modules(unet, CrossAttentionType.SELF)
|
|
412
|
+
for identifier, module in cross_attention_modules:
|
|
413
|
+
try:
|
|
414
|
+
# clear wrangler callback
|
|
415
|
+
module.set_attention_slice_wrangler(None)
|
|
416
|
+
module.set_slicing_strategy_getter(None)
|
|
417
|
+
except AttributeError as e:
|
|
418
|
+
if is_attribute_error_about(e, 'set_attention_slice_wrangler'):
|
|
419
|
+
print(f"TODO: implement set_attention_slice_wrangler for {type(module)}")
|
|
420
|
+
else:
|
|
421
|
+
raise
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def is_attribute_error_about(error: AttributeError, attribute: str):
|
|
425
|
+
if hasattr(error, 'name'): # Python 3.10
|
|
426
|
+
return error.name == attribute
|
|
427
|
+
else: # Python 3.9
|
|
428
|
+
return attribute in str(error)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def get_mem_free_total(device):
|
|
433
|
+
#only on cuda
|
|
434
|
+
if not torch.cuda.is_available():
|
|
435
|
+
return None
|
|
436
|
+
stats = torch.cuda.memory_stats(device)
|
|
437
|
+
mem_active = stats['active_bytes.all.current']
|
|
438
|
+
mem_reserved = stats['reserved_bytes.all.current']
|
|
439
|
+
mem_free_cuda, _ = torch.cuda.mem_get_info(device)
|
|
440
|
+
mem_free_torch = mem_reserved - mem_active
|
|
441
|
+
mem_free_total = mem_free_cuda + mem_free_torch
|
|
442
|
+
return mem_free_total
|
|
443
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import PIL
|
|
4
|
+
import torch
|
|
5
|
+
from torchvision.transforms.functional import resize as tv_resize, InterpolationMode
|
|
6
|
+
|
|
7
|
+
from ldm.models.diffusion.cross_attention_control import get_cross_attention_modules, CrossAttentionType
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AttentionMapSaver():
|
|
11
|
+
|
|
12
|
+
def __init__(self, token_ids: range, latents_shape: torch.Size):
|
|
13
|
+
self.token_ids = token_ids
|
|
14
|
+
self.latents_shape = latents_shape
|
|
15
|
+
#self.collated_maps = #torch.zeros([len(token_ids), latents_shape[0], latents_shape[1]])
|
|
16
|
+
self.collated_maps = {}
|
|
17
|
+
|
|
18
|
+
def clear_maps(self):
|
|
19
|
+
self.collated_maps = {}
|
|
20
|
+
|
|
21
|
+
def add_attention_maps(self, maps: torch.Tensor, key: str):
|
|
22
|
+
"""
|
|
23
|
+
Accumulate the given attention maps and store by summing with existing maps at the passed-in key (if any).
|
|
24
|
+
:param maps: Attention maps to store. Expected shape [A, (H*W), N] where A is attention heads count, H and W are the map size (fixed per-key) and N is the number of tokens (typically 77).
|
|
25
|
+
:param key: Storage key. If a map already exists for this key it will be summed with the incoming data. In this case the maps sizes (H and W) should match.
|
|
26
|
+
:return: None
|
|
27
|
+
"""
|
|
28
|
+
key_and_size = f'{key}_{maps.shape[1]}'
|
|
29
|
+
|
|
30
|
+
# extract desired tokens
|
|
31
|
+
maps = maps[:, :, self.token_ids]
|
|
32
|
+
|
|
33
|
+
# merge attention heads to a single map per token
|
|
34
|
+
maps = torch.sum(maps, 0)
|
|
35
|
+
|
|
36
|
+
# store
|
|
37
|
+
if key_and_size not in self.collated_maps:
|
|
38
|
+
self.collated_maps[key_and_size] = torch.zeros_like(maps, device='cpu')
|
|
39
|
+
self.collated_maps[key_and_size] += maps.cpu()
|
|
40
|
+
|
|
41
|
+
def write_maps_to_disk(self, path: str):
|
|
42
|
+
pil_image = self.get_stacked_maps_image()
|
|
43
|
+
pil_image.save(path, 'PNG')
|
|
44
|
+
|
|
45
|
+
def get_stacked_maps_image(self) -> PIL.Image:
|
|
46
|
+
"""
|
|
47
|
+
Scale all collected attention maps to the same size, blend them together and return as an image.
|
|
48
|
+
:return: An image containing a vertical stack of blended attention maps, one for each requested token.
|
|
49
|
+
"""
|
|
50
|
+
num_tokens = len(self.token_ids)
|
|
51
|
+
if num_tokens == 0:
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
latents_height = self.latents_shape[0]
|
|
55
|
+
latents_width = self.latents_shape[1]
|
|
56
|
+
|
|
57
|
+
merged = None
|
|
58
|
+
|
|
59
|
+
for key, maps in self.collated_maps.items():
|
|
60
|
+
|
|
61
|
+
# maps has shape [(H*W), N] for N tokens
|
|
62
|
+
# but we want [N, H, W]
|
|
63
|
+
this_scale_factor = math.sqrt(maps.shape[0] / (latents_width * latents_height))
|
|
64
|
+
this_maps_height = int(float(latents_height) * this_scale_factor)
|
|
65
|
+
this_maps_width = int(float(latents_width) * this_scale_factor)
|
|
66
|
+
# and we need to do some dimension juggling
|
|
67
|
+
maps = torch.reshape(torch.swapdims(maps, 0, 1), [num_tokens, this_maps_height, this_maps_width])
|
|
68
|
+
|
|
69
|
+
# scale to output size if necessary
|
|
70
|
+
if this_scale_factor != 1:
|
|
71
|
+
maps = tv_resize(maps, [latents_height, latents_width], InterpolationMode.BICUBIC)
|
|
72
|
+
|
|
73
|
+
# normalize
|
|
74
|
+
maps_min = torch.min(maps)
|
|
75
|
+
maps_range = torch.max(maps) - maps_min
|
|
76
|
+
#print(f"map {key} size {[this_maps_width, this_maps_height]} range {[maps_min, maps_min + maps_range]}")
|
|
77
|
+
maps_normalized = (maps - maps_min) / maps_range
|
|
78
|
+
# expand to (-0.1, 1.1) and clamp
|
|
79
|
+
maps_normalized_expanded = maps_normalized * 1.1 - 0.05
|
|
80
|
+
maps_normalized_expanded_clamped = torch.clamp(maps_normalized_expanded, 0, 1)
|
|
81
|
+
|
|
82
|
+
# merge together, producing a vertical stack
|
|
83
|
+
maps_stacked = torch.reshape(maps_normalized_expanded_clamped, [num_tokens * latents_height, latents_width])
|
|
84
|
+
|
|
85
|
+
if merged is None:
|
|
86
|
+
merged = maps_stacked
|
|
87
|
+
else:
|
|
88
|
+
# screen blend
|
|
89
|
+
merged = 1 - (1 - maps_stacked)*(1 - merged)
|
|
90
|
+
|
|
91
|
+
if merged is None:
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
merged_bytes = merged.mul(0xff).byte()
|
|
95
|
+
return PIL.Image.fromarray(merged_bytes.numpy(), mode='L')
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""SAMPLING ONLY."""
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
from ldm.models.diffusion.shared_invokeai_diffusion import InvokeAIDiffuserComponent
|
|
5
|
+
from ldm.models.diffusion.sampler import Sampler
|
|
6
|
+
from ldm.modules.diffusionmodules.util import noise_like
|
|
7
|
+
|
|
8
|
+
class DDIMSampler(Sampler):
|
|
9
|
+
def __init__(self, model, schedule='linear', device=None, **kwargs):
|
|
10
|
+
super().__init__(model,schedule,model.num_timesteps,device)
|
|
11
|
+
|
|
12
|
+
self.invokeai_diffuser = InvokeAIDiffuserComponent(self.model,
|
|
13
|
+
model_forward_callback = lambda x, sigma, cond: self.model.apply_model(x, sigma, cond))
|
|
14
|
+
|
|
15
|
+
def prepare_to_sample(self, t_enc, **kwargs):
|
|
16
|
+
super().prepare_to_sample(t_enc, **kwargs)
|
|
17
|
+
|
|
18
|
+
extra_conditioning_info = kwargs.get('extra_conditioning_info', None)
|
|
19
|
+
all_timesteps_count = kwargs.get('all_timesteps_count', t_enc)
|
|
20
|
+
|
|
21
|
+
if extra_conditioning_info is not None and extra_conditioning_info.wants_cross_attention_control:
|
|
22
|
+
self.invokeai_diffuser.setup_cross_attention_control(extra_conditioning_info, step_count = all_timesteps_count)
|
|
23
|
+
else:
|
|
24
|
+
self.invokeai_diffuser.remove_cross_attention_control()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# This is the central routine
|
|
28
|
+
@torch.no_grad()
|
|
29
|
+
def p_sample(
|
|
30
|
+
self,
|
|
31
|
+
x,
|
|
32
|
+
c,
|
|
33
|
+
t,
|
|
34
|
+
index,
|
|
35
|
+
repeat_noise=False,
|
|
36
|
+
use_original_steps=False,
|
|
37
|
+
quantize_denoised=False,
|
|
38
|
+
temperature=1.0,
|
|
39
|
+
noise_dropout=0.0,
|
|
40
|
+
score_corrector=None,
|
|
41
|
+
corrector_kwargs=None,
|
|
42
|
+
unconditional_guidance_scale=1.0,
|
|
43
|
+
unconditional_conditioning=None,
|
|
44
|
+
step_count:int=1000, # total number of steps
|
|
45
|
+
**kwargs,
|
|
46
|
+
):
|
|
47
|
+
b, *_, device = *x.shape, x.device
|
|
48
|
+
|
|
49
|
+
if (
|
|
50
|
+
unconditional_conditioning is None
|
|
51
|
+
or unconditional_guidance_scale == 1.0
|
|
52
|
+
):
|
|
53
|
+
# damian0815 would like to know when/if this code path is used
|
|
54
|
+
e_t = self.model.apply_model(x, t, c)
|
|
55
|
+
else:
|
|
56
|
+
# step_index counts in the opposite direction to index
|
|
57
|
+
step_index = step_count-(index+1)
|
|
58
|
+
e_t = self.invokeai_diffuser.do_diffusion_step(
|
|
59
|
+
x, t,
|
|
60
|
+
unconditional_conditioning, c,
|
|
61
|
+
unconditional_guidance_scale,
|
|
62
|
+
step_index=step_index
|
|
63
|
+
)
|
|
64
|
+
if score_corrector is not None:
|
|
65
|
+
assert self.model.parameterization == 'eps'
|
|
66
|
+
e_t = score_corrector.modify_score(
|
|
67
|
+
self.model, e_t, x, t, c, **corrector_kwargs
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
alphas = (
|
|
71
|
+
self.model.alphas_cumprod
|
|
72
|
+
if use_original_steps
|
|
73
|
+
else self.ddim_alphas
|
|
74
|
+
)
|
|
75
|
+
alphas_prev = (
|
|
76
|
+
self.model.alphas_cumprod_prev
|
|
77
|
+
if use_original_steps
|
|
78
|
+
else self.ddim_alphas_prev
|
|
79
|
+
)
|
|
80
|
+
sqrt_one_minus_alphas = (
|
|
81
|
+
self.model.sqrt_one_minus_alphas_cumprod
|
|
82
|
+
if use_original_steps
|
|
83
|
+
else self.ddim_sqrt_one_minus_alphas
|
|
84
|
+
)
|
|
85
|
+
sigmas = (
|
|
86
|
+
self.model.ddim_sigmas_for_original_num_steps
|
|
87
|
+
if use_original_steps
|
|
88
|
+
else self.ddim_sigmas
|
|
89
|
+
)
|
|
90
|
+
# select parameters corresponding to the currently considered timestep
|
|
91
|
+
a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
|
|
92
|
+
a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
|
|
93
|
+
sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
|
|
94
|
+
sqrt_one_minus_at = torch.full(
|
|
95
|
+
(b, 1, 1, 1), sqrt_one_minus_alphas[index], device=device
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# current prediction for x_0
|
|
99
|
+
pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt()
|
|
100
|
+
if quantize_denoised:
|
|
101
|
+
pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0)
|
|
102
|
+
# direction pointing to x_t
|
|
103
|
+
dir_xt = (1.0 - a_prev - sigma_t**2).sqrt() * e_t
|
|
104
|
+
noise = (
|
|
105
|
+
sigma_t * noise_like(x.shape, device, repeat_noise) * temperature
|
|
106
|
+
)
|
|
107
|
+
if noise_dropout > 0.0:
|
|
108
|
+
noise = torch.nn.functional.dropout(noise, p=noise_dropout)
|
|
109
|
+
x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise
|
|
110
|
+
return x_prev, pred_x0, None
|
|
111
|
+
|