Author SHA1 Message Date
asagi4 bfbc69093c Publish v0.1.0 2024-06-20 20:12:00 +03:00
asagi4 34b032c5de Merge pull request #2 from ComfyNodePRs/publish
Add Github Action for Publishing to Comfy Registry
2024-06-20 20:09:39 +03:00
asagi4 6e854add68 Fix branch in publish.yml 2024-06-20 20:09:20 +03:00
asagi4 eb6a678061 Merge pull request #1 from ComfyNodePRs/pyproject
Add pyproject.toml for Custom Node Registry
2024-06-20 20:08:14 +03:00
asagi4 b9c8e7192b Adjust pyproject.toml 2024-06-20 20:07:57 +03:00
snomiao b876f3e66c chore(publish): Add Github Action for Publishing to Comfy Registry 2024-06-20 14:05:08 +00:00
snomiao d6407efcde chore(pyproject): Add pyproject.toml for Custom Node Registry 2024-06-20 14:05:08 +00:00
asagi4 b039274899 Add note 2024-06-20 16:59:04 +03:00
asagi4 67bdba646a Add uncond zero, it seems a bit better than just running without CFG 2024-06-20 00:12:28 +03:00
asagi4 6fa00b2335 Don't calculate cosine similarity if threshold >= 1.0
Very minor optimization.
Also refactor to keep interface compatible with CFGGuider
2024-04-21 14:46:08 +03:00
4 changed files with 82 additions and 20 deletions
+21
View File
@@ -0,0 +1,21 @@
name: Publish to Comfy registry
on:
workflow_dispatch:
push:
branches:
- master
paths:
- "pyproject.toml"
jobs:
publish-node:
name: Publish Custom Node to registry
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Publish Custom Node
uses: Comfy-Org/publish-node-action@main
with:
## Add your own personal access token to your Github Repository secrets and reference it here.
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
+8
View File
@@ -11,3 +11,11 @@ There's an `AdaptiveGuidance` node (under `sampling/custom_sampling/guiders`) th
The node calculates the cosine similarity between the u-net's conditional and unconditional output ("positive" and "negative" prompts) and once the similarity crosses the specified threshold, it sets CFG to 1.0, effectively skipping negative prompt calculations and speeding up inference.
I'm not sure if the cosine similarity calculation matches the original paper since I had to translate from maths to Python, but it appears to work.
### Uncond zero
Set uncond_zero_scale to > 0 to enable "uncond zero" CFG *after* the normal CFG gets disabled. Stolen from https://github.com/Extraltodeus/Uncond-Zero-for-ComfyUI
It seems to work slightly better than just running without CFG, but YMMV
Note: this functionality is unstable and will probably change, so using it means your workflows likely won't be perfectly reproducible.
+39 -20
View File
@@ -6,40 +6,56 @@ cos = torch.nn.CosineSimilarity(dim=1)
class AdaptiveGuider(comfy.samplers.CFGGuider):
threshold_timestep = 0
uz_scale = 0.0
def set_cfg(self, cfg, threshold):
def set_cfg(self, cfg):
self.cfg = cfg
def set_threshold(self, threshold):
self.threshold = threshold
def set_uncond_zero_scale(self, scale):
self.uz_scale = scale
def zero_cond(self, args):
cond = args["cond_denoised"]
x = args["input"]
x -= x.mean()
cond -= cond.mean()
return x - (cond / cond.std() ** 0.5) * self.uz_scale
def predict_noise(self, x, timestep, model_options={}, seed=None):
cond = self.conds.get("positive")
uncond = self.conds.get("negative")
ts = timestep[0].item()
if self.threshold_timestep > ts:
if self.uz_scale > 0.0:
model_options = model_options.copy()
model_options["sampler_cfg_function"] = self.zero_cond
return comfy.samplers.sampling_function(
self.inner_model, x, timestep, uncond, cond, 1.0, model_options=model_options, seed=seed
)
else:
self.threshold_timestep = 0
uncond_pred, cond_pred = comfy.samplers.calc_cond_batch(
self.inner_model, [uncond, cond], x, timestep, model_options
)
self.threshold_timestep = 0
uncond_pred, cond_pred = comfy.samplers.calc_cond_batch(
self.inner_model, [uncond, cond], x, timestep, model_options
)
if not self.threshold >= 1.0:
# Is this reshape correct? It at least gives a scalar value...
sim = cos(cond_pred.reshape(1, -1), uncond_pred.reshape(1, -1)).item()
if sim >= self.threshold:
print("AdaptiveGuidance: Cosine similarity", sim, "exceeds threshold, setting CFG to 1.0")
self.threshold_timestep = ts
return comfy.samplers.cfg_function(
self.inner_model,
cond_pred,
uncond_pred,
self.cfg,
x,
timestep,
model_options=model_options,
cond=cond,
uncond=uncond,
)
return comfy.samplers.cfg_function(
self.inner_model,
cond_pred,
uncond_pred,
self.cfg,
x,
timestep,
model_options=model_options,
cond=cond,
uncond=uncond,
)
class AdaptiveGuidance:
@@ -52,7 +68,8 @@ class AdaptiveGuidance:
"negative": ("CONDITIONING",),
"threshold": ("FLOAT", {"default": 0.990, "min": 0.90, "max": 1.0, "step": 0.001, "round": 0.001}),
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}),
}
},
"optional": {"uncond_zero_scale": ("FLOAT", {"default": 0.0, "max": 2.0, "step": 0.01})},
}
RETURN_TYPES = ("GUIDER",)
@@ -60,10 +77,12 @@ class AdaptiveGuidance:
CATEGORY = "sampling/custom_sampling/guiders"
def patch(self, model, positive, negative, threshold, cfg):
def patch(self, model, positive, negative, threshold, cfg, uncond_zero_scale=0.0):
g = AdaptiveGuider(model)
g.set_conds(positive, negative)
g.set_cfg(cfg, threshold)
g.set_threshold(threshold)
g.set_uncond_zero_scale(uncond_zero_scale)
g.set_cfg(cfg)
return (g,)
+14
View File
@@ -0,0 +1,14 @@
[project]
name = "comfyui-adaptive-guidance"
description = "An implementation of adaptive guidance for ComfyUI\nSee https://bcv-uniandes.github.io/adaptiveguidance-wp/"
version = "0.1.0"
license = "GPL-3.0"
[project.urls]
Repository = "https://github.com/asagi4/ComfyUI-Adaptive-Guidance"
# Used by Comfy Registry https://comfyregistry.org
[tool.comfy]
PublisherId = "asagi4"
DisplayName = "ComfyUI Adaptive Guidance"
Icon = ""