Files
2025-04-05 08:22:39 +08:00

592 lines
26 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from calendar import c
from operator import invert
from webbrowser import get
import torch
import random
import torch.nn as nn
import torch.nn.functional as F
import re
from .load_models_utils import get_lora_dict
global lora_get
lora_get=get_lora_dict()
lora_lightning_list = lora_get["lightning_xl_lora"]
class SpatialAttnProcessor2_0(torch.nn.Module):
r"""
Attention processor for IP-Adapater for PyTorch 2.0.
Args:
hidden_size (`int`):
The hidden size of the attention layer.
cross_attention_dim (`int`):
The number of channels in the `encoder_hidden_states`.
text_context_len (`int`, defaults to 77):
The context length of the text features.
scale (`float`, defaults to 1.0):
the weight scale of image prompt.
"""
def __init__(self, hidden_size = None, cross_attention_dim=None,id_length = 4,device = "cuda",dtype = torch.float16):
super().__init__()
if not hasattr(F, "scaled_dot_product_attention"):
raise ImportError("AttnProcessor2_0 requires PyTorch 2.0, to use it, please upgrade PyTorch to 2.0.")
self.device = device
self.dtype = dtype
self.hidden_size = hidden_size
self.cross_attention_dim = cross_attention_dim
self.total_length = id_length + 1
self.id_length = id_length
self.id_bank = {}
def __call__(
self,
attn,
hidden_states,
encoder_hidden_states=None,
attention_mask=None,
temb=None):
# un_cond_hidden_states, cond_hidden_states = hidden_states.chunk(2)
# un_cond_hidden_states = self.__call2__(attn, un_cond_hidden_states,encoder_hidden_states,attention_mask,temb)
# 生成一个0到1之间的随机数
global total_count,attn_count,cur_step,mask256,mask1024,mask4096
global sa16, sa32, sa64
global write
if write:
self.id_bank[cur_step] = [hidden_states[:self.id_length], hidden_states[self.id_length:]]
else:
encoder_hidden_states = torch.cat(self.id_bank[cur_step][0],hidden_states[:1],self.id_bank[cur_step][1],hidden_states[1:])
# 判断随机数是否大于0.5
if cur_step <5:
hidden_states = self.__call2__(attn, hidden_states,encoder_hidden_states,attention_mask,temb)
else: # 256 1024 4096
random_number = random.random()
if cur_step <20:
rand_num = 0.3
else:
rand_num = 0.1
if random_number > rand_num:
if not write:
if hidden_states.shape[1] == 32* 32:
attention_mask = mask1024[mask1024.shape[0] // self.total_length * self.id_length:]
elif hidden_states.shape[1] ==16*16:
attention_mask = mask256[mask256.shape[0] // self.total_length * self.id_length:]
else:
attention_mask = mask4096[mask4096.shape[0] // self.total_length * self.id_length:]
else:
if hidden_states.shape[1] == 32* 32:
attention_mask = mask1024[:mask1024.shape[0] // self.total_length * self.id_length]
elif hidden_states.shape[1] ==16*16:
attention_mask = mask256[:mask256.shape[0] // self.total_length * self.id_length]
else:
attention_mask = mask4096[:mask4096.shape[0] // self.total_length * self.id_length]
hidden_states = self.__call1__(attn, hidden_states,encoder_hidden_states,attention_mask,temb)
else:
hidden_states = self.__call2__(attn, hidden_states,None,attention_mask,temb)
attn_count +=1
if attn_count == total_count:
attn_count = 0
cur_step += 1
mask256,mask1024,mask4096 = cal_attn_mask(self.total_length,self.id_length,sa16,sa32,sa64, device=self.device, dtype= self.dtype)
return hidden_states
def __call1__(
self,
attn,
hidden_states,
encoder_hidden_states=None,
attention_mask=None,
temb=None,
):
residual = hidden_states
if encoder_hidden_states is not None:
raise Exception("not implement")
if attn.spatial_norm is not None:
hidden_states = attn.spatial_norm(hidden_states, temb)
input_ndim = hidden_states.ndim
if input_ndim == 4:
total_batch_size, channel, height, width = hidden_states.shape
hidden_states = hidden_states.view(total_batch_size, channel, height * width).transpose(1, 2)
total_batch_size,nums_token,channel = hidden_states.shape
img_nums = total_batch_size//2
hidden_states = hidden_states.view(-1,img_nums,nums_token,channel).reshape(-1,img_nums * nums_token,channel)
batch_size, sequence_length, _ = hidden_states.shape
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)
if encoder_hidden_states is None:
encoder_hidden_states = hidden_states # B, N, C
else:
encoder_hidden_states = encoder_hidden_states.view(-1,self.id_length+1,nums_token,channel).reshape(-1,(self.id_length+1) * nums_token,channel)
key = attn.to_k(encoder_hidden_states)
value = attn.to_v(encoder_hidden_states)
inner_dim = key.shape[-1]
head_dim = inner_dim // attn.heads
query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
# the output of sdp = (batch, num_heads, seq_len, head_dim)
# TODO: add support for attn.scale when we move to Torch 2.1
hidden_states = F.scaled_dot_product_attention(
query, key, value, attn_mask=attention_mask, dropout_p=0.0, is_causal=False
)
hidden_states = hidden_states.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
hidden_states = hidden_states.to(query.dtype)
# linear proj
hidden_states = attn.to_out[0](hidden_states)
# dropout
hidden_states = attn.to_out[1](hidden_states)
# if input_ndim == 4:
# tile_hidden_states = tile_hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width)
# if attn.residual_connection:
# tile_hidden_states = tile_hidden_states + residual
if input_ndim == 4:
hidden_states = hidden_states.transpose(-1, -2).reshape(total_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 __call2__(
self,
attn,
hidden_states,
encoder_hidden_states=None,
attention_mask=None,
temb=None):
residual = hidden_states
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)
batch_size, sequence_length, _ = (
hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape
)
attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size)
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)
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)
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)
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)
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 cal_attn_mask(total_length,id_length,sa16,sa32,sa64,device="cuda",dtype= torch.float16):
bool_matrix256 = torch.rand((1, total_length * 256),device = device,dtype = dtype) < sa16
bool_matrix1024 = torch.rand((1, total_length * 1024),device = device,dtype = dtype) < sa32
bool_matrix4096 = torch.rand((1, total_length * 4096),device = device,dtype = dtype) < sa64
bool_matrix256 = bool_matrix256.repeat(total_length,1)
bool_matrix1024 = bool_matrix1024.repeat(total_length,1)
bool_matrix4096 = bool_matrix4096.repeat(total_length,1)
for i in range(total_length):
bool_matrix256[i:i+1,id_length*256:] = False
bool_matrix1024[i:i+1,id_length*1024:] = False
bool_matrix4096[i:i+1,id_length*4096:] = False
bool_matrix256[i:i+1,i*256:(i+1)*256] = True
bool_matrix1024[i:i+1,i*1024:(i+1)*1024] = True
bool_matrix4096[i:i+1,i*4096:(i+1)*4096] = True
mask256 = bool_matrix256.unsqueeze(1).repeat(1,256,1).reshape(-1,total_length * 256)
mask1024 = bool_matrix1024.unsqueeze(1).repeat(1,1024,1).reshape(-1,total_length * 1024)
mask4096 = bool_matrix4096.unsqueeze(1).repeat(1,4096,1).reshape(-1,total_length * 4096)
return mask256,mask1024,mask4096
def cal_attn_mask_xl(total_length,id_length,sa32,sa64,height_s,width_s,device="cuda",dtype= torch.float16):
nums_1024 = (height_s // 32) * (width_s // 32)
nums_4096 = (height_s // 16) * (width_s // 16)
bool_matrix1024 = torch.rand((1, total_length * nums_1024),device = device,dtype = dtype) < sa32
bool_matrix4096 = torch.rand((1, total_length * nums_4096),device = device,dtype = dtype) < sa64
bool_matrix1024 = bool_matrix1024.repeat(total_length,1)
bool_matrix4096 = bool_matrix4096.repeat(total_length,1)
for i in range(total_length):
bool_matrix1024[i:i+1,id_length*nums_1024:] = False
bool_matrix4096[i:i+1,id_length*nums_4096:] = False
bool_matrix1024[i:i+1,i*nums_1024:(i+1)*nums_1024] = True
bool_matrix4096[i:i+1,i*nums_4096:(i+1)*nums_4096] = True
mask1024 = bool_matrix1024.unsqueeze(1).repeat(1,nums_1024,1).reshape(-1,total_length * nums_1024)
mask4096 = bool_matrix4096.unsqueeze(1).repeat(1,nums_4096,1).reshape(-1,total_length * nums_4096)
return mask1024,mask4096
def cal_attn_indice_xl_effcient_memory(total_length,id_length,sa32,sa64,height_s,width_s,device="cuda",dtype= torch.float16):
nums_1024 = (height_s // 32) * (width_s // 32)
nums_4096 = (height_s // 16) * (width_s // 16)
bool_matrix1024 = torch.rand((total_length,nums_1024),device = device,dtype = dtype) < sa32
bool_matrix4096 = torch.rand((total_length,nums_4096),device = device,dtype = dtype) < sa64
# 用nonzero()函数获取所有为True的值的索引
indices1024 = [torch.nonzero(bool_matrix1024[i], as_tuple=True)[0] for i in range(total_length)]
indices4096 = [torch.nonzero(bool_matrix4096[i], as_tuple=True)[0] for i in range(total_length)]
return indices1024,indices4096
class AttnProcessor(nn.Module):
r"""
Default processor for performing attention-related computations.
"""
def __init__(
self,
hidden_size=None,
cross_attention_dim=None,
):
super().__init__()
def __call__(
self,
attn,
hidden_states,
encoder_hidden_states=None,
attention_mask=None,
temb=None,
):
residual = hidden_states
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)
batch_size, sequence_length, _ = (
hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape
)
attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size)
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)
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)
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)
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)
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
class AttnProcessor2_0(torch.nn.Module):
r"""
Processor for implementing scaled dot-product attention (enabled by default if you're using PyTorch 2.0).
"""
def __init__(
self,
hidden_size=None,
cross_attention_dim=None,
):
super().__init__()
if not hasattr(F, "scaled_dot_product_attention"):
raise ImportError("AttnProcessor2_0 requires PyTorch 2.0, to use it, please upgrade PyTorch to 2.0.")
def __call__(
self,
attn,
hidden_states,
encoder_hidden_states=None,
attention_mask=None,
temb=None,
):
residual = hidden_states
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)
batch_size, sequence_length, _ = (
hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape
)
if attention_mask is not None:
attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size)
# scaled_dot_product_attention expects attention_mask shape to be
# (batch, heads, source_length, target_length)
attention_mask = attention_mask.view(batch_size, attn.heads, -1, attention_mask.shape[-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)
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)
value = attn.to_v(encoder_hidden_states)
inner_dim = key.shape[-1]
head_dim = inner_dim // attn.heads
query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
# the output of sdp = (batch, num_heads, seq_len, head_dim)
# TODO: add support for attn.scale when we move to Torch 2.1
hidden_states = F.scaled_dot_product_attention(
query, key, value, attn_mask=attention_mask, dropout_p=0.0, is_causal=False
)
hidden_states = hidden_states.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
hidden_states = hidden_states.to(query.dtype)
# linear proj
hidden_states = attn.to_out[0](hidden_states)
# dropout
hidden_states = attn.to_out[1](hidden_states)
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 is_torch2_available():
return hasattr(F, "scaled_dot_product_attention")
# 将列表转换为字典的函数
def character_to_dict(general_prompt,lora,add_trigger_words):
character_dict = {}
generate_prompt_arr = general_prompt.splitlines()
if lora:
if lora not in lora_lightning_list:
generate_prompt_arr = [item + add_trigger_words for item in generate_prompt_arr]
#print(prompts)
character_index_dict = {}
invert_character_index_dict = {}
character_list = []
for ind,string in enumerate(generate_prompt_arr):
# 分割字符串寻找key和value
start = string.find('[')
end = string.find(']')
if start != -1 and end != -1:
key = string[start:end+1]
value = string[end+1:]
if "#" in value:
value = value.rpartition('#')[0]
if key in character_dict:
raise f"duplicate character descirption:{key}"
character_dict[key] = value
character_list.append(key)
return character_dict,character_list
def get_id_prompt_index(character_dict,id_prompts):
replace_id_prompts = []
character_index_dict = {}
invert_character_index_dict = {}
for ind,id_prompt in enumerate(id_prompts):
for key in character_dict.keys():
if key in id_prompt:
if key not in character_index_dict:
character_index_dict[key] = []
character_index_dict[key].append(ind)
invert_character_index_dict[ind] = key
replace_id_prompts.append(id_prompt.replace(key,character_dict[key]))
return character_index_dict,invert_character_index_dict,replace_id_prompts
def get_cur_id_list(real_prompt,character_dict,character_index_dict):
list_arr = []
for keys in character_index_dict.keys():
if keys in real_prompt:
list_arr = list_arr + character_index_dict[keys]
real_prompt = real_prompt.replace(keys,character_dict[keys])
return list_arr,real_prompt
def process_original_prompt(character_dict,prompts,id_length,img_mode):
replace_prompts = []
character_index_dict = {}
invert_character_index_dict = {}
for ind,prompt in enumerate(prompts):
for key in character_dict.keys():
if key in prompt:
if key not in character_index_dict:
character_index_dict[key] = []
character_index_dict[key].append(ind)
if ind not in invert_character_index_dict:
invert_character_index_dict[ind] = []
invert_character_index_dict[ind].append(key)
cur_prompt = prompt
if ind in invert_character_index_dict:
for key in invert_character_index_dict[ind]:
cur_prompt = cur_prompt.replace(key,character_dict[key] + " ")
replace_prompts.append(cur_prompt)
ref_index_dict = {}
ref_totals = []
for character_key in character_index_dict.keys():
if character_key not in character_index_dict:
raise f"{character_key} not have prompt description, please remove it"
index_list = character_index_dict[character_key]
index_list = [index for index in index_list if len(invert_character_index_dict[index]) == 1]
# if not img_mode:
# if len(index_list) < id_length:
# raise f"{character_key} not have enough prompt description, need no less than {id_length}, but you give {len(index_list)}"
ref_index_dict[character_key] = index_list[:id_length]
ref_totals = ref_totals + index_list[:id_length]
return character_index_dict,invert_character_index_dict,replace_prompts,ref_index_dict,ref_totals
#character_index_dict:{'[Taylor]': [0, 3], '[sam]': [1, 2]},if 1 role {'[Taylor]': [0, 1, 2]}
#invert_character_index_dict:{0: ['[Taylor]'], 1: ['[sam]'], 2: ['[sam]'], 3: ['[Taylor]']},if 1 role {0: ['[Taylor]'], 1: ['[Taylor]'], 2: ['[Taylor]']}
#ref_indexs_dict:{'[Taylor]': [0, 3], '[sam]': [1, 2]},if 1 role {'[Taylor]': [0]}
#ref_totals: [0, 3, 1, 2] if 1 role [0]
def process_original_text(role_dict,prompts):
'''
Args:
role_dict: # character_dict:{'[Taylor]': ' a woman img, wearing a white T-shirt, blue loose hair.'},character_list:['[Taylor]'] 1role
#character_dict:{'[Taylor]': ' a woman img, wearing a white T-shirt, blue loose hair.', '[Lecun]': ' a man img,wearing a suit,black hair.'} 2role
prompts: #[ list of scense txt]
Returns:
1 role
role_index_dict:{'[Taylor]': [0, 1]},
invert_role_index_dict:{0: ['[Taylor]'], 1: ['[Taylor]']},
replace_prompts:[' a woman img, wearing a white T-shirt, blue loose hair. wake up in the bed ;', ' a woman img, wearing a white T-shirt, blue loose hair. have breakfast by the window;'],
ref_role_index_dict:{'[Taylor]': [0]},
ref_role_totals:[0]
2 role
role_index_dict:{'[Taylor]': [0, 1], '[Lecun]': [2, 3]},
invert_role_index_dict:{0: ['[Taylor]'], 1: ['[Taylor]'], 2: ['[Lecun]'], 3: ['[Lecun]']},
replace_prompts:[' a woman img, wearing a white T-shirt, blue loose hair. wake up in the bed ;', ' a woman img, wearing a white T-shirt, blue loose hair. have breakfast by the window;', ' a man img,wearing a suit,black hair. driving a car;', ' a man img,wearing a suit,black hair. is working.'],
ref_role_index_dict:{'[Taylor]': [0, 1], '[Lecun]': [2, 3]},
ref_role_totals:[0, 1, 2, 3]
'''
replace_prompts = []
role_index_dict = {}
invert_role_index_dict = {}
for ind,prompt in enumerate(prompts):
for key in role_dict.keys(): # [Taylor],[Lecun]
if key in prompt: # [Taylor] a woman img
if key not in role_index_dict:
role_index_dict[key] = [] #character_index_dict:{'[Taylor]': [], '[Lecun]': []},
role_index_dict[key].append(ind) #character_index_dict:{'[Taylor]': [0, 1], '[Lecun]': [2, 3]},
if ind not in invert_role_index_dict:
invert_role_index_dict[ind] = [] #invert_character_index_dict:{0: []},
invert_role_index_dict[ind].append(key) # invert_character_index_dict:{0: ['[Taylor]'], 1: ['[Taylor]'], 2: ['[Lecun]'], 3: ['[Lecun]']},
cur_prompt = prompt
if ind in invert_role_index_dict:
for key in invert_role_index_dict[ind]:
cur_prompt = cur_prompt.replace(key,role_dict[key] + " ") #去掉[Taylor]
replace_prompts.append(cur_prompt)
ref_role_index_dict = {}
ref_role_totals = []
id_len=len(role_dict)
for character_key in role_index_dict.keys():
if character_key not in role_index_dict:
raise f"{character_key} not have prompt description, please remove it"
index_list = role_index_dict[character_key] #[0, 1],[3, 4] 如果2是NC
index_list = [index for index in index_list if len(invert_role_index_dict[index]) == 1]
# if not img_mode:
# if len(index_list) < id_length:
# raise f"{character_key} not have enough prompt description, need no less than {id_length}, but you give {len(index_list)}"
ref_role_index_dict[character_key] = index_list[:id_len]
ref_role_totals = ref_role_totals + index_list[:id_len]
return role_index_dict,invert_role_index_dict,replace_prompts,ref_role_index_dict,ref_role_totals
#character_index_dict:{'[Taylor]': [0, 3], '[sam]': [1, 2]},if 1 role {'[Taylor]': [0, 1, 2]}
#invert_character_index_dict:{0: ['[Taylor]'], 1: ['[sam]'], 2: ['[sam]'], 3: ['[Taylor]']},if 1 role {0: ['[Taylor]'], 1: ['[Taylor]'], 2: ['[Taylor]']}
#ref_indexs_dict:{'[Taylor]': [0, 3], '[sam]': [1, 2]},if 1 role {'[Taylor]': [0]}
#ref_totals: [0, 3, 1, 2] if 1 role [0]
def get_ref_character(real_prompt,character_dict):
list_arr = []
for keys in character_dict.keys():
if keys in real_prompt:
list_arr = list_arr + [keys]
return list_arr