Fix Qwen3-VL (qwen3vl) mmproj not loaded: Krea2 / Qwen3-VL CLIP falls back to QWEN3_4B - #478
Open
allanmeng wants to merge 1 commit into
Open
Fix Qwen3-VL (qwen3vl) mmproj not loaded: Krea2 / Qwen3-VL CLIP falls back to QWEN3_4B#478allanmeng wants to merge 1 commit into
allanmeng wants to merge 1 commit into
Conversation
…EN3_4B
gguf_clip_loader only called gguf_mmproj_loader() when arch == "qwen2vl", so a
qwen3vl encoder never loaded its vision tower. Without the vision keys,
comfy.sd.detect_te_model() cannot find
"model.visual.deepstack_merger_list.0.norm.weight", falls back to QWEN3_4B and
the text encoder emits a single 2560-dim layer instead of the 12 tapped layers
that Krea2 requires ("expects conditioning with 12x2560=30720 features but got
2560"). Affects all backends, not XPU-specific.
- add CLIP_VISION_SD_MAP_QWEN3VL: Qwen3-VL differs from Qwen2-VL -- merger is
{norm, linear_fc1, linear_fc2} (not {ln_q, mlp.0, mlp.2}), blocks use a fused
attn.qkv (not split attn_q/k/v) and mlp.linear_fc1/linear_fc2 (not
mlp.up_proj/down_proj). Keys are emitted in HF "model.visual.*" layout so
detect_te_model() can identify Qwen3-VL before the KREA2 branch rewrites the
prefix.
- add qwen3vl_deepstack_remap(): GGUF indexes DeepStack mergers by source vision
layer (4B: [5, 11, 17]; 8B/32B: [8, 16, 24]) while ComfyUI expects a
sequential list 0..N-1. Indices are derived by sorting the layer ids found in
the file, so nothing is hardcoded per model size.
- gate on arch in ("qwen2vl", "qwen3vl") and pass arch through to the loader.
qwen2vl behaviour is unchanged (arch defaults to None).
Verified against the authoritative qwen3vl_4b_fp8_scaled.safetensors layout
(315/315 keys, missing=0 / unexpected=0 / shape mismatch=0, cosine ~1.000) and
on hardware: Intel Arc B580, Krea2 sampling completes at 2.85 s/it with
Krea2RMSNorm shape=[400, 12, 2560].
Supersedes the Qwen3-VL mmproj part of city96#473 (see comment there: "v.deepstast."
typo and layer-index remap bound to a non-existent "ck." prefix).
Related: city96#464.
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.
Problem
Loading a
qwen3vltext encoder GGUF (e.g.Qwen3-VL-4B-Instruct-Q4_K_M.gguftype=krea2fails at sampling time:ValueError: Krea2 expects conditioning with 12x2560=30720 features but got 2560
Root cause is in
loader.py:qwen3vlis present inTXT_ARCH_LISTbut is excluded from the mmproj branch,so the vision tower is never loaded.
comfy.sd.detect_te_model()then cannot findmodel.visual.deepstack_merger_list.0.norm.weight, falls back toQWEN3_4B, andthe text encoder emits a single 2560-dim layer instead of the 12 tapped layers
(
KREA2_TAP_LAYERS) Krea2 needs.This is backend-independent - it reproduces on CUDA/ROCm/XPU alike.
Fix
loader.pyonly (+52 / -3):gguf_clip_loader:if arch in ("qwen2vl", "qwen3vl")and passarchthrough.CLIP_VISION_SD_MAP_QWEN3VLfor the Qwen3-VL vision tower. It differs fromQwen2-VL: merger is
{norm, linear_fc1, linear_fc2}(not{ln_q, mlp.0, mlp.2}),blocks use a fused
attn.qkv(not splitattn_q/k/v) andmlp.linear_fc1/linear_fc2(not
mlp.up_proj/down_proj). Keys are emitted in HFmodel.visual.*layout so thatdetect_te_model()identifies Qwen3-VL before the KREA2 branch rewrites the prefix.qwen3vl_deepstack_remap(): GGUF indexes DeepStack mergers by source visionlayer (4B:
[5, 11, 17], 8B/32B:[8, 16, 24]) while ComfyUI expects a sequentiallist
0..N-1. Mapping is derived by sorting the layer ids found in the file, so itis not hardcoded per model size.
Verification
qwen3vl_4b_fp8_scaled.safetensors:315 vs 315 keys, missing=0 / unexpected=0 / shape mismatch=0.
Q/K/V blocks gives cos = 0.999988 / 0.999999 / 0.999995 (confirms
[Q, K, V]order).detect_te_model()simulated before/after:QWEN3_4B->QWEN3VL_4B,so the
KREA2branch condition is satisfied.at 2.85 s/it with
Krea2RMSNorm shape=torch.Size([400, 12, 2560])(before the fixonly a single 2560 layer reached the DiT). Dequantization via Comfy Kitchen.
Notes
qwen2vl:archdefaults toNone, so the old path is untouched.MiniMax H3 mmproj support for Qwen3 VL 32B GGUFs #473 - see my comment there for two defects in that mapping table
(
v.deepstast.typo, and layer-index remap bound to a non-existentck.prefix).