Spaces:
Running
on
Zero
Running
on
Zero
Add application file
Browse files- app.py +429 -0
- data/content/27032.jpg +0 -0
- data/content/29812.jpg +0 -0
- data/style/27.jpg +0 -0
- data/style/47.jpg +0 -0
- requirements.txt +85 -0
- utils/__init__.py +0 -0
- utils/__pycache__/__init__.cpython-310.pyc +0 -0
- utils/__pycache__/__init__.cpython-39.pyc +0 -0
- utils/__pycache__/attn_control.cpython-310.pyc +0 -0
- utils/__pycache__/attn_control.cpython-39.pyc +0 -0
- utils/__pycache__/free_lunch_utils.cpython-310.pyc +0 -0
- utils/__pycache__/free_lunch_utils.cpython-39.pyc +0 -0
- utils/__pycache__/masactrl_utils.cpython-310.pyc +0 -0
- utils/__pycache__/masactrl_utils.cpython-39.pyc +0 -0
- utils/__pycache__/merge.cpython-310.pyc +0 -0
- utils/__pycache__/merge.cpython-39.pyc +0 -0
- utils/__pycache__/patch.cpython-310.pyc +0 -0
- utils/__pycache__/patch.cpython-39.pyc +0 -0
- utils/__pycache__/pipeline.cpython-310.pyc +0 -0
- utils/__pycache__/pipeline.cpython-39.pyc +0 -0
- utils/__pycache__/pipeline_ead.cpython-310.pyc +0 -0
- utils/__pycache__/pipeline_ead.cpython-39.pyc +0 -0
- utils/__pycache__/pipeline_stable_diffusion_xl.cpython-310.pyc +0 -0
- utils/__pycache__/pipeline_stable_diffusion_xl.cpython-39.pyc +0 -0
- utils/__pycache__/pipeline_xl_edit.cpython-310.pyc +0 -0
- utils/__pycache__/pipeline_xl_edit.cpython-39.pyc +0 -0
- utils/__pycache__/ptp_utils.cpython-310.pyc +0 -0
- utils/__pycache__/ptp_utils.cpython-39.pyc +0 -0
- utils/__pycache__/style_attn_control.cpython-310.pyc +0 -0
- utils/__pycache__/style_attn_control.cpython-39.pyc +0 -0
- utils/__pycache__/superbeastsai.cpython-310.pyc +0 -0
- utils/__pycache__/superbeastsai.cpython-39.pyc +0 -0
- utils/__pycache__/utils.cpython-310.pyc +0 -0
- utils/__pycache__/utils.cpython-39.pyc +0 -0
- utils/attn_control.py +129 -0
- utils/merge.py +124 -0
- utils/pipeline.py +434 -0
- utils/ptp_utils.py +225 -0
- utils/utils.py +32 -0
app.py
ADDED
@@ -0,0 +1,429 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import torch
|
3 |
+
import random
|
4 |
+
import numpy as np
|
5 |
+
import gradio as gr
|
6 |
+
from glob import glob
|
7 |
+
from datetime import datetime
|
8 |
+
|
9 |
+
from diffusers import StableDiffusionPipeline,AutoencoderKL
|
10 |
+
from diffusers import DDIMScheduler, LCMScheduler, EulerDiscreteScheduler
|
11 |
+
|
12 |
+
import torch.nn.functional as F
|
13 |
+
from PIL import Image,ImageDraw
|
14 |
+
from utils.pipeline import ZePoPipeline
|
15 |
+
from utils.attn_control import AttentionStyle
|
16 |
+
from torchvision.utils import save_image
|
17 |
+
import utils.ptp_utils as ptp_utils
|
18 |
+
|
19 |
+
import torchvision.transforms as transforms
|
20 |
+
|
21 |
+
try:
|
22 |
+
import xformers
|
23 |
+
is_xformers = True
|
24 |
+
except ImportError:
|
25 |
+
is_xformers = False
|
26 |
+
|
27 |
+
css = """
|
28 |
+
.toolbutton {
|
29 |
+
margin-buttom: 0em 0em 0em 0em;
|
30 |
+
max-width: 2.5em;
|
31 |
+
min-width: 2.5em !important;
|
32 |
+
height: 2.5em;
|
33 |
+
}
|
34 |
+
"""
|
35 |
+
# import sys
|
36 |
+
# sys.setrecursionlimit(100000)
|
37 |
+
|
38 |
+
|
39 |
+
class GlobalText:
|
40 |
+
def __init__(self):
|
41 |
+
|
42 |
+
# config dirs
|
43 |
+
self.basedir = os.getcwd()
|
44 |
+
self.stable_diffusion_dir = os.path.join(self.basedir, "models", "StableDiffusion")
|
45 |
+
self.personalized_model_dir = './models/Stable-diffusion'
|
46 |
+
self.lora_model_dir = './models/Lora'
|
47 |
+
self.savedir = os.path.join(self.basedir, "samples", datetime.now().strftime("Gradio-%Y-%m-%dT%H-%M-%S"))
|
48 |
+
self.savedir_sample = os.path.join(self.savedir, "sample")
|
49 |
+
|
50 |
+
# self.savedir_mask = os.path.join(self.savedir, "mask")
|
51 |
+
|
52 |
+
self.stable_diffusion_list = ["SimianLuo/LCM_Dreamshaper_v7"
|
53 |
+
]
|
54 |
+
self.personalized_model_list = []
|
55 |
+
self.lora_model_list = []
|
56 |
+
|
57 |
+
self.tokenizer = None
|
58 |
+
self.text_encoder = None
|
59 |
+
self.vae = None
|
60 |
+
self.unet = None
|
61 |
+
self.pipeline = None
|
62 |
+
self.torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
|
63 |
+
self.lora_model_state_dict = {}
|
64 |
+
self.device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
|
65 |
+
|
66 |
+
def init_source_image_path(self, source_path):
|
67 |
+
self.source_paths = sorted(glob(os.path.join(source_path, '*')))
|
68 |
+
self.max_source_index = len(self.source_paths) // 12
|
69 |
+
return self.source_paths[0:12]
|
70 |
+
def init_style_image_path(self, style_path):
|
71 |
+
self.style_paths = sorted(glob(os.path.join(style_path, '*')))
|
72 |
+
self.max_style_index = len(self.style_paths) // 12
|
73 |
+
return self.style_paths[0:12]
|
74 |
+
def init_results_image_path(self):
|
75 |
+
results_paths = [os.path.join(self.savedir_sample, file) for file in os.listdir(self.savedir_sample)]
|
76 |
+
self.results_paths = sorted(results_paths, key=os.path.getctime, reverse=True)
|
77 |
+
self.max_results_index = len(self.results_paths) // 12
|
78 |
+
return self.results_paths[0:12]
|
79 |
+
|
80 |
+
def load_base_pipeline(self, model_path):
|
81 |
+
|
82 |
+
time_start = datetime.now()
|
83 |
+
|
84 |
+
self.scheduler = 'LCM'
|
85 |
+
scheduler = LCMScheduler.from_pretrained(model_path, subfolder="scheduler")
|
86 |
+
self.pipeline = ZePoPipeline.from_pretrained(model_path,scheduler=scheduler,torch_dtype=torch.float16,).to('cuda')
|
87 |
+
if is_xformers:
|
88 |
+
self.pipeline.enable_xformers_memory_efficient_attention()
|
89 |
+
time_end = datetime.now()
|
90 |
+
print(f'Load {model_path} successful in {time_end-time_start}')
|
91 |
+
return gr.Dropdown()
|
92 |
+
|
93 |
+
def refresh_stable_diffusion(self,model_path):
|
94 |
+
|
95 |
+
self.load_base_pipeline(model_path)
|
96 |
+
|
97 |
+
return self.stable_diffusion_list[0]
|
98 |
+
|
99 |
+
def update_base_model(self, base_model_dropdown):
|
100 |
+
if self.pipeline is None:
|
101 |
+
gr.Info(f"Please select a pretrained model path.")
|
102 |
+
return None
|
103 |
+
else:
|
104 |
+
base_model = self.personalized_model_list[base_model_dropdown]
|
105 |
+
mid_model = StableDiffusionPipeline.from_single_file(base_model)
|
106 |
+
self.pipeline.vae = mid_model.vae
|
107 |
+
self.pipeline.unet = mid_model.unet
|
108 |
+
self.pipeline.text_encoder = mid_model.text_encoder
|
109 |
+
self.pipeline.to(self.device)
|
110 |
+
self.personal_model_loaded = base_model_dropdown.split('.')[0]
|
111 |
+
print(f'load {base_model_dropdown} model success!')
|
112 |
+
return gr.Dropdown()
|
113 |
+
|
114 |
+
|
115 |
+
def generate(self, source, style,
|
116 |
+
num_steps, co_feat_step,strength,
|
117 |
+
start_ac_layer, end_ac_layer,
|
118 |
+
sty_guidance,cfg_scale, mix_q_scale,
|
119 |
+
Scheduler, save_intermediate, seed, de_bug,
|
120 |
+
target_prompt, negative_prompt_textbox,
|
121 |
+
width_slider,height_slider,
|
122 |
+
tome_sx, tome_sy, tome_ratio,tome,
|
123 |
+
):
|
124 |
+
|
125 |
+
|
126 |
+
os.makedirs(self.savedir, exist_ok=True)
|
127 |
+
os.makedirs(self.savedir_sample, exist_ok=True)
|
128 |
+
|
129 |
+
if self.pipeline == None:
|
130 |
+
self.refresh_stable_diffusion(self.stable_diffusion_list[-1])
|
131 |
+
model = self.pipeline
|
132 |
+
|
133 |
+
if Scheduler == 'DDIM':
|
134 |
+
model.scheduler = DDIMScheduler.from_config(model.scheduler.config)
|
135 |
+
print(f"Successful adoption of DDIM scheduler")
|
136 |
+
if Scheduler == 'LCM':
|
137 |
+
model.scheduler = LCMScheduler.from_config(model.scheduler.config)
|
138 |
+
print(f"Successful adoption of LCM scheduler")
|
139 |
+
if Scheduler == 'EulerDiscrete':
|
140 |
+
model.scheduler = EulerDiscreteScheduler.from_config(model.scheduler.config)
|
141 |
+
|
142 |
+
if seed != '-1' and seed != "": torch.manual_seed(int(seed))
|
143 |
+
else: torch.seed()
|
144 |
+
|
145 |
+
seed = torch.initial_seed()
|
146 |
+
print(f"Seed: {seed}")
|
147 |
+
|
148 |
+
self.sample_count = len(os.listdir(self.savedir_sample))
|
149 |
+
|
150 |
+
|
151 |
+
prompts = [target_prompt] * 3
|
152 |
+
source = source.resize((width_slider, height_slider))
|
153 |
+
style = style.resize((width_slider, height_slider))
|
154 |
+
|
155 |
+
|
156 |
+
with torch.no_grad():
|
157 |
+
|
158 |
+
controller = AttentionStyle(num_steps,
|
159 |
+
start_ac_layer,
|
160 |
+
end_ac_layer,
|
161 |
+
style_guidance=sty_guidance,
|
162 |
+
mix_q_scale=mix_q_scale,
|
163 |
+
de_bug=de_bug,
|
164 |
+
)
|
165 |
+
|
166 |
+
ptp_utils.register_attention_control(model, controller,
|
167 |
+
tome,
|
168 |
+
sx=tome_sx,
|
169 |
+
sy=tome_sy,
|
170 |
+
ratio=tome_ratio,
|
171 |
+
de_bug=de_bug,)
|
172 |
+
|
173 |
+
time_begin = datetime.now()
|
174 |
+
generate_image = model(prompt=prompts,
|
175 |
+
negative_prompt=negative_prompt_textbox,
|
176 |
+
image=source,
|
177 |
+
style=style,
|
178 |
+
num_inference_steps=num_steps,
|
179 |
+
eta=0.0,
|
180 |
+
guidance_scale=cfg_scale,
|
181 |
+
strength=strength,
|
182 |
+
save_intermediate=save_intermediate,
|
183 |
+
fix_step_index=co_feat_step,
|
184 |
+
de_bug = de_bug,
|
185 |
+
callback = None
|
186 |
+
).images
|
187 |
+
time_end = datetime.now()
|
188 |
+
print('generate one image with time {}'.format(time_end-time_begin))
|
189 |
+
|
190 |
+
save_file_name = f"{self.sample_count}_step{num_steps}_sl{start_ac_layer}_el{end_ac_layer}_ST{strength}_CF{co_feat_step}_STG{sty_guidance}_MQ{mix_q_scale}_CFG{cfg_scale}_seed{seed}.jpg"
|
191 |
+
|
192 |
+
|
193 |
+
save_file_path = os.path.join(self.savedir, save_file_name)
|
194 |
+
|
195 |
+
save_image(torch.tensor(generate_image).permute(0, 3, 1, 2), save_file_path, nrow=3, padding=0)
|
196 |
+
save_image(torch.tensor(generate_image[2:]).permute(0, 3, 1, 2), os.path.join(self.savedir_sample, save_file_name), nrow=3, padding=0)
|
197 |
+
self.init_results_image_path()
|
198 |
+
return [
|
199 |
+
generate_image[0],
|
200 |
+
generate_image[1],
|
201 |
+
generate_image[2],
|
202 |
+
self.init_results_image_path()
|
203 |
+
]
|
204 |
+
|
205 |
+
|
206 |
+
global_text = GlobalText()
|
207 |
+
|
208 |
+
|
209 |
+
def ui():
|
210 |
+
with gr.Blocks(css=css) as demo:
|
211 |
+
gr.Markdown(
|
212 |
+
"""
|
213 |
+
# [ZePo: Zero-Shot Portrait Stylization with Faster Sampling](https://arxiv.org/abs/2408.05492)
|
214 |
+
Jin Liu, Huaibo Huang, Jie Cao, Ran He<br>
|
215 |
+
[Arxiv](https://arxiv.org/abs/2408.05492) | [Github](https://github.com/liujin112/ZePo)
|
216 |
+
"""
|
217 |
+
)
|
218 |
+
with gr.Column(variant="panel"):
|
219 |
+
gr.Markdown(
|
220 |
+
"""
|
221 |
+
### 1. Select a pretrained model.
|
222 |
+
"""
|
223 |
+
)
|
224 |
+
with gr.Row():
|
225 |
+
stable_diffusion_dropdown = gr.Dropdown(
|
226 |
+
label="Pretrained Model Path",
|
227 |
+
choices=global_text.stable_diffusion_list,
|
228 |
+
interactive=True,
|
229 |
+
allow_custom_value=True
|
230 |
+
)
|
231 |
+
stable_diffusion_dropdown.change(fn=global_text.load_base_pipeline, inputs=[stable_diffusion_dropdown], outputs=[stable_diffusion_dropdown])
|
232 |
+
|
233 |
+
stable_diffusion_refresh_button = gr.Button(value="\U0001F503", elem_classes="toolbutton")
|
234 |
+
def update_stable_diffusion(stable_diffusion_dropdown):
|
235 |
+
global_text.refresh_stable_diffusion(stable_diffusion_dropdown)
|
236 |
+
|
237 |
+
stable_diffusion_refresh_button.click(fn=update_stable_diffusion, inputs=[stable_diffusion_dropdown], outputs=[stable_diffusion_dropdown])
|
238 |
+
|
239 |
+
|
240 |
+
with gr.Column(variant="panel"):
|
241 |
+
gr.Markdown(
|
242 |
+
"""
|
243 |
+
### 2. Configs for ZePo.
|
244 |
+
"""
|
245 |
+
)
|
246 |
+
with gr.Tab("Configs"):
|
247 |
+
|
248 |
+
with gr.Row():
|
249 |
+
with gr.Column():
|
250 |
+
with gr.Row():
|
251 |
+
source_image = gr.Image(label="Source Image", elem_id="img2maskimg", sources="upload", type="pil",image_mode="RGB", height=256)
|
252 |
+
style_image = gr.Image(label="Style Image", elem_id="img2maskimg", sources="upload", type="pil", image_mode="RGB", height=256)
|
253 |
+
|
254 |
+
generate_image = gr.Image(label="Image with PortraitDiff", type="pil", interactive=True, image_mode="RGB", height=512)
|
255 |
+
|
256 |
+
|
257 |
+
with gr.Row():
|
258 |
+
recons_content = gr.Image(label="reconstructed content", type="pil", image_mode="RGB", height=256)
|
259 |
+
recons_style = gr.Image(label="reconstructed style", type="pil", image_mode="RGB", height=256)
|
260 |
+
prompt_textbox = gr.Textbox(label="Prompt", value='head', lines=1)
|
261 |
+
negative_prompt_textbox = gr.Textbox(label="Negative prompt", lines=1)
|
262 |
+
with gr.Row(equal_height=False):
|
263 |
+
with gr.Column():
|
264 |
+
with gr.Tab("Resolution"):
|
265 |
+
width_slider = gr.Slider(label="Width", value=512, minimum=256, maximum=1024, step=64)
|
266 |
+
height_slider = gr.Slider(label="Height", value=512, minimum=256, maximum=1024, step=64)
|
267 |
+
Scheduler = gr.Dropdown(
|
268 |
+
["DDIM", "LCM", "EulerDiscrete"],
|
269 |
+
value="LCM",
|
270 |
+
label="Scheduler", info="Select a Scheduler")
|
271 |
+
|
272 |
+
|
273 |
+
with gr.Tab("Content Gallery"):
|
274 |
+
|
275 |
+
with gr.Row():
|
276 |
+
source_path = gr.Textbox(value='./data/content', label="Source Path")
|
277 |
+
refresh_source_list_button = gr.Button(value="\U0001F503", elem_classes="toolbutton")
|
278 |
+
source_gallery_index = gr.Slider(label="Index", value=0, minimum=0, maximum=50, step=1)
|
279 |
+
num_gallery_images = 12
|
280 |
+
source_image_gallery = gr.Gallery(value=[], columns=4, label="Source Image List")
|
281 |
+
refresh_source_list_button.click(fn=global_text.init_source_image_path, inputs=[source_path], outputs=[source_image_gallery])
|
282 |
+
|
283 |
+
def update_source_list(index):
|
284 |
+
if int(index) < 0:
|
285 |
+
index = 0
|
286 |
+
if int(index) > global_text.max_source_index:
|
287 |
+
index = global_text.max_source_index
|
288 |
+
return global_text.source_paths[int(index)*num_gallery_images:(int(index)+1)*num_gallery_images]
|
289 |
+
|
290 |
+
source_gallery_index.change(fn=update_source_list, inputs=[source_gallery_index], outputs=[source_image_gallery])
|
291 |
+
|
292 |
+
with gr.Tab("Style Gallery"):
|
293 |
+
|
294 |
+
with gr.Row():
|
295 |
+
style_path = gr.Textbox(value='./data/style', label="style Path")
|
296 |
+
refresh_style_list_button = gr.Button(value="\U0001F503", elem_classes="toolbutton")
|
297 |
+
style_gallery_index = gr.Slider(label="Index", value=0, minimum=0, maximum=50, step=1)
|
298 |
+
num_gallery_images = 12
|
299 |
+
style_image_gallery = gr.Gallery(value=[], columns=4, label="style Image List")
|
300 |
+
refresh_style_list_button.click(fn=global_text.init_style_image_path, inputs=[style_path], outputs=[style_image_gallery])
|
301 |
+
|
302 |
+
|
303 |
+
def update_style_list(index):
|
304 |
+
if int(index) < 0:
|
305 |
+
index = 0
|
306 |
+
if int(index) > global_text.max_style_index:
|
307 |
+
index = global_text.max_style_index
|
308 |
+
return global_text.style_paths[int(index)*num_gallery_images:(int(index)+1)*num_gallery_images]
|
309 |
+
|
310 |
+
style_gallery_index.change(fn=update_style_list, inputs=[style_gallery_index], outputs=[style_image_gallery])
|
311 |
+
|
312 |
+
with gr.Tab("Results Gallery"):
|
313 |
+
with gr.Row():
|
314 |
+
refresh_results_list_button = gr.Button(value="\U0001F503", elem_classes="toolbutton")
|
315 |
+
results_gallery_index = gr.Slider(label="Index", value=0, minimum=0, maximum=50, step=1)
|
316 |
+
num_gallery_images = 12
|
317 |
+
results_image_gallery = gr.Gallery(value=[], columns=4, label="style Image List")
|
318 |
+
refresh_results_list_button.click(fn=global_text.init_results_image_path, inputs=[], outputs=[results_image_gallery])
|
319 |
+
|
320 |
+
|
321 |
+
def update_results_list(index):
|
322 |
+
if int(index) < 0:
|
323 |
+
index = 0
|
324 |
+
if int(index) > global_text.max_results_index:
|
325 |
+
index = global_text.max_results_index
|
326 |
+
return global_text.results_paths[int(index)*num_gallery_images:(int(index)+1)*num_gallery_images]
|
327 |
+
|
328 |
+
results_gallery_index.change(fn=update_results_list, inputs=[results_gallery_index], outputs=[style_image_gallery])
|
329 |
+
|
330 |
+
|
331 |
+
|
332 |
+
with gr.Row():
|
333 |
+
generate_button = gr.Button(value="Generate", variant='primary')
|
334 |
+
|
335 |
+
with gr.Tab('Base Configs'):
|
336 |
+
num_steps = gr.Slider(label="Total Steps", value=4, minimum=0, maximum=25, step=1)
|
337 |
+
strength = gr.Slider(label="Noisy Ratio", value=0.5, minimum=0, maximum=1, step=0.01,info="How much noise applied to souce image, 50% for better balance.")
|
338 |
+
co_feat_step = gr.Slider(label="Consistency Feature Extract Step", value=99, minimum=0, maximum=999, step=1)
|
339 |
+
|
340 |
+
|
341 |
+
with gr.Row():
|
342 |
+
start_ac_layer = gr.Slider(label="Start Layer of AC",
|
343 |
+
minimum=0,
|
344 |
+
maximum=16,
|
345 |
+
value=8,
|
346 |
+
step=1)
|
347 |
+
end_ac_layer = gr.Slider(label="End Layer of AC",
|
348 |
+
minimum=0,
|
349 |
+
maximum=16,
|
350 |
+
value=16,
|
351 |
+
step=1)
|
352 |
+
|
353 |
+
with gr.Row():
|
354 |
+
Style_Guidance = gr.Slider(label="Style Guidance Scale",
|
355 |
+
minimum=-1,
|
356 |
+
maximum=3,
|
357 |
+
value=1.2,
|
358 |
+
step=0.01,
|
359 |
+
)
|
360 |
+
mix_q_scale = gr.Slider(label='Query Mix Ratio',
|
361 |
+
minimum=0,
|
362 |
+
maximum=2,
|
363 |
+
step=0.05,
|
364 |
+
value=1.0,
|
365 |
+
)
|
366 |
+
cfg_scale_slider = gr.Slider(label="CFG Scale", value=2.5, minimum=0, maximum=20, info="Classifier-free guidance scale.")
|
367 |
+
|
368 |
+
with gr.Row():
|
369 |
+
save_intermediate = gr.Checkbox(label="save_intermediate", value=False)
|
370 |
+
de_bug = gr.Checkbox(value=False,label='DeBug')
|
371 |
+
with gr.Tab('ToMe'):
|
372 |
+
with gr.Row():
|
373 |
+
tome = gr.Checkbox(label="Token Merge", value=True)
|
374 |
+
|
375 |
+
tome_ratio = gr.Slider(label='ratio: ',
|
376 |
+
minimum=0,
|
377 |
+
maximum=1,
|
378 |
+
step=0.1,
|
379 |
+
value=0.5)
|
380 |
+
with gr.Row():
|
381 |
+
tome_sx = gr.Slider(label='sx:',
|
382 |
+
minimum=0,
|
383 |
+
maximum=64,
|
384 |
+
step=2,
|
385 |
+
value=2)
|
386 |
+
tome_sy = gr.Slider(label='sy:',
|
387 |
+
minimum=0,
|
388 |
+
maximum=64,
|
389 |
+
step=2,
|
390 |
+
value=2)
|
391 |
+
|
392 |
+
|
393 |
+
with gr.Row():
|
394 |
+
seed_textbox = gr.Textbox(label="Seed", value=-1)
|
395 |
+
seed_button = gr.Button(value="\U0001F3B2", elem_classes="toolbutton")
|
396 |
+
seed_button.click(fn=lambda: random.randint(1, 1e16), inputs=[], outputs=[seed_textbox])
|
397 |
+
inputs = [
|
398 |
+
source_image, style_image,
|
399 |
+
num_steps,co_feat_step,strength,
|
400 |
+
start_ac_layer, end_ac_layer,
|
401 |
+
Style_Guidance,cfg_scale_slider,mix_q_scale,
|
402 |
+
Scheduler, save_intermediate, seed_textbox, de_bug,
|
403 |
+
prompt_textbox, negative_prompt_textbox,
|
404 |
+
width_slider,height_slider,
|
405 |
+
tome_sx, tome_sy, tome_ratio, tome,
|
406 |
+
]
|
407 |
+
|
408 |
+
generate_button.click(
|
409 |
+
fn=global_text.generate,
|
410 |
+
inputs=inputs,
|
411 |
+
outputs=[recons_style,recons_content,generate_image,results_image_gallery]
|
412 |
+
)
|
413 |
+
|
414 |
+
ex = gr.Examples(
|
415 |
+
[
|
416 |
+
["./data/content/27032.jpg","./data/style/27.jpg",4,0.8,0.5,8427921159605868845],
|
417 |
+
["./data/content/29812.jpg","./data/style/47.jpg",4,0.5,0.65,8119359809263726691],
|
418 |
+
],
|
419 |
+
[source_image, style_image, num_steps,strength, mix_q_scale, seed_textbox],
|
420 |
+
[
|
421 |
+
"Example 1",
|
422 |
+
],)
|
423 |
+
|
424 |
+
|
425 |
+
return demo
|
426 |
+
|
427 |
+
if __name__ == "__main__":
|
428 |
+
demo = ui()
|
429 |
+
demo.launch(server_name='172.18.32.44',show_error=True)
|
data/content/27032.jpg
ADDED
data/content/29812.jpg
ADDED
data/style/27.jpg
ADDED
data/style/47.jpg
ADDED
requirements.txt
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
accelerate==0.33.0
|
2 |
+
aiofiles==23.2.1
|
3 |
+
annotated-types==0.7.0
|
4 |
+
anyio==4.4.0
|
5 |
+
Brotli @ file:///croot/brotli-split_1714483155106/work
|
6 |
+
certifi @ file:///croot/certifi_1720453481653/work/certifi
|
7 |
+
charset-normalizer @ file:///croot/charset-normalizer_1721748349566/work
|
8 |
+
click==8.1.7
|
9 |
+
contourpy==1.2.1
|
10 |
+
cycler==0.12.1
|
11 |
+
diffusers==0.30.0
|
12 |
+
exceptiongroup==1.2.2
|
13 |
+
fastapi==0.112.0
|
14 |
+
ffmpy==0.4.0
|
15 |
+
filelock @ file:///croot/filelock_1700591183607/work
|
16 |
+
fonttools==4.53.1
|
17 |
+
fsspec==2024.6.1
|
18 |
+
gmpy2 @ file:///tmp/build/80754af9/gmpy2_1645438755360/work
|
19 |
+
gradio==4.41.0
|
20 |
+
gradio_client==1.3.0
|
21 |
+
h11==0.14.0
|
22 |
+
httpcore==1.0.5
|
23 |
+
httpx==0.27.0
|
24 |
+
huggingface-hub==0.24.5
|
25 |
+
idna @ file:///croot/idna_1714398848350/work
|
26 |
+
importlib_metadata==8.2.0
|
27 |
+
importlib_resources==6.4.0
|
28 |
+
Jinja2 @ file:///croot/jinja2_1716993405101/work
|
29 |
+
kiwisolver==1.4.5
|
30 |
+
markdown-it-py==3.0.0
|
31 |
+
MarkupSafe @ file:///croot/markupsafe_1704205993651/work
|
32 |
+
matplotlib==3.9.1.post1
|
33 |
+
mdurl==0.1.2
|
34 |
+
mkl-fft @ file:///croot/mkl_fft_1695058164594/work
|
35 |
+
mkl-random @ file:///croot/mkl_random_1695059800811/work
|
36 |
+
mkl-service==2.4.0
|
37 |
+
mpmath @ file:///croot/mpmath_1690848262763/work
|
38 |
+
mypy-extensions==1.0.0
|
39 |
+
networkx @ file:///croot/networkx_1717597493534/work
|
40 |
+
numpy @ file:///croot/numpy_and_numpy_base_1708638617955/work/dist/numpy-1.26.4-cp39-cp39-linux_x86_64.whl#sha256=6094eeedd869502faa0fd0a8c5ad3a70c5779be06ddd1feb7627e5c212fac420
|
41 |
+
orjson==3.10.7
|
42 |
+
packaging==24.1
|
43 |
+
pandas==2.2.2
|
44 |
+
peft==0.12.0
|
45 |
+
pillow @ file:///croot/pillow_1721059439630/work
|
46 |
+
psutil==6.0.0
|
47 |
+
pydantic==2.8.2
|
48 |
+
pydantic_core==2.20.1
|
49 |
+
pydub==0.25.1
|
50 |
+
Pygments==2.18.0
|
51 |
+
pyparsing==3.1.2
|
52 |
+
pyre-extensions==0.0.29
|
53 |
+
PySocks @ file:///tmp/build/80754af9/pysocks_1605305812635/work
|
54 |
+
python-dateutil==2.9.0.post0
|
55 |
+
python-multipart==0.0.9
|
56 |
+
pytz==2024.1
|
57 |
+
PyYAML==6.0.2
|
58 |
+
regex==2024.7.24
|
59 |
+
requests @ file:///croot/requests_1721410876868/work
|
60 |
+
rich==13.7.1
|
61 |
+
ruff==0.5.7
|
62 |
+
safetensors==0.4.4
|
63 |
+
semantic-version==2.10.0
|
64 |
+
shellingham==1.5.4
|
65 |
+
six==1.16.0
|
66 |
+
sniffio==1.3.1
|
67 |
+
starlette==0.37.2
|
68 |
+
sympy @ file:///croot/sympy_1701397643339/work
|
69 |
+
tokenizers==0.19.1
|
70 |
+
tomlkit==0.12.0
|
71 |
+
torch==2.0.1
|
72 |
+
torchaudio==2.0.2
|
73 |
+
torchvision==0.15.2
|
74 |
+
tqdm==4.66.5
|
75 |
+
transformers==4.44.0
|
76 |
+
triton==2.0.0
|
77 |
+
typer==0.12.3
|
78 |
+
typing-inspect==0.9.0
|
79 |
+
typing_extensions @ file:///croot/typing_extensions_1715268824938/work
|
80 |
+
tzdata==2024.1
|
81 |
+
urllib3 @ file:///croot/urllib3_1718912636303/work
|
82 |
+
uvicorn==0.30.5
|
83 |
+
websockets==12.0
|
84 |
+
xformers==0.0.20
|
85 |
+
zipp==3.19.2
|
utils/__init__.py
ADDED
File without changes
|
utils/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (139 Bytes). View file
|
|
utils/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (140 Bytes). View file
|
|
utils/__pycache__/attn_control.cpython-310.pyc
ADDED
Binary file (19.8 kB). View file
|
|
utils/__pycache__/attn_control.cpython-39.pyc
ADDED
Binary file (4.08 kB). View file
|
|
utils/__pycache__/free_lunch_utils.cpython-310.pyc
ADDED
Binary file (12 kB). View file
|
|
utils/__pycache__/free_lunch_utils.cpython-39.pyc
ADDED
Binary file (12.6 kB). View file
|
|
utils/__pycache__/masactrl_utils.cpython-310.pyc
ADDED
Binary file (6.18 kB). View file
|
|
utils/__pycache__/masactrl_utils.cpython-39.pyc
ADDED
Binary file (6.67 kB). View file
|
|
utils/__pycache__/merge.cpython-310.pyc
ADDED
Binary file (4.05 kB). View file
|
|
utils/__pycache__/merge.cpython-39.pyc
ADDED
Binary file (4 kB). View file
|
|
utils/__pycache__/patch.cpython-310.pyc
ADDED
Binary file (7.38 kB). View file
|
|
utils/__pycache__/patch.cpython-39.pyc
ADDED
Binary file (7.36 kB). View file
|
|
utils/__pycache__/pipeline.cpython-310.pyc
ADDED
Binary file (6.76 kB). View file
|
|
utils/__pycache__/pipeline.cpython-39.pyc
ADDED
Binary file (12 kB). View file
|
|
utils/__pycache__/pipeline_ead.cpython-310.pyc
ADDED
Binary file (16 kB). View file
|
|
utils/__pycache__/pipeline_ead.cpython-39.pyc
ADDED
Binary file (12.1 kB). View file
|
|
utils/__pycache__/pipeline_stable_diffusion_xl.cpython-310.pyc
ADDED
Binary file (47.5 kB). View file
|
|
utils/__pycache__/pipeline_stable_diffusion_xl.cpython-39.pyc
ADDED
Binary file (47.5 kB). View file
|
|
utils/__pycache__/pipeline_xl_edit.cpython-310.pyc
ADDED
Binary file (14.3 kB). View file
|
|
utils/__pycache__/pipeline_xl_edit.cpython-39.pyc
ADDED
Binary file (14.1 kB). View file
|
|
utils/__pycache__/ptp_utils.cpython-310.pyc
ADDED
Binary file (5.97 kB). View file
|
|
utils/__pycache__/ptp_utils.cpython-39.pyc
ADDED
Binary file (5.86 kB). View file
|
|
utils/__pycache__/style_attn_control.cpython-310.pyc
ADDED
Binary file (8.98 kB). View file
|
|
utils/__pycache__/style_attn_control.cpython-39.pyc
ADDED
Binary file (8.97 kB). View file
|
|
utils/__pycache__/superbeastsai.cpython-310.pyc
ADDED
Binary file (5.64 kB). View file
|
|
utils/__pycache__/superbeastsai.cpython-39.pyc
ADDED
Binary file (5.64 kB). View file
|
|
utils/__pycache__/utils.cpython-310.pyc
ADDED
Binary file (950 Bytes). View file
|
|
utils/__pycache__/utils.cpython-39.pyc
ADDED
Binary file (946 Bytes). View file
|
|
utils/attn_control.py
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import torch.nn.functional as nnf
|
3 |
+
import abc
|
4 |
+
import math
|
5 |
+
from torchvision.utils import save_image
|
6 |
+
|
7 |
+
|
8 |
+
LOW_RESOURCE = False
|
9 |
+
MAX_NUM_WORDS = 77
|
10 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
11 |
+
torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
class AttentionControl(abc.ABC):
|
16 |
+
|
17 |
+
def step_callback(self, x_t):
|
18 |
+
return x_t
|
19 |
+
|
20 |
+
def between_steps(self):
|
21 |
+
return
|
22 |
+
|
23 |
+
@property
|
24 |
+
def start_att_layers(self):
|
25 |
+
return self.start_ac_layer #if LOW_RESOURCE else 0
|
26 |
+
@property
|
27 |
+
def end_att_layers(self):
|
28 |
+
return self.end_ac_layer
|
29 |
+
|
30 |
+
|
31 |
+
|
32 |
+
|
33 |
+
@abc.abstractmethod
|
34 |
+
def forward(self, q, k, v, num_heads,attn):
|
35 |
+
raise NotImplementedError
|
36 |
+
|
37 |
+
def attn_forward(self, q, k, v, num_heads,attention_probs,attn):
|
38 |
+
if q.shape[0]//num_heads == 3:
|
39 |
+
h_s_re = self.forward(q, k, v, num_heads,attention_probs, attn)
|
40 |
+
|
41 |
+
else:
|
42 |
+
uq,cq = q.chunk(2)
|
43 |
+
uk,ck = k.chunk(2)
|
44 |
+
uv,cv = v.chunk(2)
|
45 |
+
u_attn, c_attn = attention_probs.chunk(2)
|
46 |
+
|
47 |
+
u_h_s_re = self.forward(uq, uk, uv, num_heads,u_attn, attn)
|
48 |
+
|
49 |
+
c_h_s_re = self.forward(cq, ck, cv, num_heads,c_attn, attn)
|
50 |
+
h_s_re = (u_h_s_re, c_h_s_re)
|
51 |
+
return h_s_re
|
52 |
+
|
53 |
+
def __call__(self, q, k, v, num_heads,attention_probs,attn):
|
54 |
+
|
55 |
+
|
56 |
+
if self.cur_att_layer >= self.start_att_layers and self.cur_att_layer < self.end_att_layers:
|
57 |
+
h_s_re = self.attn_forward(q, k, v, num_heads,attention_probs,attn)
|
58 |
+
else:
|
59 |
+
h_s_re=None
|
60 |
+
|
61 |
+
|
62 |
+
self.cur_att_layer += 1
|
63 |
+
|
64 |
+
if self.cur_att_layer == self.num_att_layers // 2: #+ self.num_uncond_att_layers:
|
65 |
+
self.cur_att_layer = 0 #self.num_uncond_att_layers
|
66 |
+
self.cur_step += 1
|
67 |
+
self.between_steps()
|
68 |
+
return h_s_re
|
69 |
+
|
70 |
+
def reset(self):
|
71 |
+
self.cur_step = 0
|
72 |
+
self.cur_att_layer = 0
|
73 |
+
|
74 |
+
def __init__(self):
|
75 |
+
self.cur_step = 0
|
76 |
+
self.num_att_layers = -1
|
77 |
+
self.cur_att_layer = 0
|
78 |
+
|
79 |
+
def enhance_tensor(tensor: torch.Tensor, contrast_factor: float = 1.67) -> torch.Tensor:
|
80 |
+
""" Compute the attention map contrasting. """
|
81 |
+
mean_feat = tensor.mean(dim=-1, keepdims=True)
|
82 |
+
adjusted_tensor = (tensor - mean_feat) * contrast_factor + mean_feat
|
83 |
+
return adjusted_tensor
|
84 |
+
|
85 |
+
class AttentionStyle(AttentionControl):
|
86 |
+
|
87 |
+
def __init__(self,
|
88 |
+
num_steps,
|
89 |
+
start_ac_layer, end_ac_layer,
|
90 |
+
style_guidance=0.3,
|
91 |
+
mix_q_scale=1.0,
|
92 |
+
de_bug=False,
|
93 |
+
):
|
94 |
+
super(AttentionStyle, self).__init__()
|
95 |
+
|
96 |
+
|
97 |
+
self.start_ac_layer = start_ac_layer
|
98 |
+
self.end_ac_layer = end_ac_layer
|
99 |
+
self.num_steps=num_steps
|
100 |
+
self.de_bug = de_bug
|
101 |
+
self.style_guidance = style_guidance
|
102 |
+
self.coef = None
|
103 |
+
self.mix_q_scale = mix_q_scale
|
104 |
+
|
105 |
+
def forward(self, q, k, v, num_heads, attention_probs, attn):
|
106 |
+
|
107 |
+
|
108 |
+
if self.de_bug:
|
109 |
+
import pdb; pdb.set_trace()
|
110 |
+
|
111 |
+
if self.mix_q_scale < 1.0:
|
112 |
+
q[num_heads*2:] = q[num_heads*2:] * self.mix_q_scale + (1 - self.mix_q_scale) * q[num_heads*1:num_heads*2]
|
113 |
+
b,n,d = k.shape
|
114 |
+
re_q = q[num_heads*2:] # b,n,d,
|
115 |
+
re_k = torch.cat([k[num_heads*1:num_heads*2],k[num_heads*0:num_heads*1]],dim=1) #b,2n,d
|
116 |
+
v_re = torch.cat([v[num_heads*1:num_heads*2],v[num_heads*0:num_heads*1]],dim=1) #b,2n,d
|
117 |
+
re_sim = torch.bmm(re_q, re_k.transpose(-1, -2)) * attn.scale
|
118 |
+
re_sim[:,:,n:] = re_sim[:,:,n:] * self.style_guidance
|
119 |
+
re_attention_map = re_sim.softmax(-1)
|
120 |
+
h_s_re = torch.bmm(re_attention_map, v_re)
|
121 |
+
|
122 |
+
|
123 |
+
|
124 |
+
return h_s_re
|
125 |
+
|
126 |
+
|
127 |
+
|
128 |
+
|
129 |
+
|
utils/merge.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from typing import Tuple, Callable
|
3 |
+
|
4 |
+
|
5 |
+
def do_nothing(x: torch.Tensor, mode:str=None):
|
6 |
+
return x
|
7 |
+
|
8 |
+
|
9 |
+
def mps_gather_workaround(input, dim, index):
|
10 |
+
if input.shape[-1] == 1:
|
11 |
+
return torch.gather(
|
12 |
+
input.unsqueeze(-1),
|
13 |
+
dim - 1 if dim < 0 else dim,
|
14 |
+
index.unsqueeze(-1)
|
15 |
+
).squeeze(-1)
|
16 |
+
else:
|
17 |
+
return torch.gather(input, dim, index)
|
18 |
+
|
19 |
+
|
20 |
+
def bipartite_soft_matching_random2d(metric: torch.Tensor,
|
21 |
+
w: int, h: int, sx: int, sy: int, r: int,
|
22 |
+
no_rand: bool = False,
|
23 |
+
generator: torch.Generator = None) -> Tuple[Callable, Callable]:
|
24 |
+
"""
|
25 |
+
Partitions the tokens into src and dst and merges r tokens from src to dst.
|
26 |
+
Dst tokens are partitioned by choosing one randomy in each (sx, sy) region.
|
27 |
+
|
28 |
+
Args:
|
29 |
+
- metric [B, N, C]: metric to use for similarity
|
30 |
+
- w: image width in tokens
|
31 |
+
- h: image height in tokens
|
32 |
+
- sx: stride in the x dimension for dst, must divide w
|
33 |
+
- sy: stride in the y dimension for dst, must divide h
|
34 |
+
- r: number of tokens to remove (by merging)
|
35 |
+
- no_rand: if true, disable randomness (use top left corner only)
|
36 |
+
- rand_seed: if no_rand is false, and if not None, sets random seed.
|
37 |
+
"""
|
38 |
+
B, N, _ = metric.shape
|
39 |
+
|
40 |
+
if r <= 0:
|
41 |
+
return do_nothing, do_nothing
|
42 |
+
|
43 |
+
gather = mps_gather_workaround if metric.device.type == "mps" else torch.gather
|
44 |
+
|
45 |
+
with torch.no_grad():
|
46 |
+
hsy, wsx = h // sy, w // sx
|
47 |
+
|
48 |
+
# For each sy by sx kernel, randomly assign one token to be dst and the rest src
|
49 |
+
if no_rand:
|
50 |
+
rand_idx = torch.zeros(hsy, wsx, 1, device=metric.device, dtype=torch.int64)
|
51 |
+
else:
|
52 |
+
rand_idx = torch.randint(sy*sx, size=(hsy, wsx, 1), device=generator.device, generator=generator).to(metric.device)
|
53 |
+
|
54 |
+
# The image might not divide sx and sy, so we need to work on a view of the top left if the idx buffer instead
|
55 |
+
idx_buffer_view = torch.zeros(hsy, wsx, sy*sx, device=metric.device, dtype=torch.int64)
|
56 |
+
idx_buffer_view.scatter_(dim=2, index=rand_idx, src=-torch.ones_like(rand_idx, dtype=rand_idx.dtype))
|
57 |
+
idx_buffer_view = idx_buffer_view.view(hsy, wsx, sy, sx).transpose(1, 2).reshape(hsy * sy, wsx * sx)
|
58 |
+
|
59 |
+
# Image is not divisible by sx or sy so we need to move it into a new buffer
|
60 |
+
if (hsy * sy) < h or (wsx * sx) < w:
|
61 |
+
idx_buffer = torch.zeros(h, w, device=metric.device, dtype=torch.int64)
|
62 |
+
idx_buffer[:(hsy * sy), :(wsx * sx)] = idx_buffer_view
|
63 |
+
else:
|
64 |
+
idx_buffer = idx_buffer_view
|
65 |
+
|
66 |
+
# We set dst tokens to be -1 and src to be 0, so an argsort gives us dst|src indices
|
67 |
+
rand_idx = idx_buffer.reshape(1, -1, 1).argsort(dim=1)
|
68 |
+
|
69 |
+
# We're finished with these
|
70 |
+
del idx_buffer, idx_buffer_view
|
71 |
+
|
72 |
+
# rand_idx is currently dst|src, so split them
|
73 |
+
num_dst = hsy * wsx
|
74 |
+
a_idx = rand_idx[:, num_dst:, :] # src
|
75 |
+
b_idx = rand_idx[:, :num_dst, :] # dst
|
76 |
+
|
77 |
+
def split(x):
|
78 |
+
C = x.shape[-1]
|
79 |
+
src = gather(x, dim=1, index=a_idx.expand(B, N - num_dst, C))
|
80 |
+
dst = gather(x, dim=1, index=b_idx.expand(B, num_dst, C))
|
81 |
+
return src, dst
|
82 |
+
|
83 |
+
# Cosine similarity between A and B
|
84 |
+
metric = metric / metric.norm(dim=-1, keepdim=True)
|
85 |
+
a, b = split(metric)
|
86 |
+
scores = a @ b.transpose(-1, -2)
|
87 |
+
|
88 |
+
# Can't reduce more than the # tokens in src
|
89 |
+
r = min(a.shape[1], r)
|
90 |
+
|
91 |
+
# Find the most similar greedily
|
92 |
+
node_max, node_idx = scores.max(dim=-1)
|
93 |
+
edge_idx = node_max.argsort(dim=-1, descending=True)[..., None]
|
94 |
+
|
95 |
+
unm_idx = edge_idx[..., r:, :] # Unmerged Tokens
|
96 |
+
src_idx = edge_idx[..., :r, :] # Merged Tokens
|
97 |
+
dst_idx = gather(node_idx[..., None], dim=-2, index=src_idx)
|
98 |
+
|
99 |
+
def merge(x: torch.Tensor, mode="mean") -> torch.Tensor:
|
100 |
+
src, dst = split(x)
|
101 |
+
n, t1, c = src.shape
|
102 |
+
|
103 |
+
unm = gather(src, dim=-2, index=unm_idx.expand(n, t1 - r, c))
|
104 |
+
src = gather(src, dim=-2, index=src_idx.expand(n, r, c))
|
105 |
+
dst = dst.scatter_reduce(-2, dst_idx.expand(n, r, c), src, reduce=mode)
|
106 |
+
|
107 |
+
return torch.cat([unm, dst], dim=1)
|
108 |
+
|
109 |
+
def unmerge(x: torch.Tensor) -> torch.Tensor:
|
110 |
+
unm_len = unm_idx.shape[1]
|
111 |
+
unm, dst = x[..., :unm_len, :], x[..., unm_len:, :]
|
112 |
+
_, _, c = unm.shape
|
113 |
+
|
114 |
+
src = gather(dst, dim=-2, index=dst_idx.expand(B, r, c))
|
115 |
+
|
116 |
+
# Combine back to the original shape
|
117 |
+
out = torch.zeros(B, N, c, device=x.device, dtype=x.dtype)
|
118 |
+
out.scatter_(dim=-2, index=b_idx.expand(B, num_dst, c), src=dst)
|
119 |
+
out.scatter_(dim=-2, index=gather(a_idx.expand(B, a_idx.shape[1], 1), dim=1, index=unm_idx).expand(B, unm_len, c), src=unm)
|
120 |
+
out.scatter_(dim=-2, index=gather(a_idx.expand(B, a_idx.shape[1], 1), dim=1, index=src_idx).expand(B, r, c), src=src)
|
121 |
+
|
122 |
+
return out
|
123 |
+
|
124 |
+
return merge, unmerge
|
utils/pipeline.py
ADDED
@@ -0,0 +1,434 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import inspect
|
2 |
+
from typing import Any, Callable, Dict, List, Optional, Union
|
3 |
+
import os
|
4 |
+
import numpy as np
|
5 |
+
import PIL
|
6 |
+
import torch
|
7 |
+
from packaging import version
|
8 |
+
from transformers import CLIPImageProcessor, CLIPTextModel, CLIPTokenizer
|
9 |
+
|
10 |
+
from diffusers.configuration_utils import FrozenDict
|
11 |
+
from diffusers.image_processor import PipelineImageInput, VaeImageProcessor
|
12 |
+
from diffusers.loaders import LoraLoaderMixin, TextualInversionLoaderMixin
|
13 |
+
from diffusers.models import AutoencoderKL, UNet2DConditionModel
|
14 |
+
from diffusers.schedulers import LCMScheduler
|
15 |
+
from diffusers.utils import PIL_INTERPOLATION, deprecate, logging
|
16 |
+
from diffusers.utils.torch_utils import randn_tensor
|
17 |
+
from diffusers.pipelines.pipeline_utils import DiffusionPipeline
|
18 |
+
from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput
|
19 |
+
from diffusers.pipelines.stable_diffusion.safety_checker import StableDiffusionSafetyChecker
|
20 |
+
|
21 |
+
logger = logging.get_logger(__name__)
|
22 |
+
|
23 |
+
|
24 |
+
|
25 |
+
class ZePoPipeline(DiffusionPipeline, TextualInversionLoaderMixin, LoraLoaderMixin):
|
26 |
+
model_cpu_offload_seq = "text_encoder->unet->vae"
|
27 |
+
_optional_components = ["safety_checker", "feature_extractor"]
|
28 |
+
|
29 |
+
def __init__(
|
30 |
+
self,
|
31 |
+
vae: AutoencoderKL,
|
32 |
+
text_encoder: CLIPTextModel,
|
33 |
+
tokenizer: CLIPTokenizer,
|
34 |
+
unet: UNet2DConditionModel,
|
35 |
+
scheduler: LCMScheduler,
|
36 |
+
safety_checker: StableDiffusionSafetyChecker,
|
37 |
+
feature_extractor: CLIPImageProcessor,
|
38 |
+
requires_safety_checker: bool = True,
|
39 |
+
):
|
40 |
+
super().__init__()
|
41 |
+
|
42 |
+
if hasattr(scheduler.config, "steps_offset") and scheduler.config.steps_offset != 1:
|
43 |
+
deprecation_message = (
|
44 |
+
f"The configuration file of this scheduler: {scheduler} is outdated. `steps_offset`"
|
45 |
+
f" should be set to 1 instead of {scheduler.config.steps_offset}. Please make sure "
|
46 |
+
"to update the config accordingly as leaving `steps_offset` might led to incorrect results"
|
47 |
+
" in future versions. If you have downloaded this checkpoint from the Hugging Face Hub,"
|
48 |
+
" it would be very nice if you could open a Pull request for the `scheduler/scheduler_config.json`"
|
49 |
+
" file"
|
50 |
+
)
|
51 |
+
deprecate("steps_offset!=1", "1.0.0", deprecation_message, standard_warn=False)
|
52 |
+
new_config = dict(scheduler.config)
|
53 |
+
new_config["steps_offset"] = 1
|
54 |
+
scheduler._internal_dict = FrozenDict(new_config)
|
55 |
+
|
56 |
+
if safety_checker is None and requires_safety_checker:
|
57 |
+
logger.warning(
|
58 |
+
f"You have disabled the safety checker for {self.__class__} by passing `safety_checker=None`. Ensure"
|
59 |
+
" that you abide to the conditions of the Stable Diffusion license and do not expose unfiltered"
|
60 |
+
" results in services or applications open to the public. Both the diffusers team and Hugging Face"
|
61 |
+
" strongly recommend to keep the safety filter enabled in all public facing circumstances, disabling"
|
62 |
+
" it only for use-cases that involve analyzing network behavior or auditing its results. For more"
|
63 |
+
" information, please have a look at https://github.com/huggingface/diffusers/pull/254 ."
|
64 |
+
)
|
65 |
+
|
66 |
+
if safety_checker is not None and feature_extractor is None:
|
67 |
+
raise ValueError(
|
68 |
+
"Make sure to define a feature extractor when loading {self.__class__} if you want to use the safety"
|
69 |
+
" checker. If you do not want to use the safety checker, you can pass `'safety_checker=None'` instead."
|
70 |
+
)
|
71 |
+
is_unet_version_less_0_9_0 = hasattr(unet.config, "_diffusers_version") and version.parse(
|
72 |
+
version.parse(unet.config._diffusers_version).base_version
|
73 |
+
) < version.parse("0.9.0.dev0")
|
74 |
+
is_unet_sample_size_less_64 = hasattr(unet.config, "sample_size") and unet.config.sample_size < 64
|
75 |
+
if is_unet_version_less_0_9_0 and is_unet_sample_size_less_64:
|
76 |
+
deprecation_message = (
|
77 |
+
"The configuration file of the unet has set the default `sample_size` to smaller than"
|
78 |
+
" 64 which seems highly unlikely .If you're checkpoint is a fine-tuned version of any of the"
|
79 |
+
" following: \n- CompVis/stable-diffusion-v1-4 \n- CompVis/stable-diffusion-v1-3 \n-"
|
80 |
+
" CompVis/stable-diffusion-v1-2 \n- CompVis/stable-diffusion-v1-1 \n- runwayml/stable-diffusion-v1-5"
|
81 |
+
" \n- runwayml/stable-diffusion-inpainting \n you should change 'sample_size' to 64 in the"
|
82 |
+
" configuration file. Please make sure to update the config accordingly as leaving `sample_size=32`"
|
83 |
+
" in the config might lead to incorrect results in future versions. If you have downloaded this"
|
84 |
+
" checkpoint from the Hugging Face Hub, it would be very nice if you could open a Pull request for"
|
85 |
+
" the `unet/config.json` file"
|
86 |
+
)
|
87 |
+
deprecate("sample_size<64", "1.0.0", deprecation_message, standard_warn=False)
|
88 |
+
new_config = dict(unet.config)
|
89 |
+
new_config["sample_size"] = 64
|
90 |
+
unet._internal_dict = FrozenDict(new_config)
|
91 |
+
|
92 |
+
self.register_modules(
|
93 |
+
vae=vae,
|
94 |
+
text_encoder=text_encoder,
|
95 |
+
tokenizer=tokenizer,
|
96 |
+
unet=unet,
|
97 |
+
scheduler=scheduler,
|
98 |
+
safety_checker=safety_checker,
|
99 |
+
feature_extractor=feature_extractor,
|
100 |
+
)
|
101 |
+
self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1)
|
102 |
+
self.image_processor = VaeImageProcessor(vae_scale_factor=self.vae_scale_factor)
|
103 |
+
self.register_to_config(requires_safety_checker=requires_safety_checker)
|
104 |
+
|
105 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_img2img.StableDiffusionImg2ImgPipeline.check_inputs
|
106 |
+
def check_inputs(
|
107 |
+
self, prompt, strength, callback_steps, negative_prompt=None, prompt_embeds=None, negative_prompt_embeds=None
|
108 |
+
):
|
109 |
+
if strength < 0 or strength > 1:
|
110 |
+
raise ValueError(f"The value of strength should in [0.0, 1.0] but is {strength}")
|
111 |
+
|
112 |
+
if (callback_steps is None) or (
|
113 |
+
callback_steps is not None and (not isinstance(callback_steps, int) or callback_steps <= 0)
|
114 |
+
):
|
115 |
+
raise ValueError(
|
116 |
+
f"`callback_steps` has to be a positive integer but is {callback_steps} of type"
|
117 |
+
f" {type(callback_steps)}."
|
118 |
+
)
|
119 |
+
|
120 |
+
if prompt is not None and prompt_embeds is not None:
|
121 |
+
raise ValueError(
|
122 |
+
f"Cannot forward both `prompt`: {prompt} and `prompt_embeds`: {prompt_embeds}. Please make sure to"
|
123 |
+
" only forward one of the two."
|
124 |
+
)
|
125 |
+
elif prompt is None and prompt_embeds is None:
|
126 |
+
raise ValueError(
|
127 |
+
"Provide either `prompt` or `prompt_embeds`. Cannot leave both `prompt` and `prompt_embeds` undefined."
|
128 |
+
)
|
129 |
+
elif prompt is not None and (not isinstance(prompt, str) and not isinstance(prompt, list)):
|
130 |
+
raise ValueError(f"`prompt` has to be of type `str` or `list` but is {type(prompt)}")
|
131 |
+
|
132 |
+
if negative_prompt is not None and negative_prompt_embeds is not None:
|
133 |
+
raise ValueError(
|
134 |
+
f"Cannot forward both `negative_prompt`: {negative_prompt} and `negative_prompt_embeds`:"
|
135 |
+
f" {negative_prompt_embeds}. Please make sure to only forward one of the two."
|
136 |
+
)
|
137 |
+
|
138 |
+
if prompt_embeds is not None and negative_prompt_embeds is not None:
|
139 |
+
if prompt_embeds.shape != negative_prompt_embeds.shape:
|
140 |
+
raise ValueError(
|
141 |
+
"`prompt_embeds` and `negative_prompt_embeds` must have the same shape when passed directly, but"
|
142 |
+
f" got: `prompt_embeds` {prompt_embeds.shape} != `negative_prompt_embeds`"
|
143 |
+
f" {negative_prompt_embeds.shape}."
|
144 |
+
)
|
145 |
+
|
146 |
+
def prepare_extra_step_kwargs(self, generator, eta):
|
147 |
+
|
148 |
+
|
149 |
+
accepts_eta = "eta" in set(inspect.signature(self.scheduler.step).parameters.keys())
|
150 |
+
extra_step_kwargs = {}
|
151 |
+
if accepts_eta:
|
152 |
+
extra_step_kwargs["eta"] = eta
|
153 |
+
|
154 |
+
# check if the scheduler accepts generator
|
155 |
+
accepts_generator = "generator" in set(inspect.signature(self.scheduler.step).parameters.keys())
|
156 |
+
if accepts_generator:
|
157 |
+
extra_step_kwargs["generator"] = generator
|
158 |
+
return extra_step_kwargs
|
159 |
+
|
160 |
+
|
161 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline.decode_latents
|
162 |
+
def decode_latents(self, latents):
|
163 |
+
deprecation_message = "The decode_latents method is deprecated and will be removed in 1.0.0. Please use VaeImageProcessor.postprocess(...) instead"
|
164 |
+
deprecate("decode_latents", "1.0.0", deprecation_message, standard_warn=False)
|
165 |
+
|
166 |
+
latents = 1 / self.vae.config.scaling_factor * latents
|
167 |
+
image = self.vae.decode(latents, return_dict=False)[0]
|
168 |
+
image = (image / 2 + 0.5).clamp(0, 1)
|
169 |
+
# we always cast to float32 as this does not cause significant overhead and is compatible with bfloat16
|
170 |
+
image = image.cpu().permute(0, 2, 3, 1).float().numpy()
|
171 |
+
return image
|
172 |
+
|
173 |
+
# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_img2img.StableDiffusionImg2ImgPipeline.get_timesteps
|
174 |
+
def get_timesteps(self, num_inference_steps, strength, device):
|
175 |
+
# get the original timestep using init_timestep
|
176 |
+
init_timestep = min( int(num_inference_steps * strength), num_inference_steps)
|
177 |
+
init_timestep = max(init_timestep, 1)
|
178 |
+
t_start = max(num_inference_steps - init_timestep, 0)
|
179 |
+
|
180 |
+
timesteps = self.scheduler.timesteps[t_start * self.scheduler.order :]
|
181 |
+
|
182 |
+
return timesteps, num_inference_steps - t_start
|
183 |
+
|
184 |
+
def prepare_latents(self, image, timestep, device,dtype, denoise_model, generator=None):
|
185 |
+
image = image.to(device=device,dtype=dtype)
|
186 |
+
|
187 |
+
batch_size = image.shape[0]
|
188 |
+
|
189 |
+
if image.shape[1] == 4:
|
190 |
+
init_latents = image
|
191 |
+
|
192 |
+
else:
|
193 |
+
if isinstance(generator, list) and len(generator) != batch_size:
|
194 |
+
raise ValueError(
|
195 |
+
f"You have passed a list of generators of length {len(generator)}, but requested an effective batch"
|
196 |
+
f" size of {batch_size}. Make sure the batch size matches the length of the generators."
|
197 |
+
)
|
198 |
+
|
199 |
+
if isinstance(generator, list):
|
200 |
+
init_latents = [
|
201 |
+
self.vae.encode(image[i : i + 1]).latent_dist.sample(generator[i]) for i in range(batch_size)
|
202 |
+
]
|
203 |
+
init_latents = torch.cat(init_latents, dim=0)
|
204 |
+
else:
|
205 |
+
init_latents = self.vae.encode(image).latent_dist.sample(generator)
|
206 |
+
|
207 |
+
init_latents = self.vae.config.scaling_factor * init_latents
|
208 |
+
|
209 |
+
|
210 |
+
|
211 |
+
# add noise to latents using the timestep
|
212 |
+
shape = init_latents.shape
|
213 |
+
noise = randn_tensor(shape, generator=generator, device=device, dtype=dtype)
|
214 |
+
|
215 |
+
# get latents
|
216 |
+
clean_latents = init_latents
|
217 |
+
if denoise_model:
|
218 |
+
init_latents = self.scheduler.add_noise(init_latents, noise, timestep)
|
219 |
+
latents = init_latents
|
220 |
+
else:
|
221 |
+
latents = noise
|
222 |
+
|
223 |
+
return latents, clean_latents
|
224 |
+
|
225 |
+
@torch.no_grad()
|
226 |
+
def __call__(
|
227 |
+
self,
|
228 |
+
prompt: Union[str, List[str]],
|
229 |
+
negative_prompt: Union[str, List[str]]=None,
|
230 |
+
image: PipelineImageInput = None,
|
231 |
+
style: PipelineImageInput = None,
|
232 |
+
strength: float = 0.5,
|
233 |
+
num_inference_steps: Optional[int] = 50,
|
234 |
+
original_inference_steps: Optional[int] = 50,
|
235 |
+
guidance_scale: Optional[float] = 7.5,
|
236 |
+
eta: Optional[float] = 1.0,
|
237 |
+
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
|
238 |
+
prompt_embeds: Optional[torch.FloatTensor] = None,
|
239 |
+
output_type: Optional[str] = "pil",
|
240 |
+
return_dict: bool = True,
|
241 |
+
callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None,
|
242 |
+
callback_steps: int = 1,
|
243 |
+
cross_attention_kwargs: Optional[Dict[str, Any]] = None,
|
244 |
+
denoise_model: Optional[bool] = True,
|
245 |
+
fix_step_index = 0,
|
246 |
+
target_start_step = -1,
|
247 |
+
save_intermediate = False,
|
248 |
+
de_bug=False,
|
249 |
+
|
250 |
+
):
|
251 |
+
# 1. Check inputs
|
252 |
+
self.check_inputs(prompt, strength, callback_steps)
|
253 |
+
num_inference_steps = int(num_inference_steps * (1/strength))
|
254 |
+
print(f'num_inference_steps {num_inference_steps} is multiple by {int(1/strength)}.')
|
255 |
+
# 2. Define call parameters
|
256 |
+
batch_size = len(prompt)
|
257 |
+
device = self._execution_device
|
258 |
+
# here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)
|
259 |
+
# of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`
|
260 |
+
# corresponds to doing no classifier free guidance.
|
261 |
+
do_classifier_free_guidance = guidance_scale > 1.0
|
262 |
+
|
263 |
+
|
264 |
+
# text embeddings
|
265 |
+
text_input = self.tokenizer(
|
266 |
+
prompt,
|
267 |
+
padding="max_length",
|
268 |
+
max_length=77,
|
269 |
+
return_tensors="pt"
|
270 |
+
)
|
271 |
+
dtype=self.unet.dtype
|
272 |
+
prompt_embeds = self.text_encoder(text_input.input_ids.to(device))[0]
|
273 |
+
prompt_embeds=prompt_embeds.to(dtype=dtype, device=device)
|
274 |
+
#print("input text embeddings :", prompt_embeds.shape)
|
275 |
+
|
276 |
+
if guidance_scale > 1.:
|
277 |
+
max_length = text_input.input_ids.shape[-1]
|
278 |
+
if negative_prompt:
|
279 |
+
uc_text = negative_prompt
|
280 |
+
else:
|
281 |
+
uc_text = ""
|
282 |
+
# uc_text = "ugly, tiling, poorly drawn hands, poorly drawn feet, body out of frame, cut off, low contrast, underexposed, distorted face"
|
283 |
+
unconditional_input = self.tokenizer(
|
284 |
+
[uc_text] * batch_size,
|
285 |
+
padding="max_length",
|
286 |
+
max_length=77,
|
287 |
+
return_tensors="pt"
|
288 |
+
)
|
289 |
+
# unconditional_input.input_ids = unconditional_input.input_ids[:, 1:]
|
290 |
+
unconditional_embeddings = self.text_encoder(unconditional_input.input_ids.to(device))[0]
|
291 |
+
unconditional_embeddings=unconditional_embeddings.to(dtype=dtype, device=device)
|
292 |
+
prompt_embeds = torch.cat([unconditional_embeddings, prompt_embeds], dim=0)
|
293 |
+
|
294 |
+
#print("prompt embeds shape: ", prompt_embeds.shape)
|
295 |
+
|
296 |
+
|
297 |
+
# 4. Preprocess image
|
298 |
+
image = self.image_processor.preprocess(image)
|
299 |
+
style = self.image_processor.preprocess(style)
|
300 |
+
|
301 |
+
# 5. Prepare timesteps
|
302 |
+
if isinstance(self.scheduler, LCMScheduler):
|
303 |
+
self.scheduler.set_timesteps(
|
304 |
+
num_inference_steps=num_inference_steps,
|
305 |
+
device=device,
|
306 |
+
original_inference_steps=original_inference_steps)
|
307 |
+
else:
|
308 |
+
self.scheduler.set_timesteps(
|
309 |
+
num_inference_steps=num_inference_steps,
|
310 |
+
device=device,)
|
311 |
+
print(f"num_inference_steps is {self.scheduler.timesteps}")
|
312 |
+
timesteps, num_inference_steps = self.get_timesteps(num_inference_steps, strength, device)
|
313 |
+
|
314 |
+
#print(f"All timesteps is : {timesteps}")
|
315 |
+
latent_timestep = torch.tensor([fix_step_index], device=device)
|
316 |
+
|
317 |
+
assert timesteps != []
|
318 |
+
|
319 |
+
print("The time-steps are: ", timesteps)
|
320 |
+
|
321 |
+
# 6. Prepare latent variables
|
322 |
+
src_latents, src_clean_latents = self.prepare_latents(
|
323 |
+
image, latent_timestep, device,dtype, denoise_model, generator
|
324 |
+
)
|
325 |
+
|
326 |
+
|
327 |
+
sty_latents, sty_clean_latents = self.prepare_latents(
|
328 |
+
style, latent_timestep, device,dtype, denoise_model, generator
|
329 |
+
)
|
330 |
+
|
331 |
+
|
332 |
+
mutual_latents, _ = self.prepare_latents(
|
333 |
+
image, timesteps[:1], device, dtype, denoise_model, generator
|
334 |
+
)
|
335 |
+
|
336 |
+
# mutual_latents = src_latents
|
337 |
+
#latents = torch.cat([sty_t_latents, src_t_latents], dim=0)
|
338 |
+
# 7. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
|
339 |
+
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
|
340 |
+
generator = extra_step_kwargs.pop("generator", None)
|
341 |
+
|
342 |
+
# 8. Denoising loop
|
343 |
+
num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order
|
344 |
+
with self.progress_bar(total=num_inference_steps) as progress_bar:
|
345 |
+
for i, t in enumerate(timesteps):
|
346 |
+
if de_bug:
|
347 |
+
|
348 |
+
import pdb; pdb.set_trace()
|
349 |
+
|
350 |
+
model_input = torch.cat(
|
351 |
+
[
|
352 |
+
sty_latents,
|
353 |
+
src_latents,
|
354 |
+
mutual_latents
|
355 |
+
|
356 |
+
],
|
357 |
+
dim=0,
|
358 |
+
)
|
359 |
+
# predict the noise residual
|
360 |
+
if do_classifier_free_guidance:
|
361 |
+
concat_latent_model_input = torch.cat([model_input] * 2)
|
362 |
+
concat_prompt_embeds = prompt_embeds
|
363 |
+
#raise NotImplementedError("Classifier free guidance is not yet supported")
|
364 |
+
else:
|
365 |
+
concat_latent_model_input = model_input
|
366 |
+
concat_prompt_embeds = prompt_embeds
|
367 |
+
assert len(concat_prompt_embeds) == len(concat_latent_model_input)
|
368 |
+
|
369 |
+
timestep = torch.cat([latent_timestep] * (batch_size-1)+[t[None]], dim=0)
|
370 |
+
|
371 |
+
if do_classifier_free_guidance:
|
372 |
+
timestep = torch.cat([timestep] * 2)
|
373 |
+
|
374 |
+
|
375 |
+
concat_noise_pred = self.unet(
|
376 |
+
concat_latent_model_input,
|
377 |
+
timestep,
|
378 |
+
cross_attention_kwargs=cross_attention_kwargs,
|
379 |
+
encoder_hidden_states=concat_prompt_embeds,
|
380 |
+
).sample
|
381 |
+
# perform guidance
|
382 |
+
if do_classifier_free_guidance:
|
383 |
+
|
384 |
+
(
|
385 |
+
noise_pred,
|
386 |
+
noise_pred_uncond,
|
387 |
+
) = concat_noise_pred.chunk(2, dim=0)
|
388 |
+
|
389 |
+
|
390 |
+
noise_pred = noise_pred_uncond + guidance_scale * (noise_pred - noise_pred_uncond)
|
391 |
+
|
392 |
+
else:
|
393 |
+
noise_pred = concat_noise_pred
|
394 |
+
|
395 |
+
(style_noise_pred, source_noise_pred, mutual_noise_pred) = noise_pred.chunk(3, dim=0)
|
396 |
+
|
397 |
+
noise = torch.randn_like(
|
398 |
+
source_noise_pred
|
399 |
+
)
|
400 |
+
|
401 |
+
|
402 |
+
if isinstance(self.scheduler, LCMScheduler):
|
403 |
+
mutual_latents, pred_x0_mutual = self.scheduler.step(mutual_noise_pred, t, mutual_latents, return_dict=False)
|
404 |
+
else:
|
405 |
+
ddim_out = self.scheduler.step(mutual_noise_pred, t, mutual_latents)
|
406 |
+
mutual_latents, pred_x0_mutual = ddim_out.prev_sample, ddim_out.pred_original_sample
|
407 |
+
|
408 |
+
|
409 |
+
pred_x0 = torch.cat([sty_clean_latents,src_clean_latents,pred_x0_mutual ], dim=0)
|
410 |
+
|
411 |
+
if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):
|
412 |
+
progress_bar.update()
|
413 |
+
|
414 |
+
model_input = torch.cat([sty_latents,src_latents,mutual_latents],dim=0,)
|
415 |
+
|
416 |
+
# 9. Post-processing
|
417 |
+
if not output_type == "latent":
|
418 |
+
image = self.vae.decode(pred_x0 / self.vae.config.scaling_factor, return_dict=False)[0]
|
419 |
+
has_nsfw_concept = None
|
420 |
+
else:
|
421 |
+
image = pred_x0
|
422 |
+
has_nsfw_concept = None
|
423 |
+
|
424 |
+
if has_nsfw_concept is None:
|
425 |
+
do_denormalize = [True] * image.shape[0]
|
426 |
+
else:
|
427 |
+
do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept]
|
428 |
+
|
429 |
+
image = self.image_processor.postprocess(image, output_type='np', do_denormalize=do_denormalize)
|
430 |
+
|
431 |
+
if not return_dict:
|
432 |
+
return (image, has_nsfw_concept)
|
433 |
+
|
434 |
+
return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)
|
utils/ptp_utils.py
ADDED
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright 2022 Google LLC
|
2 |
+
#
|
3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4 |
+
# you may not use this file except in compliance with the License.
|
5 |
+
# You may obtain a copy of the License at
|
6 |
+
#
|
7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8 |
+
#
|
9 |
+
# Unless required by applicable law or agreed to in writing, software
|
10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 |
+
# See the License for the specific language governing permissions and
|
13 |
+
# limitations under the License.
|
14 |
+
|
15 |
+
import numpy as np
|
16 |
+
import torch
|
17 |
+
from typing import Optional, Union, Tuple, Dict
|
18 |
+
from PIL import Image
|
19 |
+
from . import merge
|
20 |
+
from .utils import isinstance_str, init_generator
|
21 |
+
|
22 |
+
def save_images(images,dest, num_rows=1, offset_ratio=0.02):
|
23 |
+
if type(images) is list:
|
24 |
+
num_empty = len(images) % num_rows
|
25 |
+
elif images.ndim == 4:
|
26 |
+
num_empty = images.shape[0] % num_rows
|
27 |
+
else:
|
28 |
+
images = [images]
|
29 |
+
num_empty = 0
|
30 |
+
|
31 |
+
pil_img = Image.fromarray(images[-1])
|
32 |
+
pil_img.save(dest)
|
33 |
+
# display(pil_img)
|
34 |
+
|
35 |
+
|
36 |
+
def save_image(images,dest, num_rows=1, offset_ratio=0.02):
|
37 |
+
print(images.shape)
|
38 |
+
pil_img = Image.fromarray(images[0])
|
39 |
+
pil_img.save(dest)
|
40 |
+
|
41 |
+
def register_attention_control(model, controller, tome, ratio, sx, sy, de_bug):
|
42 |
+
class AttnProcessor():
|
43 |
+
def __init__(self,place_in_unet,de_bug):
|
44 |
+
self.place_in_unet = place_in_unet
|
45 |
+
self.de_bug = de_bug
|
46 |
+
def __call__(self,
|
47 |
+
attn,
|
48 |
+
hidden_states,
|
49 |
+
encoder_hidden_states=None,
|
50 |
+
attention_mask=None,
|
51 |
+
temb=None,
|
52 |
+
scale=1.0,):
|
53 |
+
# The `Attention` class can call different attention processors / attention functions
|
54 |
+
|
55 |
+
residual = hidden_states
|
56 |
+
|
57 |
+
if attn.spatial_norm is not None:
|
58 |
+
hidden_states = attn.spatial_norm(hidden_states, temb)
|
59 |
+
|
60 |
+
input_ndim = hidden_states.ndim
|
61 |
+
|
62 |
+
if input_ndim == 4:
|
63 |
+
batch_size, channel, height, width = hidden_states.shape
|
64 |
+
hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2)
|
65 |
+
|
66 |
+
h = attn.heads
|
67 |
+
is_cross = encoder_hidden_states is not None
|
68 |
+
if encoder_hidden_states is None:
|
69 |
+
encoder_hidden_states = hidden_states
|
70 |
+
elif attn.norm_cross:
|
71 |
+
encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states)
|
72 |
+
|
73 |
+
batch_size, sequence_length, _ = (
|
74 |
+
hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape
|
75 |
+
)
|
76 |
+
attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size)
|
77 |
+
|
78 |
+
|
79 |
+
|
80 |
+
|
81 |
+
q = attn.to_q(hidden_states)
|
82 |
+
k = attn.to_k(encoder_hidden_states)
|
83 |
+
v = attn.to_v(encoder_hidden_states)
|
84 |
+
q = attn.head_to_batch_dim(q)
|
85 |
+
k = attn.head_to_batch_dim(k)
|
86 |
+
v = attn.head_to_batch_dim(v)
|
87 |
+
|
88 |
+
|
89 |
+
# print('unmerge:', q.shape)
|
90 |
+
#pass
|
91 |
+
attention_probs = attn.get_attention_scores(q, k, attention_mask) # bh,n,n
|
92 |
+
|
93 |
+
#
|
94 |
+
|
95 |
+
if is_cross:
|
96 |
+
pass
|
97 |
+
#attention_probs = controller(attention_probs , is_cross, self.place_in_unet)
|
98 |
+
x = hidden_states
|
99 |
+
|
100 |
+
hidden_states = torch.bmm(attention_probs, v)
|
101 |
+
|
102 |
+
if not is_cross:
|
103 |
+
|
104 |
+
if tome:
|
105 |
+
|
106 |
+
r = int(x.shape[1] * ratio)
|
107 |
+
H = W = int(np.sqrt(x.shape[1]))
|
108 |
+
generator = init_generator(x.device)
|
109 |
+
m, u = merge.bipartite_soft_matching_random2d(x, W, H, sx, sy, r,
|
110 |
+
no_rand=False, generator=generator)
|
111 |
+
x = m(x)
|
112 |
+
m_k = attn.to_k(x)
|
113 |
+
m_v = attn.to_v(x)
|
114 |
+
m_k = attn.head_to_batch_dim(m_k)
|
115 |
+
m_v = attn.head_to_batch_dim(m_v)
|
116 |
+
# print('merged:', m_q.shape)
|
117 |
+
# m_k = k
|
118 |
+
# m_v = v
|
119 |
+
#m_k, m_v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (m_k, m_v))
|
120 |
+
else:
|
121 |
+
m_k = k
|
122 |
+
m_v = v
|
123 |
+
# if self.de_bug:
|
124 |
+
# import pdb;pdb.set_trace()
|
125 |
+
h_s_re = controller(q, m_k, m_v, attn.heads, attention_probs, attn)
|
126 |
+
|
127 |
+
if h_s_re != None and hidden_states.shape[0]//attn.heads == 3:
|
128 |
+
|
129 |
+
hidden_states[2*attn.heads:]=h_s_re
|
130 |
+
|
131 |
+
if hidden_states.shape[0]//attn.heads != 3 and h_s_re != None:
|
132 |
+
(u_h_s_re, c_h_s_re) = h_s_re
|
133 |
+
if u_h_s_re != None:
|
134 |
+
|
135 |
+
hidden_states[2*attn.heads:3*attn.heads] = u_h_s_re
|
136 |
+
hidden_states[5*attn.heads:] = c_h_s_re
|
137 |
+
hidden_states = attn.batch_to_head_dim(hidden_states)
|
138 |
+
|
139 |
+
# linear proj
|
140 |
+
hidden_states = attn.to_out[0](hidden_states)
|
141 |
+
# dropout
|
142 |
+
hidden_states = attn.to_out[1](hidden_states)
|
143 |
+
|
144 |
+
if input_ndim == 4:
|
145 |
+
hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width)
|
146 |
+
|
147 |
+
if attn.residual_connection:
|
148 |
+
hidden_states = hidden_states + residual
|
149 |
+
|
150 |
+
hidden_states = hidden_states / attn.rescale_output_factor
|
151 |
+
|
152 |
+
return hidden_states
|
153 |
+
|
154 |
+
|
155 |
+
def register_recr(net_, count, place_in_unet):
|
156 |
+
for idx, m in enumerate(net_.modules()):
|
157 |
+
# print(m.__class__.__name__)
|
158 |
+
if m.__class__.__name__ == "Attention":
|
159 |
+
count+=1
|
160 |
+
m.processor = AttnProcessor( place_in_unet, de_bug)
|
161 |
+
return count
|
162 |
+
|
163 |
+
cross_att_count = 0
|
164 |
+
sub_nets = model.unet.named_children()
|
165 |
+
for net in sub_nets:
|
166 |
+
if "down" in net[0]:
|
167 |
+
cross_att_count += register_recr(net[1], 0, "down")
|
168 |
+
elif "up" in net[0]:
|
169 |
+
cross_att_count += register_recr(net[1], 0, "up")
|
170 |
+
elif "mid" in net[0]:
|
171 |
+
cross_att_count += register_recr(net[1], 0, "mid")
|
172 |
+
controller.num_att_layers = cross_att_count
|
173 |
+
#print(f'this model have {cross_att_count} attn layer')
|
174 |
+
|
175 |
+
def get_word_inds(text: str, word_place: int, tokenizer):
|
176 |
+
split_text = text.split(" ")
|
177 |
+
if type(word_place) is str:
|
178 |
+
word_place = [i for i, word in enumerate(split_text) if word_place == word]
|
179 |
+
elif type(word_place) is int:
|
180 |
+
word_place = [word_place]
|
181 |
+
out = []
|
182 |
+
if len(word_place) > 0:
|
183 |
+
words_encode = [tokenizer.decode([item]).strip("#") for item in tokenizer.encode(text)][1:-1]
|
184 |
+
cur_len, ptr = 0, 0
|
185 |
+
|
186 |
+
for i in range(len(words_encode)):
|
187 |
+
cur_len += len(words_encode[i])
|
188 |
+
if ptr in word_place:
|
189 |
+
out.append(i + 1)
|
190 |
+
if cur_len >= len(split_text[ptr]):
|
191 |
+
ptr += 1
|
192 |
+
cur_len = 0
|
193 |
+
return np.array(out)
|
194 |
+
|
195 |
+
|
196 |
+
def update_alpha_time_word(alpha, bounds: Union[float, Tuple[float, float]], prompt_ind: int, word_inds: Optional[torch.Tensor]=None):
|
197 |
+
if type(bounds) is float:
|
198 |
+
bounds = 0, bounds
|
199 |
+
start, end = int(bounds[0] * alpha.shape[0]), int(bounds[1] * alpha.shape[0])
|
200 |
+
if word_inds is None:
|
201 |
+
word_inds = torch.arange(alpha.shape[2])
|
202 |
+
alpha[: start, prompt_ind, word_inds] = 0
|
203 |
+
alpha[start: end, prompt_ind, word_inds] = 1
|
204 |
+
alpha[end:, prompt_ind, word_inds] = 0
|
205 |
+
return alpha
|
206 |
+
|
207 |
+
|
208 |
+
def get_time_words_attention_alpha(prompts, num_steps, cross_replace_steps: Union[float, Tuple[float, float], Dict[str, Tuple[float, float]]],
|
209 |
+
tokenizer, max_num_words=77):
|
210 |
+
if type(cross_replace_steps) is not dict:
|
211 |
+
cross_replace_steps = {"default_": cross_replace_steps}
|
212 |
+
if "default_" not in cross_replace_steps:
|
213 |
+
cross_replace_steps["default_"] = (0., 1.)
|
214 |
+
alpha_time_words = torch.zeros(num_steps + 1, len(prompts) - 1, max_num_words)
|
215 |
+
for i in range(len(prompts) - 1):
|
216 |
+
alpha_time_words = update_alpha_time_word(alpha_time_words, cross_replace_steps["default_"],
|
217 |
+
i)
|
218 |
+
for key, item in cross_replace_steps.items():
|
219 |
+
if key != "default_":
|
220 |
+
inds = [get_word_inds(prompts[i], key, tokenizer) for i in range(1, len(prompts))]
|
221 |
+
for i, ind in enumerate(inds):
|
222 |
+
if len(ind) > 0:
|
223 |
+
alpha_time_words = update_alpha_time_word(alpha_time_words, item, i, ind)
|
224 |
+
alpha_time_words = alpha_time_words.reshape(num_steps + 1, len(prompts) - 1, 1, 1, max_num_words) # time, batch, heads, pixels, words
|
225 |
+
return alpha_time_words
|
utils/utils.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
|
3 |
+
|
4 |
+
def isinstance_str(x: object, cls_name: str):
|
5 |
+
"""
|
6 |
+
Checks whether x has any class *named* cls_name in its ancestry.
|
7 |
+
Doesn't require access to the class's implementation.
|
8 |
+
|
9 |
+
Useful for patching!
|
10 |
+
"""
|
11 |
+
|
12 |
+
for _cls in x.__class__.__mro__:
|
13 |
+
if _cls.__name__ == cls_name:
|
14 |
+
return True
|
15 |
+
|
16 |
+
return False
|
17 |
+
|
18 |
+
|
19 |
+
def init_generator(device: torch.device, fallback: torch.Generator=None):
|
20 |
+
"""
|
21 |
+
Forks the current default random generator given device.
|
22 |
+
"""
|
23 |
+
if device.type == "cpu":
|
24 |
+
return torch.Generator(device="cpu").set_state(torch.get_rng_state())
|
25 |
+
elif device.type == "cuda":
|
26 |
+
return torch.Generator(device=device).set_state(torch.cuda.get_rng_state())
|
27 |
+
else:
|
28 |
+
if fallback is None:
|
29 |
+
return init_generator(torch.device("cpu"))
|
30 |
+
else:
|
31 |
+
return fallback
|
32 |
+
|