Compare commits
2
Commits
main
..
testing_wip
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e0c320949 | ||
|
|
64314b1726 |
@@ -15,76 +15,9 @@ All are to be used like any model patching node, right after the model loader.
|
||||
|
||||
# Nodes:
|
||||
|
||||
## Other nodes
|
||||
|
||||
There are now too many nodes for me to just add a screenshot and a bunch of details but it would be a shame not to describe them:
|
||||
|
||||
- Perturbed attention guidance: adaptation of PAG as a pre-CFG node.
|
||||
- Variable CFG: Make you scale vary along the generation
|
||||
- channel multipliers
|
||||
- subtract prediction mean: gives more balanced colors
|
||||
- "flip flop": swap the positive with the negative. Since the order matter, you may chain it with other nodes and go back to the correct order after. For experimental purposes.
|
||||
- Shape attention (for SDXL) can turn off the input layer 8.
|
||||
- Support empty uncond: Combined with "menu>advanced>conditioning>set timestep range" at ~65% you can now get a speed boost on any workflow.
|
||||
- Set timestep range from sigmas: same as the default node except that you're using sigmas instead of step percentage
|
||||
- [The testing branch](https://github.com/Extraltodeus/pre_cfg_comfy_nodes_for_ComfyUI/tree/testing_wip) has a few more and is the current state of these nodes for me.
|
||||
|
||||
|
||||
## Pre CFG automatic scale
|
||||
|
||||

|
||||
|
||||
### mode:
|
||||
- Automatic CFG: applies the same predictable scaling as my other nodes based on this logic
|
||||
- Strict scaling: applies a scaling which will always give the exact desired value. This tends to create artifacts and random blurs if carried through the end.
|
||||
|
||||
### Support empty uncond:
|
||||
|
||||
If you use the already available node named ConditioningSetTimestepRange you can stop generating a negative prediction earlier by letting your negative conditioning go through it while setting it like this:
|
||||
|
||||

|
||||
|
||||
This speeds up your generation speed by two for the steps where there is no negative.
|
||||
|
||||
The only issue if you do this is that the CFG function will weight your positive prediction times your CFG scale against nothing and you will get a black image.
|
||||
|
||||
"support_empty_uncond" therefore divides your positive prediction by your CFG scale and avoids this issue.
|
||||
|
||||
Doing this combination is similar to the "boost" feature of my original automatic CFG node. It can also let you avoid artifacts if you want to use the strict scaling.
|
||||
|
||||
If you want to use this option in a chained setup using this node multiple times I recommand to use it only once and on the last.
|
||||
|
||||
## Pre CFG perp-neg
|
||||
|
||||

|
||||
|
||||
Applies the already known [perp-neg logic](https://perp-neg.github.io/).
|
||||
|
||||
Code taken and adapted from ComfyAnon implementation.
|
||||
|
||||
The context length (added after the screenshot of the node) can be set to a higher value if you are using a tensor rt engine requiring a higher context length.
|
||||
|
||||
For more details you can check [my node related to this "Conditioning crop or fill"](https://github.com/Extraltodeus/Uncond-Zero-for-ComfyUI?tab=readme-ov-file#conditioning-crop-or-fill) where I explain a bit more about this.
|
||||
|
||||
## Pre CFG sharpening (experimental)
|
||||
|
||||

|
||||
|
||||
Subtract from the current step something from the previous step. This tends to make the images sharper and less saturated.
|
||||
|
||||
A negative value can be set.
|
||||
|
||||
## Pre CFG exponentiation (experimental)
|
||||
|
||||

|
||||
|
||||
A value lower than one will simplify the end result and enhance the saturation / contrasts.
|
||||
|
||||
A value higher than one will do the opposite and if pushed too far will most likely make a mess.
|
||||
|
||||
## Gradient scaling:
|
||||
|
||||
Named like this because I initially wanted to test what would happen if I used, instead of a single CFG scale, a tensor shaped like the latent space with a gradual variation. And then why not try to use masks instead? And what if I could make it so each value will match as closely as possible another input image?
|
||||
Named like this because I initially wanted to test what would happen if I used, instead of a single CFG scale, a tensor shaped like the latent space with a gradual variation. So, not the kind of gradient used for backpropagation. Then why not try to use masks instead? And what if I could make it so each value will participate so the image would match as close as possible to an input image?
|
||||
|
||||
The result is an arithmetic scaling method which does not noticeably slow down the sampling while also scaling the intensity of the values like an "automatic cfg".
|
||||
|
||||
@@ -146,3 +79,56 @@ Note:
|
||||
- Given that this is a non-ml solution, unlike controlnet, it can not tell the difference in between a banana and a person. It simply tries to make the values match the input image. A giraffe is just an apple with different values at a different place.
|
||||
- It is possible to chain multiple times this node for as long as the sum of all the strength sliders is equal or below one.
|
||||
- I added two image generators. One simply using RGB sliders and a gradient generator which can also make circular patterns while outputting a mask, to make vignetting easy. You will find them in the "image" category.
|
||||
|
||||
## Pre CFG automatic scale
|
||||
|
||||

|
||||
|
||||
### mode:
|
||||
- Automatic CFG: applies the same predictable scaling as my other nodes based on this logic
|
||||
- Strict scaling: applies a scaling which will always give the exact desired value. This tends to create artifacts and random blurs if carried through the end.
|
||||
|
||||
### Support empty uncond:
|
||||
|
||||
If you use the already available node named ConditioningSetTimestepRange you can stop generating a negative prediction earlier by letting your negative conditioning go through it while setting it like this:
|
||||
|
||||

|
||||
|
||||
This speeds up your generation speed by two for the steps where there is no negative.
|
||||
|
||||
The only issue if you do this is that the CFG function will weight your positive prediction times your CFG scale against nothing and you will get a black image.
|
||||
|
||||
"support_empty_uncond" therefore divides your positive prediction by your CFG scale and avoids this issue.
|
||||
|
||||
Doing this combination is similar to the "boost" feature of my original automatic CFG node. It can also let you avoid artifacts if you want to use the strict scaling.
|
||||
|
||||
If you want to use this option in a chained setup using this node multiple times I recommand to use it only once and on the last.
|
||||
|
||||
## Pre CFG perp-neg
|
||||
|
||||

|
||||
|
||||
Applies the already known [perp-neg logic](https://perp-neg.github.io/).
|
||||
|
||||
Code taken and adapted from ComfyAnon implementation.
|
||||
|
||||
The context length (added after the screenshot of the node) can be set to a higher value if you are using a tensor rt engine requiring a higher context length.
|
||||
|
||||
For more details you can check [my node related to this "Conditioning crop or fill"](https://github.com/Extraltodeus/Uncond-Zero-for-ComfyUI?tab=readme-ov-file#conditioning-crop-or-fill) where I explain a bit more about this.
|
||||
|
||||
## Pre CFG sharpening (experimental)
|
||||
|
||||

|
||||
|
||||
Subtract from the current step something from the previous step. This tends to make the images sharper and less saturated.
|
||||
|
||||
A negative value can be set.
|
||||
|
||||
## Pre CFG exponentiation (experimental)
|
||||
|
||||

|
||||
|
||||
A value lower than one will simplify the end result and enhance the saturation / contrasts.
|
||||
|
||||
A value higher than one will do the opposite and if pushed too far will most likely make a mess.
|
||||
|
||||
|
||||
+42
-3
@@ -2,41 +2,80 @@ from .nodes import *
|
||||
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
|
||||
# try:
|
||||
# from .skimmed_CFG import cond_skimming_pre_cfg_node
|
||||
# NODE_CLASS_MAPPINGS["Skimmed CFG"] = cond_skimming_pre_cfg_node
|
||||
# except:
|
||||
# pass
|
||||
|
||||
NODE_CLASS_MAPPINGS_ADD = {
|
||||
"Pre CFG automatic scale": automatic_pre_cfg,
|
||||
"Pre CFG uncond zero": uncondZeroPreCFGNode,
|
||||
"Pre CFG perp-neg": pre_cfg_perp_neg,
|
||||
# "Pre CFG re-negative": pre_cfg_re_negative,
|
||||
"Pre CFG re-negative": pre_cfg_re_negative,
|
||||
|
||||
"Pre CFG PAG": perturbed_attention_guidance_pre_cfg_node,
|
||||
"Pre CFG zero attention": zero_attention_pre_cfg_node,
|
||||
# "Pre CFG color control": latent_color_control_pre_cfg_node,
|
||||
"Pre CFG channel multiplier": channel_multiplier_node,
|
||||
"Pre CFG multiplier": multiply_cond_pre_cfg_node,
|
||||
"Pre CFG roll latent": PreCFGRollLatentNode,
|
||||
"Pre CFG mirror flip": PreCFGMirrorFlipLatentNode,
|
||||
|
||||
"Pre CFG clamp negative": clamp_sign_uncond_pre_cfg_node,
|
||||
"Pre CFG clamp negative to denoised relation": clamp_uncond_to_denoised_pre_cfg_node,
|
||||
|
||||
"Pre CFG clamp min max": minmax_clamp_pre_cfg_node,
|
||||
"Pre CFG lerp": lerp_conds_pre_cfg_node,
|
||||
|
||||
"Pre CFG norm neg to pos": norm_uncond_to_cond_pre_cfg_node,
|
||||
"Pre CFG subtract mean": PreCFGsubtractMeanNode,
|
||||
"Pre CFG variable scaling": variable_scale_pre_cfg_node,
|
||||
"Pre CFG gradient scaling": gradient_scaling_pre_cfg_node,
|
||||
|
||||
|
||||
"Pre CFG flip flop": flip_flip_conds_pre_cfg_node,
|
||||
"Pre CFG replace negative channel": replace_uncond_channel_pre_cfg_node,
|
||||
"Pre CFG merge negative channel": merge_uncond_channel_pre_cfg_node,
|
||||
"Pre CFG merge negative channel": merge_uncond_channel_pre_cfg_node,
|
||||
"Pre CFG timed CFG rescale": rescale_cfg_during_sigma_pre_cfg_node,
|
||||
|
||||
"Pre CFG sharpening": condDiffSharpeningNode,
|
||||
"Pre CFG sharpen/blur": condBlurSharpeningNode,
|
||||
|
||||
"Pre CFG exponentiation": condExpNode,
|
||||
"Pre CFG cond boost": boost_std_pre_cfg_node,
|
||||
"tHe dArK GuiDaNcE": dark_guidance_pre_cfg_node,
|
||||
|
||||
"Conditioning set timestep from sigma": ConditioningSetTimestepRangeFromSigma,
|
||||
"Support empty uncond": support_empty_uncond_pre_cfg_node,
|
||||
"Shape attention": ShapeAttentionNode,
|
||||
"Excellent attention": ExlAttentionNode,
|
||||
"Post CFG subtract mean": PostCFGsubtractMeanNode,
|
||||
# "Post CFG make a dot": PostCFGDotNode,
|
||||
"Individual channel selector": individual_channel_selection_node,
|
||||
"Subtract noise mean": latent_noise_subtract_mean_node,
|
||||
"Empty RGB image": EmptyRGBImage,
|
||||
"Gradient RGB image": GradientRGBImage,
|
||||
"colors test node": colors_test_node,
|
||||
"gradient batch mask": gradientNoisyLatentMaskBatch,
|
||||
"Load latent from path": load_latent_for_guidance,
|
||||
"Latent recombine by channels": latent_recombine_channels,
|
||||
}
|
||||
|
||||
NODE_CLASS_MAPPINGS.update(NODE_CLASS_MAPPINGS_ADD)
|
||||
|
||||
for c in [4,8,16,32,64,128]:
|
||||
NODE_CLASS_MAPPINGS[f"Channel selector for {c} channels"] = type("channel_selection_node", (channel_selection_node,), { "CHANNELS_AMOUNT": c})
|
||||
|
||||
try:
|
||||
from .tester_nodes import *
|
||||
NODE_CLASS_MAPPINGS["K-K-K-K-KOMBO BREAKER"] = combo_breaker
|
||||
NODE_CLASS_MAPPINGS["K-K-K-K-KOMBO BREAKER X2"] = combo_breaker_x2
|
||||
|
||||
NODE_CLASS_MAPPINGS["K-K-K-K-KOMBO BREAKER 6 bool"] = combo_breaker_6_bool
|
||||
NODE_CLASS_MAPPINGS["K-K-K-K-KOMBO BREAKER 4 bool"] = combo_breaker_4_bool
|
||||
|
||||
NODE_CLASS_MAPPINGS["CFG_TEST"] = cfg_test_node
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import torch
|
||||
|
||||
@torch.no_grad()
|
||||
def get_skimming_mask(x_orig, cond, uncond, cond_scale, return_denoised=False, disable_flipping_filter=False, release_inner_scaling=False):
|
||||
denoised = x_orig - ((x_orig - uncond) + cond_scale * ((x_orig - cond) - (x_orig - uncond)))
|
||||
matching_pred_signs = (cond - uncond).sign() == cond.sign()
|
||||
matching_diff_after = cond.sign() == (cond * cond_scale - uncond * (cond_scale - 1)).sign()
|
||||
if disable_flipping_filter:
|
||||
outer_influence = matching_pred_signs & matching_diff_after
|
||||
else:
|
||||
deviation_influence = (denoised.sign() == (denoised - x_orig).sign())
|
||||
outer_influence = matching_pred_signs & matching_diff_after & deviation_influence
|
||||
if return_denoised:
|
||||
return outer_influence, denoised
|
||||
else:
|
||||
return outer_influence
|
||||
|
||||
@torch.no_grad()
|
||||
def skimmed_CFG(x_orig, cond, uncond, cond_scale, skimming_scale, disable_flipping_filter=False):
|
||||
outer_influence, denoised = get_skimming_mask(x_orig, cond, uncond, cond_scale, return_denoised=True, disable_flipping_filter=disable_flipping_filter)
|
||||
low_cfg_denoised_outer = x_orig - ((x_orig - uncond) + skimming_scale * ((x_orig - cond) - (x_orig - uncond)))
|
||||
low_cfg_denoised_outer_difference = denoised - low_cfg_denoised_outer
|
||||
cond[outer_influence] = cond[outer_influence] - (low_cfg_denoised_outer_difference[outer_influence] / cond_scale)
|
||||
return cond
|
||||
|
||||
def skimmed_CFG_patch_wrap(model,Skimming_CFG=-1,end_proportion=1,full_skim_negative=True,disable_flipping_filter=False):
|
||||
@torch.no_grad()
|
||||
def skimmed_CFG_patch(args):
|
||||
conds_out = args["conds_out"]
|
||||
cond_scale = args["cond_scale"]
|
||||
x_orig = args['input']
|
||||
if not torch.any(conds_out[1]):
|
||||
return conds_out
|
||||
if end_proportion != 1:
|
||||
c0,c1=conds_out[0].clone(),conds_out[1].clone()
|
||||
practical_scale = cond_scale if Skimming_CFG < 0 else Skimming_CFG
|
||||
conds_out[1] = skimmed_CFG(x_orig, conds_out[1], conds_out[0], cond_scale, practical_scale if not full_skim_negative else 0, disable_flipping_filter)
|
||||
conds_out[0] = skimmed_CFG(x_orig, conds_out[0], conds_out[1], cond_scale, practical_scale, disable_flipping_filter)
|
||||
if end_proportion != 1:
|
||||
conds_out[0] = conds_out[0] * end_proportion + c0 * (1 - end_proportion)
|
||||
conds_out[1] = conds_out[1] * end_proportion + c1 * (1 - end_proportion)
|
||||
return conds_out
|
||||
m = model.clone()
|
||||
m.set_model_sampler_pre_cfg_function(skimmed_CFG_patch)
|
||||
return m,
|
||||
|
||||
# def skimmed_CFG_patch_wrap(model,Skimming_CFG=-1,end_proportion=1,full_skim_negative=False,disable_flipping_filter=False):
|
||||
# @torch.no_grad()
|
||||
# def skimmed_CFG_patch(args):
|
||||
# conds_out = args["conds_out"]
|
||||
# cond_scale = args["cond_scale"]
|
||||
# x_orig = args['input']
|
||||
# if not torch.any(conds_out[1]):
|
||||
# return conds_out
|
||||
# if end_proportion != 1:
|
||||
# c0,c1=conds_out[0].clone(),conds_out[1].clone()
|
||||
# practical_scale = cond_scale if Skimming_CFG < 0 else Skimming_CFG
|
||||
# conds_out[1] = skimmed_CFG(x_orig, conds_out[1], conds_out[0], cond_scale, practical_scale if not full_skim_negative else 0, disable_flipping_filter)
|
||||
# conds_out[0] = skimmed_CFG(x_orig, conds_out[0], conds_out[1], cond_scale, practical_scale, disable_flipping_filter)
|
||||
# if end_proportion != 1:
|
||||
# conds_out[0] = conds_out[0] * end_proportion + c0 * (1 - end_proportion)
|
||||
# conds_out[1] = conds_out[1] * end_proportion + c1 * (1 - end_proportion)
|
||||
# return conds_out
|
||||
# m = model.clone()
|
||||
# m.set_model_sampler_pre_cfg_function(skimmed_CFG_patch)
|
||||
# return m,
|
||||
Binary file not shown.
Reference in New Issue
Block a user