From aeef359bd7d7d0ae149deb37305e7da8fc10635a Mon Sep 17 00:00:00 2001 From: CalamitousFelicitousness Date: Thu, 25 Jun 2026 02:06:05 +0100 Subject: [PATCH] fix(prompt): restore textual inversion on clip-skip>=2 transformers 5.6 flattened CLIPTextModel, removing the .text_model wrapper that compel_hijack and the xhinker parser dereference on the normalized clip-skip path. On SD1.5 at clip-skip >= 2 this raised AttributeError, which processing_prompt caught and silently fell back to fixed-attention encoding, dropping textual inversion and prompt weighting. Resolve the submodule via getattr(te, 'text_model', te), correct for flattened CLIPTextModel, CLIPTextModelWithProjection (still nested), and transformers < 5.6. --- modules/prompt_parser_diffusers.py | 4 +++- modules/prompt_parser_xhinker.py | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/prompt_parser_diffusers.py b/modules/prompt_parser_diffusers.py index 1b356d7e9..2025a4ca6 100644 --- a/modules/prompt_parser_diffusers.py +++ b/modules/prompt_parser_diffusers.py @@ -327,7 +327,9 @@ def compel_hijack(self, token_ids: torch.Tensor, attention_mask: torch.Tensor | else: hidden_state = text_encoder_output.hidden_states[-clip_skip] if normalized: - hidden_state = self.text_encoder.text_model.final_layer_norm(hidden_state) + # transformers >=5.6 flattened CLIPTextModel; CLIPTextModelWithProjection still nests it under .text_model + text_model = getattr(self.text_encoder, 'text_model', self.text_encoder) + hidden_state = text_model.final_layer_norm(hidden_state) return hidden_state diff --git a/modules/prompt_parser_xhinker.py b/modules/prompt_parser_xhinker.py index 344f0778c..1eeefe88d 100644 --- a/modules/prompt_parser_xhinker.py +++ b/modules/prompt_parser_xhinker.py @@ -216,9 +216,11 @@ def get_weighted_text_embeddings_sd15( , generator = torch.Generator(text2img_pipe.device).manual_seed(2) ).images[0] """ - original_clip_layers = pipe.text_encoder.text_model.encoder.layers + # transformers >=5.6 flattened CLIPTextModel; CLIPTextModelWithProjection still nests it under .text_model + clip_text_model = getattr(pipe.text_encoder, 'text_model', pipe.text_encoder) + original_clip_layers = clip_text_model.encoder.layers if clip_skip > 0: - pipe.text_encoder.text_model.encoder.layers = original_clip_layers[:-clip_skip] + clip_text_model.encoder.layers = original_clip_layers[:-clip_skip] eos = pipe.tokenizer.eos_token_id prompt_tokens, prompt_weights = get_prompts_tokens_with_weights( @@ -310,7 +312,7 @@ def get_weighted_text_embeddings_sd15( # recover clip layers if clip_skip > 0: - pipe.text_encoder.text_model.encoder.layers = original_clip_layers + clip_text_model.encoder.layers = original_clip_layers return prompt_embeds, neg_prompt_embeds