Skip to content

INT8 weights get re-quantized as plain tensorwise on LoRA offload (convrot, per-channel params dropped) #14642

Closed

Description

@JLuke73

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

N/A

Other

init.py Monkey Patch written by Claude.

Activity

  1. coderabbitai commented on Jun 26, 2026

    @coderabbitai
    🔗 Related PRs

    #14298 - feat: Support text generation with Qwen3-VL (CORE-276) [merged]
    #14636 - Support int8 models. [merged]


    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. comfyanonymous commented on Jun 26, 2026

    @comfyanonymous
    Member
  3. JLuke73 commented on Jun 27, 2026

    @JLuke73
    Author

    Good fix. Thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Potential BugUser is reporting a bug. This should be tested.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions