#!/usr/bin/env python3 """Make a ComfyUI-GGUF-compatible copy of an AtomicChat Qwen-Image-2.1(-Turbo) GGUF. Problem: the AtomicChat GGUF stores the 1-D RMSNorm weights (transformer_blocks.N.attn.norm_q.weight / norm_k.weight, shape [128]) quantized as Q8_0. stable-diffusion.cpp dequantizes them, but ComfyUI-GGUF has no quantized RMSNorm op, so the fused rms_rope in ComfyUI receives the raw Q8_0 bytes (128 values -> 4 blocks x 34 bytes = 136) and fails with "Expected weight ... shape [136] and normalized_shape = [128]". Fix: rewrite the file with every quantized 1-D tensor dequantized to F32 (the convention llama.cpp and city96 convert.py use for norms). All other tensors are copied byte-for-byte; the header keeps its original (empty) KV table so stable-diffusion.cpp still loads it the same way. The original is never touched. usage: python fix_atomicchat_gguf.py IN.gguf OUT.gguf (needs: pip install gguf numpy) """ import struct, sys, numpy as np, gguf from gguf.quants import dequantize from gguf.constants import GGMLQuantizationType as Q src, dst = sys.argv[1], sys.argv[2] assert src != dst, "refusing to overwrite the original" r = gguf.GGUFReader(src) ALIGN = 32 NOQ = {Q.F32, Q.F16, Q.BF16, Q.F64} def s(b): return struct.pack(" 4: print(" ...") # verify r2 = gguf.GGUFReader(dst) assert len(r2.tensors) == len(r.tensors) for a, b in zip(r.tensors, r2.tensors): assert a.name == b.name and list(a.shape) == list(b.shape) if a.tensor_type == b.tensor_type: assert np.array_equal(a.data, b.data), a.name else: assert np.array_equal(dequantize(a.data, a.tensor_type).reshape(-1), np.asarray(b.data).reshape(-1)), a.name print("verified: every tensor identical; fixed ones equal their dequantized values")