From 3dd0cd590cd02ce0850b4ad6ce55df77622cb0d1 Mon Sep 17 00:00:00 2001 From: CalamitousFelicitousness Date: Thu, 25 Jun 2026 02:06:05 +0100 Subject: [PATCH] fix(pipelines): restore clip-skip text encoding for transformers 5.6+ The vendored encode_prompt copies in the PAG, APG, ControlNet-XS and differential diffusion pipelines dereference the .text_model wrapper that transformers 5.6 removed from CLIPTextModel, so their clip-skip path crashes on SD1.5 and SDXL TE1. Apply the same getattr(te, 'text_model', te) fix as the core parser. Mirrors upstream diffusers, which still carries this deref in pipeline encode_prompt; only the single-file loader was fixed there. --- modules/apg/pipeline_stable_diffusion_apg.py | 3 ++- modules/control/units/xs_pipe.py | 3 ++- modules/pag/pipe_sd.py | 3 ++- scripts/differential_diffusion.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/apg/pipeline_stable_diffusion_apg.py b/modules/apg/pipeline_stable_diffusion_apg.py index 57aebafca..1508b3f13 100644 --- a/modules/apg/pipeline_stable_diffusion_apg.py +++ b/modules/apg/pipeline_stable_diffusion_apg.py @@ -404,7 +404,8 @@ class StableDiffusionPipelineAPG( # representations. The `last_hidden_states` that we typically use for # obtaining the final prompt representations passes through the LayerNorm # layer. - prompt_embeds = self.text_encoder.text_model.final_layer_norm(prompt_embeds) + # transformers >=5.6 flattened CLIPTextModel; CLIPTextModelWithProjection still nests it under .text_model + prompt_embeds = getattr(self.text_encoder, 'text_model', self.text_encoder).final_layer_norm(prompt_embeds) if self.text_encoder is not None: prompt_embeds_dtype = self.text_encoder.dtype diff --git a/modules/control/units/xs_pipe.py b/modules/control/units/xs_pipe.py index 282b4f996..078293831 100644 --- a/modules/control/units/xs_pipe.py +++ b/modules/control/units/xs_pipe.py @@ -1321,7 +1321,8 @@ class StableDiffusionControlNetXSPipeline( # representations. The `last_hidden_states` that we typically use for # obtaining the final prompt representations passes through the LayerNorm # layer. - prompt_embeds = self.text_encoder.text_model.final_layer_norm(prompt_embeds) + # transformers >=5.6 flattened CLIPTextModel; CLIPTextModelWithProjection still nests it under .text_model + prompt_embeds = getattr(self.text_encoder, 'text_model', self.text_encoder).final_layer_norm(prompt_embeds) if self.text_encoder is not None: prompt_embeds_dtype = self.text_encoder.dtype diff --git a/modules/pag/pipe_sd.py b/modules/pag/pipe_sd.py index 9a7af9bda..8e3f24429 100644 --- a/modules/pag/pipe_sd.py +++ b/modules/pag/pipe_sd.py @@ -619,7 +619,8 @@ class StableDiffusionPAGPipeline( # representations. The `last_hidden_states` that we typically use for # obtaining the final prompt representations passes through the LayerNorm # layer. - prompt_embeds = self.text_encoder.text_model.final_layer_norm(prompt_embeds) + # transformers >=5.6 flattened CLIPTextModel; CLIPTextModelWithProjection still nests it under .text_model + prompt_embeds = getattr(self.text_encoder, 'text_model', self.text_encoder).final_layer_norm(prompt_embeds) if self.text_encoder is not None: prompt_embeds_dtype = self.text_encoder.dtype diff --git a/scripts/differential_diffusion.py b/scripts/differential_diffusion.py index 2843bf62f..11eb177af 100644 --- a/scripts/differential_diffusion.py +++ b/scripts/differential_diffusion.py @@ -1546,7 +1546,8 @@ class StableDiffusionDiffImg2ImgPipeline(DiffusionPipeline): # representations. The `last_hidden_states` that we typically use for # obtaining the final prompt representations passes through the LayerNorm # layer. - prompt_embeds = self.text_encoder.text_model.final_layer_norm(prompt_embeds) + # transformers >=5.6 flattened CLIPTextModel; CLIPTextModelWithProjection still nests it under .text_model + prompt_embeds = getattr(self.text_encoder, 'text_model', self.text_encoder).final_layer_norm(prompt_embeds) if self.text_encoder is not None: prompt_embeds_dtype = self.text_encoder.dtype