1.0
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
# KSampler DF (with Refiner)
|
||||
|
||||
A custom ComfyUI node that splits sampling steps between a main sampler and a refiner sampler, with independent denoise control for each phase.
|
||||
|
||||
## Features
|
||||
|
||||
- **Split Steps**: Divide total steps between main sampler and refiner sampler
|
||||
- **Dual Sampler Support**: Use different samplers/schedulers for main and refiner phases
|
||||
- **Independent Denoise Control**: Separate denoise parameters for main and refiner phases
|
||||
- **Refiner Intensity**: Control how much the refiner affects the final result (0.0 to 1.0)
|
||||
|
||||
## Installation
|
||||
|
||||
### Method 1: Git Clone (Recommended)
|
||||
|
||||
1. Open a terminal/command prompt
|
||||
2. Navigate to your ComfyUI custom nodes folder:
|
||||
```bash
|
||||
cd ComfyUI/custom_nodes
|
||||
```
|
||||
3. Clone this repository:
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USERNAME/ksamplerwithrefiner.git
|
||||
```
|
||||
4. Restart ComfyUI
|
||||
|
||||
### Method 2: Manual Installation
|
||||
|
||||
1. Download this repository as a ZIP file
|
||||
2. Extract the contents to `ComfyUI/custom_nodes/ksamplerwithrefiner/`
|
||||
3. Restart ComfyUI
|
||||
|
||||
## Usage
|
||||
|
||||
Find the node in the **Add Node** menu under: `sampling` → `KSampler DF (with Refiner)`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| **model** | The model used for denoising |
|
||||
| **positive** | Positive conditioning (prompt) |
|
||||
| **negative** | Negative conditioning (negative prompt) |
|
||||
| **latent_image** | The latent image to denoise |
|
||||
| **seed** | Random seed for noise generation |
|
||||
| **steps** | Total number of steps (split between main and refiner) |
|
||||
| **cfg** | Classifier-Free Guidance scale |
|
||||
| **sampler_name** | Sampler algorithm for the main phase |
|
||||
| **scheduler** | Scheduler for the main phase |
|
||||
| **denoise** | Denoise amount for the main phase (0.0 to 1.0) |
|
||||
| **refiner_at_step** | Step at which to switch from main to refiner |
|
||||
| **sampler_refiner** | Sampler algorithm for the refiner phase |
|
||||
| **scheduler_refiner** | Scheduler for the refiner phase |
|
||||
| **denoise_refiner** | Denoise amount for the refiner phase (0.0 to 1.0) |
|
||||
|
||||
### Example
|
||||
|
||||
With these settings:
|
||||
- **steps**: 20
|
||||
- **refiner_at_step**: 12
|
||||
|
||||
The node will:
|
||||
1. Run **12 steps** with the main sampler/scheduler
|
||||
2. Run **8 steps** with the refiner sampler/scheduler
|
||||
|
||||
### Refiner Denoise Control
|
||||
|
||||
The `denoise_refiner` parameter controls how much the refiner phase affects the image:
|
||||
|
||||
| Value | Effect |
|
||||
|-------|--------|
|
||||
| `0.0` | Refiner is skipped (only main sampler runs) |
|
||||
| `0.5` | Refiner applies 50% denoising |
|
||||
| `1.0` | Refiner applies full denoising |
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
ksamplerwithrefiner/
|
||||
├── __init__.py
|
||||
├── nodes.py
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- ComfyUI (latest version recommended)
|
||||
- No additional dependencies required
|
||||
|
||||
## License
|
||||
|
||||
MIT License - Feel free to use and modify as needed.
|
||||
@@ -0,0 +1,7 @@
|
||||
# KSampler with Refiner Custom Node for ComfyUI
|
||||
# Custom node that implements a KSampler with refiner functionality
|
||||
# Allows using different samplers for main and refiner phases
|
||||
|
||||
from .nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
@@ -0,0 +1,133 @@
|
||||
from __future__ import annotations
|
||||
import torch
|
||||
import comfy.samplers
|
||||
import comfy.sample
|
||||
import comfy.utils
|
||||
import comfy.model_management
|
||||
from comfy.comfy_types import IO, ComfyNodeABC, InputTypeDict
|
||||
|
||||
class KsamplerDF(ComfyNodeABC):
|
||||
"""
|
||||
Custom KSampler with Refiner functionality for ComfyUI.
|
||||
Splits steps between main sampler and refiner sampler.
|
||||
Example: 12 total steps with refiner at step 6 = 6 main + 6 refiner steps.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> InputTypeDict:
|
||||
return {
|
||||
"required": {
|
||||
"model": (IO.MODEL, {"tooltip": "The model used for denoising the input latent."}),
|
||||
"positive": (IO.CONDITIONING, {"tooltip": "The conditioning describing the attributes to include."}),
|
||||
"negative": (IO.CONDITIONING, {"tooltip": "The conditioning describing the attributes to exclude."}),
|
||||
"latent_image": (IO.LATENT, {"tooltip": "The latent image to denoise."}),
|
||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff, "control_after_generate": True, "tooltip": "The random seed used for creating the noise."}),
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000, "tooltip": "Total number of steps (main + refiner)."}),
|
||||
"cfg": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01, "tooltip": "The Classifier-Free Guidance scale."}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, {"default": "euler", "tooltip": "The algorithm used for the main sampling phase."}),
|
||||
"scheduler": (comfy.samplers.KSampler.SCHEDULERS, {"default": "normal", "tooltip": "The scheduler for the main sampling phase."}),
|
||||
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "tooltip": "Main denoise amount."}),
|
||||
"refiner_at_step": ("INT", {"default": 10, "min": 0, "max": 10000, "tooltip": "Step at which to switch to refiner sampler."}),
|
||||
"sampler_refiner": (comfy.samplers.KSampler.SAMPLERS, {"default": "euler", "tooltip": "The algorithm used for the refiner phase."}),
|
||||
"scheduler_refiner": (comfy.samplers.KSampler.SCHEDULERS, {"default": "normal", "tooltip": "The scheduler for the refiner phase."}),
|
||||
"denoise_refiner": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "tooltip": "Refiner denoise - controls how much the refiner interferes (0.0 = no effect, 1.0 = full effect)."}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = (IO.LATENT,)
|
||||
OUTPUT_TOOLTIPS = ("The denoised latent image.",)
|
||||
FUNCTION = "sample"
|
||||
CATEGORY = "sampling"
|
||||
DESCRIPTION = "KSampler with Refiner - Splits steps between main sampler and refiner sampler with independent denoise control."
|
||||
|
||||
def sample(self, model, positive, negative, latent_image, seed, steps, cfg,
|
||||
sampler_name, scheduler, denoise, refiner_at_step, sampler_refiner,
|
||||
scheduler_refiner, denoise_refiner):
|
||||
|
||||
import nodes
|
||||
|
||||
# Clamp refiner_at_step to valid range
|
||||
refiner_at_step = max(0, min(refiner_at_step, steps))
|
||||
|
||||
# Calculate steps for each phase
|
||||
main_steps = refiner_at_step
|
||||
refiner_steps = steps - refiner_at_step
|
||||
|
||||
current_latent = latent_image
|
||||
|
||||
# Phase 1: Main sampling (if main_steps > 0)
|
||||
if main_steps > 0:
|
||||
print(f"[KSampler DF] Main phase: {main_steps} steps with {sampler_name}/{scheduler}, denoise={denoise}")
|
||||
result = nodes.common_ksampler(
|
||||
model=model,
|
||||
seed=seed,
|
||||
steps=main_steps,
|
||||
cfg=cfg,
|
||||
sampler_name=sampler_name,
|
||||
scheduler=scheduler,
|
||||
positive=positive,
|
||||
negative=negative,
|
||||
latent=current_latent,
|
||||
denoise=denoise,
|
||||
disable_noise=False,
|
||||
start_step=None,
|
||||
last_step=None,
|
||||
force_full_denoise=False # Don't fully denoise, refiner continues
|
||||
)
|
||||
current_latent = result[0]
|
||||
|
||||
# Phase 2: Refiner sampling (if refiner_steps > 0 and denoise_refiner > 0)
|
||||
if refiner_steps > 0 and denoise_refiner > 0:
|
||||
print(f"[KSampler DF] Refiner phase: {refiner_steps} steps with {sampler_refiner}/{scheduler_refiner}, denoise={denoise_refiner}")
|
||||
result = nodes.common_ksampler(
|
||||
model=model,
|
||||
seed=seed,
|
||||
steps=refiner_steps,
|
||||
cfg=cfg,
|
||||
sampler_name=sampler_refiner,
|
||||
scheduler=scheduler_refiner,
|
||||
positive=positive,
|
||||
negative=negative,
|
||||
latent=current_latent,
|
||||
denoise=denoise_refiner,
|
||||
disable_noise=False,
|
||||
start_step=None,
|
||||
last_step=None,
|
||||
force_full_denoise=True # Final phase, full denoise
|
||||
)
|
||||
current_latent = result[0]
|
||||
elif main_steps > 0:
|
||||
# If no refiner, we need to do a final denoise on main result
|
||||
# Run one more step to finalize
|
||||
print(f"[KSampler DF] Finalizing without refiner...")
|
||||
result = nodes.common_ksampler(
|
||||
model=model,
|
||||
seed=seed,
|
||||
steps=1,
|
||||
cfg=cfg,
|
||||
sampler_name=sampler_name,
|
||||
scheduler=scheduler,
|
||||
positive=positive,
|
||||
negative=negative,
|
||||
latent=current_latent,
|
||||
denoise=0.0,
|
||||
disable_noise=True,
|
||||
start_step=None,
|
||||
last_step=None,
|
||||
force_full_denoise=True
|
||||
)
|
||||
current_latent = result[0]
|
||||
|
||||
print(f"[KSampler DF] Complete! Total: {steps} steps ({main_steps} main + {refiner_steps} refiner)")
|
||||
|
||||
return (current_latent,)
|
||||
|
||||
|
||||
# Register the node
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"KsamplerDF": KsamplerDF,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"KsamplerDF": "KSampler DF (with Refiner)",
|
||||
}
|
||||
Reference in New Issue
Block a user