Files
Yo1up-Diffusion-Model-Detailer/Detail_Model_Patch_Custom.py
T
Cody Schultz b1ac358ddc Update Detail_Model_Patch_Custom.py for ComfyUI model patcher code
re-wrote codebase to utilize ComfyUIs model patcher functions so it is easier to use and more robust. this change also makes it so positive values add detail and negative values remove detail.
2025-08-02 19:37:11 -04:00

109 lines
4.3 KiB
Python

import torch
import torch.nn.functional as F
import comfy.model_patcher
import comfy.samplers
import math
class Detailer:
"""
A ComfyUI node that uses the `set_model_unet_function_wrapper` hook to precisely modify
the raw noise prediction output from the UNet model. This allows for fine-grained
control over detail before or during the CFG calculation.
- A positive `scaling_factor` amplifies details by increasing the residual noise in the output.
- A negative `scaling_factor` smoothens details by dampening the residual noise in the output.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"model": ("MODEL",),
"scaling_factor": ("FLOAT", {
"default": 0.05,
"min": -1.0,
"max": 1.0,
"step": 0.005,
"display": "slider",
"tooltip": "Positive values increase detail, negative values reduce detail."
}),
"scaling_narrowness": ("FLOAT", {
"default": 1.0,
"min": 0.1,
"max": 10.0,
"step": 0.1,
"display": "slider",
"tooltip": "Controls the focus of the scaling effect within the sampling process (higher = narrower peak)."
}),
}
}
RETURN_TYPES = ("MODEL",)
FUNCTION = "patch"
CATEGORY = "model_patches/details" # This defines where it appears in the ComfyUI menu
def patch(self, model, scaling_factor, scaling_narrowness):
"""
Applies a patch to the model's UNet function to modify noise predictions
based on a sine wave schedule and a scaling factor.
"""
# we scale the user input to make it an acceptable sigma modification so the user doesn't have to work with very small numbers'
actual_scaling_factor = scaling_factor * 0.05
def sin_schedule_for_unet(timestep_tensor, current_sigmas):
"""
Calculates a scaling multiplier based on the current timestep (noise level).
This function creates a sine wave curve across the sampling steps,
allowing the effect to be strongest in the middle of the process.
"""
# ComfyUI's `model.apply_model`
# typically passes the current 'sigma' value as the 't' (timestep_tensor) argument.
boolean_mask = (timestep_tensor.item() == current_sigmas)
steps = len(current_sigmas) - 1
step = torch.argwhere(boolean_mask)
current_sigmas = timestep_tensor
normalized_progress = step / steps
# Clamp the normalized sigma to ensure it stays within [0, 1] just in case my code is too jank
normalized_progress_clamped = torch.clamp(normalized_progress, 0.0, 1.0)
# Apply the sine wave schedule. The `scaling_narrowness`
# controls the sharpness of the peak of the sine wave.
return torch.sin(normalized_progress_clamped * math.pi) ** scaling_narrowness
def apply_detailer(apply_model, args):
input_x = args["input"]
timestep = args["timestep"]
cond_or_uncond = args["cond_or_uncond"]
c = args["c"]
mod_strength = sin_schedule_for_unet(timestep[0], c["transformer_options"]["sample_sigmas"])
timestep[0] = torch.mul(timestep[0], (1 + (mod_strength * actual_scaling_factor)))
noise_pred = apply_model(input_x, timestep, **c)
return noise_pred
# Clone the model to ensure that this patch only affects the current branch
# of the ComfyUI workflow and does not modify the original model in place. idk if this is really necessary but I don't think it can hurt.
model_clone = model.clone()
# Apply the custom `apply_detailer` method using ComfyUI's patching mechanism.
# This hooks into the model's internal UNet forward pass.
model_clone.set_model_unet_function_wrapper(apply_detailer)
return (model_clone,)
# Node registration for ComfyUI.
# These dictionaries tell ComfyUI how to display and interact with your custom node.
NODE_CLASS_MAPPINGS = {
"Detailer": Detailer,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Detailer": "Detailer (UNet Patch)",
}