Custom Node Testing
Expected Behavior
INT8 model + LoRA should produce the same quality regardless of --disable-dynamic-vram or whether layers offload - matching the clean output you get from an INT8 model with no LoRA.
What actually happens ("my journey", lol): INT8 model + LoRA + --disable-dynamic-vram = broken (low image quality in Ideogram4 with a normal LoRA loaded on both conditioned and unconditioned models). Removed the flag and it worked sometimes. INT8 model with no LoRA seems to work always. Tracing it, the degradation tracks with weights getting offloaded/re-quantized (the LoRA path), not the LoRA math itself.
I had GLM 5.2 take a crack at fixing it, but it couldn't. Then had Claude dig in, which found the re-quant calls drop the convrot/per_channel params (details below) and wrote a monkey-patch that avoids touching core code (also below, as an ugly init.py file). That restores quality and Opus claims its self-test shows ~6x lower re-quant error.
Actual Behavior
INT8 *_convrot_simple models degrade with LoRA because the re-quant calls drop the layout params.
Both sites in comfy/ops.py call:
QuantizedTensor.from_float(weight, "TensorWiseINT8Layout", scale="recalculate", ...)
without passing convrot / per_channel / convrot_groupsize, so TensorWiseINT8Layout.quantize defaults them to False/False/256 and a convrot + per-channel weight comes back as plain tensorwise INT8 (rotation gone, per-row scales collapsed to a scalar).
set_weight - resident LoRA path. Main "with LoRA -> degraded."
resolve_cast_module_with_vbar / post_cast - dynamic-VRAM re-quant (update_weight/want_requant); its orig.copy_(y) then broadcasts the scalar scale and flips convrot=False on the cached weight. Explains the no-LoRA "sometimes degraded" case.
Fix: inherit the original _params instead of defaulting. At both sites the original QuantizedTensor is in scope (self.weight / orig):
p = self.weight._params # or orig._params in post_cast
QuantizedTensor.from_float(
weight, self.layout_type,
per_channel=(p.scale.numel() > 1),
convrot=getattr(p, "convrot", False),
convrot_groupsize=getattr(p, "convrot_groupsize", 256),
)
Cleaner still: a from_float/quantize path that recalculates only the scale and reuses the existing Params. And consider not round-tripping back to INT8 after a LoRA delta at all - the offloaded weight_function branch already keeps those layers in bf16.
Attached __init__.py is a monkey-patch that re-injects the params at both sites; restores quality, self-test shows ~6x lower re-quant error.
Env: ComfyUI @ 7cb784e, comfy-kitchen 0.2.12, torch 2.11.0+cu130.
Steps to Reproduce
Load a Ideogram 4 with any INT8 quant using the default (new) Comfy Load Diffusion Model node, and any LoRA with the normal Comfy Lora Loader node. Generate an image 512x512 (with enough VRAM) and it should look fine. Generate at 2048x2048 and it will break. Switch to a non-INT8 model in both cases, and the 512x512 will match the INT8 image, but the 2048x2048 will be similar in composition but with dramatically improved image quality.
Debug Logs
Other
init.py Monkey Patch written by Claude.
Custom Node Testing
Expected Behavior
INT8 model + LoRA should produce the same quality regardless of --disable-dynamic-vram or whether layers offload - matching the clean output you get from an INT8 model with no LoRA.
What actually happens ("my journey", lol): INT8 model + LoRA + --disable-dynamic-vram = broken (low image quality in Ideogram4 with a normal LoRA loaded on both conditioned and unconditioned models). Removed the flag and it worked sometimes. INT8 model with no LoRA seems to work always. Tracing it, the degradation tracks with weights getting offloaded/re-quantized (the LoRA path), not the LoRA math itself.
I had GLM 5.2 take a crack at fixing it, but it couldn't. Then had Claude dig in, which found the re-quant calls drop the convrot/per_channel params (details below) and wrote a monkey-patch that avoids touching core code (also below, as an ugly init.py file). That restores quality and Opus claims its self-test shows ~6x lower re-quant error.
Actual Behavior
INT8
*_convrot_simplemodels degrade with LoRA because the re-quant calls drop the layout params.Both sites in
comfy/ops.pycall:without passing
convrot/per_channel/convrot_groupsize, soTensorWiseINT8Layout.quantizedefaults them toFalse/False/256and aconvrot + per-channelweight comes back as plain tensorwise INT8 (rotation gone, per-row scales collapsed to a scalar).set_weight- resident LoRA path. Main "with LoRA -> degraded."resolve_cast_module_with_vbar/post_cast- dynamic-VRAM re-quant (update_weight/want_requant); itsorig.copy_(y)then broadcasts the scalar scale and flipsconvrot=Falseon the cached weight. Explains the no-LoRA "sometimes degraded" case.Fix: inherit the original
_paramsinstead of defaulting. At both sites the originalQuantizedTensoris in scope (self.weight/orig):Cleaner still: a
from_float/quantizepath that recalculates only the scale and reuses the existingParams. And consider not round-tripping back to INT8 after a LoRA delta at all - the offloadedweight_functionbranch already keeps those layers in bf16.Attached
__init__.pyis a monkey-patch that re-injects the params at both sites; restores quality, self-test shows ~6x lower re-quant error.Env: ComfyUI @ 7cb784e, comfy-kitchen 0.2.12, torch 2.11.0+cu130.
Steps to Reproduce
Load a Ideogram 4 with any INT8 quant using the default (new) Comfy Load Diffusion Model node, and any LoRA with the normal Comfy Lora Loader node. Generate an image 512x512 (with enough VRAM) and it should look fine. Generate at 2048x2048 and it will break. Switch to a non-INT8 model in both cases, and the 512x512 will match the INT8 image, but the 2048x2048 will be similar in composition but with dramatically improved image quality.
Debug Logs
N/AOther
init.py Monkey Patch written by Claude.