Conversation
Ming-Image text encoders (Ling-Mini 17.3B MoE) require the comfy.ops MoEExperts interface (bank_resident / expert_linear / expert_weight) which GGMLOps did not implement, so Ming GGUF files fail with "GGMLOps has no attribute MoEExperts". Implement GGMLMoEExperts as a GGMLLayer over the full packed expert bank [num_experts, out_features, in_features]: bank_resident dequantizes the bank once through the standard cast path and expert_linear indexes into it; expert_weight lazily dequantizes a single expert by slicing its contiguous byte range from the packed buffer and dequantizing it as a 2D matrix (verified bit-exact against full-bank dequantization on Q4_K). Also convert tokenizer_json tensors stored as F32 (one float value per byte) to uint8 bytes in gguf_clip_loader; Ming GGUFs store the tokenizer this way and the core Ming tokenizer expects raw utf-8. Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
|
Independent verification from a third setup — both issues this PR targets are confirmed against the published files; the fix direction looks right. Setup: ComfyUI pinned at Tokenizer tensor (read with MoEExperts: Both failures were reproduced independently; with a local prototype of this PR's two fixes (a GGMLLayer-based One data point to double-check: after decoding, my tokenizer reports vocab size 157,179 (identical with and without |
Problem
Loading the Ming-Image GGUF text encoders (Ling-Mini-2.0 17.3B MoE) fails with:
Recent comfy core added
comfy.ops.MoEExperts, andcomfy.text_encoders.ming_image.BailingExpertsroutes its expert banks (experts.gate_up_proj.weight,experts.down_proj.weight) throughmoe_experts_forward, which requires thebank_resident/expert_linear/expert_weightinterface.GGMLOpshad no implementation of it, so every Ming GGUF TE fails at load time.A second, independent failure follows after that: the
tokenizer_jsontensor inside these GGUFs is stored as F32 with one float value per byte (the byte stream of the HFtokenizer.jsonencoded as floats), while the core Ming tokenizer expects raw utf-8 bytes — it currently errors withUnicodeDecodeErrorinstead.Fix 1:
GGMLMoEExperts(ops.py)A
GGMLLayerover the full packed expert bank (logical shape[num_experts, out_features, in_features], exposed as-is by the loader):bank_resident(input)dequantizes the bank once through the standardcast_bias_weightpath (so it goes through the usual dequant + patch machinery), thenexpert_linear(input, i)indexes into the resident bank. This is the hot path used bymoe_experts_forward.expert_weight(i, input=...)lazily dequantizes a single expert: experts are contiguous in the packed buffer, so it slices the expert's byte range and dequantizes it as a 2D[out_features, in_features]matrix. This avoids materializing the full bank when used without the context manager.MoEExperts(num_experts, in_features, out_features, bias, device, dtype) and shape mismatches fail loudly. Also exposed asGGMLOps.MoEExperts.Verified on a real Q4_K bank (
thinker.layers.1.mlp.experts.*from Ming-Image-0.1-Ling-Mini-2.0-Q4_K_M.gguf, E=256):torch.equal) for bothgate_up_projanddown_proj;bank_resident+expert_linearmatches a manualF.linearreference (max diff 0.0);comfy.text_encoders.llama.moe_experts_forwardruns end-to-end over both banks and returns the expected[tokens, hidden]output.Fix 2: F32
tokenizer_jsontensors (loader.py)gguf_clip_loadernow converts atokenizer_jsontensor stored as F32-per-byte into a plain uint8 byte tensor, so the core tokenizer can.decode("utf-8")it. Validated against the actual file: all 12,210,709 values are integral, and the converted bytes parse as valid tokenizer JSON (vocab size 156,891).Testing
88ab4a06), RTX 3090 24GB, python 3.10 / torch 2.14+cu126.UnetLoaderGGUF+CLIPLoaderGGUF(type=ming): full t2i workflow completes in 27s, output is a valid 1024×1024 RGBA PNG.Notes
tokenizer_jsontensors, which previously could not be consumed at all.bias=False.