Skip to content

Commit

Permalink
Update SMEA Dy CFG++ samplers
Browse files Browse the repository at this point in the history
  • Loading branch information
pamparamm committed Aug 14, 2024
1 parent 7bed3fa commit 96d887d
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 25 deletions.
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ComfyUI-ppm
Just a bunch of random nodes modified/fixed/created by me or others. If any node starts throwing errors after an update - try re-adding it.
Just a bunch of random nodes modified/fixed/created by me or others. If any node starts throwing errors after an update - try to delete and re-add the node.

I'll add some example workflows soon.
I'll probably add some example workflows in the future (but I'm kinda lazy, kek).

# Nodes

Expand All @@ -11,22 +11,25 @@ Modified implementation of NegPiP by [laksjdjf](https://github.com/laksjdjf) and

`CLIPNegPip` node allows you to use negative weights in prompts. You should connect CLIPNegPip before other model/clip patches. After that, you can enter negative weights in your prompts (CTRL + arrows hotkey is capped at 0.0, will probably fix that soon).

You can read more about NegPiP [in the original repo](https://github.com/hako-mikan/sd-webui-negpip). I recommend putting everything from negative prompt to positive with a negative weight of something like -1.1 or -1.3. It's also better to keep all commas inside weight braces (i.e. `(worst quality,:-1.3) (sketch:-1.1,)` instead of `(worst quality:-1.3), (sketch:-1.1),`).
Read more about NegPiP [in the original repo](https://github.com/hako-mikan/sd-webui-negpip). I recommend putting everything from negative prompt to positive with a negative weight of something like -1.1 or -1.3. It's also better to keep all commas inside weight braces (i.e. `(worst quality,:-1.3) (sketch:-1.1,)` instead of `(worst quality:-1.3), (sketch:-1.1),`).

## AttentionCouplePPM
Modified implementation of AttentionCouple by [laksjdjf](https://github.com/laksjdjf) and [Haoming02](https://github.com/Haoming02). I made `AttentionCouplePPM` node compatible with `CLIPNegPiP` node and with default `PatchModelAddDownscale (Kohya Deep Shrink)` node. You can add/remove regions by right-clicking the node and selecting `Add Region`/`Remove Region`.

You can use multiple `LatentToMaskBB` nodes to set bounding box masks for `AttentionCouplePPM`. The parameters are relative to your initial latent: `x=0.5, y=0.0, w=0.5, h=1.0` will produce a mask covering right half of your image.
Use multiple `LatentToMaskBB` nodes to set bounding box masks for `AttentionCouplePPM`. The parameters are relative to your initial latent: `x=0.5, y=0.0, w=0.5, h=1.0` will produce a mask covering right half of your image.

## CFG++SamplerSelect
Samplers adapted to [CFG++: Manifold-constrained Classifier Free Guidance for Diffusion Models by Chung et al.](https://cfgpp-diffusion.github.io/)
Samplers adapted to [CFG++: Manifold-constrained Classifier Free Guidance for Diffusion Models by Chung et al.](https://cfgpp-diffusion.github.io/).
Includes some samplers from [Euler-Smea-Dyn-Sampler by Koishi-Star](https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler).

Should greatly reduce overexposure effect. Use together with `SamplerCustom` node. Don't forget to set CFG scale to 1.0-2.0 and PAG scale (if used) to 0.5-1.0.
Should greatly reduce overexposure effect. Use together with `SamplerCustom` node. Don't forget to set CFG scale to 1.0-2.0 and PAG/SEG scale (if used) to 0.5-1.0.

Tweak `s_dy_pow` parameter while using `*_dy_*` samplers to reduce blur artifacts (value `-1` disables this feature).

## Guidance Limiter
Implementation of [Applying Guidance in a Limited Interval Improves Sample and Distribution Quality in Diffusion Models by Kynkäänniemi et al.](https://arxiv.org/abs/2404.07724) (also contains `RescaleCFG` functionality)

Guidance Limiter is also available in a format of guider node `CFGLimiterGuider` for `SamplerCustomAdvanced`.
Guidance Limiter is also available as a `CFGLimiterGuider` guider node for `SamplerCustomAdvanced`.

## Empty Latent Image (Aspect Ratio)
`Empty Latent Image (Aspect Ratio)` node generates empty latent with specified aspect ratio and with respect to target resolution.
Expand Down
13 changes: 9 additions & 4 deletions ppm_cfgpp_dyn_sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from comfy.k_diffusion import sampling
import comfy.model_patcher

CFGPP_SAMPLER_NAMES_DYN = ["euler_dy_cfg_pp", "euler_smea_dy_cfg_pp"]
CFGPP_SAMPLER_NAMES_DYN_ETA = []


class _Rescaler:
def __init__(self, model, x, mode, **extra_args):
Expand Down Expand Up @@ -81,7 +84,7 @@ def post_cfg_function(args):

@torch.no_grad()
def sample_euler_dy_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0.,
s_tmax=float('inf'), s_noise=1., s_gamma=None):
s_tmax=float('inf'), s_noise=1., s_dy_pow=-1):
extra_args = {} if extra_args is None else extra_args
s_in = x.new_ones([x.shape[0]])

Expand All @@ -95,8 +98,8 @@ def post_cfg_function(args):

for i in trange(len(sigmas) - 1, disable=disable):
gamma = max(s_churn / (len(sigmas) - 1), 2 ** 0.5 - 1) if s_tmin <= sigmas[i] <= s_tmax else 0.
if s_gamma is not None:
gamma = s_gamma
if s_dy_pow >= 0:
gamma = gamma * (1.0 - (i / (len(sigmas) - 2))**s_dy_pow)
sigma_hat = sigmas[i] * (gamma + 1)
# print(sigma_hat)
dt = sigmas[i + 1] - sigma_hat
Expand Down Expand Up @@ -137,7 +140,7 @@ def post_cfg_function(args):

@torch.no_grad()
def sample_euler_smea_dy_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0.,
s_tmax=float('inf'), s_noise=1.):
s_tmax=float('inf'), s_noise=1., s_dy_pow=-1):
extra_args = {} if extra_args is None else extra_args
s_in = x.new_ones([x.shape[0]])

Expand All @@ -151,6 +154,8 @@ def post_cfg_function(args):

for i in trange(len(sigmas) - 1, disable=disable):
gamma = max(s_churn / (len(sigmas) - 1), 2 ** 0.5 - 1) if s_tmin <= sigmas[i] <= s_tmax else 0.
if s_dy_pow >= 0:
gamma = gamma * (1.0 - (i / (len(sigmas) - 2))**s_dy_pow)
sigma_hat = sigmas[i] * (gamma + 1)
dt = sigmas[i + 1] - sigma_hat
if gamma > 0:
Expand Down
15 changes: 15 additions & 0 deletions ppm_cfgpp_sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@
import comfy.model_patcher
from comfy.k_diffusion.sampling import BrownianTreeNoiseSampler

CFGPP_SAMPLER_NAMES_KD = [
"dpmpp_2m_cfg_pp",
"dpmpp_2m_sde_cfg_pp",
"dpmpp_2m_sde_gpu_cfg_pp",
"dpmpp_3m_sde_cfg_pp",
"dpmpp_3m_sde_gpu_cfg_pp",
]

CFGPP_SAMPLER_NAMES_KD_ETA = [
"dpmpp_2m_sde_cfg_pp",
"dpmpp_2m_sde_gpu_cfg_pp",
"dpmpp_3m_sde_cfg_pp",
"dpmpp_3m_sde_gpu_cfg_pp",
]


@torch.no_grad()
def sample_dpmpp_2m_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "comfyui-ppm"
description = "Fixed AttentionCouple/NegPip(negative weights in prompts), more CFG++ samplers, etc."
version = "1.0.6"
version = "1.0.7"
license = { text = "GNU Affero General Public License v3" }

[project.urls]
Expand Down
36 changes: 23 additions & 13 deletions samplers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@

INITIALIZED = False
CFGPP_SAMPLER_NAMES_ORIGINAL = ["euler_cfg_pp", "euler_ancestral_cfg_pp"]
CFGPP_SAMPLER_NAMES_DYN = ["euler_dy_cfg_pp", "euler_smea_dy_cfg_pp"]
CFGPP_SAMPLER_NAMES = CFGPP_SAMPLER_NAMES_ORIGINAL + [
"dpmpp_2m_cfg_pp",
"dpmpp_2m_sde_cfg_pp",
"dpmpp_2m_sde_gpu_cfg_pp",
"dpmpp_3m_sde_cfg_pp",
"dpmpp_3m_sde_gpu_cfg_pp",
] + CFGPP_SAMPLER_NAMES_DYN
CFGPP_SAMPLER_NAMES_ORIGINAL_ETA = ["euler_ancestral_cfg_pp"]


CFGPP_SAMPLER_NAMES = [
*CFGPP_SAMPLER_NAMES_ORIGINAL,
*ppm_cfgpp_sampling.CFGPP_SAMPLER_NAMES_KD,
*ppm_cfgpp_dyn_sampling.CFGPP_SAMPLER_NAMES_DYN,
]
CFGPP_SAMPLER_NAMES_ETA = [
*CFGPP_SAMPLER_NAMES_ORIGINAL_ETA,
*ppm_cfgpp_sampling.CFGPP_SAMPLER_NAMES_KD_ETA,
*ppm_cfgpp_dyn_sampling.CFGPP_SAMPLER_NAMES_DYN_ETA,
]


def inject_samplers():
Expand All @@ -29,6 +34,7 @@ def INPUT_TYPES(s):
"required": {
"sampler_name": (CFGPP_SAMPLER_NAMES,),
"eta": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": False}),
"s_dy_pow": ("INT", {"default": -1, "min": -1, "max": 100}),
}
}

Expand All @@ -37,13 +43,17 @@ def INPUT_TYPES(s):

FUNCTION = "get_sampler"

def get_sampler(self, sampler_name, eta: float):
def get_sampler(self, sampler_name, eta: float, s_dy_pow: int):
if sampler_name in CFGPP_SAMPLER_NAMES_ORIGINAL:
sampler_func = getattr(k_diffusion_sampling, "sample_{}".format(sampler_name))
elif sampler_name in CFGPP_SAMPLER_NAMES_DYN:
sampler_func = getattr(ppm_cfgpp_dyn_sampling, "sample_{}".format(sampler_name))
else:
elif sampler_name in ppm_cfgpp_sampling.CFGPP_SAMPLER_NAMES_KD:
sampler_func = getattr(ppm_cfgpp_sampling, "sample_{}".format(sampler_name))
extra_options = {} if sampler_name in {"euler_cfg_pp", "dpmpp_2m_cfg_pp", "euler_dy_cfg_pp", "euler_smea_dy_cfg_pp"} else {"eta": eta}
elif sampler_name in ppm_cfgpp_dyn_sampling.CFGPP_SAMPLER_NAMES_DYN:
sampler_func = getattr(ppm_cfgpp_dyn_sampling, "sample_{}".format(sampler_name))
extra_options = {}
if sampler_name in CFGPP_SAMPLER_NAMES_ETA:
extra_options["eta"] = eta
if sampler_name in ppm_cfgpp_dyn_sampling.CFGPP_SAMPLER_NAMES_DYN:
extra_options["s_dy_pow"] = s_dy_pow
sampler = KSAMPLER(sampler_func, extra_options=extra_options)
return (sampler,)

0 comments on commit 96d887d

Please sign in to comment.