add new node.
This commit is contained in:
@@ -632,11 +632,11 @@ class PreRun:
|
||||
layer = 0
|
||||
model_type = "flux"
|
||||
|
||||
text_len = fg_condition_mask.shape[-1]
|
||||
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
||||
attn_dtype = torch.bfloat16 if model_management.should_use_bf16(device=device) else torch.float16
|
||||
fg_bg_mask = None
|
||||
accum_sim = None
|
||||
text_len = fg_condition_mask.shape[-1]
|
||||
accum_sim = None
|
||||
fg_condition_mask = fg_condition_mask.to(device)
|
||||
def masked_attention(q: Tensor, k: Tensor, v: Tensor, pe: Tensor, mask: Tensor) -> Tensor:
|
||||
"""
|
||||
@@ -787,3 +787,108 @@ class CrossSimMaskExtract:
|
||||
cross_mask = torch.zeros(1, 1, 1, dtype=torch.float32)
|
||||
|
||||
return (cross_mask, fg_mask)
|
||||
|
||||
|
||||
class GenConsistent:
|
||||
RETURN_TYPES = ("MODEL",)
|
||||
FUNCTION = "go"
|
||||
CATEGORY = "chara_consist"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"model": ("MODEL",),
|
||||
"subject": ("SUBJECT",),
|
||||
"cross_sim": ("CROSSSIM",),
|
||||
"fg_condition_mask": ("MASK",),
|
||||
"kv_start_step": ("INT",{"default":1,"min":0}),
|
||||
"kv_end_step": ("INT",{"default":5,"min":0}),
|
||||
},
|
||||
"optional": {
|
||||
"latent":("LATENT",)
|
||||
}
|
||||
}
|
||||
@classmethod
|
||||
def go(cls, model, subject, cross_sim, fg_condition_mask, kv_start_step, kv_end_step, latent):
|
||||
|
||||
index = len(subject) - 1
|
||||
def prepare_callback(model, max_steps, x0_output_dict=None):
|
||||
nonlocal subject, fg_condition_mask
|
||||
sampled_step = -1
|
||||
sampling_step = -1
|
||||
layer = 0
|
||||
model_type = "flux"
|
||||
|
||||
text_len = fg_condition_mask.shape[-1]
|
||||
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
||||
attn_dtype = torch.bfloat16 if model_management.should_use_bf16(device=device) else torch.float16
|
||||
fg_bg_mask = None
|
||||
fg_condition_mask = fg_condition_mask.to(device)
|
||||
def masked_attention(q: Tensor, k: Tensor, v: Tensor, pe: Tensor, mask: Tensor) -> Tensor:
|
||||
"""
|
||||
Implementation using PyTorch's scaled_dot_product_attention with custom masking.
|
||||
|
||||
Args:
|
||||
q: Query tensor of shape [B, H, L, D]
|
||||
k: Key tensor of shape [B, H, L, D]
|
||||
v: Value tensor of shape [B, H, L, D]
|
||||
pe: Positional encoding tensor
|
||||
attn_mask: Optional attention mask of shape [B, H, L, L]
|
||||
|
||||
Returns:
|
||||
Output tensor of shape [B, L, H*D]
|
||||
"""
|
||||
nonlocal sampling_step, sampled_step, layer, subject, text_len, fg_bg_mask
|
||||
if sampling_step != sampled_step + 1:
|
||||
layer = 0
|
||||
sampling_step = sampled_step + 1
|
||||
# Store k, v, and x in a dict with layer id as key
|
||||
if sampling_step >= kv_start_step and sampling_step < kv_end_step:
|
||||
subject[index][sampling_step]["layers"][layer]
|
||||
# todo
|
||||
|
||||
# Apply rotary positional encoding for Flux models
|
||||
if pe is not None:
|
||||
q, k = flux_math.apply_rope(q, k, pe)
|
||||
|
||||
x = F.scaled_dot_product_attention(
|
||||
q, k, v, attn_mask=mask
|
||||
)
|
||||
# Reshape back to the expected output format
|
||||
x = rearrange(x, "B H L D -> B L (H D)")
|
||||
|
||||
layer += 1
|
||||
return x
|
||||
|
||||
# Create the attention override function
|
||||
def attention_override(q: Tensor, k: Tensor, v: Tensor, pe: Tensor, mask: Tensor, transformer_options) -> Tensor:
|
||||
if transformer_options["cond_or_uncond"][-1]:#q.shape[2] != text_len + (w * h)
|
||||
return orig_attention(q, k, v, pe)
|
||||
else:
|
||||
return masked_attention(q, k, v, pe, mask)
|
||||
|
||||
# Apply the attention override based on model type
|
||||
overrider = attention_override
|
||||
|
||||
if model.model.__class__.__name__ == "Chroma":
|
||||
model_type = "chroma"
|
||||
|
||||
print(f'GenSubject Detected model type: {model_type}')
|
||||
|
||||
if model_type == "flux":
|
||||
flux_layers.attention = overrider
|
||||
else: # chroma
|
||||
chroma_layers.attention = overrider
|
||||
origin_callback = orig_prepare_callback(model, max_steps, x0_output_dict)
|
||||
def callback_change_sampled_step(step, x0, x, total_steps):
|
||||
nonlocal max_steps
|
||||
nonlocal sampling_step, sampled_step, layer, fg_bg_mask, model
|
||||
sampled_step = step
|
||||
origin_callback(step, x0, x, total_steps)
|
||||
return callback_change_sampled_step
|
||||
model = copy.copy(model)
|
||||
model.model_options = copy.copy(model.model_options)
|
||||
model.model_options["prepare_callback"] = prepare_callback
|
||||
hook_prepare_callback()
|
||||
return (model, subject,)
|
||||
Reference in New Issue
Block a user