Add files via upload

This commit is contained in:
smthemex
2024-11-15 16:11:02 +08:00
committed by GitHub
parent e4db43ba2e
commit 57e8a149bc
9 changed files with 3214 additions and 1 deletions
-1
View File
@@ -1 +0,0 @@
+292
View File
@@ -0,0 +1,292 @@
# Copyright 2023 The HuggingFace Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Not a contribution
# Changes made by NVIDIA CORPORATION & AFFILIATES enabling ConsiStory or otherwise documented as NVIDIA-proprietary
# are not a contribution and subject to the license under the LICENSE file located at the root directory.
from diffusers.utils import USE_PEFT_BACKEND
from typing import Callable, Optional
import torch
from diffusers.models.attention_processor import Attention
from .consistory_utils import AnchorCache, FeatureInjector, QueryStore, xformers
class ConsistoryAttnStoreProcessor:
def __init__(self, attnstore, place_in_unet):
super().__init__()
self.attnstore = attnstore
self.place_in_unet = place_in_unet
def __call__(self, attn: Attention, hidden_states, encoder_hidden_states=None, attention_mask=None, record_attention=True, **kwargs):
batch_size, sequence_length, _ = hidden_states.shape
attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size)
query = attn.to_q(hidden_states)
is_cross = encoder_hidden_states is not None
encoder_hidden_states = encoder_hidden_states if encoder_hidden_states is not None else hidden_states
key = attn.to_k(encoder_hidden_states)
value = attn.to_v(encoder_hidden_states)
query = attn.head_to_batch_dim(query)
key = attn.head_to_batch_dim(key)
value = attn.head_to_batch_dim(value)
attention_probs = attn.get_attention_scores(query, key, attention_mask)
# only need to store attention maps during the Attend and Excite process
# if attention_probs.requires_grad:
if record_attention:
self.attnstore(attention_probs, is_cross, self.place_in_unet, attn.heads)
hidden_states = torch.bmm(attention_probs, value)
hidden_states = attn.batch_to_head_dim(hidden_states)
# linear proj
hidden_states = attn.to_out[0](hidden_states)
# dropout
hidden_states = attn.to_out[1](hidden_states)
return hidden_states
class ConsistoryExtendedAttnXFormersAttnProcessor:
r"""
Processor for implementing memory efficient attention using xFormers.
Args:
attention_op (`Callable`, *optional*, defaults to `None`):
The base
[operator](https://facebookresearch.github.io/xformers/components/ops.html#xformers.ops.AttentionOpBase) to
use as the attention operator. It is recommended to set to `None`, and allow xFormers to choose the best
operator.
"""
def __init__(self, place_in_unet, attnstore, extended_attn_kwargs, attention_op: Optional[Callable] = None):
self.attention_op = attention_op
self.t_range = extended_attn_kwargs.get('t_range', [])
self.extend_kv_unet_parts = extended_attn_kwargs.get('extend_kv_unet_parts', ['down', 'mid', 'up'])
self.place_in_unet = place_in_unet
self.curr_unet_part = self.place_in_unet.split('_')[0]
self.attnstore = attnstore
def __call__(
self,
attn: Attention,
hidden_states: torch.FloatTensor,
encoder_hidden_states: Optional[torch.FloatTensor] = None,
attention_mask: Optional[torch.FloatTensor] = None,
temb: Optional[torch.FloatTensor] = None,
scale: float = 1.0,
perform_extend_attn: bool = False,
query_store: Optional[QueryStore] = None,
feature_injector: Optional[FeatureInjector] = None,
anchors_cache: Optional[AnchorCache] = None,
**kwargs
) -> torch.FloatTensor:
residual = hidden_states
args = () if USE_PEFT_BACKEND else (scale,)
if attn.spatial_norm is not None:
hidden_states = attn.spatial_norm(hidden_states, temb)
input_ndim = hidden_states.ndim
if input_ndim == 4:
batch_size, channel, height, width = hidden_states.shape
hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2)
else:
batch_size, wh, channel = hidden_states.shape
height = width = int(wh ** 0.5)
is_cross = encoder_hidden_states is not None
perform_extend_attn = perform_extend_attn and (not is_cross) and \
any([self.attnstore.curr_iter >= x[0] and self.attnstore.curr_iter <= x[1] for x in self.t_range]) and \
self.curr_unet_part in self.extend_kv_unet_parts
batch_size, key_tokens, _ = (
hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape
)
attention_mask = attn.prepare_attention_mask(attention_mask, key_tokens, batch_size)
if attention_mask is not None:
# expand our mask's singleton query_tokens dimension:
# [batch*heads, 1, key_tokens] ->
# [batch*heads, query_tokens, key_tokens]
# so that it can be added as a bias onto the attention scores that xformers computes:
# [batch*heads, query_tokens, key_tokens]
# we do this explicitly because xformers doesn't broadcast the singleton dimension for us.
_, query_tokens, _ = hidden_states.shape
attention_mask = attention_mask.expand(-1, query_tokens, -1)
if attn.group_norm is not None:
hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2)
query = attn.to_q(hidden_states, *args)
if (self.curr_unet_part in self.extend_kv_unet_parts) and query_store and query_store.mode == 'cache':
query_store.cache_query(query, self.place_in_unet)
elif perform_extend_attn and query_store and query_store.mode == 'inject':
query = query_store.inject_query(query, self.place_in_unet, self.attnstore.curr_iter)
if encoder_hidden_states is None:
encoder_hidden_states = hidden_states
elif attn.norm_cross:
encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states)
key = attn.to_k(encoder_hidden_states, *args)
value = attn.to_v(encoder_hidden_states, *args)
query = attn.head_to_batch_dim(query).contiguous()
if perform_extend_attn:
# Anchor Caching
if anchors_cache and anchors_cache.is_cache_mode():
if self.place_in_unet not in anchors_cache.input_h_cache:
anchors_cache.input_h_cache[self.place_in_unet] = {}
# Hidden states inside the mask, for uncond (index 0) and cond (index 1) prompts
subjects_hidden_states = torch.stack([x[self.attnstore.last_mask_dropout[width]] for x in hidden_states.chunk(2)])
anchors_cache.input_h_cache[self.place_in_unet][self.attnstore.curr_iter] = subjects_hidden_states
if anchors_cache and anchors_cache.is_inject_mode():
# We make extended key and value by concatenating the original key and value with the query.
anchors_hidden_states = anchors_cache.input_h_cache[self.place_in_unet][self.attnstore.curr_iter]
anchors_keys = attn.to_k(anchors_hidden_states, *args)
anchors_values = attn.to_v(anchors_hidden_states, *args)
extended_key = torch.cat([torch.cat([key.chunk(2, dim=0)[x], anchors_keys[x].unsqueeze(0)], dim=1) for x in range(2)])
extended_value = torch.cat([torch.cat([value.chunk(2, dim=0)[x], anchors_values[x].unsqueeze(0)], dim=1) for x in range(2)])
extended_key = attn.head_to_batch_dim(extended_key).contiguous()
extended_value = attn.head_to_batch_dim(extended_value).contiguous()
# attn_masks needs to be of shape [batch_size, query_tokens, key_tokens]
hidden_states = xformers.ops.memory_efficient_attention(
query, extended_key, extended_value, op=self.attention_op, scale=attn.scale
)
else:
# # We make extended key and value by concatenating the original key and value with the query.
# attention_mask_bias = self.attnstore.get_attn_mask_bias(tgt_size = width, bsz = batch_size)
# if attention_mask_bias is not None:
# attention_mask_bias = torch.cat([x.unsqueeze(0).expand(attn.heads, -1, -1) for x in attention_mask_bias])
# Pre-allocate the output tensor
ex_out = torch.empty_like(query)
for i in range(batch_size):
start_idx = i * attn.heads
end_idx = start_idx + attn.heads
attention_mask = self.attnstore.get_extended_attn_mask_instance(width, i%(batch_size//2))
curr_q = query[start_idx:end_idx]
if i < batch_size//2:
curr_k = key[:batch_size//2]
curr_v = value[:batch_size//2]
else:
curr_k = key[batch_size//2:]
curr_v = value[batch_size//2:]
curr_k = curr_k.flatten(0,1)[attention_mask].unsqueeze(0)
curr_v = curr_v.flatten(0,1)[attention_mask].unsqueeze(0)
curr_k = attn.head_to_batch_dim(curr_k).contiguous()
curr_v = attn.head_to_batch_dim(curr_v).contiguous()
hidden_states = xformers.ops.memory_efficient_attention(
curr_q, curr_k, curr_v,
op=self.attention_op, scale=attn.scale
)
ex_out[start_idx:end_idx] = hidden_states
hidden_states = ex_out
else:
key = attn.head_to_batch_dim(key).contiguous()
value = attn.head_to_batch_dim(value).contiguous()
# attn_masks needs to be of shape [batch_size, query_tokens, key_tokens]
hidden_states = xformers.ops.memory_efficient_attention(
query, key, value, op=self.attention_op, scale=attn.scale
)
hidden_states = hidden_states.to(query.dtype)
hidden_states = attn.batch_to_head_dim(hidden_states)
# linear proj
hidden_states = attn.to_out[0](hidden_states, *args)
# dropout
hidden_states = attn.to_out[1](hidden_states)
if (feature_injector is not None):
output_res = int(hidden_states.shape[1] ** 0.5)
if anchors_cache and anchors_cache.is_inject_mode():
hidden_states[batch_size//2:] = feature_injector.inject_anchors(hidden_states[batch_size//2:], self.attnstore.curr_iter, output_res, self.attnstore.extended_mapping, self.place_in_unet, anchors_cache)
else:
hidden_states[batch_size//2:] = feature_injector.inject_outputs(hidden_states[batch_size//2:], self.attnstore.curr_iter, output_res, self.attnstore.extended_mapping, self.place_in_unet, anchors_cache)
if input_ndim == 4:
hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width)
if attn.residual_connection:
hidden_states = hidden_states + residual
hidden_states = hidden_states / attn.rescale_output_factor
return hidden_states
def register_extended_self_attn(unet, attnstore, extended_attn_kwargs):
DICT_PLACE_TO_RES = {'down_0': 64, 'down_1': 64, 'down_2': 64, 'down_3': 64, 'down_4': 64, 'down_5': 64, 'down_6': 64, 'down_7': 64,
'down_8': 32, 'down_9': 32, 'down_10': 32, 'down_11': 32, 'down_12': 32, 'down_13': 32, 'down_14': 32, 'down_15': 32,
'down_16': 32, 'down_17': 32, 'down_18': 32, 'down_19': 32, 'down_20': 32, 'down_21': 32, 'down_22': 32, 'down_23': 32,
'down_24': 32, 'down_25': 32, 'down_26': 32, 'down_27': 32, 'down_28': 32, 'down_29': 32, 'down_30': 32, 'down_31': 32,
'down_32': 32, 'down_33': 32, 'down_34': 32, 'down_35': 32, 'down_36': 32, 'down_37': 32, 'down_38': 32, 'down_39': 32,
'down_40': 32, 'down_41': 32, 'down_42': 32, 'down_43': 32, 'down_44': 32, 'down_45': 32, 'down_46': 32, 'down_47': 32,
'mid_120': 32, 'mid_121': 32, 'mid_122': 32, 'mid_123': 32, 'mid_124': 32, 'mid_125': 32, 'mid_126': 32, 'mid_127': 32,
'mid_128': 32, 'mid_129': 32, 'mid_130': 32, 'mid_131': 32, 'mid_132': 32, 'mid_133': 32, 'mid_134': 32, 'mid_135': 32,
'mid_136': 32, 'mid_137': 32, 'mid_138': 32, 'mid_139': 32, 'up_49': 32, 'up_51': 32, 'up_53': 32, 'up_55': 32, 'up_57': 32,
'up_59': 32, 'up_61': 32, 'up_63': 32, 'up_65': 32, 'up_67': 32, 'up_69': 32, 'up_71': 32, 'up_73': 32, 'up_75': 32,
'up_77': 32, 'up_79': 32, 'up_81': 32, 'up_83': 32, 'up_85': 32, 'up_87': 32, 'up_89': 32, 'up_91': 32, 'up_93': 32,
'up_95': 32, 'up_97': 32, 'up_99': 32, 'up_101': 32, 'up_103': 32, 'up_105': 32, 'up_107': 32, 'up_109': 64, 'up_111': 64,
'up_113': 64, 'up_115': 64, 'up_117': 64, 'up_119': 64}
attn_procs = {}
for i, name in enumerate(unet.attn_processors.keys()):
is_self_attn = (i % 2 == 0)
if name.startswith("mid_block"):
place_in_unet = f"mid_{i}"
elif name.startswith("up_blocks"):
place_in_unet = f"up_{i}"
elif name.startswith("down_blocks"):
place_in_unet = f"down_{i}"
else:
continue
if is_self_attn:
attn_procs[name] = ConsistoryExtendedAttnXFormersAttnProcessor(place_in_unet, attnstore, extended_attn_kwargs)
else:
attn_procs[name] = ConsistoryAttnStoreProcessor(attnstore, place_in_unet)
unet.set_attn_processor(attn_procs)
+82
View File
@@ -0,0 +1,82 @@
# Copyright (C) 2024 NVIDIA Corporation. All rights reserved.
#
# This work is licensed under the LICENSE file
# located at the root directory.
import os
import argparse
from .consistory_run import load_pipeline, run_batch_generation, run_anchor_generation, run_extra_generation
def run_batch(gpu, seed=40, mask_dropout=0.5, same_latent=False,
style="A photo of ", subject="a cute dog", concept_token=['dog'],
settings=["sitting in the beach", "standing in the snow"],
out_dir = None):
story_pipeline = load_pipeline(gpu)
prompts = [f'{style}{subject} {setting}' for setting in settings]
images, image_all = run_batch_generation(story_pipeline, prompts, concept_token, seed, mask_dropout=mask_dropout, same_latent=same_latent)
if out_dir is not None:
for i, image in enumerate(images):
image.save(f'{out_dir}/image_{i}.png')
return images, image_all
def run_cached_anchors(gpu, seed=40, mask_dropout=0.5, same_latent=False,
style="A photo of ", subject="a cute dog", concept_token=['dog'],
settings=["sitting in the beach", "standing in the snow"],
cache_cpu_offloading=False, out_dir = None):
story_pipeline = load_pipeline(gpu)
prompts = [f'{style}{subject} {setting}' for setting in settings]
anchor_prompts = prompts[:2]
extra_prompts = prompts[2:]
anchor_out_images, anchor_image_all, anchor_cache_first_stage, anchor_cache_second_stage = run_anchor_generation(story_pipeline, anchor_prompts, concept_token,
seed=seed, mask_dropout=mask_dropout, same_latent=same_latent,
cache_cpu_offloading=cache_cpu_offloading)
if out_dir is not None:
for i, image in enumerate(anchor_out_images):
image.save(f'{out_dir}/anchor_image_{i}.png')
for i, extra_prompt in enumerate(extra_prompts):
extra_out_images, extra_image_all = run_extra_generation(story_pipeline, [extra_prompt], concept_token, anchor_cache_first_stage, anchor_cache_second_stage,
seed=seed, mask_dropout=mask_dropout, same_latent=same_latent, cache_cpu_offloading=cache_cpu_offloading)
if out_dir is not None:
extra_out_images[0].save(f'{out_dir}/extra_image_{i}.png')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--run_type', default="batch", type=str, required=False) # batch, cached
parser.add_argument('--gpu', default=0, type=int, required=False)
parser.add_argument('--seed', default=40, type=int, required=False)
parser.add_argument('--mask_dropout', default=0.5, type=float, required=False)
parser.add_argument('--same_latent', default=False, type=bool, required=False)
parser.add_argument('--style', default="A photo of ", type=str, required=False)
parser.add_argument('--subject', default="a cute dog", type=str, required=False)
parser.add_argument('--concept_token', default=["dog"],
type=str, nargs='*', required=False)
parser.add_argument('--settings', default=["sitting in the beach", "standing in the snow"],
type=str, nargs='*', required=False)
parser.add_argument('--cache_cpu_offloading', default=False, type=bool, required=False)
parser.add_argument('--out_dir', default=None, type=str, required=False)
args = parser.parse_args()
if args.out_dir is not None:
os.makedirs(args.out_dir, exist_ok=True)
if args.run_type == "batch":
run_batch(args.gpu, args.seed, args.mask_dropout, args.same_latent, args.style,
args.subject, args.concept_token, args.settings, args.out_dir)
elif args.run_type == "cached":
run_cached_anchors(args.gpu, args.seed, args.mask_dropout, args.same_latent, args.style,
args.subject, args.concept_token, args.settings, args.cache_cpu_offloading, args.out_dir)
else:
print("Invalid run type")
+245
View File
@@ -0,0 +1,245 @@
# Copyright (C) 2024 NVIDIA Corporation. All rights reserved.
#
# This work is licensed under the LICENSE file
# located at the root directory.
import torch
from diffusers import DDIMScheduler
from .consistory_unet_sdxl import ConsistorySDXLUNet2DConditionModel
from .consistory_pipeline import ConsistoryExtendAttnSDXLPipeline
from .consistory_utils import FeatureInjector, AnchorCache
from .utils.general_utils import *
import gc
from .utils.ptp_utils import view_images
def load_pipeline(gpu_id=0):
float_type = torch.float16
sd_id = "stabilityai/stable-diffusion-xl-base-1.0"
device = torch.device(f'cuda:{gpu_id}') if torch.cuda.is_available() else torch.device('cpu')
unet = ConsistorySDXLUNet2DConditionModel.from_pretrained(sd_id, subfolder="unet", torch_dtype=float_type)
scheduler = DDIMScheduler.from_pretrained(sd_id, subfolder="scheduler")
story_pipeline = ConsistoryExtendAttnSDXLPipeline.from_pretrained(
sd_id, unet=unet, torch_dtype=float_type, variant="fp16", use_safetensors=True, scheduler=scheduler
).to(device)
story_pipeline.enable_freeu(s1=0.6, s2=0.4, b1=1.1, b2=1.2)
return story_pipeline
def create_anchor_mapping(bsz, anchor_indices=[0]):
anchor_mapping = torch.eye(bsz, dtype=torch.bool)
for anchor_idx in anchor_indices:
anchor_mapping[:, anchor_idx] = True
return anchor_mapping
def create_token_indices(prompts, batch_size, concept_token, tokenizer):
if isinstance(concept_token, str):
concept_token = [concept_token]
concept_token_id = [tokenizer.encode(x, add_special_tokens=False)[0] for x in concept_token]
tokens = tokenizer.batch_encode_plus(prompts, padding=True, return_tensors='pt')['input_ids']
token_indices = torch.full((len(concept_token), batch_size), -1, dtype=torch.int64)
for i, token_id in enumerate(concept_token_id):
batch_loc, token_loc = torch.where(tokens == token_id)
token_indices[i, batch_loc] = token_loc
return token_indices
def create_latents(story_pipeline, seed, batch_size, same_latent, device, float_type):
# if seed is int
if isinstance(seed, int):
g = torch.Generator('cuda').manual_seed(seed)
shape = (batch_size, story_pipeline.unet.config.in_channels, 128, 128)
latents = randn_tensor(shape, generator=g, device=device, dtype=float_type)
elif isinstance(seed, list):
shape = (batch_size, story_pipeline.unet.config.in_channels, 128, 128)
latents = torch.empty(shape, device=device, dtype=float_type)
for i, seed_i in enumerate(seed):
g = torch.Generator('cuda').manual_seed(seed_i)
curr_latent = randn_tensor(shape, generator=g, device=device, dtype=float_type)
latents[i] = curr_latent[i]
if same_latent:
latents = latents[:1].repeat(batch_size, 1, 1, 1)
return latents, g
def run_anchor_generation(story_pipeline, prompts, concept_token,
seed=40, n_steps=50, mask_dropout=0.5,
same_latent=False, share_queries=True,
perform_sdsa=True, perform_injection=True,
downscale_rate=4):
latent_resolutions = [32, 64]
device = story_pipeline.device
tokenizer = story_pipeline.tokenizer
float_type = story_pipeline.dtype
unet = story_pipeline.unet
batch_size = len(prompts)
token_indices = create_token_indices(prompts, batch_size, concept_token, tokenizer)
default_attention_store_kwargs = {
'token_indices': token_indices,
'mask_dropout': mask_dropout
}
default_extended_attn_kwargs = {'extend_kv_unet_parts': ['up']}
query_store_kwargs={'t_range': [0,n_steps//10], 'strength_start': 0.9, 'strength_end': 0.81836735}
latents, g = create_latents(story_pipeline, seed, batch_size, same_latent, device, float_type)
anchor_cache_first_stage = AnchorCache()
anchor_cache_second_stage = AnchorCache()
# ------------------ #
# Extended attention First Run #
if perform_sdsa:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': [(1, n_steps)]}
else:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': []}
print(extended_attn_kwargs['t_range'])
out = story_pipeline(prompt=prompts, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
anchors_cache=anchor_cache_first_stage,
num_inference_steps=n_steps)
last_masks = story_pipeline.attention_store.last_mask
dift_features = unet.latent_store.dift_features['261_0'][batch_size:]
dift_features = torch.stack([gaussian_smooth(x, kernel_size=3, sigma=1) for x in dift_features], dim=0)
anchor_cache_first_stage.dift_cache = dift_features
anchor_cache_first_stage.anchors_last_mask = last_masks
nn_map, nn_distances = cyclic_nn_map(dift_features, last_masks, latent_resolutions, device)
torch.cuda.empty_cache()
gc.collect()
# ------------------ #
# Extended attention with nn_map #
if perform_injection:
feature_injector = FeatureInjector(nn_map, nn_distances, last_masks, inject_range_alpha=[(n_steps//10, n_steps//3,0.8)],
swap_strategy='min', inject_unet_parts=['up', 'down'], dist_thr='dynamic')
out = story_pipeline(prompt=prompts, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
feature_injector=feature_injector,
anchors_cache=anchor_cache_second_stage,
num_inference_steps=n_steps)
img_all = view_images([np.array(x) for x in out.images], display_image=False, downscale_rate=downscale_rate)
# display_attn_maps(story_pipeline.attention_store.last_mask, out.images)
anchor_cache_second_stage.dift_cache = dift_features
anchor_cache_second_stage.anchors_last_mask = last_masks
torch.cuda.empty_cache()
gc.collect()
else:
img_all = view_images([np.array(x) for x in out.images], display_image=False, downscale_rate=downscale_rate)
return out.images, img_all, anchor_cache_first_stage, anchor_cache_second_stage
def run_extra_generation(story_pipeline, prompts, concept_token,
anchor_cache_first_stage, anchor_cache_second_stage,
seed=40, n_steps=50, mask_dropout=0.5,
same_latent=False, share_queries=True,
perform_sdsa=True, perform_injection=True,
downscale_rate=4):
latent_resolutions = [32, 64]
device = story_pipeline.device
tokenizer = story_pipeline.tokenizer
float_type = story_pipeline.dtype
unet = story_pipeline.unet
batch_size = len(prompts)
token_indices = create_token_indices(prompts, batch_size, concept_token, tokenizer)
default_attention_store_kwargs = {
'token_indices': token_indices,
'mask_dropout': mask_dropout
}
default_extended_attn_kwargs = {'extend_kv_unet_parts': ['up']}
query_store_kwargs={'t_range': [0,n_steps//10], 'strength_start': 0.9, 'strength_end': 0.81836735}
extra_batch_size = batch_size + 2
if isinstance(seed, list):
seed = [seed[0], seed[0], *seed]
latents, g = create_latents(story_pipeline, seed, extra_batch_size, same_latent, device, float_type)
latents = latents[2:]
anchor_cache_first_stage.set_mode_inject()
anchor_cache_second_stage.set_mode_inject()
# ------------------ #
# Extended attention First Run #
if perform_sdsa:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': [(1, n_steps)]}
else:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': []}
print(extended_attn_kwargs['t_range'])
out = story_pipeline(prompt=prompts, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
anchors_cache=anchor_cache_first_stage,
num_inference_steps=n_steps)
last_masks = story_pipeline.attention_store.last_mask
dift_features = unet.latent_store.dift_features['261_0'][batch_size:]
dift_features = torch.stack([gaussian_smooth(x, kernel_size=3, sigma=1) for x in dift_features], dim=0)
anchor_dift_features = anchor_cache_first_stage.dift_cache
anchor_last_masks = anchor_cache_first_stage.anchors_last_mask
nn_map, nn_distances = anchor_nn_map(dift_features, anchor_dift_features, last_masks, anchor_last_masks, latent_resolutions, device)
torch.cuda.empty_cache()
gc.collect()
# ------------------ #
# Extended attention with nn_map #
if perform_injection:
feature_injector = FeatureInjector(nn_map, nn_distances, last_masks, inject_range_alpha=[(n_steps//10, n_steps//3,0.8)],
swap_strategy='min', inject_unet_parts=['up', 'down'], dist_thr='dynamic')
out = story_pipeline(prompt=prompts, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
feature_injector=feature_injector,
anchors_cache=anchor_cache_second_stage,
num_inference_steps=n_steps)
img_all = view_images([np.array(x) for x in out.images], display_image=False, downscale_rate=downscale_rate)
# display_attn_maps(story_pipeline.attention_store.last_mask, out.images)
torch.cuda.empty_cache()
gc.collect()
else:
img_all = view_images([np.array(x) for x in out.images], display_image=False, downscale_rate=downscale_rate)
return out.images, img_all
+580
View File
@@ -0,0 +1,580 @@
# Copyright 2023 The HuggingFace Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Not a contribution
# Changes made by NVIDIA CORPORATION & AFFILIATES enabling ConsiStory or otherwise documented as NVIDIA-proprietary
# are not a contribution and subject to the license under the LICENSE file located at the root directory.
import torch
from diffusers.pipelines.stable_diffusion_xl.pipeline_output import StableDiffusionXLPipelineOutput
from diffusers.pipelines.stable_diffusion_xl.pipeline_stable_diffusion_xl import StableDiffusionXLPipeline, \
rescale_noise_cfg, EXAMPLE_DOC_STRING
from diffusers.models.attention_processor import (
AttnProcessor2_0,
FusedAttnProcessor2_0,
XFormersAttnProcessor,)
from diffusers.loaders import FromSingleFileMixin
from diffusers.utils import (
deprecate,
is_torch_xla_available,
logging,
replace_example_docstring,
)
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
from .attention_processor import register_extended_self_attn
from .consistory_utils import FeatureInjector, AnchorCache, QueryStore
from .utils.ptp_utils import AttentionStore
if is_torch_xla_available():
# import torch_xla.core.xla_model as xm
XLA_AVAILABLE = True
else:
XLA_AVAILABLE = False
logger = logging.get_logger(__name__) # pylint: disable=invalid-name
T = torch.Tensor
class ConsistoryExtendAttnSDXLPipeline(
StableDiffusionXLPipeline
):
model_cpu_offload_seq = "text_encoder->text_encoder_2->image_encoder->unet->vae"
_optional_components = [
"tokenizer",
"tokenizer_2",
"text_encoder",
"text_encoder_2",
"image_encoder",
"feature_extractor",
]
_callback_tensor_inputs = [
"latents",
"prompt_embeds",
"negative_prompt_embeds",
"add_text_embeds",
"add_time_ids",
"negative_pooled_prompt_embeds",
"negative_add_time_ids",
]
def upcast_vae(self):
dtype = self.vae.dtype
self.vae.to(dtype=torch.float32)
use_torch_2_0_or_xformers = isinstance(
self.vae.decoder.mid_block.attentions[0].processor,
(
AttnProcessor2_0,
XFormersAttnProcessor,
FusedAttnProcessor2_0,
),
)
# if xformers or torch_2_0 is used attention block does not need
# to be in float32 which can save lots of memory
if use_torch_2_0_or_xformers:
self.vae.post_quant_conv.to(dtype)
self.vae.decoder.conv_in.to(dtype)
self.vae.decoder.mid_block.to(dtype)
@torch.no_grad()
@replace_example_docstring(EXAMPLE_DOC_STRING)
def __call__(
self,
prompt: Union[str, List[str]] = None,
prompt_2: Optional[Union[str, List[str]]] = None,
height: Optional[int] = None,
width: Optional[int] = None,
num_inference_steps: int = 50,
denoising_end: Optional[float] = None,
guidance_scale: float = 5.0,
negative_prompt: Optional[Union[str, List[str]]] = None,
negative_prompt_2: Optional[Union[str, List[str]]] = None,
num_images_per_prompt: Optional[int] = 1,
eta: float = 0.0,
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
latents: Optional[torch.FloatTensor] = None,
prompt_embeds: Optional[torch.FloatTensor] = None,
negative_prompt_embeds: Optional[torch.FloatTensor] = None,
pooled_prompt_embeds: Optional[torch.FloatTensor] = None,
negative_pooled_prompt_embeds: Optional[torch.FloatTensor] = None,
output_type: Optional[str] = "pil",
return_dict: bool = True,
cross_attention_kwargs: Optional[Dict[str, Any]] = None,
guidance_rescale: float = 0.0,
original_size: Optional[Tuple[int, int]] = None,
crops_coords_top_left: Tuple[int, int] = (0, 0),
target_size: Optional[Tuple[int, int]] = None,
negative_original_size: Optional[Tuple[int, int]] = None,
negative_crops_coords_top_left: Tuple[int, int] = (0, 0),
negative_target_size: Optional[Tuple[int, int]] = None,
clip_skip: Optional[int] = None,
callback_on_step_end: Optional[Callable[[int, int, Dict], None]] = None,
callback_on_step_end_tensor_inputs: List[str] = ["latents"],
attention_store_kwargs: Optional[Dict] = None,
extended_attn_kwargs: Optional[Dict] = None,
share_queries: bool = False,
query_store_kwargs: Optional[Dict] = {},
feature_injector: Optional[FeatureInjector] = None,
anchors_cache: Optional[AnchorCache] = None,
instance_latents: Optional[torch.FloatTensor] = None,
**kwargs,
):
r"""
Function invoked when calling the pipeline for generation.
Args:
prompt (`str` or `List[str]`, *optional*):
The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`.
instead.
prompt_2 (`str` or `List[str]`, *optional*):
The prompt or prompts to be sent to the `tokenizer_2` and `text_encoder_2`. If not defined, `prompt` is
used in both text-encoders
height (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):
The height in pixels of the generated image. This is set to 1024 by default for the best results.
Anything below 512 pixels won't work well for
[stabilityai/stable-diffusion-xl-base-1.0](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0)
and checkpoints that are not specifically fine-tuned on low resolutions.
width (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):
The width in pixels of the generated image. This is set to 1024 by default for the best results.
Anything below 512 pixels won't work well for
[stabilityai/stable-diffusion-xl-base-1.0](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0)
and checkpoints that are not specifically fine-tuned on low resolutions.
num_inference_steps (`int`, *optional*, defaults to 50):
The number of denoising steps. More denoising steps usually lead to a higher quality image at the
expense of slower inference.
denoising_end (`float`, *optional*):
When specified, determines the fraction (between 0.0 and 1.0) of the total denoising process to be
completed before it is intentionally prematurely terminated. As a result, the returned sample will
still retain a substantial amount of noise as determined by the discrete timesteps selected by the
scheduler. The denoising_end parameter should ideally be utilized when this pipeline forms a part of a
"Mixture of Denoisers" multi-pipeline setup, as elaborated in [**Refining the Image
Output**](https://huggingface.co/docs/diffusers/api/pipelines/stable_diffusion/stable_diffusion_xl#refining-the-image-output)
guidance_scale (`float`, *optional*, defaults to 5.0):
Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).
`guidance_scale` is defined as `w` of equation 2. of [Imagen
Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >
1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`,
usually at the expense of lower image quality.
negative_prompt (`str` or `List[str]`, *optional*):
The prompt or prompts not to guide the image generation. If not defined, one has to pass
`negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is
less than `1`).
negative_prompt_2 (`str` or `List[str]`, *optional*):
The prompt or prompts not to guide the image generation to be sent to `tokenizer_2` and
`text_encoder_2`. If not defined, `negative_prompt` is used in both text-encoders
num_images_per_prompt (`int`, *optional*, defaults to 1):
The number of images to generate per prompt.
eta (`float`, *optional*, defaults to 0.0):
Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to
[`schedulers.DDIMScheduler`], will be ignored for others.
generator (`torch.Generator` or `List[torch.Generator]`, *optional*):
One or a list of [torch generator(s)](https://pytorch.org/docs/stable/generated/torch.Generator.html)
to make generation deterministic.
latents (`torch.FloatTensor`, *optional*):
Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image
generation. Can be used to tweak the same generation with different prompts. If not provided, a latents
tensor will ge generated by sampling using the supplied random `generator`.
prompt_embeds (`torch.FloatTensor`, *optional*):
Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not
provided, text embeddings will be generated from `prompt` input argument.
negative_prompt_embeds (`torch.FloatTensor`, *optional*):
Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt
weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input
argument.
pooled_prompt_embeds (`torch.FloatTensor`, *optional*):
Pre-generated pooled text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting.
If not provided, pooled text embeddings will be generated from `prompt` input argument.
negative_pooled_prompt_embeds (`torch.FloatTensor`, *optional*):
Pre-generated negative pooled text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt
weighting. If not provided, pooled negative_prompt_embeds will be generated from `negative_prompt`
input argument.
output_type (`str`, *optional*, defaults to `"pil"`):
The output format of the generate image. Choose between
[PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`.
return_dict (`bool`, *optional*, defaults to `True`):
Whether or not to return a [`~pipelines.stable_diffusion_xl.StableDiffusionXLPipelineOutput`] instead
of a plain tuple.
cross_attention_kwargs (`dict`, *optional*):
A kwargs dictionary that if specified is passed along to the `AttentionProcessor` as defined under
`self.processor` in
[diffusers.models.attention_processor](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_processor.py).
guidance_rescale (`float`, *optional*, defaults to 0.0):
Guidance rescale factor proposed by [Common Diffusion Noise Schedules and Sample Steps are
Flawed](https://arxiv.org/pdf/2305.08891.pdf) `guidance_scale` is defined as `φ` in equation 16. of
[Common Diffusion Noise Schedules and Sample Steps are Flawed](https://arxiv.org/pdf/2305.08891.pdf).
Guidance rescale factor should fix overexposure when using zero terminal SNR.
original_size (`Tuple[int]`, *optional*, defaults to (1024, 1024)):
If `original_size` is not the same as `target_size` the image will appear to be down- or upsampled.
`original_size` defaults to `(height, width)` if not specified. Part of SDXL's micro-conditioning as
explained in section 2.2 of
[https://huggingface.co/papers/2307.01952](https://huggingface.co/papers/2307.01952).
crops_coords_top_left (`Tuple[int]`, *optional*, defaults to (0, 0)):
`crops_coords_top_left` can be used to generate an image that appears to be "cropped" from the position
`crops_coords_top_left` downwards. Favorable, well-centered images are usually achieved by setting
`crops_coords_top_left` to (0, 0). Part of SDXL's micro-conditioning as explained in section 2.2 of
[https://huggingface.co/papers/2307.01952](https://huggingface.co/papers/2307.01952).
target_size (`Tuple[int]`, *optional*, defaults to (1024, 1024)):
For most cases, `target_size` should be set to the desired height and width of the generated image. If
not specified it will default to `(height, width)`. Part of SDXL's micro-conditioning as explained in
section 2.2 of [https://huggingface.co/papers/2307.01952](https://huggingface.co/papers/2307.01952).
negative_original_size (`Tuple[int]`, *optional*, defaults to (1024, 1024)):
To negatively condition the generation process based on a specific image resolution. Part of SDXL's
micro-conditioning as explained in section 2.2 of
[https://huggingface.co/papers/2307.01952](https://huggingface.co/papers/2307.01952). For more
information, refer to this issue thread: https://github.com/huggingface/diffusers/issues/4208.
negative_crops_coords_top_left (`Tuple[int]`, *optional*, defaults to (0, 0)):
To negatively condition the generation process based on a specific crop coordinates. Part of SDXL's
micro-conditioning as explained in section 2.2 of
[https://huggingface.co/papers/2307.01952](https://huggingface.co/papers/2307.01952). For more
information, refer to this issue thread: https://github.com/huggingface/diffusers/issues/4208.
negative_target_size (`Tuple[int]`, *optional*, defaults to (1024, 1024)):
To negatively condition the generation process based on a target image resolution. It should be as same
as the `target_size` for most cases. Part of SDXL's micro-conditioning as explained in section 2.2 of
[https://huggingface.co/papers/2307.01952](https://huggingface.co/papers/2307.01952). For more
information, refer to this issue thread: https://github.com/huggingface/diffusers/issues/4208.
callback_on_step_end (`Callable`, *optional*):
A function that calls at the end of each denoising steps during the inference. The function is called
with the following arguments: `callback_on_step_end(self: DiffusionPipeline, step: int, timestep: int,
callback_kwargs: Dict)`. `callback_kwargs` will include a list of all tensors as specified by
`callback_on_step_end_tensor_inputs`.
callback_on_step_end_tensor_inputs (`List`, *optional*):
The list of tensor inputs for the `callback_on_step_end` function. The tensors specified in the list
will be passed as `callback_kwargs` argument. You will only be able to include variables listed in the
`._callback_tensor_inputs` attribute of your pipeine class.
Examples:
Returns:
[`~pipelines.stable_diffusion_xl.StableDiffusionXLPipelineOutput`] or `tuple`:
[`~pipelines.stable_diffusion_xl.StableDiffusionXLPipelineOutput`] if `return_dict` is True, otherwise a
`tuple`. When returning a tuple, the first element is a list with the generated images.
"""
callback = kwargs.pop("callback", None)
callback_steps = kwargs.pop("callback_steps", None)
if callback is not None:
deprecate(
"callback",
"1.0.0",
"Passing `callback` as an input argument to `__call__` is deprecated, consider use `callback_on_step_end`",
)
if callback_steps is not None:
deprecate(
"callback_steps",
"1.0.0",
"Passing `callback_steps` as an input argument to `__call__` is deprecated, consider use `callback_on_step_end`",
)
# 0. Default height and width to unet
height = height or self.default_sample_size * self.vae_scale_factor
width = width or self.default_sample_size * self.vae_scale_factor
original_size = original_size or (height, width)
target_size = target_size or (height, width)
# 1. Check inputs. Raise error if not correct
self.check_inputs(
prompt,
prompt_2,
height,
width,
callback_steps,
negative_prompt,
negative_prompt_2,
prompt_embeds,
negative_prompt_embeds,
pooled_prompt_embeds,
negative_pooled_prompt_embeds,
callback_on_step_end_tensor_inputs,
)
self._guidance_scale = guidance_scale
self._guidance_rescale = guidance_rescale
self._clip_skip = clip_skip
self._cross_attention_kwargs = cross_attention_kwargs
self._denoising_end = denoising_end
# 2. Define call parameters
if prompt is not None and isinstance(prompt, str):
batch_size = 1
elif prompt is not None and isinstance(prompt, list):
batch_size = len(prompt)
else:
batch_size = prompt_embeds.shape[0]
device = self._execution_device
# 3. Encode input prompt
lora_scale = (
self.cross_attention_kwargs.get("scale", None) if self.cross_attention_kwargs is not None else None
)
(
prompt_embeds,
negative_prompt_embeds,
pooled_prompt_embeds,
negative_pooled_prompt_embeds,
) = self.encode_prompt(
prompt=prompt,
prompt_2=prompt_2,
device=device,
num_images_per_prompt=num_images_per_prompt,
do_classifier_free_guidance=self.do_classifier_free_guidance,
negative_prompt=negative_prompt,
negative_prompt_2=negative_prompt_2,
prompt_embeds=prompt_embeds,
negative_prompt_embeds=negative_prompt_embeds,
pooled_prompt_embeds=pooled_prompt_embeds,
negative_pooled_prompt_embeds=negative_pooled_prompt_embeds,
lora_scale=lora_scale,
clip_skip=self.clip_skip,
)
# 4. Prepare timesteps
self.scheduler.set_timesteps(num_inference_steps, device=device)
timesteps = self.scheduler.timesteps
# 5. Prepare latent variables
num_channels_latents = self.unet.config.in_channels
latents = self.prepare_latents(
batch_size * num_images_per_prompt,
num_channels_latents,
height,
width,
prompt_embeds.dtype,
device,
generator,
latents,
)
# 6. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
if share_queries:
query_store = QueryStore(**query_store_kwargs)
else:
query_store = None
self.attention_store = AttentionStore(attention_store_kwargs)
register_extended_self_attn(self.unet, self.attention_store, extended_attn_kwargs)
# 7. Prepare added time ids & embeddings
add_text_embeds = pooled_prompt_embeds
if self.text_encoder_2 is None:
text_encoder_projection_dim = int(pooled_prompt_embeds.shape[-1])
else:
text_encoder_projection_dim = self.text_encoder_2.config.projection_dim
add_time_ids = self._get_add_time_ids(
original_size,
crops_coords_top_left,
target_size,
dtype=prompt_embeds.dtype,
text_encoder_projection_dim=text_encoder_projection_dim,
)
if negative_original_size is not None and negative_target_size is not None:
negative_add_time_ids = self._get_add_time_ids(
negative_original_size,
negative_crops_coords_top_left,
negative_target_size,
dtype=prompt_embeds.dtype,
text_encoder_projection_dim=text_encoder_projection_dim,
)
else:
negative_add_time_ids = add_time_ids
if self.do_classifier_free_guidance:
prompt_embeds = torch.cat([negative_prompt_embeds, prompt_embeds], dim=0)
add_text_embeds = torch.cat([negative_pooled_prompt_embeds, add_text_embeds], dim=0)
add_time_ids = torch.cat([negative_add_time_ids, add_time_ids], dim=0)
prompt_embeds = prompt_embeds.to(device)
add_text_embeds = add_text_embeds.to(device)
add_time_ids = add_time_ids.to(device).repeat(batch_size * num_images_per_prompt, 1)
# 8. Denoising loop
num_warmup_steps = max(len(timesteps) - num_inference_steps * self.scheduler.order, 0)
# 8.1 Apply denoising_end
if (
self.denoising_end is not None
and isinstance(self.denoising_end, float)
and self.denoising_end > 0
and self.denoising_end < 1
):
discrete_timestep_cutoff = int(
round(
self.scheduler.config.num_train_timesteps
- (self.denoising_end * self.scheduler.config.num_train_timesteps)
)
)
num_inference_steps = len(list(filter(lambda ts: ts >= discrete_timestep_cutoff, timesteps)))
timesteps = timesteps[:num_inference_steps]
# 9. Optionally get Guidance Scale Embedding
timestep_cond = None
if self.unet.config.time_cond_proj_dim is not None:
guidance_scale_tensor = torch.tensor(self.guidance_scale - 1).repeat(batch_size * num_images_per_prompt)
timestep_cond = self.get_guidance_scale_embedding(
guidance_scale_tensor, embedding_dim=self.unet.config.time_cond_proj_dim
).to(device=device, dtype=latents.dtype)
self._num_timesteps = len(timesteps)
if instance_latents is not None:
n_instances = instance_latents.shape[0]
instance_noise = latents[:n_instances].clone()
with self.progress_bar(total=num_inference_steps) as progress_bar:
for i, t in enumerate(timesteps):
self.attention_store.curr_iter = i
if instance_latents is not None:
noised_instances = self.scheduler.add_noise(instance_latents, instance_noise, t.repeat(n_instances).long())
latents[:n_instances] = noised_instances
# expand the latents if we are doing classifier free guidance
latent_model_input = torch.cat([latents] * 2) if self.do_classifier_free_guidance else latents
latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)
# predict the noise residual
added_cond_kwargs = {"text_embeds": add_text_embeds, "time_ids": add_time_ids}
if share_queries and (i >= query_store.t_range[0] and i <= query_store.t_range[1]):
query_store.set_mode('cache')
noise_pred_vanilla = self.unet(
latent_model_input,
t,
encoder_hidden_states=prompt_embeds,
timestep_cond=timestep_cond,
cross_attention_kwargs={'query_store': query_store,
'perform_extend_attn': False,
'record_attention': False},
added_cond_kwargs=added_cond_kwargs,
return_dict=False,
)[0]
query_store.set_mode('inject')
noise_pred = self.unet(
latent_model_input,
t,
encoder_hidden_states=prompt_embeds,
timestep_cond=timestep_cond,
cross_attention_kwargs={'query_store': query_store,
'perform_extend_attn': True,
'record_attention': True,
'feature_injector': feature_injector,
'anchors_cache': anchors_cache},
added_cond_kwargs=added_cond_kwargs,
return_dict=False,
)[0]
# perform guidance
if self.do_classifier_free_guidance:
noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
noise_pred = noise_pred_uncond + self.guidance_scale * (noise_pred_text - noise_pred_uncond)
if self.do_classifier_free_guidance and self.guidance_rescale > 0.0:
# Based on 3.4. in https://arxiv.org/pdf/2305.08891.pdf
noise_pred = rescale_noise_cfg(noise_pred, noise_pred_text, guidance_rescale=self.guidance_rescale)
# compute the previous noisy sample x_t -> x_t-1
latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs, return_dict=False)[0]
if callback_on_step_end is not None:
callback_kwargs = {}
for k in callback_on_step_end_tensor_inputs:
callback_kwargs[k] = locals()[k]
callback_outputs = callback_on_step_end(self, i, t, callback_kwargs)
latents = callback_outputs.pop("latents", latents)
prompt_embeds = callback_outputs.pop("prompt_embeds", prompt_embeds)
negative_prompt_embeds = callback_outputs.pop("negative_prompt_embeds", negative_prompt_embeds)
add_text_embeds = callback_outputs.pop("add_text_embeds", add_text_embeds)
negative_pooled_prompt_embeds = callback_outputs.pop(
"negative_pooled_prompt_embeds", negative_pooled_prompt_embeds
)
add_time_ids = callback_outputs.pop("add_time_ids", add_time_ids)
negative_add_time_ids = callback_outputs.pop("negative_add_time_ids", negative_add_time_ids)
# call the callback, if provided
if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):
progress_bar.update()
if callback is not None and i % callback_steps == 0:
step_idx = i // getattr(self.scheduler, "order", 1)
callback(step_idx, t, latents)
if XLA_AVAILABLE:
# xm.mark_step()
pass
# Update attention store mask
self.attention_store.aggregate_last_steps_attention()
if not output_type == "latent":
# make sure the VAE is in float32 mode, as it overflows in float16
#print(self.vae.config.force_upcast)
needs_upcasting = self.vae.dtype == torch.float16 and self.vae.config.force_upcast
#print(needs_upcasting,112233)
if needs_upcasting:
self.upcast_vae()
latents = latents.to(next(iter(self.vae.post_quant_conv.parameters())).dtype)
elif latents.dtype != self.vae.dtype:
if torch.backends.mps.is_available():
# some platforms (eg. apple mps) misbehave due to a pytorch bug: https://github.com/pytorch/pytorch/pull/99272
self.vae = self.vae.to(latents.dtype)
# unscale/denormalize the latents
# denormalize with the mean and std if available and not None
has_latents_mean = hasattr(self.vae.config, "latents_mean") and self.vae.config.latents_mean is not None
has_latents_std = hasattr(self.vae.config, "latents_std") and self.vae.config.latents_std is not None
if has_latents_mean and has_latents_std:
latents_mean = (
torch.tensor(self.vae.config.latents_mean).view(1, 4, 1, 1).to(latents.device, latents.dtype)
)
latents_std = (
torch.tensor(self.vae.config.latents_std).view(1, 4, 1, 1).to(latents.device, latents.dtype)
)
latents = latents * latents_std / self.vae.config.scaling_factor + latents_mean
else:
latents = latents / self.vae.config.scaling_factor
image = self.vae.decode(latents, return_dict=False)[0]
#image = self.vae.decode(latents / self.vae.config.scaling_factor, return_dict=False)[0]
# cast back to fp16 if needed
if needs_upcasting:
self.vae.to(dtype=torch.float16)
else:
image = latents
if not output_type == "latent":
# apply watermark if available
# if self.watermark is not None:
# image = self.watermark.apply_watermark(image)
image = self.image_processor.postprocess(image, output_type=output_type)
# Offload all models
self.maybe_free_model_hooks()
if not return_dict:
return (image,)
return StableDiffusionXLPipelineOutput(images=image)
+369
View File
@@ -0,0 +1,369 @@
# Copyright (C) 2024 NVIDIA Corporation. All rights reserved.
#
# This work is licensed under the LICENSE file
# located at the root directory.
import os.path
import torch
from diffusers import DDIMScheduler, UNet2DConditionModel
from .consistory_unet_sdxl import ConsistorySDXLUNet2DConditionModel
from .consistory_pipeline import ConsistoryExtendAttnSDXLPipeline
from .consistory_utils import FeatureInjector, AnchorCache
from .utils.general_utils import *
import gc
import folder_paths
from .utils.ptp_utils import view_images
LATENT_RESOLUTIONS = [32, 64]
def clear_memory():
torch.cuda.empty_cache()
gc.collect()
def load_pipeline(repo_id,unet_path,inject,gpu_id=0):
float_type = torch.float16
#sd_id = "stabilityai/stable-diffusion-xl-base-1.0"
device = torch.device(f'cuda:{gpu_id}') if torch.cuda.is_available() else torch.device('cpu')
if repo_id:
unet = ConsistorySDXLUNet2DConditionModel.from_pretrained(repo_id, subfolder="unet", torch_dtype=float_type)
scheduler = DDIMScheduler.from_pretrained(repo_id, subfolder="scheduler")
story_pipeline = ConsistoryExtendAttnSDXLPipeline.from_pretrained(
repo_id, unet=unet, torch_dtype=float_type, variant="fp16", use_safetensors=True, scheduler=scheduler
).to(device)
elif not repo_id and unet_path:
config_file = os.path.join(folder_paths.base_path, "custom_nodes/ComfyUI_StoryDiffusion/local_repo/unet/config.json")
sdxl_repo = os.path.join(folder_paths.base_path, "custom_nodes/ComfyUI_StoryDiffusion/local_repo")
original_config_file = os.path.join(folder_paths.base_path, "custom_nodes/ComfyUI_StoryDiffusion/config/sd_xl_base.yaml")
from safetensors.torch import load_file
from diffusers.pipelines.stable_diffusion.convert_from_ckpt import convert_ldm_unet_checkpoint
state_dict = load_file(unet_path)
unet_config = ConsistorySDXLUNet2DConditionModel.load_config(config_file)
Unet = ConsistorySDXLUNet2DConditionModel.from_config(unet_config).to(device,torch.float16)
state_dict = convert_ldm_unet_checkpoint(state_dict, Unet.config)
Unet.load_state_dict(state_dict, strict=False)
del state_dict
clear_memory()
scheduler = DDIMScheduler.from_pretrained(sdxl_repo, subfolder="scheduler")
try:
story_pipeline = ConsistoryExtendAttnSDXLPipeline.from_single_file(
unet_path,unet=Unet, config=sdxl_repo, original_config=original_config_file, torch_dtype=float_type, variant="fp16", use_safetensors=True, scheduler=scheduler
).to(device)
except:
story_pipeline = ConsistoryExtendAttnSDXLPipeline.from_single_file(
unet_path, unet=Unet,config=sdxl_repo, original_config_file=original_config_file, torch_dtype=float_type, variant="fp16", use_safetensors=True, scheduler=scheduler
).to(device)
else:
raise "need a repo or chocie a sdxl checkpoints"
story_pipeline.enable_freeu(s1=0.6, s2=0.4, b1=1.1, b2=1.2)
return story_pipeline
def create_anchor_mapping(bsz, anchor_indices=[0]):
anchor_mapping = torch.eye(bsz, dtype=torch.bool)
for anchor_idx in anchor_indices:
anchor_mapping[:, anchor_idx] = True
return anchor_mapping
def create_token_indices(prompts, batch_size, concept_token, tokenizer):
if isinstance(concept_token, str):
concept_token = [concept_token]
concept_token_id = [tokenizer.encode(x, add_special_tokens=False)[0] for x in concept_token]
tokens = tokenizer.batch_encode_plus(prompts, padding=True, return_tensors='pt')['input_ids']
token_indices = torch.full((len(concept_token), batch_size), -1, dtype=torch.int64)
for i, token_id in enumerate(concept_token_id):
batch_loc, token_loc = torch.where(tokens == token_id)
token_indices[i, batch_loc] = token_loc
return token_indices
def create_latents(story_pipeline, seed, batch_size, same_latent, device, float_type):
# if seed is int
if isinstance(seed, int):
#g = torch.Generator('cuda').manual_seed(seed)
g = torch.Generator(device).manual_seed(seed)
shape = (batch_size, story_pipeline.unet.config.in_channels, 128, 128)
latents = randn_tensor(shape, generator=g, device=device, dtype=float_type)
elif isinstance(seed, list):
shape = (batch_size, story_pipeline.unet.config.in_channels, 128, 128)
latents = torch.empty(shape, device=device, dtype=float_type)
for i, seed_i in enumerate(seed):
#g = torch.Generator('cuda').manual_seed(seed_i)
g = torch.Generator(device).manual_seed(seed_i)
curr_latent = randn_tensor(shape, generator=g, device=device, dtype=float_type)
latents[i] = curr_latent[i]
if same_latent:
latents = latents[:1].repeat(batch_size, 1, 1, 1)
return latents, g
# Batch inference
def run_batch_generation(story_pipeline, prompts, concept_token,negative_prompt,
seed=40, n_steps=50, mask_dropout=0.5,
same_latent=False, share_queries=True,
perform_sdsa=True, perform_injection=True,
downscale_rate=4, n_achors=2):
device = story_pipeline.device
tokenizer = story_pipeline.tokenizer
float_type = story_pipeline.dtype
unet = story_pipeline.unet
batch_size = len(prompts)
token_indices = create_token_indices(prompts, batch_size, concept_token, tokenizer)
anchor_mappings = create_anchor_mapping(batch_size, anchor_indices=list(range(n_achors)))
default_attention_store_kwargs = {
'token_indices': token_indices,
'mask_dropout': mask_dropout,
'extended_mapping': anchor_mappings
}
default_extended_attn_kwargs = {'extend_kv_unet_parts': ['up']}
query_store_kwargs= {'t_range': [0,n_steps//10], 'strength_start': 0.9, 'strength_end': 0.81836735}
latents, g = create_latents(story_pipeline, seed, batch_size, same_latent, device, float_type)
# ------------------ #
# Extended attention First Run #
if perform_sdsa:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': [(1, n_steps)]}
else:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': []}
print(extended_attn_kwargs['t_range'])
out = story_pipeline(prompt=prompts,negative_prompt=negative_prompt, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
num_inference_steps=n_steps)
# Extended attention with nn_map #
if perform_injection:
last_masks = story_pipeline.attention_store.last_mask
dift_features = unet.latent_store.dift_features['251_0'][batch_size:]
unet.latent_store.reset() # turn to {}
del out
clear_memory()
dift_features = torch.stack([gaussian_smooth(x, kernel_size=3, sigma=1) for x in dift_features], dim=0)
nn_map, nn_distances = cyclic_nn_map(dift_features, last_masks, LATENT_RESOLUTIONS, device)
clear_memory()
feature_injector = FeatureInjector(nn_map, nn_distances, last_masks,
inject_range_alpha=[(n_steps // 10, n_steps // 3, 0.8)],
swap_strategy='min', inject_unet_parts=['up', 'down'],
dist_thr='dynamic')
out = story_pipeline(prompt=prompts, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
feature_injector=feature_injector,
num_inference_steps=n_steps)
#img_all = view_images([np.array(x) for x in out.images], display_image=False, downscale_rate=downscale_rate)
# display_attn_maps(story_pipeline.attention_store.last_mask, out.images)
clear_memory()
return out.images
# Anchors
def run_anchor_generation(story_pipeline, prompts, concept_token,negative_prompt,
seed=40, n_steps=50, mask_dropout=0.5,
same_latent=False, share_queries=True,
perform_sdsa=True, perform_injection=True,
downscale_rate=4, cache_cpu_offloading=False):
device = story_pipeline.device
tokenizer = story_pipeline.tokenizer
float_type = story_pipeline.dtype
unet = story_pipeline.unet
batch_size = len(prompts)
token_indices = create_token_indices(prompts, batch_size, concept_token, tokenizer)
default_attention_store_kwargs = {
'token_indices': token_indices,
'mask_dropout': mask_dropout
}
default_extended_attn_kwargs = {'extend_kv_unet_parts': ['up']}
query_store_kwargs={'t_range': [0,n_steps//10], 'strength_start': 0.9, 'strength_end': 0.81836735}
latents, g = create_latents(story_pipeline, seed, batch_size, same_latent, device, float_type)
anchor_cache_first_stage = AnchorCache()
anchor_cache_second_stage = AnchorCache()
# ------------------ #
# Extended attention First Run #
if perform_sdsa:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': [(1, n_steps)]}
else:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': []}
print(extended_attn_kwargs['t_range'])
out = story_pipeline(prompt=prompts,negative_prompt=negative_prompt, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
anchors_cache=anchor_cache_first_stage,
num_inference_steps=n_steps)
last_masks = story_pipeline.attention_store.last_mask
dift_features = unet.latent_store.dift_features['251_0'][batch_size:]
unet.latent_store.reset() # turn to {}
clear_memory()
dift_features = torch.stack([gaussian_smooth(x, kernel_size=3, sigma=1) for x in dift_features], dim=0)
anchor_cache_first_stage.dift_cache = dift_features
anchor_cache_first_stage.anchors_last_mask = last_masks
if cache_cpu_offloading:
anchor_cache_first_stage.to_device(torch.device('cpu'))
nn_map, nn_distances = cyclic_nn_map(dift_features, last_masks, LATENT_RESOLUTIONS, device)
clear_memory()
# ------------------ #
# Extended attention with nn_map #
if perform_injection:
feature_injector = FeatureInjector(nn_map, nn_distances, last_masks, inject_range_alpha=[(n_steps//10, n_steps//3,0.8)],
swap_strategy='min', inject_unet_parts=['up', 'down'], dist_thr='dynamic')
out = story_pipeline(prompt=prompts,negative_prompt=negative_prompt, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
feature_injector=feature_injector,
anchors_cache=anchor_cache_second_stage,
num_inference_steps=n_steps)
#img_all = view_images([np.array(x) for x in out.images], display_image=False, downscale_rate=downscale_rate)
# display_attn_maps(story_pipeline.attention_store.last_mask, out.images)
anchor_cache_second_stage.dift_cache = dift_features
anchor_cache_second_stage.anchors_last_mask = last_masks
if cache_cpu_offloading:
anchor_cache_second_stage.to_device(torch.device('cpu'))
clear_memory()
# else:
# img_all = view_images([np.array(x) for x in out.images], display_image=False, downscale_rate=downscale_rate)
return out.images, anchor_cache_first_stage, anchor_cache_second_stage
def run_extra_generation(story_pipeline, prompts, concept_token, negative_prompt,
anchor_cache_first_stage, anchor_cache_second_stage,
seed=40, n_steps=50, mask_dropout=0.5,
same_latent=False, share_queries=True,
perform_sdsa=True, perform_injection=True,
downscale_rate=4, cache_cpu_offloading=False):
device = story_pipeline.device
tokenizer = story_pipeline.tokenizer
float_type = story_pipeline.dtype
unet = story_pipeline.unet
batch_size = len(prompts)
token_indices = create_token_indices(prompts, batch_size, concept_token, tokenizer)
default_attention_store_kwargs = {
'token_indices': token_indices,
'mask_dropout': mask_dropout
}
default_extended_attn_kwargs = {'extend_kv_unet_parts': ['up']}
query_store_kwargs={'t_range': [0,n_steps//10], 'strength_start': 0.9, 'strength_end': 0.81836735}
extra_batch_size = batch_size + 2
if isinstance(seed, list):
seed = [seed[0], seed[0], *seed]
latents, g = create_latents(story_pipeline, seed, extra_batch_size, same_latent, device, float_type)
latents = latents[2:]
anchor_cache_first_stage.set_mode_inject()
anchor_cache_second_stage.set_mode_inject()
# ------------------ #
# Extended attention First Run #
if cache_cpu_offloading:
anchor_cache_first_stage.to_device(device)
if perform_sdsa:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': [(1, n_steps)]}
else:
extended_attn_kwargs = {**default_extended_attn_kwargs, 't_range': []}
print(extended_attn_kwargs['t_range'])
out = story_pipeline(prompt=prompts,negative_prompt=negative_prompt, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
anchors_cache=anchor_cache_first_stage,
num_inference_steps=n_steps)
# ------------------ #
# Extended attention with nn_map #
last_masks = story_pipeline.attention_store.last_mask
dift_features = unet.latent_store.dift_features['251_0'][batch_size:]
unet.latent_store.reset() # turn to {}
clear_memory()
dift_features = torch.stack([gaussian_smooth(x, kernel_size=3, sigma=1) for x in dift_features], dim=0)
anchor_dift_features = anchor_cache_first_stage.dift_cache
anchor_last_masks = anchor_cache_first_stage.anchors_last_mask
nn_map, nn_distances = anchor_nn_map(dift_features, anchor_dift_features, last_masks, anchor_last_masks,
LATENT_RESOLUTIONS, device)
if cache_cpu_offloading:
anchor_cache_first_stage.to_device(torch.device('cpu'))
clear_memory()
if perform_injection:
if cache_cpu_offloading:
anchor_cache_second_stage.to_device(device)
feature_injector = FeatureInjector(nn_map, nn_distances, last_masks, inject_range_alpha=[(n_steps//10, n_steps//3,0.8)],
swap_strategy='min', inject_unet_parts=['up', 'down'], dist_thr='dynamic')
out = story_pipeline(prompt=prompts,negative_prompt=negative_prompt, generator=g, latents=latents,
attention_store_kwargs=default_attention_store_kwargs,
extended_attn_kwargs=extended_attn_kwargs,
share_queries=share_queries,
query_store_kwargs=query_store_kwargs,
feature_injector=feature_injector,
anchors_cache=anchor_cache_second_stage,
num_inference_steps=n_steps)
#img_all = view_images([np.array(x) for x in out.images], display_image=False, downscale_rate=downscale_rate)
# display_attn_maps(story_pipeline.attention_store.last_mask, out.images)
if cache_cpu_offloading:
anchor_cache_second_stage.to_device(torch.device('cpu'))
clear_memory()
# else:
# img_all = view_images([np.array(x) for x in out.images], display_image=False, downscale_rate=downscale_rate)
return out.images
File diff suppressed because it is too large Load Diff
+200
View File
@@ -0,0 +1,200 @@
# Copyright (C) 2024 NVIDIA Corporation. All rights reserved.
#
# This work is licensed under the LICENSE file
# located at the root directory.
import numpy as np
import torch
from collections import defaultdict
from diffusers.utils.import_utils import is_xformers_available
from typing import Optional, List
from .utils.general_utils import get_dynamic_threshold
if is_xformers_available():
import xformers
import xformers.ops
else:
xformers = None
class FeatureInjector:
def __init__(self, nn_map, nn_distances, attn_masks, inject_range_alpha=[(10,20,0.8)], swap_strategy='min', dist_thr='dynamic', inject_unet_parts=['up']):
self.nn_map = nn_map
self.nn_distances = nn_distances
self.attn_masks = attn_masks
self.inject_range_alpha = inject_range_alpha if isinstance(inject_range_alpha, list) else [inject_range_alpha]
self.swap_strategy = swap_strategy # 'min / 'mean' / 'first'
self.dist_thr = dist_thr
self.inject_unet_parts = inject_unet_parts
self.inject_res = [64]
def inject_outputs(self, output, curr_iter, output_res, extended_mapping, place_in_unet, anchors_cache=None):
curr_unet_part = place_in_unet.split('_')[0]
# Inject only in the specified unet parts (up, mid, down)
if (curr_unet_part not in self.inject_unet_parts) or output_res not in self.inject_res:
return output
bsz = output.shape[0]
nn_map = self.nn_map[output_res]
nn_distances = self.nn_distances[output_res]
attn_masks = self.attn_masks[output_res]
vector_dim = output_res**2
alpha = next((alpha for min_range, max_range, alpha in self.inject_range_alpha if min_range <= curr_iter <= max_range), None)
if alpha:
old_output = output#.clone()
for i in range(bsz):
other_outputs = []
if self.swap_strategy == 'min':
curr_mapping = extended_mapping[i]
# If the current image is not mapped to any other image, skip
if not torch.any(torch.cat([curr_mapping[:i], curr_mapping[i+1:]])):
continue
min_dists = nn_distances[i][curr_mapping].argmin(dim=0)
curr_nn_map = nn_map[i][curr_mapping][min_dists, torch.arange(vector_dim)]
curr_nn_distances = nn_distances[i][curr_mapping][min_dists, torch.arange(vector_dim)]
dist_thr = get_dynamic_threshold(curr_nn_distances) if self.dist_thr == 'dynamic' else self.dist_thr
dist_mask = curr_nn_distances < dist_thr
final_mask_tgt = attn_masks[i] & dist_mask
other_outputs = old_output[curr_mapping][min_dists, curr_nn_map][final_mask_tgt]
output[i][final_mask_tgt] = alpha * other_outputs + (1 - alpha)*old_output[i][final_mask_tgt]
if anchors_cache and anchors_cache.is_cache_mode():
if place_in_unet not in anchors_cache.h_out_cache:
anchors_cache.h_out_cache[place_in_unet] = {}
anchors_cache.h_out_cache[place_in_unet][curr_iter] = output
return output
def inject_anchors(self, output, curr_iter, output_res, extended_mapping, place_in_unet, anchors_cache):
curr_unet_part = place_in_unet.split('_')[0]
# Inject only in the specified unet parts (up, mid, down)
if (curr_unet_part not in self.inject_unet_parts) or output_res not in self.inject_res:
return output
bsz = output.shape[0]
nn_map = self.nn_map[output_res]
nn_distances = self.nn_distances[output_res]
attn_masks = self.attn_masks[output_res]
vector_dim = output_res**2
alpha = next((alpha for min_range, max_range, alpha in self.inject_range_alpha if min_range <= curr_iter <= max_range), None)
if alpha:
anchor_outputs = anchors_cache.h_out_cache[place_in_unet][curr_iter]
old_output = output#.clone()
for i in range(bsz):
other_outputs = []
if self.swap_strategy == 'min':
min_dists = nn_distances[i].argmin(dim=0)
curr_nn_map = nn_map[i][min_dists, torch.arange(vector_dim)]
curr_nn_distances = nn_distances[i][min_dists, torch.arange(vector_dim)]
dist_thr = get_dynamic_threshold(curr_nn_distances) if self.dist_thr == 'dynamic' else self.dist_thr
dist_mask = curr_nn_distances < dist_thr
final_mask_tgt = attn_masks[i] & dist_mask
other_outputs = anchor_outputs[min_dists, curr_nn_map][final_mask_tgt]
output[i][final_mask_tgt] = alpha * other_outputs + (1 - alpha)*old_output[i][final_mask_tgt]
return output
class AnchorCache:
def __init__(self):
self.input_h_cache = {} # place_in_unet, iter, h_in
self.h_out_cache = {} # place_in_unet, iter, h_out
self.anchors_last_mask = None
self.dift_cache = None
self.mode = 'cache' # mode can be 'cache' or 'inject'
def set_mode(self, mode):
self.mode = mode
def set_mode_inject(self):
self.mode = 'inject'
def set_mode_cache(self):
self.mode = 'cache'
def is_inject_mode(self):
return self.mode == 'inject'
def is_cache_mode(self):
return self.mode == 'cache'
def to_device(self, device):
for key, value in self.input_h_cache.items():
self.input_h_cache[key] = {k: v.to(device) for k, v in value.items()}
for key, value in self.h_out_cache.items():
self.h_out_cache[key] = {k: v.to(device) for k, v in value.items()}
if self.anchors_last_mask:
self.anchors_last_mask = {k: v.to(device) for k, v in self.anchors_last_mask.items()}
if self.dift_cache is not None:
self.dift_cache = self.dift_cache.to(device)
class QueryStore:
def __init__(self, mode='store', t_range=[0, 1000], strength_start=1, strength_end=1):
"""
Initialize an empty ActivationsStore
"""
self.query_store = defaultdict(list)
self.mode = mode
self.t_range = t_range
self.strengthes = np.linspace(strength_start, strength_end, (t_range[1] - t_range[0])+1)
def set_mode(self, mode): # mode can be 'cache' or 'inject'
self.mode = mode
def cache_query(self, query, place_in_unet: str):
self.query_store[place_in_unet] = query
def inject_query(self, query, place_in_unet, t):
if t >= self.t_range[0] and t <= self.t_range[1]:
relative_t = t - self.t_range[0]
strength = self.strengthes[relative_t]
new_query = strength * self.query_store[place_in_unet] + (1 - strength) * query
else:
new_query = query
return new_query
class DIFTLatentStore:
def __init__(self, steps: List[int], up_ft_indices: List[int]):
self.steps = steps
self.up_ft_indices = up_ft_indices
self.dift_features = {}
def __call__(self, features: torch.Tensor, t: int, layer_index: int):
if t in self.steps and layer_index in self.up_ft_indices:
self.dift_features[f'{int(t)}_{layer_index}'] = features
def copy(self):
copy_dift = DIFTLatentStore(self.steps, self.up_ft_indices)
for key, value in self.dift_features.items():
copy_dift.dift_features[key] = value.clone()
return copy_dift
def reset(self):
self.dift_features = {}
+251
View File
@@ -0,0 +1,251 @@
name: consistory
channels:
- pytorch
- nvidia
- conda-forge
- defaults
dependencies:
- _libgcc_mutex=0.1=main
- _openmp_mutex=5.1=1_gnu
- asttokens=2.4.1=pyhd8ed1ab_0
- backports=1.0=pyhd8ed1ab_3
- backports.functools_lru_cache=1.6.5=pyhd8ed1ab_0
- blas=1.0=mkl
- brotli-python=1.0.9=py310h6a678d5_7
- bzip2=1.0.8=h7b6447c_0
- ca-certificates=2023.7.22=hbcca054_0
- certifi=2023.7.22=pyhd8ed1ab_0
- cffi=1.15.1=py310h5eee18b_3
- charset-normalizer=2.0.4=pyhd3eb1b0_0
- comm=0.1.4=pyhd8ed1ab_0
- cryptography=41.0.3=py310hdda0065_0
- cuda-cudart=12.1.105=0
- cuda-cupti=12.1.105=0
- cuda-libraries=12.1.0=0
- cuda-nvrtc=12.1.105=0
- cuda-nvtx=12.1.105=0
- cuda-opencl=12.3.52=0
- cuda-runtime=12.1.0=0
- debugpy=1.6.7=py310h6a678d5_0
- decorator=5.1.1=pyhd8ed1ab_0
- entrypoints=0.4=pyhd8ed1ab_0
- exceptiongroup=1.1.3=pyhd8ed1ab_0
- executing=2.0.1=pyhd8ed1ab_0
- ffmpeg=4.3=hf484d3e_0
- filelock=3.9.0=py310h06a4308_0
- freetype=2.12.1=h4a9f257_0
- giflib=5.2.1=h5eee18b_3
- gmp=6.2.1=h295c915_3
- gmpy2=2.1.2=py310heeb90bb_0
- gnutls=3.6.15=he1e5248_0
- idna=3.4=py310h06a4308_0
- intel-openmp=2023.1.0=hdb19cb5_46306
- ipykernel=6.26.0=pyhf8b6a83_0
- ipython=8.17.2=pyh41d4057_0
- jedi=0.19.1=pyhd8ed1ab_0
- jinja2=3.1.2=py310h06a4308_0
- jpeg=9e=h5eee18b_1
- jupyter_core=5.5.0=py310hff52083_0
- lame=3.100=h7b6447c_0
- lcms2=2.12=h3be6417_0
- ld_impl_linux-64=2.38=h1181459_1
- lerc=3.0=h295c915_0
- libcublas=12.1.0.26=0
- libcufft=11.0.2.4=0
- libcufile=1.8.0.34=0
- libcurand=10.3.4.52=0
- libcusolver=11.4.4.55=0
- libcusparse=12.0.2.55=0
- libdeflate=1.17=h5eee18b_1
- libffi=3.4.4=h6a678d5_0
- libgcc-ng=11.2.0=h1234567_1
- libgomp=11.2.0=h1234567_1
- libiconv=1.16=h7f8727e_2
- libidn2=2.3.4=h5eee18b_0
- libjpeg-turbo=2.0.0=h9bf148f_0
- libnpp=12.0.2.50=0
- libnvjitlink=12.1.105=0
- libnvjpeg=12.1.1.14=0
- libpng=1.6.39=h5eee18b_0
- libsodium=1.0.18=h36c2ea0_1
- libstdcxx-ng=11.2.0=h1234567_1
- libtasn1=4.19.0=h5eee18b_0
- libtiff=4.5.1=h6a678d5_0
- libunistring=0.9.10=h27cfd23_0
- libuuid=1.41.5=h5eee18b_0
- libwebp=1.3.2=h11a3e52_0
- libwebp-base=1.3.2=h5eee18b_0
- llvm-openmp=14.0.6=h9e868ea_0
- lz4-c=1.9.4=h6a678d5_0
- markupsafe=2.1.1=py310h7f8727e_0
- matplotlib-inline=0.1.6=pyhd8ed1ab_0
- mkl=2023.1.0=h213fc3f_46344
- mkl-service=2.4.0=py310h5eee18b_1
- mkl_fft=1.3.8=py310h5eee18b_0
- mkl_random=1.2.4=py310hdb19cb5_0
- mpc=1.1.0=h10f8cd9_1
- mpfr=4.0.2=hb69a4c5_1
- mpmath=1.3.0=py310h06a4308_0
- ncurses=6.4=h6a678d5_0
- nest-asyncio=1.5.8=pyhd8ed1ab_0
- nettle=3.7.3=hbbd107a_1
- networkx=3.1=py310h06a4308_0
- numpy=1.26.0=py310h5f9d8c6_0
- numpy-base=1.26.0=py310hb5e798b_0
- openh264=2.1.1=h4ff587b_0
- openjpeg=2.4.0=h3ad879b_0
- openssl=3.0.12=h7f8727e_0
- packaging=23.2=pyhd8ed1ab_0
- parso=0.8.3=pyhd8ed1ab_0
- pexpect=4.8.0=pyh1a96a4e_2
- pickleshare=0.7.5=py_1003
- pillow=10.0.1=py310ha6cbd5a_0
- pip=23.3=py310h06a4308_0
- platformdirs=4.0.0=pyhd8ed1ab_0
- prompt-toolkit=3.0.40=pyha770c72_0
- prompt_toolkit=3.0.40=hd8ed1ab_0
- ptyprocess=0.7.0=pyhd3deb0d_0
- pure_eval=0.2.2=pyhd8ed1ab_0
- pycparser=2.21=pyhd3eb1b0_0
- pygments=2.16.1=pyhd8ed1ab_0
- pyopenssl=23.2.0=py310h06a4308_0
- pysocks=1.7.1=py310h06a4308_0
- python=3.10.13=h955ad1f_0
- python-dateutil=2.8.2=pyhd8ed1ab_0
- python_abi=3.10=2_cp310
- pytorch=2.1.0=py3.10_cuda12.1_cudnn8.9.2_0
- pytorch-cuda=12.1=ha16c6d3_5
- pytorch-mutex=1.0=cuda
- pyyaml=6.0.1=py310h5eee18b_0
- pyzmq=25.1.0=py310h6a678d5_0
- readline=8.2=h5eee18b_0
- requests=2.31.0=py310h06a4308_0
- setuptools=68.0.0=py310h06a4308_0
- six=1.16.0=pyh6c4a22f_0
- sqlite=3.41.2=h5eee18b_0
- stack_data=0.6.2=pyhd8ed1ab_0
- sympy=1.11.1=py310h06a4308_0
- tbb=2021.8.0=hdb19cb5_0
- tk=8.6.12=h1ccaba5_0
- torchaudio=2.1.0=py310_cu121
- torchtriton=2.1.0=py310
- torchvision=0.16.0=py310_cu121
- traitlets=5.13.0=pyhd8ed1ab_0
- typing_extensions=4.7.1=py310h06a4308_0
- urllib3=1.26.18=py310h06a4308_0
- wcwidth=0.2.9=pyhd8ed1ab_0
- wheel=0.41.2=py310h06a4308_0
- xz=5.4.2=h5eee18b_0
- yaml=0.2.5=h7b6447c_0
- zeromq=4.3.4=h2531618_0
- zlib=1.2.13=h5eee18b_0
- zstd=1.5.5=hc292b87_0
- pip:
- accelerate==0.30.0
- aiohttp==3.9.0
- aiosignal==1.3.1
- anyio==4.3.0
- appdirs==1.4.4
- argon2-cffi==23.1.0
- argon2-cffi-bindings==21.2.0
- arrow==1.3.0
- async-lru==2.0.4
- async-timeout==4.0.3
- attrs==23.1.0
- babel==2.15.0
- beautifulsoup4==4.12.3
- bitsandbytes==0.41.2.post2
- bleach==6.1.0
- click==8.1.7
- contourpy==1.2.0
- cycler==0.12.1
- datasets==2.14.7
- defusedxml==0.7.1
- diffusers==0.23.1
- dill==0.3.7
- docker-pycreds==0.4.0
- fastjsonschema==2.19.1
- fonttools==4.44.0
- fqdn==1.5.1
- frozenlist==1.4.0
- fsspec==2023.10.0
- gitdb==4.0.11
- gitpython==3.1.40
- h11==0.14.0
- httpcore==1.0.5
- httpx==0.27.0
- huggingface-hub==0.17.3
- imageio==2.32.0
- importlib-metadata==6.8.0
- isoduration==20.11.0
- joblib==1.3.2
- json5==0.9.25
- jsonpointer==2.4
- jsonschema==4.22.0
- jsonschema-specifications==2023.12.1
- jupyter-client==8.6.1
- jupyter-events==0.10.0
- jupyter-lsp==2.2.5
- jupyter-server==2.14.0
- jupyter-server-terminals==0.5.3
- jupyterlab==4.1.8
- jupyterlab-pygments==0.3.0
- jupyterlab-server==2.27.1
- kiwisolver==1.4.5
- lazy-loader==0.3
- matplotlib==3.8.1
- mistune==3.0.2
- multidict==6.0.4
- multiprocess==0.70.15
- nbclient==0.10.0
- nbconvert==7.16.4
- nbformat==5.10.4
- notebook==7.1.3
- notebook-shim==0.2.4
- opencv-python==4.8.1.78
- overrides==7.7.0
- pandas==2.1.3
- pandocfilters==1.5.1
- prometheus-client==0.20.0
- protobuf==4.25.1
- psutil==5.9.6
- pyarrow==14.0.1
- pyarrow-hotfix==0.5
- pyparsing==3.1.1
- python-json-logger==2.0.7
- pytz==2023.3.post1
- referencing==0.35.1
- regex==2023.10.3
- rfc3339-validator==0.1.4
- rfc3986-validator==0.1.1
- rpds-py==0.18.1
- safetensors==0.4.0
- scikit-image==0.22.0
- scikit-learn==1.3.2
- scipy==1.11.3
- send2trash==1.8.3
- sentry-sdk==1.35.0
- setproctitle==1.3.3
- smmap==5.0.1
- sniffio==1.3.1
- soupsieve==2.5
- terminado==0.18.1
- threadpoolctl==3.2.0
- tifffile==2023.9.26
- tinycss2==1.3.0
- tokenizers==0.14.1
- tomli==2.0.1
- tornado==6.4
- tqdm==4.66.1
- transformers==4.35.0
- types-python-dateutil==2.9.0.20240316
- tzdata==2023.3
- uri-template==1.3.0
- wandb==0.16.0
- webcolors==1.13
- webencodings==0.5.1
- websocket-client==1.8.0
- xformers==0.0.22.post7
- xxhash==3.4.1
- yarl==1.9.2
- zipp==3.17.0