fix: detect and route around corrupted CLIP-L final layer on SDXL - #1892
Open
Rojikku wants to merge 3 commits into
Open
fix: detect and route around corrupted CLIP-L final layer on SDXL#1892Rojikku wants to merge 3 commits into
Rojikku wants to merge 3 commits into
Conversation
SDXL's CLIP-G (OpenCLIP ViT-bigG) is only ever trained against its penultimate layer output. An explicit clip_skip of 1 (or any value below 2) runs its untrained final layer, whose activations overflow fp16 on some backends (observed on ROCm/gfx1100) and propagate through the UNet and VAE decode into a blank white image. The existing clip_skip<=0 default already resolved to 2 for SDXL, so this only affects requests that explicitly pass a value of 0 < n < 2.
wbruna
suggested changes
Aug 21, 2026
This reverts commit 5a1e81e.
Rojikku
marked this pull request as draft
August 21, 2026 04:13
Many distributed SDXL checkpoints (verified: waiIllustriousSDXL, cyberrealisticXL, both independently) carry NaN weights across every weight matrix (q/k/v/out_proj, mlp.fc1/fc2) in CLIP-L's final transformer layer. This is not a precision or backend issue - verified by reading the raw safetensors bytes directly: the layer is NaN in the file itself, on both CPU and GPU, regardless of backend. SDXL's UNet was only ever trained against CLIP-L's penultimate layer, so this last layer is architecturally unused, and it appears the common conversion/merge pipeline these checkpoints share never populated it with valid data. Requesting a clip_skip low enough to reach that layer (clip_skip=1) therefore produces a NaN encoder output, which propagates through generation and comes out as a blank white image. Rather than unconditionally clamping clip_skip for all SDXL requests (which would needlessly break a checkpoint using a valid standalone CLIP-L, e.g. via --clip-l), detect the corruption from the actual computed output: if requesting clip_skip<2 on SDXL yields a NaN result, warn and recompute with clip_skip=2. Costs one extra (cheap, CLIP-L-only) compute, only when explicitly requesting the affected range on an affected checkpoint. CLIP-G's own final layer was checked and confirmed valid in both tested checkpoints, so this only touches the CLIP-L path.
Rojikku
marked this pull request as ready for review
August 21, 2026 05:08
Author
|
The fix has been adjusted. Instead of all SDXL, it specifically checks if CLIP-L produces bad output, then changes clip_skip=2 with a log if it does. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR no cat (white image) if SDXL && clip_skip = 1
Fix: clip_skip min 2 when NaF (Not A Feline) || Made cat not decat
I will not pretend to understand your project, I came from like 2 projects downstream trying to figure out a config issue, turned out to be a bug here. I am confident I understand this fix, but can't be certain of edge cases.
Edit: Fixed for edge case 1 (Which was a lie, but there might be others where it's true)
That project defaulted to clip_skip = 1 which is a "harmless default"
Figured it was easier to make the AI fix it than make a bug report TBH.
Claude's explanation
Problem
Passing an explicit
clip_skipof 1 (or any value below 2) on an SDXL model produces a blank white image — generation completes normally (all steps, VAE decode, HTTP 200), no errors, just solid white output.Root cause
This is not a precision, overflow, or backend issue — it's corrupted data in the checkpoint file itself.
Verified by reading the raw safetensors bytes directly, bypassing this codebase entirely: in two independent, unrelated SDXL checkpoints (
waiIllustriousSDXL_v170andcyberrealisticXL_v100), every weight matrix in CLIP-L's final transformer layer (q_proj,k_proj,v_proj,out_proj,mlp.fc1,mlp.fc2) is 100% NaN, on disk, in both files. The layer immediately before it (a known-good control) is completely clean. Biases and layer-norm parameters in that same "bad" layer are untouched — only the big weight matrices are NaN.This tracks with how SDXL was trained: its UNet was only ever conditioned on CLIP-L's penultimate layer (which is why the existing
clip_skip<=0default already resolves to2for SDXL). That final layer is architecturally unused, and the common conversion/merge pipeline nearly every distributed SDXL checkpoint shares appears to have never populated it with valid data. CLIP-G's own final layer was checked in both files and is completely valid — this defect is specific to CLIP-L.Requesting
clip_skip=1reaches that never-populated layer, producing NaN conditioning that propagates through the UNet and VAE decode; the final pixel clamp turns the resulting garbage into flat white.Why not just clamp clip_skip unconditionally
An earlier version of this PR did exactly that, and was correctly flagged in review: some SDXL derivatives (e.g. cyberrealistic-xl) are documented to want
clip_skip=1, and a blanket clamp would silently override that for anyone using a checkpoint whose CLIP-L isn't corrupted (e.g. via a valid standalone--clip-loverride).Fix
Detect the corruption from the actual computed output instead of assuming every checkpoint is affected: if
clip_skip<2is requested on SDXL and the resulting CLIP-L encoder output contains NaN, warn and recompute withclip_skip=2. This costs one extra, CLIP-L-only compute — only in the narrow case of explicitly requesting the affected range on an affected checkpoint. A checkpoint with valid CLIP-L weights (however it's supplied) is never touched by this path.Verification
Built locally with
-DSD_HIPBLAS=ON -DAMDGPU_TARGETS=gfx1100. Tested against both real checkpoints:waiIllustriousSDXL_v170atclip_skip=1: warns, clamps, produces a normal image (was solid white before the fix)cyberrealisticXL_v100atclip_skip=1: sameclip_skip: unchanged, no warning, no extra compute (guard is skipped onceclip_skip>=2)dreamshaper_8(SD1.5) atclip_skip=1: completely untouched (guard is SDXL-only), unchanged outputVerification
Hardware:
Downloaded
sd-master-97d2990-bin-Linux-Ubuntu-24.04-x86_64-rocm-7.14.0.zip, verified problem reproduces.Compiled fix, verified fix doesn't reproduce.
Method:
I believe this fits all standards, please let me know if I need to make corrections or add context. Edit as you please.