152 lines
6.0 KiB
Markdown
152 lines
6.0 KiB
Markdown
# ComfyUI-ScaleLockedResidualDiffusion
|
|
|
|
A custom ComfyUI node pack implementing a practical MVP of Scale-Locked Residual Diffusion for the specific failure mode where a model behaves well around its native / comfortable resolution (for example ~1 MP) but drifts badly in composition, anatomy, or identity at much higher resolutions.
|
|
|
|
## What it does
|
|
|
|
Instead of letting the high-resolution branch freely re-plan the image, the node:
|
|
|
|
1. creates a low-resolution planner pass at a target megapixel level,
|
|
2. records the planner's per-step denoised x0 trajectory,
|
|
3. builds nested high-resolution noise so the high-res branch shares the same coarse stochastic layout,
|
|
4. runs the final high-res sampling with a custom CFG guider that locks only the low-frequency denoised structure toward the planner trajectory while preserving the base model's high-frequency residual detail.
|
|
|
|
In practice, this is meant to reduce:
|
|
|
|
- composition drift,
|
|
- anatomy drift,
|
|
- duplicate limbs / body parts,
|
|
- scene re-planning between 1 MP and 4 MP,
|
|
- the "looks like a different sample entirely" problem.
|
|
|
|
## Nodes
|
|
|
|
### 1. Scale-Locked Residual KSampler
|
|
|
|
Main all-in-one node.
|
|
|
|
**Outputs**
|
|
- `output`: final high-res latent
|
|
- `lowres_planner`: final low-res planner latent
|
|
- `denoised_output`: final high-res denoised x0 latent when available
|
|
|
|
**Important controls**
|
|
- `target_megapixels`: planner resolution in pixel-space megapixels (usually `0.8` to `1.5` for Flux-like native planning)
|
|
- `lock_strength`: global multiplier for the scale lock
|
|
- `lock_strength_start` / `lock_strength_end`: how strongly the lock applies early vs late in denoising
|
|
- `lock_schedule`: linear / cosine / flat interpolation for the lock schedule
|
|
- `coarse_cutoff`: retained spatial fraction for the strongest coarse lock band
|
|
- `mid_band_cutoff`: retained spatial fraction for an additional mid-frequency lock band
|
|
- `mid_band_strength`: how strongly the mid-band is pulled toward the planner relative to the low-band schedule
|
|
- `nested_noise_strength`: amount of zero-mean high-frequency detail noise added on top of the lifted low-res noise
|
|
- `lock_mask` (optional): spatial mask to strengthen the lock only in selected regions (for example body / face / hands)
|
|
- `pin_anchors`: store planner anchors in pinned CPU memory when possible for faster non-blocking transfer during the high-res pass
|
|
- `sampler_guard`: `warn` / `error` / `off` guard for samplers outside a conservative alignment-safe allowlist
|
|
|
|
### 2. Scale-Locked Nested Noise Preview
|
|
|
|
Utility/debug node to inspect the nested-noise construction separately.
|
|
|
|
## Installation
|
|
|
|
Clone or copy this directory into your ComfyUI `custom_nodes` folder:
|
|
|
|
```bash
|
|
git clone <this-repo> ComfyUI/custom_nodes/ComfyUI-ScaleLockedResidualDiffusion
|
|
```
|
|
|
|
Then restart ComfyUI.
|
|
|
|
No extra Python dependencies are required beyond ComfyUI + PyTorch.
|
|
|
|
## Suggested first settings for Flux.2 Klein 9B style use
|
|
|
|
For a first test when your high-res target is around 4 MP:
|
|
|
|
- `target_megapixels = 1.0`
|
|
- `lock_strength = 0.85`
|
|
- `lock_strength_start = 0.95`
|
|
- `lock_strength_end = 0.25`
|
|
- `lock_schedule = cosine`
|
|
- `coarse_cutoff = 0.33`
|
|
- `mid_band_cutoff = 0.60`
|
|
- `mid_band_strength = 0.35`
|
|
- `sampler_guard = warn`
|
|
- `nested_noise_strength = 0.35`
|
|
|
|
If the result still drifts too much:
|
|
- raise `lock_strength` toward `0.95`
|
|
- lower `coarse_cutoff` toward `0.25`
|
|
- use a `lock_mask` over body / face / hands
|
|
|
|
If the result feels too constrained / too similar to the low-res planner:
|
|
- lower `mid_band_strength`
|
|
- raise `mid_band_cutoff`
|
|
- lower `lock_strength`
|
|
- raise `coarse_cutoff`
|
|
- lower `lock_strength_end`
|
|
|
|
## Recommended workflow pattern
|
|
|
|
Use this node exactly where you would normally use a KSampler for the high-resolution generation pass.
|
|
|
|
Typical graph:
|
|
|
|
1. checkpoint / text encodes
|
|
2. empty latent or incoming img2img latent at your final target resolution
|
|
3. Scale-Locked Residual KSampler
|
|
4. VAE decode / detailers / final upscaling if desired
|
|
|
|
The node internally creates the planner pass for you, so you do not need to build a separate 1 MP sampler branch unless you want to compare outputs.
|
|
|
|
## Current limitations
|
|
|
|
This is a carefully implemented MVP, not a mathematically complete research system.
|
|
|
|
What is already implemented:
|
|
- low-res planner trajectory capture,
|
|
- nested-noise initialization,
|
|
- denoised-space low-frequency locking,
|
|
- denoised-space mid-frequency locking,
|
|
- residual-preserving coarse-field replacement,
|
|
- optional pinned-memory anchor staging,
|
|
- conservative sampler-alignment safety gating,
|
|
- optional spatial masking.
|
|
|
|
What is not implemented yet:
|
|
- automatic anatomy / pose / segmentation mask extraction,
|
|
- explicit residual-only tiled model execution,
|
|
- sigma-perfect trajectory matching for samplers that perform unusual extra model evaluations,
|
|
- multi-stage 1 MP -> 2 MP -> 4 MP progressive ladder inside one node,
|
|
- exact support tuning for every possible exotic custom sampler.
|
|
|
|
## Why this implementation is conservative
|
|
|
|
This node avoids invasive patching of ComfyUI's internal sampler code. Instead it uses:
|
|
|
|
- the standard Comfy custom-node registration path,
|
|
- the standard custom-sampling guider path,
|
|
- standard sigma generation,
|
|
- standard sampler objects,
|
|
- standard preview callback behavior.
|
|
|
|
That makes it much easier to maintain and much less likely to break when ComfyUI internals shift.
|
|
|
|
## Files
|
|
|
|
- `__init__.py` - node registration
|
|
- `nodes.py` - ComfyUI node definitions and runtime integration
|
|
- `slrd_core.py` - algorithm core, nested noise, latent resizing, residual locking, trajectory helpers
|
|
|
|
## Sampler safety note
|
|
|
|
The current implementation aligns planner anchors to the final pass using outer-step / sigma progression heuristics.
|
|
That works best with a conservative subset of samplers whose effective evaluation pattern is close to one visible step <-> one anchor step.
|
|
|
|
Because Comfy's custom sampling system is flexible and some samplers can perform more complicated internal evaluations,
|
|
the node exposes `sampler_guard`:
|
|
|
|
- `warn`: log a warning for samplers outside the conservative safe set
|
|
- `error`: refuse to run those samplers
|
|
- `off`: trust the sampler and run anyway
|