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,276 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import numpy as np
|
|
3
|
+
import torch
|
|
4
|
+
from torch import nn, Tensor
|
|
5
|
+
import torch.nn.functional as F
|
|
6
|
+
from typing import Optional, List
|
|
7
|
+
|
|
8
|
+
from ldm.invoke.restoration.vqgan_arch import *
|
|
9
|
+
from basicsr.utils import get_root_logger
|
|
10
|
+
from basicsr.utils.registry import ARCH_REGISTRY
|
|
11
|
+
|
|
12
|
+
def calc_mean_std(feat, eps=1e-5):
|
|
13
|
+
"""Calculate mean and std for adaptive_instance_normalization.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
feat (Tensor): 4D tensor.
|
|
17
|
+
eps (float): A small value added to the variance to avoid
|
|
18
|
+
divide-by-zero. Default: 1e-5.
|
|
19
|
+
"""
|
|
20
|
+
size = feat.size()
|
|
21
|
+
assert len(size) == 4, 'The input feature should be 4D tensor.'
|
|
22
|
+
b, c = size[:2]
|
|
23
|
+
feat_var = feat.view(b, c, -1).var(dim=2) + eps
|
|
24
|
+
feat_std = feat_var.sqrt().view(b, c, 1, 1)
|
|
25
|
+
feat_mean = feat.view(b, c, -1).mean(dim=2).view(b, c, 1, 1)
|
|
26
|
+
return feat_mean, feat_std
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def adaptive_instance_normalization(content_feat, style_feat):
|
|
30
|
+
"""Adaptive instance normalization.
|
|
31
|
+
|
|
32
|
+
Adjust the reference features to have the similar color and illuminations
|
|
33
|
+
as those in the degradate features.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
content_feat (Tensor): The reference feature.
|
|
37
|
+
style_feat (Tensor): The degradate features.
|
|
38
|
+
"""
|
|
39
|
+
size = content_feat.size()
|
|
40
|
+
style_mean, style_std = calc_mean_std(style_feat)
|
|
41
|
+
content_mean, content_std = calc_mean_std(content_feat)
|
|
42
|
+
normalized_feat = (content_feat - content_mean.expand(size)) / content_std.expand(size)
|
|
43
|
+
return normalized_feat * style_std.expand(size) + style_mean.expand(size)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class PositionEmbeddingSine(nn.Module):
|
|
47
|
+
"""
|
|
48
|
+
This is a more standard version of the position embedding, very similar to the one
|
|
49
|
+
used by the Attention is all you need paper, generalized to work on images.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None):
|
|
53
|
+
super().__init__()
|
|
54
|
+
self.num_pos_feats = num_pos_feats
|
|
55
|
+
self.temperature = temperature
|
|
56
|
+
self.normalize = normalize
|
|
57
|
+
if scale is not None and normalize is False:
|
|
58
|
+
raise ValueError("normalize should be True if scale is passed")
|
|
59
|
+
if scale is None:
|
|
60
|
+
scale = 2 * math.pi
|
|
61
|
+
self.scale = scale
|
|
62
|
+
|
|
63
|
+
def forward(self, x, mask=None):
|
|
64
|
+
if mask is None:
|
|
65
|
+
mask = torch.zeros((x.size(0), x.size(2), x.size(3)), device=x.device, dtype=torch.bool)
|
|
66
|
+
not_mask = ~mask
|
|
67
|
+
y_embed = not_mask.cumsum(1, dtype=torch.float32)
|
|
68
|
+
x_embed = not_mask.cumsum(2, dtype=torch.float32)
|
|
69
|
+
if self.normalize:
|
|
70
|
+
eps = 1e-6
|
|
71
|
+
y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale
|
|
72
|
+
x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale
|
|
73
|
+
|
|
74
|
+
dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device)
|
|
75
|
+
dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats)
|
|
76
|
+
|
|
77
|
+
pos_x = x_embed[:, :, :, None] / dim_t
|
|
78
|
+
pos_y = y_embed[:, :, :, None] / dim_t
|
|
79
|
+
pos_x = torch.stack(
|
|
80
|
+
(pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4
|
|
81
|
+
).flatten(3)
|
|
82
|
+
pos_y = torch.stack(
|
|
83
|
+
(pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4
|
|
84
|
+
).flatten(3)
|
|
85
|
+
pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2)
|
|
86
|
+
return pos
|
|
87
|
+
|
|
88
|
+
def _get_activation_fn(activation):
|
|
89
|
+
"""Return an activation function given a string"""
|
|
90
|
+
if activation == "relu":
|
|
91
|
+
return F.relu
|
|
92
|
+
if activation == "gelu":
|
|
93
|
+
return F.gelu
|
|
94
|
+
if activation == "glu":
|
|
95
|
+
return F.glu
|
|
96
|
+
raise RuntimeError(F"activation should be relu/gelu, not {activation}.")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class TransformerSALayer(nn.Module):
|
|
100
|
+
def __init__(self, embed_dim, nhead=8, dim_mlp=2048, dropout=0.0, activation="gelu"):
|
|
101
|
+
super().__init__()
|
|
102
|
+
self.self_attn = nn.MultiheadAttention(embed_dim, nhead, dropout=dropout)
|
|
103
|
+
# Implementation of Feedforward model - MLP
|
|
104
|
+
self.linear1 = nn.Linear(embed_dim, dim_mlp)
|
|
105
|
+
self.dropout = nn.Dropout(dropout)
|
|
106
|
+
self.linear2 = nn.Linear(dim_mlp, embed_dim)
|
|
107
|
+
|
|
108
|
+
self.norm1 = nn.LayerNorm(embed_dim)
|
|
109
|
+
self.norm2 = nn.LayerNorm(embed_dim)
|
|
110
|
+
self.dropout1 = nn.Dropout(dropout)
|
|
111
|
+
self.dropout2 = nn.Dropout(dropout)
|
|
112
|
+
|
|
113
|
+
self.activation = _get_activation_fn(activation)
|
|
114
|
+
|
|
115
|
+
def with_pos_embed(self, tensor, pos: Optional[Tensor]):
|
|
116
|
+
return tensor if pos is None else tensor + pos
|
|
117
|
+
|
|
118
|
+
def forward(self, tgt,
|
|
119
|
+
tgt_mask: Optional[Tensor] = None,
|
|
120
|
+
tgt_key_padding_mask: Optional[Tensor] = None,
|
|
121
|
+
query_pos: Optional[Tensor] = None):
|
|
122
|
+
|
|
123
|
+
# self attention
|
|
124
|
+
tgt2 = self.norm1(tgt)
|
|
125
|
+
q = k = self.with_pos_embed(tgt2, query_pos)
|
|
126
|
+
tgt2 = self.self_attn(q, k, value=tgt2, attn_mask=tgt_mask,
|
|
127
|
+
key_padding_mask=tgt_key_padding_mask)[0]
|
|
128
|
+
tgt = tgt + self.dropout1(tgt2)
|
|
129
|
+
|
|
130
|
+
# ffn
|
|
131
|
+
tgt2 = self.norm2(tgt)
|
|
132
|
+
tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2))))
|
|
133
|
+
tgt = tgt + self.dropout2(tgt2)
|
|
134
|
+
return tgt
|
|
135
|
+
|
|
136
|
+
class Fuse_sft_block(nn.Module):
|
|
137
|
+
def __init__(self, in_ch, out_ch):
|
|
138
|
+
super().__init__()
|
|
139
|
+
self.encode_enc = ResBlock(2*in_ch, out_ch)
|
|
140
|
+
|
|
141
|
+
self.scale = nn.Sequential(
|
|
142
|
+
nn.Conv2d(in_ch, out_ch, kernel_size=3, padding=1),
|
|
143
|
+
nn.LeakyReLU(0.2, True),
|
|
144
|
+
nn.Conv2d(out_ch, out_ch, kernel_size=3, padding=1))
|
|
145
|
+
|
|
146
|
+
self.shift = nn.Sequential(
|
|
147
|
+
nn.Conv2d(in_ch, out_ch, kernel_size=3, padding=1),
|
|
148
|
+
nn.LeakyReLU(0.2, True),
|
|
149
|
+
nn.Conv2d(out_ch, out_ch, kernel_size=3, padding=1))
|
|
150
|
+
|
|
151
|
+
def forward(self, enc_feat, dec_feat, w=1):
|
|
152
|
+
enc_feat = self.encode_enc(torch.cat([enc_feat, dec_feat], dim=1))
|
|
153
|
+
scale = self.scale(enc_feat)
|
|
154
|
+
shift = self.shift(enc_feat)
|
|
155
|
+
residual = w * (dec_feat * scale + shift)
|
|
156
|
+
out = dec_feat + residual
|
|
157
|
+
return out
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@ARCH_REGISTRY.register()
|
|
161
|
+
class CodeFormer(VQAutoEncoder):
|
|
162
|
+
def __init__(self, dim_embd=512, n_head=8, n_layers=9,
|
|
163
|
+
codebook_size=1024, latent_size=256,
|
|
164
|
+
connect_list=['32', '64', '128', '256'],
|
|
165
|
+
fix_modules=['quantize','generator']):
|
|
166
|
+
super(CodeFormer, self).__init__(512, 64, [1, 2, 2, 4, 4, 8], 'nearest',2, [16], codebook_size)
|
|
167
|
+
|
|
168
|
+
if fix_modules is not None:
|
|
169
|
+
for module in fix_modules:
|
|
170
|
+
for param in getattr(self, module).parameters():
|
|
171
|
+
param.requires_grad = False
|
|
172
|
+
|
|
173
|
+
self.connect_list = connect_list
|
|
174
|
+
self.n_layers = n_layers
|
|
175
|
+
self.dim_embd = dim_embd
|
|
176
|
+
self.dim_mlp = dim_embd*2
|
|
177
|
+
|
|
178
|
+
self.position_emb = nn.Parameter(torch.zeros(latent_size, self.dim_embd))
|
|
179
|
+
self.feat_emb = nn.Linear(256, self.dim_embd)
|
|
180
|
+
|
|
181
|
+
# transformer
|
|
182
|
+
self.ft_layers = nn.Sequential(*[TransformerSALayer(embed_dim=dim_embd, nhead=n_head, dim_mlp=self.dim_mlp, dropout=0.0)
|
|
183
|
+
for _ in range(self.n_layers)])
|
|
184
|
+
|
|
185
|
+
# logits_predict head
|
|
186
|
+
self.idx_pred_layer = nn.Sequential(
|
|
187
|
+
nn.LayerNorm(dim_embd),
|
|
188
|
+
nn.Linear(dim_embd, codebook_size, bias=False))
|
|
189
|
+
|
|
190
|
+
self.channels = {
|
|
191
|
+
'16': 512,
|
|
192
|
+
'32': 256,
|
|
193
|
+
'64': 256,
|
|
194
|
+
'128': 128,
|
|
195
|
+
'256': 128,
|
|
196
|
+
'512': 64,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
# after second residual block for > 16, before attn layer for ==16
|
|
200
|
+
self.fuse_encoder_block = {'512':2, '256':5, '128':8, '64':11, '32':14, '16':18}
|
|
201
|
+
# after first residual block for > 16, before attn layer for ==16
|
|
202
|
+
self.fuse_generator_block = {'16':6, '32': 9, '64':12, '128':15, '256':18, '512':21}
|
|
203
|
+
|
|
204
|
+
# fuse_convs_dict
|
|
205
|
+
self.fuse_convs_dict = nn.ModuleDict()
|
|
206
|
+
for f_size in self.connect_list:
|
|
207
|
+
in_ch = self.channels[f_size]
|
|
208
|
+
self.fuse_convs_dict[f_size] = Fuse_sft_block(in_ch, in_ch)
|
|
209
|
+
|
|
210
|
+
def _init_weights(self, module):
|
|
211
|
+
if isinstance(module, (nn.Linear, nn.Embedding)):
|
|
212
|
+
module.weight.data.normal_(mean=0.0, std=0.02)
|
|
213
|
+
if isinstance(module, nn.Linear) and module.bias is not None:
|
|
214
|
+
module.bias.data.zero_()
|
|
215
|
+
elif isinstance(module, nn.LayerNorm):
|
|
216
|
+
module.bias.data.zero_()
|
|
217
|
+
module.weight.data.fill_(1.0)
|
|
218
|
+
|
|
219
|
+
def forward(self, x, w=0, detach_16=True, code_only=False, adain=False):
|
|
220
|
+
# ################### Encoder #####################
|
|
221
|
+
enc_feat_dict = {}
|
|
222
|
+
out_list = [self.fuse_encoder_block[f_size] for f_size in self.connect_list]
|
|
223
|
+
for i, block in enumerate(self.encoder.blocks):
|
|
224
|
+
x = block(x)
|
|
225
|
+
if i in out_list:
|
|
226
|
+
enc_feat_dict[str(x.shape[-1])] = x.clone()
|
|
227
|
+
|
|
228
|
+
lq_feat = x
|
|
229
|
+
# ################# Transformer ###################
|
|
230
|
+
# quant_feat, codebook_loss, quant_stats = self.quantize(lq_feat)
|
|
231
|
+
pos_emb = self.position_emb.unsqueeze(1).repeat(1,x.shape[0],1)
|
|
232
|
+
# BCHW -> BC(HW) -> (HW)BC
|
|
233
|
+
feat_emb = self.feat_emb(lq_feat.flatten(2).permute(2,0,1))
|
|
234
|
+
query_emb = feat_emb
|
|
235
|
+
# Transformer encoder
|
|
236
|
+
for layer in self.ft_layers:
|
|
237
|
+
query_emb = layer(query_emb, query_pos=pos_emb)
|
|
238
|
+
|
|
239
|
+
# output logits
|
|
240
|
+
logits = self.idx_pred_layer(query_emb) # (hw)bn
|
|
241
|
+
logits = logits.permute(1,0,2) # (hw)bn -> b(hw)n
|
|
242
|
+
|
|
243
|
+
if code_only: # for training stage II
|
|
244
|
+
# logits doesn't need softmax before cross_entropy loss
|
|
245
|
+
return logits, lq_feat
|
|
246
|
+
|
|
247
|
+
# ################# Quantization ###################
|
|
248
|
+
# if self.training:
|
|
249
|
+
# quant_feat = torch.einsum('btn,nc->btc', [soft_one_hot, self.quantize.embedding.weight])
|
|
250
|
+
# # b(hw)c -> bc(hw) -> bchw
|
|
251
|
+
# quant_feat = quant_feat.permute(0,2,1).view(lq_feat.shape)
|
|
252
|
+
# ------------
|
|
253
|
+
soft_one_hot = F.softmax(logits, dim=2)
|
|
254
|
+
_, top_idx = torch.topk(soft_one_hot, 1, dim=2)
|
|
255
|
+
quant_feat = self.quantize.get_codebook_feat(top_idx, shape=[x.shape[0],16,16,256])
|
|
256
|
+
# preserve gradients
|
|
257
|
+
# quant_feat = lq_feat + (quant_feat - lq_feat).detach()
|
|
258
|
+
|
|
259
|
+
if detach_16:
|
|
260
|
+
quant_feat = quant_feat.detach() # for training stage III
|
|
261
|
+
if adain:
|
|
262
|
+
quant_feat = adaptive_instance_normalization(quant_feat, lq_feat)
|
|
263
|
+
|
|
264
|
+
# ################## Generator ####################
|
|
265
|
+
x = quant_feat
|
|
266
|
+
fuse_list = [self.fuse_generator_block[f_size] for f_size in self.connect_list]
|
|
267
|
+
|
|
268
|
+
for i, block in enumerate(self.generator.blocks):
|
|
269
|
+
x = block(x)
|
|
270
|
+
if i in fuse_list: # fuse after i-th block
|
|
271
|
+
f_size = str(x.shape[-1])
|
|
272
|
+
if w>0:
|
|
273
|
+
x = self.fuse_convs_dict[f_size](enc_feat_dict[f_size].detach(), x, w)
|
|
274
|
+
out = x
|
|
275
|
+
# logits doesn't need softmax before cross_entropy loss
|
|
276
|
+
return out, logits, lq_feat
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
import warnings
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import numpy as np
|
|
6
|
+
from ldm.invoke.globals import Globals
|
|
7
|
+
|
|
8
|
+
from PIL import Image
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GFPGAN():
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
gfpgan_model_path='models/gfpgan/GFPGANv1.4.pth'
|
|
15
|
+
) -> None:
|
|
16
|
+
|
|
17
|
+
if not os.path.isabs(gfpgan_model_path):
|
|
18
|
+
gfpgan_model_path=os.path.abspath(os.path.join(Globals.root,gfpgan_model_path))
|
|
19
|
+
self.model_path = gfpgan_model_path
|
|
20
|
+
self.gfpgan_model_exists = os.path.isfile(self.model_path)
|
|
21
|
+
|
|
22
|
+
if not self.gfpgan_model_exists:
|
|
23
|
+
print('## NOT FOUND: GFPGAN model not found at ' + self.model_path)
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
def model_exists(self):
|
|
27
|
+
return os.path.isfile(self.model_path)
|
|
28
|
+
|
|
29
|
+
def process(self, image, strength: float, seed: str = None):
|
|
30
|
+
if seed is not None:
|
|
31
|
+
print(f'>> GFPGAN - Restoring Faces for image seed:{seed}')
|
|
32
|
+
|
|
33
|
+
with warnings.catch_warnings():
|
|
34
|
+
warnings.filterwarnings('ignore', category=DeprecationWarning)
|
|
35
|
+
warnings.filterwarnings('ignore', category=UserWarning)
|
|
36
|
+
try:
|
|
37
|
+
from gfpgan import GFPGANer
|
|
38
|
+
self.gfpgan = GFPGANer(
|
|
39
|
+
model_path=self.model_path,
|
|
40
|
+
upscale=1,
|
|
41
|
+
arch='clean',
|
|
42
|
+
channel_multiplier=2,
|
|
43
|
+
bg_upsampler=None,
|
|
44
|
+
)
|
|
45
|
+
except Exception:
|
|
46
|
+
import traceback
|
|
47
|
+
print('>> Error loading GFPGAN:', file=sys.stderr)
|
|
48
|
+
print(traceback.format_exc(), file=sys.stderr)
|
|
49
|
+
|
|
50
|
+
if self.gfpgan is None:
|
|
51
|
+
print(
|
|
52
|
+
f'>> WARNING: GFPGAN not initialized.'
|
|
53
|
+
)
|
|
54
|
+
print(
|
|
55
|
+
f'>> Download https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth to {self.model_path}'
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
image = image.convert('RGB')
|
|
59
|
+
|
|
60
|
+
# GFPGAN expects a BGR np array; make array and flip channels
|
|
61
|
+
bgr_image_array = np.array(image, dtype=np.uint8)[...,::-1]
|
|
62
|
+
|
|
63
|
+
_, _, restored_img = self.gfpgan.enhance(
|
|
64
|
+
bgr_image_array,
|
|
65
|
+
has_aligned=False,
|
|
66
|
+
only_center_face=False,
|
|
67
|
+
paste_back=True,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Flip the channels back to RGB
|
|
71
|
+
res = Image.fromarray(restored_img[...,::-1])
|
|
72
|
+
|
|
73
|
+
if strength < 1.0:
|
|
74
|
+
# Resize the image to the new image if the sizes have changed
|
|
75
|
+
if restored_img.size != image.size:
|
|
76
|
+
image = image.resize(res.size)
|
|
77
|
+
res = Image.blend(image, res, strength)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if torch.cuda.is_available():
|
|
81
|
+
torch.cuda.empty_cache()
|
|
82
|
+
self.gfpgan = None
|
|
83
|
+
|
|
84
|
+
return res
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
import math
|
|
3
|
+
from PIL import Image, ImageFilter
|
|
4
|
+
|
|
5
|
+
class Outcrop(object):
|
|
6
|
+
def __init__(
|
|
7
|
+
self,
|
|
8
|
+
image,
|
|
9
|
+
generate, # current generate object
|
|
10
|
+
):
|
|
11
|
+
self.image = image
|
|
12
|
+
self.generate = generate
|
|
13
|
+
|
|
14
|
+
def process (
|
|
15
|
+
self,
|
|
16
|
+
extents:dict,
|
|
17
|
+
opt, # current options
|
|
18
|
+
orig_opt, # ones originally used to generate the image
|
|
19
|
+
image_callback = None,
|
|
20
|
+
prefix = None
|
|
21
|
+
):
|
|
22
|
+
# grow and mask the image
|
|
23
|
+
extended_image = self._extend_all(extents)
|
|
24
|
+
|
|
25
|
+
# switch samplers temporarily
|
|
26
|
+
curr_sampler = self.generate.sampler
|
|
27
|
+
self.generate.sampler_name = opt.sampler_name
|
|
28
|
+
self.generate._set_sampler()
|
|
29
|
+
|
|
30
|
+
def wrapped_callback(img,seed,**kwargs):
|
|
31
|
+
preferred_seed = orig_opt.seed if orig_opt.seed is not None and orig_opt.seed >= 0 else seed
|
|
32
|
+
image_callback(img,preferred_seed,use_prefix=prefix,**kwargs)
|
|
33
|
+
|
|
34
|
+
result= self.generate.prompt2image(
|
|
35
|
+
opt.prompt,
|
|
36
|
+
seed = opt.seed or orig_opt.seed,
|
|
37
|
+
sampler = self.generate.sampler,
|
|
38
|
+
steps = opt.steps,
|
|
39
|
+
cfg_scale = opt.cfg_scale,
|
|
40
|
+
ddim_eta = self.generate.ddim_eta,
|
|
41
|
+
width = extended_image.width,
|
|
42
|
+
height = extended_image.height,
|
|
43
|
+
init_img = extended_image,
|
|
44
|
+
strength = 0.90,
|
|
45
|
+
image_callback = wrapped_callback if image_callback else None,
|
|
46
|
+
seam_size = opt.seam_size or 96,
|
|
47
|
+
seam_blur = opt.seam_blur or 16,
|
|
48
|
+
seam_strength = opt.seam_strength or 0.7,
|
|
49
|
+
seam_steps = 20,
|
|
50
|
+
tile_size = 32,
|
|
51
|
+
color_match = True,
|
|
52
|
+
force_outpaint = True, # this just stops the warning about erased regions
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# swap sampler back
|
|
56
|
+
self.generate.sampler = curr_sampler
|
|
57
|
+
return result
|
|
58
|
+
|
|
59
|
+
def _extend_all(
|
|
60
|
+
self,
|
|
61
|
+
extents:dict,
|
|
62
|
+
) -> Image:
|
|
63
|
+
'''
|
|
64
|
+
Extend the image in direction ('top','bottom','left','right') by
|
|
65
|
+
the indicated value. The image canvas is extended, and the empty
|
|
66
|
+
rectangular section will be filled with a blurred copy of the
|
|
67
|
+
adjacent image.
|
|
68
|
+
'''
|
|
69
|
+
image = self.image
|
|
70
|
+
for direction in extents:
|
|
71
|
+
assert direction in ['top', 'left', 'bottom', 'right'],'Direction must be one of "top", "left", "bottom", "right"'
|
|
72
|
+
pixels = extents[direction]
|
|
73
|
+
# round pixels up to the nearest 64
|
|
74
|
+
pixels = math.ceil(pixels/64) * 64
|
|
75
|
+
print(f'>> extending image {direction}ward by {pixels} pixels')
|
|
76
|
+
image = self._rotate(image,direction)
|
|
77
|
+
image = self._extend(image,pixels)
|
|
78
|
+
image = self._rotate(image,direction,reverse=True)
|
|
79
|
+
return image
|
|
80
|
+
|
|
81
|
+
def _rotate(self,image:Image,direction:str,reverse=False) -> Image:
|
|
82
|
+
'''
|
|
83
|
+
Rotates image so that the area to extend is always at the top top.
|
|
84
|
+
Simplifies logic later. The reverse argument, if true, will undo the
|
|
85
|
+
previous transpose.
|
|
86
|
+
'''
|
|
87
|
+
transposes = {
|
|
88
|
+
'right': ['ROTATE_90','ROTATE_270'],
|
|
89
|
+
'bottom': ['ROTATE_180','ROTATE_180'],
|
|
90
|
+
'left': ['ROTATE_270','ROTATE_90']
|
|
91
|
+
}
|
|
92
|
+
if direction not in transposes:
|
|
93
|
+
return image
|
|
94
|
+
transpose = transposes[direction][1 if reverse else 0]
|
|
95
|
+
return image.transpose(Image.Transpose.__dict__[transpose])
|
|
96
|
+
|
|
97
|
+
def _extend(self,image:Image,pixels:int)-> Image:
|
|
98
|
+
extended_img = Image.new('RGBA',(image.width,image.height+pixels))
|
|
99
|
+
|
|
100
|
+
extended_img.paste((0,0,0),[0,0,image.width,image.height+pixels])
|
|
101
|
+
extended_img.paste(image,box=(0,pixels))
|
|
102
|
+
|
|
103
|
+
# now make the top part transparent to use as a mask
|
|
104
|
+
alpha = extended_img.getchannel('A')
|
|
105
|
+
alpha.paste(0,(0,0,extended_img.width,pixels))
|
|
106
|
+
extended_img.putalpha(alpha)
|
|
107
|
+
|
|
108
|
+
return extended_img
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
import math
|
|
3
|
+
from PIL import Image, ImageFilter
|
|
4
|
+
|
|
5
|
+
class Outpaint(object):
|
|
6
|
+
def __init__(self, image, generate):
|
|
7
|
+
self.image = image
|
|
8
|
+
self.generate = generate
|
|
9
|
+
|
|
10
|
+
def process(self, opt, old_opt, image_callback = None, prefix = None):
|
|
11
|
+
image = self._create_outpaint_image(self.image, opt.out_direction)
|
|
12
|
+
|
|
13
|
+
seed = old_opt.seed
|
|
14
|
+
prompt = old_opt.prompt
|
|
15
|
+
|
|
16
|
+
def wrapped_callback(img,seed,**kwargs):
|
|
17
|
+
image_callback(img,seed,use_prefix=prefix,**kwargs)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
return self.generate.prompt2image(
|
|
21
|
+
prompt,
|
|
22
|
+
seed = seed,
|
|
23
|
+
sampler = self.generate.sampler,
|
|
24
|
+
steps = opt.steps,
|
|
25
|
+
cfg_scale = opt.cfg_scale,
|
|
26
|
+
ddim_eta = self.generate.ddim_eta,
|
|
27
|
+
width = opt.width,
|
|
28
|
+
height = opt.height,
|
|
29
|
+
init_img = image,
|
|
30
|
+
strength = 0.83,
|
|
31
|
+
image_callback = wrapped_callback,
|
|
32
|
+
prefix = prefix,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def _create_outpaint_image(self, image, direction_args):
|
|
36
|
+
assert len(direction_args) in [1, 2], 'Direction (-D) must have exactly one or two arguments.'
|
|
37
|
+
|
|
38
|
+
if len(direction_args) == 1:
|
|
39
|
+
direction = direction_args[0]
|
|
40
|
+
pixels = None
|
|
41
|
+
elif len(direction_args) == 2:
|
|
42
|
+
direction = direction_args[0]
|
|
43
|
+
pixels = int(direction_args[1])
|
|
44
|
+
|
|
45
|
+
assert direction in ['top', 'left', 'bottom', 'right'], 'Direction (-D) must be one of "top", "left", "bottom", "right"'
|
|
46
|
+
|
|
47
|
+
image = image.convert("RGBA")
|
|
48
|
+
# we always extend top, but rotate to extend along the requested side
|
|
49
|
+
if direction == 'left':
|
|
50
|
+
image = image.transpose(Image.Transpose.ROTATE_270)
|
|
51
|
+
elif direction == 'bottom':
|
|
52
|
+
image = image.transpose(Image.Transpose.ROTATE_180)
|
|
53
|
+
elif direction == 'right':
|
|
54
|
+
image = image.transpose(Image.Transpose.ROTATE_90)
|
|
55
|
+
|
|
56
|
+
pixels = image.height//2 if pixels is None else int(pixels)
|
|
57
|
+
assert 0 < pixels < image.height, 'Direction (-D) pixels length must be in the range 0 - image.size'
|
|
58
|
+
|
|
59
|
+
# the top part of the image is taken from the source image mirrored
|
|
60
|
+
# coordinates (0,0) are the upper left corner of an image
|
|
61
|
+
top = image.transpose(Image.Transpose.FLIP_TOP_BOTTOM).convert("RGBA")
|
|
62
|
+
top = top.crop((0, top.height - pixels, top.width, top.height))
|
|
63
|
+
|
|
64
|
+
# setting all alpha of the top part to 0
|
|
65
|
+
alpha = top.getchannel("A")
|
|
66
|
+
alpha.paste(0, (0, 0, top.width, top.height))
|
|
67
|
+
top.putalpha(alpha)
|
|
68
|
+
|
|
69
|
+
# taking the bottom from the original image
|
|
70
|
+
bottom = image.crop((0, 0, image.width, image.height - pixels))
|
|
71
|
+
|
|
72
|
+
new_img = image.copy()
|
|
73
|
+
new_img.paste(top, (0, 0))
|
|
74
|
+
new_img.paste(bottom, (0, pixels))
|
|
75
|
+
|
|
76
|
+
# create a 10% dither in the middle
|
|
77
|
+
dither = min(image.height//10, pixels)
|
|
78
|
+
for x in range(0, image.width, 2):
|
|
79
|
+
for y in range(pixels - dither, pixels + dither):
|
|
80
|
+
(r, g, b, a) = new_img.getpixel((x, y))
|
|
81
|
+
new_img.putpixel((x, y), (r, g, b, 0))
|
|
82
|
+
|
|
83
|
+
# let's rotate back again
|
|
84
|
+
if direction == 'left':
|
|
85
|
+
new_img = new_img.transpose(Image.Transpose.ROTATE_90)
|
|
86
|
+
elif direction == 'bottom':
|
|
87
|
+
new_img = new_img.transpose(Image.Transpose.ROTATE_180)
|
|
88
|
+
elif direction == 'right':
|
|
89
|
+
new_img = new_img.transpose(Image.Transpose.ROTATE_270)
|
|
90
|
+
|
|
91
|
+
return new_img
|
|
92
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
import warnings
|
|
3
|
+
import numpy as np
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from ldm.invoke.globals import Globals
|
|
7
|
+
from PIL import Image
|
|
8
|
+
from PIL.Image import Image as ImageType
|
|
9
|
+
|
|
10
|
+
class ESRGAN():
|
|
11
|
+
def __init__(self, bg_tile_size=400) -> None:
|
|
12
|
+
self.bg_tile_size = bg_tile_size
|
|
13
|
+
|
|
14
|
+
if not torch.cuda.is_available(): # CPU or MPS on M1
|
|
15
|
+
use_half_precision = False
|
|
16
|
+
else:
|
|
17
|
+
use_half_precision = True
|
|
18
|
+
|
|
19
|
+
def load_esrgan_bg_upsampler(self):
|
|
20
|
+
if not torch.cuda.is_available(): # CPU or MPS on M1
|
|
21
|
+
use_half_precision = False
|
|
22
|
+
else:
|
|
23
|
+
use_half_precision = True
|
|
24
|
+
|
|
25
|
+
from realesrgan.archs.srvgg_arch import SRVGGNetCompact
|
|
26
|
+
from realesrgan import RealESRGANer
|
|
27
|
+
|
|
28
|
+
model = SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=32, upscale=4, act_type='prelu')
|
|
29
|
+
model_path = os.path.join(Globals.root,'models/realesrgan/realesr-general-x4v3.pth')
|
|
30
|
+
scale = 4
|
|
31
|
+
|
|
32
|
+
bg_upsampler = RealESRGANer(
|
|
33
|
+
scale=scale,
|
|
34
|
+
model_path=model_path,
|
|
35
|
+
model=model,
|
|
36
|
+
tile=self.bg_tile_size,
|
|
37
|
+
tile_pad=10,
|
|
38
|
+
pre_pad=0,
|
|
39
|
+
half=use_half_precision,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return bg_upsampler
|
|
43
|
+
|
|
44
|
+
def process(self, image: ImageType, strength: float, seed: str = None, upsampler_scale: int = 2):
|
|
45
|
+
with warnings.catch_warnings():
|
|
46
|
+
warnings.filterwarnings('ignore', category=DeprecationWarning)
|
|
47
|
+
warnings.filterwarnings('ignore', category=UserWarning)
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
upsampler = self.load_esrgan_bg_upsampler()
|
|
51
|
+
except Exception:
|
|
52
|
+
import traceback
|
|
53
|
+
import sys
|
|
54
|
+
print('>> Error loading Real-ESRGAN:', file=sys.stderr)
|
|
55
|
+
print(traceback.format_exc(), file=sys.stderr)
|
|
56
|
+
|
|
57
|
+
if upsampler_scale == 0:
|
|
58
|
+
print('>> Real-ESRGAN: Invalid scaling option. Image not upscaled.')
|
|
59
|
+
return image
|
|
60
|
+
|
|
61
|
+
if seed is not None:
|
|
62
|
+
print(
|
|
63
|
+
f'>> Real-ESRGAN Upscaling seed:{seed} : scale:{upsampler_scale}x'
|
|
64
|
+
)
|
|
65
|
+
# ESRGAN outputs images with partial transparency if given RGBA images; convert to RGB
|
|
66
|
+
image = image.convert("RGB")
|
|
67
|
+
|
|
68
|
+
# REALSRGAN expects a BGR np array; make array and flip channels
|
|
69
|
+
bgr_image_array = np.array(image, dtype=np.uint8)[...,::-1]
|
|
70
|
+
|
|
71
|
+
output, _ = upsampler.enhance(
|
|
72
|
+
bgr_image_array,
|
|
73
|
+
outscale=upsampler_scale,
|
|
74
|
+
alpha_upsampler='realesrgan',
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Flip the channels back to RGB
|
|
78
|
+
res = Image.fromarray(output[...,::-1])
|
|
79
|
+
|
|
80
|
+
if strength < 1.0:
|
|
81
|
+
# Resize the image to the new image if the sizes have changed
|
|
82
|
+
if output.size != image.size:
|
|
83
|
+
image = image.resize(res.size)
|
|
84
|
+
res = Image.blend(image, res, strength)
|
|
85
|
+
|
|
86
|
+
if torch.cuda.is_available():
|
|
87
|
+
torch.cuda.empty_cache()
|
|
88
|
+
upsampler = None
|
|
89
|
+
|
|
90
|
+
return res
|