Spaces:
Running
on
Zero
Running
on
Zero
flatcherlee
commited on
Commit
•
3d5837a
1
Parent(s):
932ae62
Upload 2334 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +30 -0
- ComfyUI/custom_nodes/ComfyMath/LICENSE +201 -0
- ComfyUI/custom_nodes/ComfyMath/README.md +19 -0
- ComfyUI/custom_nodes/ComfyMath/__init__.py +31 -0
- ComfyUI/custom_nodes/ComfyMath/__pycache__/__init__.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/pyproject.toml +19 -0
- ComfyUI/custom_nodes/ComfyMath/requirements.txt +1 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__init__.py +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/__init__.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/bool.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/control.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/convert.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/float.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/graphics.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/int.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/number.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/vec.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/bool.py +59 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/control.py +3 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/convert.py +273 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/float.py +159 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/graphics.py +77 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/int.py +129 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/number.py +95 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/py.typed +0 -0
- ComfyUI/custom_nodes/ComfyMath/src/comfymath/vec.py +501 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/README.md +175 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__init__.py +27 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__pycache__/__init__.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__pycache__/experimental_temperature.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__pycache__/nodes.cpython-310.pyc +0 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/experimental_temperature.py +208 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/Enhanced_details_and_tweaked_attention.png +3 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/Iris_Lux_v1051_base_image_vanilla_sampling.png +3 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_a.jpg +3 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_b.jpg +3 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/presets.jpg +3 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/nodes.py +1292 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/nodes_sag_custom.py +190 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/A subtle touch.json +1 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Crossed conds customized 1.json +1 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Crossed conds customized 2.json +1 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Crossed conds customized 3.json +1 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Enhanced_details_and_tweaked_attention +1 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Excellent_attention.json +1 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/For magic.json +1 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Kickstart.json +1 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Mute input layer 8 attn1 and attn2 for uncond.json +72 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Mute input layer 8 attn1 for uncond.json +1 -0
- ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Mute input layer 8 attn2 for uncond.json +1 -0
.gitattributes
CHANGED
@@ -33,3 +33,33 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
ComfyUI/custom_nodes/comfyui_controlnet_aux/examples/example_mesh_graphormer.png filter=lfs diff=lfs merge=lfs -text
|
37 |
+
ComfyUI/custom_nodes/comfyui_controlnet_aux/src/controlnet_aux/mesh_graphormer/hand_landmarker.task filter=lfs diff=lfs merge=lfs -text
|
38 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/Enhanced_details_and_tweaked_attention.png filter=lfs diff=lfs merge=lfs -text
|
39 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_a.jpg filter=lfs diff=lfs merge=lfs -text
|
40 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_b.jpg filter=lfs diff=lfs merge=lfs -text
|
41 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/Iris_Lux_v1051_base_image_vanilla_sampling.png filter=lfs diff=lfs merge=lfs -text
|
42 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/presets.jpg filter=lfs diff=lfs merge=lfs -text
|
43 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/10[[:space:]]steps[[:space:]]SDXL[[:space:]]AYS[[:space:]]Warp[[:space:]]drive[[:space:]]variation.png filter=lfs diff=lfs merge=lfs -text
|
44 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/11728UI_00001_.png filter=lfs diff=lfs merge=lfs -text
|
45 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/12[[:space:]]steps[[:space:]]SDXL[[:space:]]AYS[[:space:]]Warp[[:space:]]drive[[:space:]]workflow.png filter=lfs diff=lfs merge=lfs -text
|
46 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/12steps.png filter=lfs diff=lfs merge=lfs -text
|
47 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/24steps.png filter=lfs diff=lfs merge=lfs -text
|
48 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/attention_modifiers_explainations.png filter=lfs diff=lfs merge=lfs -text
|
49 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/00382UI_00001_.png filter=lfs diff=lfs merge=lfs -text
|
50 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/01207UI_00001_.png filter=lfs diff=lfs merge=lfs -text
|
51 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/01217UI_00001_.png filter=lfs diff=lfs merge=lfs -text
|
52 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/a[[:space:]]bad[[:space:]]upscale[[:space:]]looks[[:space:]]like[[:space:]]low[[:space:]]quality[[:space:]]jpeg.png filter=lfs diff=lfs merge=lfs -text
|
53 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/another[[:space:]]bad[[:space:]]upscale[[:space:]]looking[[:space:]]like[[:space:]]jpeg.png filter=lfs diff=lfs merge=lfs -text
|
54 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/intradasting.png filter=lfs diff=lfs merge=lfs -text
|
55 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/laule.png filter=lfs diff=lfs merge=lfs -text
|
56 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/niiiiiice.png filter=lfs diff=lfs merge=lfs -text
|
57 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/special[[:space:]]double[[:space:]]pass.png filter=lfs diff=lfs merge=lfs -text
|
58 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/I'm[[:space:]]just[[:space:]]throwing[[:space:]]a[[:space:]]few[[:space:]]here[[:space:]]that[[:space:]]I[[:space:]]find[[:space:]]nice/web.png filter=lfs diff=lfs merge=lfs -text
|
59 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/My[[:space:]]current[[:space:]]go-to[[:space:]]settings.png filter=lfs diff=lfs merge=lfs -text
|
60 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/potato[[:space:]]attention[[:space:]]guidance.png filter=lfs diff=lfs merge=lfs -text
|
61 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/simple[[:space:]]SD[[:space:]]upscale.png filter=lfs diff=lfs merge=lfs -text
|
62 |
+
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/workflows/Start_by_this_one.png filter=lfs diff=lfs merge=lfs -text
|
63 |
+
ComfyUI/custom_nodes/was-node-suite-comfyui/repos/SAM/assets/masks1.png filter=lfs diff=lfs merge=lfs -text
|
64 |
+
ComfyUI/custom_nodes/was-node-suite-comfyui/repos/SAM/assets/minidemo.gif filter=lfs diff=lfs merge=lfs -text
|
65 |
+
ComfyUI/custom_nodes/was-node-suite-comfyui/repos/SAM/assets/notebook2.png filter=lfs diff=lfs merge=lfs -text
|
ComfyUI/custom_nodes/ComfyMath/LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Apache License
|
2 |
+
Version 2.0, January 2004
|
3 |
+
http://www.apache.org/licenses/
|
4 |
+
|
5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6 |
+
|
7 |
+
1. Definitions.
|
8 |
+
|
9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
11 |
+
|
12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13 |
+
the copyright owner that is granting the License.
|
14 |
+
|
15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
16 |
+
other entities that control, are controlled by, or are under common
|
17 |
+
control with that entity. For the purposes of this definition,
|
18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
19 |
+
direction or management of such entity, whether by contract or
|
20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22 |
+
|
23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24 |
+
exercising permissions granted by this License.
|
25 |
+
|
26 |
+
"Source" form shall mean the preferred form for making modifications,
|
27 |
+
including but not limited to software source code, documentation
|
28 |
+
source, and configuration files.
|
29 |
+
|
30 |
+
"Object" form shall mean any form resulting from mechanical
|
31 |
+
transformation or translation of a Source form, including but
|
32 |
+
not limited to compiled object code, generated documentation,
|
33 |
+
and conversions to other media types.
|
34 |
+
|
35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
36 |
+
Object form, made available under the License, as indicated by a
|
37 |
+
copyright notice that is included in or attached to the work
|
38 |
+
(an example is provided in the Appendix below).
|
39 |
+
|
40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41 |
+
form, that is based on (or derived from) the Work and for which the
|
42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
44 |
+
of this License, Derivative Works shall not include works that remain
|
45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46 |
+
the Work and Derivative Works thereof.
|
47 |
+
|
48 |
+
"Contribution" shall mean any work of authorship, including
|
49 |
+
the original version of the Work and any modifications or additions
|
50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
54 |
+
means any form of electronic, verbal, or written communication sent
|
55 |
+
to the Licensor or its representatives, including but not limited to
|
56 |
+
communication on electronic mailing lists, source code control systems,
|
57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
59 |
+
excluding communication that is conspicuously marked or otherwise
|
60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
61 |
+
|
62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
64 |
+
subsequently incorporated within the Work.
|
65 |
+
|
66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
71 |
+
Work and such Derivative Works in Source or Object form.
|
72 |
+
|
73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76 |
+
(except as stated in this section) patent license to make, have made,
|
77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78 |
+
where such license applies only to those patent claims licensable
|
79 |
+
by such Contributor that are necessarily infringed by their
|
80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
82 |
+
institute patent litigation against any entity (including a
|
83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84 |
+
or a Contribution incorporated within the Work constitutes direct
|
85 |
+
or contributory patent infringement, then any patent licenses
|
86 |
+
granted to You under this License for that Work shall terminate
|
87 |
+
as of the date such litigation is filed.
|
88 |
+
|
89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
90 |
+
Work or Derivative Works thereof in any medium, with or without
|
91 |
+
modifications, and in Source or Object form, provided that You
|
92 |
+
meet the following conditions:
|
93 |
+
|
94 |
+
(a) You must give any other recipients of the Work or
|
95 |
+
Derivative Works a copy of this License; and
|
96 |
+
|
97 |
+
(b) You must cause any modified files to carry prominent notices
|
98 |
+
stating that You changed the files; and
|
99 |
+
|
100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
101 |
+
that You distribute, all copyright, patent, trademark, and
|
102 |
+
attribution notices from the Source form of the Work,
|
103 |
+
excluding those notices that do not pertain to any part of
|
104 |
+
the Derivative Works; and
|
105 |
+
|
106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107 |
+
distribution, then any Derivative Works that You distribute must
|
108 |
+
include a readable copy of the attribution notices contained
|
109 |
+
within such NOTICE file, excluding those notices that do not
|
110 |
+
pertain to any part of the Derivative Works, in at least one
|
111 |
+
of the following places: within a NOTICE text file distributed
|
112 |
+
as part of the Derivative Works; within the Source form or
|
113 |
+
documentation, if provided along with the Derivative Works; or,
|
114 |
+
within a display generated by the Derivative Works, if and
|
115 |
+
wherever such third-party notices normally appear. The contents
|
116 |
+
of the NOTICE file are for informational purposes only and
|
117 |
+
do not modify the License. You may add Your own attribution
|
118 |
+
notices within Derivative Works that You distribute, alongside
|
119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
120 |
+
that such additional attribution notices cannot be construed
|
121 |
+
as modifying the License.
|
122 |
+
|
123 |
+
You may add Your own copyright statement to Your modifications and
|
124 |
+
may provide additional or different license terms and conditions
|
125 |
+
for use, reproduction, or distribution of Your modifications, or
|
126 |
+
for any such Derivative Works as a whole, provided Your use,
|
127 |
+
reproduction, and distribution of the Work otherwise complies with
|
128 |
+
the conditions stated in this License.
|
129 |
+
|
130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
132 |
+
by You to the Licensor shall be under the terms and conditions of
|
133 |
+
this License, without any additional terms or conditions.
|
134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135 |
+
the terms of any separate license agreement you may have executed
|
136 |
+
with Licensor regarding such Contributions.
|
137 |
+
|
138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
140 |
+
except as required for reasonable and customary use in describing the
|
141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
142 |
+
|
143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144 |
+
agreed to in writing, Licensor provides the Work (and each
|
145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147 |
+
implied, including, without limitation, any warranties or conditions
|
148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150 |
+
appropriateness of using or redistributing the Work and assume any
|
151 |
+
risks associated with Your exercise of permissions under this License.
|
152 |
+
|
153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
154 |
+
whether in tort (including negligence), contract, or otherwise,
|
155 |
+
unless required by applicable law (such as deliberate and grossly
|
156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157 |
+
liable to You for damages, including any direct, indirect, special,
|
158 |
+
incidental, or consequential damages of any character arising as a
|
159 |
+
result of this License or out of the use or inability to use the
|
160 |
+
Work (including but not limited to damages for loss of goodwill,
|
161 |
+
work stoppage, computer failure or malfunction, or any and all
|
162 |
+
other commercial damages or losses), even if such Contributor
|
163 |
+
has been advised of the possibility of such damages.
|
164 |
+
|
165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168 |
+
or other liability obligations and/or rights consistent with this
|
169 |
+
License. However, in accepting such obligations, You may act only
|
170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171 |
+
of any other Contributor, and only if You agree to indemnify,
|
172 |
+
defend, and hold each Contributor harmless for any liability
|
173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
174 |
+
of your accepting any such warranty or additional liability.
|
175 |
+
|
176 |
+
END OF TERMS AND CONDITIONS
|
177 |
+
|
178 |
+
APPENDIX: How to apply the Apache License to your work.
|
179 |
+
|
180 |
+
To apply the Apache License to your work, attach the following
|
181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182 |
+
replaced with your own identifying information. (Don't include
|
183 |
+
the brackets!) The text should be enclosed in the appropriate
|
184 |
+
comment syntax for the file format. We also recommend that a
|
185 |
+
file or class name and description of purpose be included on the
|
186 |
+
same "printed page" as the copyright notice for easier
|
187 |
+
identification within third-party archives.
|
188 |
+
|
189 |
+
Copyright [yyyy] [name of copyright owner]
|
190 |
+
|
191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192 |
+
you may not use this file except in compliance with the License.
|
193 |
+
You may obtain a copy of the License at
|
194 |
+
|
195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
196 |
+
|
197 |
+
Unless required by applicable law or agreed to in writing, software
|
198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200 |
+
See the License for the specific language governing permissions and
|
201 |
+
limitations under the License.
|
ComfyUI/custom_nodes/ComfyMath/README.md
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# ComfyMath
|
2 |
+
|
3 |
+
Provides Math Nodes for [ComfyUI](https://github.com/comfyanonymous/ComfyUI)
|
4 |
+
|
5 |
+
## Features
|
6 |
+
|
7 |
+
Provides nodes for:
|
8 |
+
* Boolean Logic
|
9 |
+
* Integer Arithmetic
|
10 |
+
* Floating Point Arithmetic and Functions
|
11 |
+
* Vec2, Vec3, and Vec4 Arithmetic and Functions
|
12 |
+
|
13 |
+
## Installation
|
14 |
+
|
15 |
+
From the `custom_nodes` directory in your ComfyUI installation, run:
|
16 |
+
|
17 |
+
```sh
|
18 |
+
git clone https://github.com/evanspearman/ComfyMath.git
|
19 |
+
```
|
ComfyUI/custom_nodes/ComfyMath/__init__.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .src.comfymath.convert import NODE_CLASS_MAPPINGS as convert_NCM
|
2 |
+
from .src.comfymath.bool import NODE_CLASS_MAPPINGS as bool_NCM
|
3 |
+
from .src.comfymath.int import NODE_CLASS_MAPPINGS as int_NCM
|
4 |
+
from .src.comfymath.float import NODE_CLASS_MAPPINGS as float_NCM
|
5 |
+
from .src.comfymath.number import NODE_CLASS_MAPPINGS as number_NCM
|
6 |
+
from .src.comfymath.vec import NODE_CLASS_MAPPINGS as vec_NCM
|
7 |
+
from .src.comfymath.control import NODE_CLASS_MAPPINGS as control_NCM
|
8 |
+
from .src.comfymath.graphics import NODE_CLASS_MAPPINGS as graphics_NCM
|
9 |
+
|
10 |
+
|
11 |
+
|
12 |
+
|
13 |
+
NODE_CLASS_MAPPINGS = {
|
14 |
+
**convert_NCM,
|
15 |
+
**bool_NCM,
|
16 |
+
**int_NCM,
|
17 |
+
**float_NCM,
|
18 |
+
**number_NCM,
|
19 |
+
**vec_NCM,
|
20 |
+
**control_NCM,
|
21 |
+
**graphics_NCM,
|
22 |
+
}
|
23 |
+
|
24 |
+
|
25 |
+
def remove_cm_prefix(node_mapping: str) -> str:
|
26 |
+
if node_mapping.startswith("CM_"):
|
27 |
+
return node_mapping[3:]
|
28 |
+
return node_mapping
|
29 |
+
|
30 |
+
|
31 |
+
NODE_DISPLAY_NAME_MAPPINGS = {key: remove_cm_prefix(key) for key in NODE_CLASS_MAPPINGS}
|
ComfyUI/custom_nodes/ComfyMath/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (979 Bytes). View file
|
|
ComfyUI/custom_nodes/ComfyMath/pyproject.toml
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[tool.poetry]
|
2 |
+
name = "comfymath"
|
3 |
+
version = "0.1.0"
|
4 |
+
description = "Math nodes for ComfyUI"
|
5 |
+
authors = ["Evan Spearman <[email protected]>"]
|
6 |
+
license = "Apache-2.0"
|
7 |
+
readme = "README.md"
|
8 |
+
|
9 |
+
[tool.poetry.dependencies]
|
10 |
+
python = "^3.10"
|
11 |
+
numpy = "^1.25.1"
|
12 |
+
|
13 |
+
[tool.poetry.group.dev.dependencies]
|
14 |
+
mypy = "^1.4.1"
|
15 |
+
black = "^23.7.0"
|
16 |
+
|
17 |
+
[build-system]
|
18 |
+
requires = ["poetry-core"]
|
19 |
+
build-backend = "poetry.core.masonry.api"
|
ComfyUI/custom_nodes/ComfyMath/requirements.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
numpy
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__init__.py
ADDED
File without changes
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (164 Bytes). View file
|
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/bool.cpython-310.pyc
ADDED
Binary file (2.63 kB). View file
|
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/control.cpython-310.pyc
ADDED
Binary file (287 Bytes). View file
|
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/convert.cpython-310.pyc
ADDED
Binary file (8.76 kB). View file
|
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/float.cpython-310.pyc
ADDED
Binary file (8.98 kB). View file
|
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/graphics.cpython-310.pyc
ADDED
Binary file (2.5 kB). View file
|
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/int.cpython-310.pyc
ADDED
Binary file (6.5 kB). View file
|
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/number.cpython-310.pyc
ADDED
Binary file (2.83 kB). View file
|
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/vec.cpython-310.pyc
ADDED
Binary file (14 kB). View file
|
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/bool.py
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Any, Callable, Mapping
|
2 |
+
|
3 |
+
DEFAULT_BOOL = ("BOOL", {"default": False})
|
4 |
+
|
5 |
+
|
6 |
+
BOOL_UNARY_OPERATIONS: Mapping[str, Callable[[bool], bool]] = {
|
7 |
+
"Not": lambda a: not a,
|
8 |
+
}
|
9 |
+
|
10 |
+
BOOL_BINARY_OPERATIONS: Mapping[str, Callable[[bool, bool], bool]] = {
|
11 |
+
"Nor": lambda a, b: not (a or b),
|
12 |
+
"Xor": lambda a, b: a ^ b,
|
13 |
+
"Nand": lambda a, b: not (a and b),
|
14 |
+
"And": lambda a, b: a and b,
|
15 |
+
"Xnor": lambda a, b: not (a ^ b),
|
16 |
+
"Or": lambda a, b: a or b,
|
17 |
+
"Eq": lambda a, b: a == b,
|
18 |
+
"Neq": lambda a, b: a != b,
|
19 |
+
}
|
20 |
+
|
21 |
+
|
22 |
+
class BoolUnaryOperation:
|
23 |
+
@classmethod
|
24 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
25 |
+
return {
|
26 |
+
"required": {"op": (list(BOOL_UNARY_OPERATIONS.keys()),), "a": DEFAULT_BOOL}
|
27 |
+
}
|
28 |
+
|
29 |
+
RETURN_TYPES = ("BOOL",)
|
30 |
+
FUNCTION = "op"
|
31 |
+
CATEGORY = "math/bool"
|
32 |
+
|
33 |
+
def op(self, op: str, a: bool) -> tuple[bool]:
|
34 |
+
return (BOOL_UNARY_OPERATIONS[op](a),)
|
35 |
+
|
36 |
+
|
37 |
+
class BoolBinaryOperation:
|
38 |
+
@classmethod
|
39 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
40 |
+
return {
|
41 |
+
"required": {
|
42 |
+
"op": (list(BOOL_BINARY_OPERATIONS.keys()),),
|
43 |
+
"a": DEFAULT_BOOL,
|
44 |
+
"b": DEFAULT_BOOL,
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
RETURN_TYPES = ("BOOL",)
|
49 |
+
FUNCTION = "op"
|
50 |
+
CATEGORY = "math/bool"
|
51 |
+
|
52 |
+
def op(self, op: str, a: bool, b: bool) -> tuple[bool]:
|
53 |
+
return (BOOL_BINARY_OPERATIONS[op](a, b),)
|
54 |
+
|
55 |
+
|
56 |
+
NODE_CLASS_MAPPINGS = {
|
57 |
+
"CM_BoolUnaryOperation": BoolUnaryOperation,
|
58 |
+
"CM_BoolBinaryOperation": BoolBinaryOperation,
|
59 |
+
}
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/control.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Any, Mapping
|
2 |
+
|
3 |
+
NODE_CLASS_MAPPINGS: Mapping[str, Any] = {}
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/convert.py
ADDED
@@ -0,0 +1,273 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Any, Mapping
|
2 |
+
|
3 |
+
from .vec import Vec2, VEC2_ZERO, Vec3, VEC3_ZERO, Vec4, VEC4_ZERO
|
4 |
+
from .number import number
|
5 |
+
|
6 |
+
|
7 |
+
class BoolToInt:
|
8 |
+
@classmethod
|
9 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
10 |
+
return {"required": {"a": ("BOOL", {"default": False})}}
|
11 |
+
|
12 |
+
RETURN_TYPES = ("INT",)
|
13 |
+
FUNCTION = "op"
|
14 |
+
CATEGORY = "math/conversion"
|
15 |
+
|
16 |
+
def op(self, a: bool) -> tuple[int]:
|
17 |
+
return (int(a),)
|
18 |
+
|
19 |
+
|
20 |
+
class IntToBool:
|
21 |
+
@classmethod
|
22 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
23 |
+
return {"required": {"a": ("INT", {"default": 0})}}
|
24 |
+
|
25 |
+
RETURN_TYPES = ("BOOL",)
|
26 |
+
FUNCTION = "op"
|
27 |
+
CATEGORY = "math/conversion"
|
28 |
+
|
29 |
+
def op(self, a: int) -> tuple[bool]:
|
30 |
+
return (a != 0,)
|
31 |
+
|
32 |
+
|
33 |
+
class FloatToInt:
|
34 |
+
@classmethod
|
35 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
36 |
+
return {"required": {"a": ("FLOAT", {"default": 0.0})}}
|
37 |
+
|
38 |
+
RETURN_TYPES = ("INT",)
|
39 |
+
FUNCTION = "op"
|
40 |
+
CATEGORY = "math/conversion"
|
41 |
+
|
42 |
+
def op(self, a: float) -> tuple[int]:
|
43 |
+
return (int(a),)
|
44 |
+
|
45 |
+
|
46 |
+
class IntToFloat:
|
47 |
+
@classmethod
|
48 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
49 |
+
return {"required": {"a": ("INT", {"default": 0})}}
|
50 |
+
|
51 |
+
RETURN_TYPES = ("FLOAT",)
|
52 |
+
FUNCTION = "op"
|
53 |
+
CATEGORY = "math/conversion"
|
54 |
+
|
55 |
+
def op(self, a: int) -> tuple[float]:
|
56 |
+
return (float(a),)
|
57 |
+
|
58 |
+
|
59 |
+
class IntToNumber:
|
60 |
+
@classmethod
|
61 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
62 |
+
return {"required": {"a": ("INT", {"default": 0})}}
|
63 |
+
|
64 |
+
RETURN_TYPES = ("NUMBER",)
|
65 |
+
FUNCTION = "op"
|
66 |
+
CATEGORY = "math/conversion"
|
67 |
+
|
68 |
+
def op(self, a: int) -> tuple[number]:
|
69 |
+
return (a,)
|
70 |
+
|
71 |
+
|
72 |
+
class NumberToInt:
|
73 |
+
@classmethod
|
74 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
75 |
+
return {"required": {"a": ("NUMBER", {"default": 0.0})}}
|
76 |
+
|
77 |
+
RETURN_TYPES = ("INT",)
|
78 |
+
FUNCTION = "op"
|
79 |
+
CATEGORY = "math/conversion"
|
80 |
+
|
81 |
+
def op(self, a: number) -> tuple[int]:
|
82 |
+
return (int(a),)
|
83 |
+
|
84 |
+
|
85 |
+
class FloatToNumber:
|
86 |
+
@classmethod
|
87 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
88 |
+
return {"required": {"a": ("FLOAT", {"default": 0.0})}}
|
89 |
+
|
90 |
+
RETURN_TYPES = ("NUMBER",)
|
91 |
+
FUNCTION = "op"
|
92 |
+
CATEGORY = "math/conversion"
|
93 |
+
|
94 |
+
def op(self, a: float) -> tuple[number]:
|
95 |
+
return (a,)
|
96 |
+
|
97 |
+
|
98 |
+
class NumberToFloat:
|
99 |
+
@classmethod
|
100 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
101 |
+
return {"required": {"a": ("NUMBER", {"default": 0.0})}}
|
102 |
+
|
103 |
+
RETURN_TYPES = ("FLOAT",)
|
104 |
+
FUNCTION = "op"
|
105 |
+
CATEGORY = "math/conversion"
|
106 |
+
|
107 |
+
def op(self, a: number) -> tuple[float]:
|
108 |
+
return (float(a),)
|
109 |
+
|
110 |
+
|
111 |
+
class ComposeVec2:
|
112 |
+
@classmethod
|
113 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
114 |
+
return {
|
115 |
+
"required": {
|
116 |
+
"x": ("FLOAT", {"default": 0.0}),
|
117 |
+
"y": ("FLOAT", {"default": 0.0}),
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
RETURN_TYPES = ("VEC2",)
|
122 |
+
FUNCTION = "op"
|
123 |
+
CATEGORY = "math/conversion"
|
124 |
+
|
125 |
+
def op(self, x: float, y: float) -> tuple[Vec2]:
|
126 |
+
return ((x, y),)
|
127 |
+
|
128 |
+
|
129 |
+
class FillVec2:
|
130 |
+
@classmethod
|
131 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
132 |
+
return {
|
133 |
+
"required": {
|
134 |
+
"a": ("FLOAT", {"default": 0.0}),
|
135 |
+
}
|
136 |
+
}
|
137 |
+
|
138 |
+
RETURN_TYPES = ("VEC2",)
|
139 |
+
FUNCTION = "op"
|
140 |
+
CATEGORY = "math/conversion"
|
141 |
+
|
142 |
+
def op(self, a: float) -> tuple[Vec2]:
|
143 |
+
return ((a, a),)
|
144 |
+
|
145 |
+
|
146 |
+
class BreakoutVec2:
|
147 |
+
@classmethod
|
148 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
149 |
+
return {"required": {"a": ("VEC2", {"default": VEC2_ZERO})}}
|
150 |
+
|
151 |
+
RETURN_TYPES = ("FLOAT", "FLOAT")
|
152 |
+
FUNCTION = "op"
|
153 |
+
CATEGORY = "math/conversion"
|
154 |
+
|
155 |
+
def op(self, a: Vec2) -> tuple[float, float]:
|
156 |
+
return (a[0], a[1])
|
157 |
+
|
158 |
+
|
159 |
+
class ComposeVec3:
|
160 |
+
@classmethod
|
161 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
162 |
+
return {
|
163 |
+
"required": {
|
164 |
+
"x": ("FLOAT", {"default": 0.0}),
|
165 |
+
"y": ("FLOAT", {"default": 0.0}),
|
166 |
+
"z": ("FLOAT", {"default": 0.0}),
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
RETURN_TYPES = ("VEC3",)
|
171 |
+
FUNCTION = "op"
|
172 |
+
CATEGORY = "math/conversion"
|
173 |
+
|
174 |
+
def op(self, x: float, y: float, z: float) -> tuple[Vec3]:
|
175 |
+
return ((x, y, z),)
|
176 |
+
|
177 |
+
|
178 |
+
class FillVec3:
|
179 |
+
@classmethod
|
180 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
181 |
+
return {
|
182 |
+
"required": {
|
183 |
+
"a": ("FLOAT", {"default": 0.0}),
|
184 |
+
}
|
185 |
+
}
|
186 |
+
|
187 |
+
RETURN_TYPES = ("VEC3",)
|
188 |
+
FUNCTION = "op"
|
189 |
+
CATEGORY = "math/conversion"
|
190 |
+
|
191 |
+
def op(self, a: float) -> tuple[Vec3]:
|
192 |
+
return ((a, a, a),)
|
193 |
+
|
194 |
+
|
195 |
+
class BreakoutVec3:
|
196 |
+
@classmethod
|
197 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
198 |
+
return {"required": {"a": ("VEC3", {"default": VEC3_ZERO})}}
|
199 |
+
|
200 |
+
RETURN_TYPES = ("FLOAT", "FLOAT", "FLOAT")
|
201 |
+
FUNCTION = "op"
|
202 |
+
CATEGORY = "math/conversion"
|
203 |
+
|
204 |
+
def op(self, a: Vec3) -> tuple[float, float, float]:
|
205 |
+
return (a[0], a[1], a[2])
|
206 |
+
|
207 |
+
|
208 |
+
class ComposeVec4:
|
209 |
+
@classmethod
|
210 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
211 |
+
return {
|
212 |
+
"required": {
|
213 |
+
"x": ("FLOAT", {"default": 0.0}),
|
214 |
+
"y": ("FLOAT", {"default": 0.0}),
|
215 |
+
"z": ("FLOAT", {"default": 0.0}),
|
216 |
+
"w": ("FLOAT", {"default": 0.0}),
|
217 |
+
}
|
218 |
+
}
|
219 |
+
|
220 |
+
RETURN_TYPES = ("VEC4",)
|
221 |
+
FUNCTION = "op"
|
222 |
+
CATEGORY = "math/conversion"
|
223 |
+
|
224 |
+
def op(self, x: float, y: float, z: float, w: float) -> tuple[Vec4]:
|
225 |
+
return ((x, y, z, w),)
|
226 |
+
|
227 |
+
|
228 |
+
class FillVec4:
|
229 |
+
@classmethod
|
230 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
231 |
+
return {
|
232 |
+
"required": {
|
233 |
+
"a": ("FLOAT", {"default": 0.0}),
|
234 |
+
}
|
235 |
+
}
|
236 |
+
|
237 |
+
RETURN_TYPES = ("VEC4",)
|
238 |
+
FUNCTION = "op"
|
239 |
+
CATEGORY = "math/conversion"
|
240 |
+
|
241 |
+
def op(self, a: float) -> tuple[Vec4]:
|
242 |
+
return ((a, a, a, a),)
|
243 |
+
|
244 |
+
|
245 |
+
class BreakoutVec4:
|
246 |
+
@classmethod
|
247 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
248 |
+
return {"required": {"a": ("VEC4", {"default": VEC4_ZERO})}}
|
249 |
+
|
250 |
+
RETURN_TYPES = ("FLOAT", "FLOAT", "FLOAT", "FLOAT")
|
251 |
+
FUNCTION = "op"
|
252 |
+
CATEGORY = "math/conversion"
|
253 |
+
|
254 |
+
def op(self, a: Vec4) -> tuple[float, float, float, float]:
|
255 |
+
return (a[0], a[1], a[2], a[3])
|
256 |
+
|
257 |
+
|
258 |
+
NODE_CLASS_MAPPINGS = {
|
259 |
+
"CM_BoolToInt": BoolToInt,
|
260 |
+
"CM_IntToBool": IntToBool,
|
261 |
+
"CM_FloatToInt": FloatToInt,
|
262 |
+
"CM_IntToFloat": IntToFloat,
|
263 |
+
"CM_IntToNumber": IntToNumber,
|
264 |
+
"CM_NumberToInt": NumberToInt,
|
265 |
+
"CM_FloatToNumber": FloatToNumber,
|
266 |
+
"CM_NumberToFloat": NumberToFloat,
|
267 |
+
"CM_ComposeVec2": ComposeVec2,
|
268 |
+
"CM_ComposeVec3": ComposeVec3,
|
269 |
+
"CM_ComposeVec4": ComposeVec4,
|
270 |
+
"CM_BreakoutVec2": BreakoutVec2,
|
271 |
+
"CM_BreakoutVec3": BreakoutVec3,
|
272 |
+
"CM_BreakoutVec4": BreakoutVec4,
|
273 |
+
}
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/float.py
ADDED
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
|
3 |
+
from typing import Any, Callable, Mapping
|
4 |
+
|
5 |
+
DEFAULT_FLOAT = ("FLOAT", {"default": 0.0})
|
6 |
+
|
7 |
+
FLOAT_UNARY_OPERATIONS: Mapping[str, Callable[[float], float]] = {
|
8 |
+
"Neg": lambda a: -a,
|
9 |
+
"Inc": lambda a: a + 1,
|
10 |
+
"Dec": lambda a: a - 1,
|
11 |
+
"Abs": lambda a: abs(a),
|
12 |
+
"Sqr": lambda a: a * a,
|
13 |
+
"Cube": lambda a: a * a * a,
|
14 |
+
"Sqrt": lambda a: math.sqrt(a),
|
15 |
+
"Exp": lambda a: math.exp(a),
|
16 |
+
"Ln": lambda a: math.log(a),
|
17 |
+
"Log10": lambda a: math.log10(a),
|
18 |
+
"Log2": lambda a: math.log2(a),
|
19 |
+
"Sin": lambda a: math.sin(a),
|
20 |
+
"Cos": lambda a: math.cos(a),
|
21 |
+
"Tan": lambda a: math.tan(a),
|
22 |
+
"Asin": lambda a: math.asin(a),
|
23 |
+
"Acos": lambda a: math.acos(a),
|
24 |
+
"Atan": lambda a: math.atan(a),
|
25 |
+
"Sinh": lambda a: math.sinh(a),
|
26 |
+
"Cosh": lambda a: math.cosh(a),
|
27 |
+
"Tanh": lambda a: math.tanh(a),
|
28 |
+
"Asinh": lambda a: math.asinh(a),
|
29 |
+
"Acosh": lambda a: math.acosh(a),
|
30 |
+
"Atanh": lambda a: math.atanh(a),
|
31 |
+
"Round": lambda a: round(a),
|
32 |
+
"Floor": lambda a: math.floor(a),
|
33 |
+
"Ceil": lambda a: math.ceil(a),
|
34 |
+
"Trunc": lambda a: math.trunc(a),
|
35 |
+
"Erf": lambda a: math.erf(a),
|
36 |
+
"Erfc": lambda a: math.erfc(a),
|
37 |
+
"Gamma": lambda a: math.gamma(a),
|
38 |
+
"Radians": lambda a: math.radians(a),
|
39 |
+
"Degrees": lambda a: math.degrees(a),
|
40 |
+
}
|
41 |
+
|
42 |
+
FLOAT_UNARY_CONDITIONS: Mapping[str, Callable[[float], bool]] = {
|
43 |
+
"IsZero": lambda a: a == 0.0,
|
44 |
+
"IsPositive": lambda a: a > 0.0,
|
45 |
+
"IsNegative": lambda a: a < 0.0,
|
46 |
+
"IsNonZero": lambda a: a != 0.0,
|
47 |
+
"IsPositiveInfinity": lambda a: math.isinf(a) and a > 0.0,
|
48 |
+
"IsNegativeInfinity": lambda a: math.isinf(a) and a < 0.0,
|
49 |
+
"IsNaN": lambda a: math.isnan(a),
|
50 |
+
"IsFinite": lambda a: math.isfinite(a),
|
51 |
+
"IsInfinite": lambda a: math.isinf(a),
|
52 |
+
"IsEven": lambda a: a % 2 == 0.0,
|
53 |
+
"IsOdd": lambda a: a % 2 != 0.0,
|
54 |
+
}
|
55 |
+
|
56 |
+
FLOAT_BINARY_OPERATIONS: Mapping[str, Callable[[float, float], float]] = {
|
57 |
+
"Add": lambda a, b: a + b,
|
58 |
+
"Sub": lambda a, b: a - b,
|
59 |
+
"Mul": lambda a, b: a * b,
|
60 |
+
"Div": lambda a, b: a / b,
|
61 |
+
"Mod": lambda a, b: a % b,
|
62 |
+
"Pow": lambda a, b: a**b,
|
63 |
+
"FloorDiv": lambda a, b: a // b,
|
64 |
+
"Max": lambda a, b: max(a, b),
|
65 |
+
"Min": lambda a, b: min(a, b),
|
66 |
+
"Log": lambda a, b: math.log(a, b),
|
67 |
+
"Atan2": lambda a, b: math.atan2(a, b),
|
68 |
+
}
|
69 |
+
|
70 |
+
FLOAT_BINARY_CONDITIONS: Mapping[str, Callable[[float, float], bool]] = {
|
71 |
+
"Eq": lambda a, b: a == b,
|
72 |
+
"Neq": lambda a, b: a != b,
|
73 |
+
"Gt": lambda a, b: a > b,
|
74 |
+
"Gte": lambda a, b: a >= b,
|
75 |
+
"Lt": lambda a, b: a < b,
|
76 |
+
"Lte": lambda a, b: a <= b,
|
77 |
+
}
|
78 |
+
|
79 |
+
|
80 |
+
class FloatUnaryOperation:
|
81 |
+
@classmethod
|
82 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
83 |
+
return {
|
84 |
+
"required": {
|
85 |
+
"op": (list(FLOAT_UNARY_OPERATIONS.keys()),),
|
86 |
+
"a": DEFAULT_FLOAT,
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
RETURN_TYPES = ("FLOAT",)
|
91 |
+
FUNCTION = "op"
|
92 |
+
CATEGORY = "math/float"
|
93 |
+
|
94 |
+
def op(self, op: str, a: float) -> tuple[float]:
|
95 |
+
return (FLOAT_UNARY_OPERATIONS[op](a),)
|
96 |
+
|
97 |
+
|
98 |
+
class FloatUnaryCondition:
|
99 |
+
@classmethod
|
100 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
101 |
+
return {
|
102 |
+
"required": {
|
103 |
+
"op": (list(FLOAT_UNARY_CONDITIONS.keys()),),
|
104 |
+
"a": DEFAULT_FLOAT,
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
RETURN_TYPES = ("BOOL",)
|
109 |
+
FUNCTION = "op"
|
110 |
+
CATEGORY = "math/float"
|
111 |
+
|
112 |
+
def op(self, op: str, a: float) -> tuple[bool]:
|
113 |
+
return (FLOAT_UNARY_CONDITIONS[op](a),)
|
114 |
+
|
115 |
+
|
116 |
+
class FloatBinaryOperation:
|
117 |
+
@classmethod
|
118 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
119 |
+
return {
|
120 |
+
"required": {
|
121 |
+
"op": (list(FLOAT_BINARY_OPERATIONS.keys()),),
|
122 |
+
"a": DEFAULT_FLOAT,
|
123 |
+
"b": DEFAULT_FLOAT,
|
124 |
+
}
|
125 |
+
}
|
126 |
+
|
127 |
+
RETURN_TYPES = ("FLOAT",)
|
128 |
+
FUNCTION = "op"
|
129 |
+
CATEGORY = "math/float"
|
130 |
+
|
131 |
+
def op(self, op: str, a: float, b: float) -> tuple[float]:
|
132 |
+
return (FLOAT_BINARY_OPERATIONS[op](a, b),)
|
133 |
+
|
134 |
+
|
135 |
+
class FloatBinaryCondition:
|
136 |
+
@classmethod
|
137 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
138 |
+
return {
|
139 |
+
"required": {
|
140 |
+
"op": (list(FLOAT_BINARY_CONDITIONS.keys()),),
|
141 |
+
"a": DEFAULT_FLOAT,
|
142 |
+
"b": DEFAULT_FLOAT,
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
RETURN_TYPES = ("BOOL",)
|
147 |
+
FUNCTION = "op"
|
148 |
+
CATEGORY = "math/float"
|
149 |
+
|
150 |
+
def op(self, op: str, a: float, b: float) -> tuple[bool]:
|
151 |
+
return (FLOAT_BINARY_CONDITIONS[op](a, b),)
|
152 |
+
|
153 |
+
|
154 |
+
NODE_CLASS_MAPPINGS = {
|
155 |
+
"CM_FloatUnaryOperation": FloatUnaryOperation,
|
156 |
+
"CM_FloatUnaryCondition": FloatUnaryCondition,
|
157 |
+
"CM_FloatBinaryOperation": FloatBinaryOperation,
|
158 |
+
"CM_FloatBinaryCondition": FloatBinaryCondition,
|
159 |
+
}
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/graphics.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Any, Mapping
|
2 |
+
|
3 |
+
|
4 |
+
SDXL_SUPPORTED_RESOLUTIONS = [
|
5 |
+
(1024, 1024, 1.0),
|
6 |
+
(1152, 896, 1.2857142857142858),
|
7 |
+
(896, 1152, 0.7777777777777778),
|
8 |
+
(1216, 832, 1.4615384615384615),
|
9 |
+
(832, 1216, 0.6842105263157895),
|
10 |
+
(1344, 768, 1.75),
|
11 |
+
(768, 1344, 0.5714285714285714),
|
12 |
+
(1536, 640, 2.4),
|
13 |
+
(640, 1536, 0.4166666666666667),
|
14 |
+
]
|
15 |
+
|
16 |
+
|
17 |
+
class SDXLResolution:
|
18 |
+
@classmethod
|
19 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
20 |
+
return {
|
21 |
+
"required": {
|
22 |
+
"resolution": (
|
23 |
+
[f"{res[0]}x{res[1]}" for res in SDXL_SUPPORTED_RESOLUTIONS],
|
24 |
+
)
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
RETURN_TYPES = ("INT", "INT")
|
29 |
+
RETURN_NAMES = ("width", "height")
|
30 |
+
FUNCTION = "op"
|
31 |
+
CATEGORY = "math/graphics"
|
32 |
+
|
33 |
+
def op(self, resolution: str) -> tuple[int, int]:
|
34 |
+
width, height = resolution.split("x")
|
35 |
+
return (int(width), int(height))
|
36 |
+
|
37 |
+
|
38 |
+
class NearestSDXLResolution:
|
39 |
+
@classmethod
|
40 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
41 |
+
return {"required": {"image": ("IMAGE",)}}
|
42 |
+
|
43 |
+
RETURN_TYPES = ("INT", "INT")
|
44 |
+
RETURN_NAMES = ("width", "height")
|
45 |
+
FUNCTION = "op"
|
46 |
+
CATEGORY = "math/graphics"
|
47 |
+
|
48 |
+
def op(self, image) -> tuple[int, int]:
|
49 |
+
image_width = image.size()[2]
|
50 |
+
image_height = image.size()[1]
|
51 |
+
print(f"Input image resolution: {image_width}x{image_height}")
|
52 |
+
image_ratio = image_width / image_height
|
53 |
+
differences = [
|
54 |
+
(abs(image_ratio - resolution[2]), resolution)
|
55 |
+
for resolution in SDXL_SUPPORTED_RESOLUTIONS
|
56 |
+
]
|
57 |
+
smallest = None
|
58 |
+
for difference in differences:
|
59 |
+
if smallest is None:
|
60 |
+
smallest = difference
|
61 |
+
else:
|
62 |
+
if difference[0] < smallest[0]:
|
63 |
+
smallest = difference
|
64 |
+
if smallest is not None:
|
65 |
+
width = smallest[1][0]
|
66 |
+
height = smallest[1][1]
|
67 |
+
else:
|
68 |
+
width = 1024
|
69 |
+
height = 1024
|
70 |
+
print(f"Selected SDXL resolution: {width}x{height}")
|
71 |
+
return (width, height)
|
72 |
+
|
73 |
+
|
74 |
+
NODE_CLASS_MAPPINGS = {
|
75 |
+
"CM_SDXLResolution": SDXLResolution,
|
76 |
+
"CM_NearestSDXLResolution": NearestSDXLResolution,
|
77 |
+
}
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/int.py
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
|
3 |
+
from typing import Any, Callable, Mapping
|
4 |
+
|
5 |
+
DEFAULT_INT = ("INT", {"default": 0})
|
6 |
+
|
7 |
+
INT_UNARY_OPERATIONS: Mapping[str, Callable[[int], int]] = {
|
8 |
+
"Abs": lambda a: abs(a),
|
9 |
+
"Neg": lambda a: -a,
|
10 |
+
"Inc": lambda a: a + 1,
|
11 |
+
"Dec": lambda a: a - 1,
|
12 |
+
"Sqr": lambda a: a * a,
|
13 |
+
"Cube": lambda a: a * a * a,
|
14 |
+
"Not": lambda a: ~a,
|
15 |
+
"Factorial": lambda a: math.factorial(a),
|
16 |
+
}
|
17 |
+
|
18 |
+
INT_UNARY_CONDITIONS: Mapping[str, Callable[[int], bool]] = {
|
19 |
+
"IsZero": lambda a: a == 0,
|
20 |
+
"IsNonZero": lambda a: a != 0,
|
21 |
+
"IsPositive": lambda a: a > 0,
|
22 |
+
"IsNegative": lambda a: a < 0,
|
23 |
+
"IsEven": lambda a: a % 2 == 0,
|
24 |
+
"IsOdd": lambda a: a % 2 == 1,
|
25 |
+
}
|
26 |
+
|
27 |
+
INT_BINARY_OPERATIONS: Mapping[str, Callable[[int, int], int]] = {
|
28 |
+
"Add": lambda a, b: a + b,
|
29 |
+
"Sub": lambda a, b: a - b,
|
30 |
+
"Mul": lambda a, b: a * b,
|
31 |
+
"Div": lambda a, b: a // b,
|
32 |
+
"Mod": lambda a, b: a % b,
|
33 |
+
"Pow": lambda a, b: a**b,
|
34 |
+
"And": lambda a, b: a & b,
|
35 |
+
"Nand": lambda a, b: ~a & b,
|
36 |
+
"Or": lambda a, b: a | b,
|
37 |
+
"Nor": lambda a, b: ~a & b,
|
38 |
+
"Xor": lambda a, b: a ^ b,
|
39 |
+
"Xnor": lambda a, b: ~a ^ b,
|
40 |
+
"Shl": lambda a, b: a << b,
|
41 |
+
"Shr": lambda a, b: a >> b,
|
42 |
+
"Max": lambda a, b: max(a, b),
|
43 |
+
"Min": lambda a, b: min(a, b),
|
44 |
+
}
|
45 |
+
|
46 |
+
INT_BINARY_CONDITIONS: Mapping[str, Callable[[int, int], bool]] = {
|
47 |
+
"Eq": lambda a, b: a == b,
|
48 |
+
"Neq": lambda a, b: a != b,
|
49 |
+
"Gt": lambda a, b: a > b,
|
50 |
+
"Lt": lambda a, b: a < b,
|
51 |
+
"Geq": lambda a, b: a >= b,
|
52 |
+
"Leq": lambda a, b: a <= b,
|
53 |
+
}
|
54 |
+
|
55 |
+
|
56 |
+
class IntUnaryOperation:
|
57 |
+
@classmethod
|
58 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
59 |
+
return {
|
60 |
+
"required": {"op": (list(INT_UNARY_OPERATIONS.keys()),), "a": DEFAULT_INT}
|
61 |
+
}
|
62 |
+
|
63 |
+
RETURN_TYPES = ("INT",)
|
64 |
+
FUNCTION = "op"
|
65 |
+
CATEGORY = "math/int"
|
66 |
+
|
67 |
+
def op(self, op: str, a: int) -> tuple[int]:
|
68 |
+
return (INT_UNARY_OPERATIONS[op](a),)
|
69 |
+
|
70 |
+
|
71 |
+
class IntUnaryCondition:
|
72 |
+
@classmethod
|
73 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
74 |
+
return {
|
75 |
+
"required": {"op": (list(INT_UNARY_CONDITIONS.keys()),), "a": DEFAULT_INT}
|
76 |
+
}
|
77 |
+
|
78 |
+
RETURN_TYPES = ("BOOL",)
|
79 |
+
FUNCTION = "op"
|
80 |
+
CATEGORY = "math/int"
|
81 |
+
|
82 |
+
def op(self, op: str, a: int) -> tuple[bool]:
|
83 |
+
return (INT_UNARY_CONDITIONS[op](a),)
|
84 |
+
|
85 |
+
|
86 |
+
class IntBinaryOperation:
|
87 |
+
@classmethod
|
88 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
89 |
+
return {
|
90 |
+
"required": {
|
91 |
+
"op": (list(INT_BINARY_OPERATIONS.keys()),),
|
92 |
+
"a": DEFAULT_INT,
|
93 |
+
"b": DEFAULT_INT,
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
RETURN_TYPES = ("INT",)
|
98 |
+
FUNCTION = "op"
|
99 |
+
CATEGORY = "math/int"
|
100 |
+
|
101 |
+
def op(self, op: str, a: int, b: int) -> tuple[int]:
|
102 |
+
return (INT_BINARY_OPERATIONS[op](a, b),)
|
103 |
+
|
104 |
+
|
105 |
+
class IntBinaryCondition:
|
106 |
+
@classmethod
|
107 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
108 |
+
return {
|
109 |
+
"required": {
|
110 |
+
"op": (list(INT_BINARY_CONDITIONS.keys()),),
|
111 |
+
"a": DEFAULT_INT,
|
112 |
+
"b": DEFAULT_INT,
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
RETURN_TYPES = ("BOOL",)
|
117 |
+
FUNCTION = "op"
|
118 |
+
CATEGORY = "math/int"
|
119 |
+
|
120 |
+
def op(self, op: str, a: int, b: int) -> tuple[bool]:
|
121 |
+
return (INT_BINARY_CONDITIONS[op](a, b),)
|
122 |
+
|
123 |
+
|
124 |
+
NODE_CLASS_MAPPINGS = {
|
125 |
+
"CM_IntUnaryOperation": IntUnaryOperation,
|
126 |
+
"CM_IntUnaryCondition": IntUnaryCondition,
|
127 |
+
"CM_IntBinaryOperation": IntBinaryOperation,
|
128 |
+
"CM_IntBinaryCondition": IntBinaryCondition,
|
129 |
+
}
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/number.py
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from dataclasses import dataclass
|
2 |
+
from typing import Any, Callable, Mapping, TypeAlias
|
3 |
+
|
4 |
+
from .float import (
|
5 |
+
FLOAT_UNARY_OPERATIONS,
|
6 |
+
FLOAT_UNARY_CONDITIONS,
|
7 |
+
FLOAT_BINARY_OPERATIONS,
|
8 |
+
FLOAT_BINARY_CONDITIONS,
|
9 |
+
)
|
10 |
+
|
11 |
+
DEFAULT_NUMBER = ("NUMBER", {"default": 0.0})
|
12 |
+
|
13 |
+
number: TypeAlias = int | float
|
14 |
+
|
15 |
+
|
16 |
+
class NumberUnaryOperation:
|
17 |
+
@classmethod
|
18 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
19 |
+
return {
|
20 |
+
"required": {
|
21 |
+
"op": (list(FLOAT_UNARY_OPERATIONS.keys()),),
|
22 |
+
"a": DEFAULT_NUMBER,
|
23 |
+
}
|
24 |
+
}
|
25 |
+
|
26 |
+
RETURN_TYPES = ("NUMBER",)
|
27 |
+
FUNCTION = "op"
|
28 |
+
CATEGORY = "math/number"
|
29 |
+
|
30 |
+
def op(self, op: str, a: number) -> tuple[float]:
|
31 |
+
return (FLOAT_UNARY_OPERATIONS[op](float(a)),)
|
32 |
+
|
33 |
+
|
34 |
+
class NumberUnaryCondition:
|
35 |
+
@classmethod
|
36 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
37 |
+
return {
|
38 |
+
"required": {
|
39 |
+
"op": (list(FLOAT_UNARY_CONDITIONS.keys()),),
|
40 |
+
"a": DEFAULT_NUMBER,
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
RETURN_TYPES = ("BOOL",)
|
45 |
+
FUNCTION = "op"
|
46 |
+
CATEGORY = "math/number"
|
47 |
+
|
48 |
+
def op(self, op: str, a: number) -> tuple[bool]:
|
49 |
+
return (FLOAT_UNARY_CONDITIONS[op](float(a)),)
|
50 |
+
|
51 |
+
|
52 |
+
class NumberBinaryOperation:
|
53 |
+
@classmethod
|
54 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
55 |
+
return {
|
56 |
+
"required": {
|
57 |
+
"op": (list(FLOAT_BINARY_OPERATIONS.keys()),),
|
58 |
+
"a": DEFAULT_NUMBER,
|
59 |
+
"b": DEFAULT_NUMBER,
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
RETURN_TYPES = ("NUMBER",)
|
64 |
+
FUNCTION = "op"
|
65 |
+
CATEGORY = "math/number"
|
66 |
+
|
67 |
+
def op(self, op: str, a: number, b: number) -> tuple[float]:
|
68 |
+
return (FLOAT_BINARY_OPERATIONS[op](float(a), float(b)),)
|
69 |
+
|
70 |
+
|
71 |
+
class NumberBinaryCondition:
|
72 |
+
@classmethod
|
73 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
74 |
+
return {
|
75 |
+
"required": {
|
76 |
+
"op": (list(FLOAT_BINARY_CONDITIONS.keys()),),
|
77 |
+
"a": DEFAULT_NUMBER,
|
78 |
+
"b": DEFAULT_NUMBER,
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
RETURN_TYPES = ("BOOL",)
|
83 |
+
FUNCTION = "op"
|
84 |
+
CATEGORY = "math/float"
|
85 |
+
|
86 |
+
def op(self, op: str, a: number, b: number) -> tuple[bool]:
|
87 |
+
return (FLOAT_BINARY_CONDITIONS[op](float(a), float(b)),)
|
88 |
+
|
89 |
+
|
90 |
+
NODE_CLASS_MAPPINGS = {
|
91 |
+
"CM_NumberUnaryOperation": NumberUnaryOperation,
|
92 |
+
"CM_NumberUnaryCondition": NumberUnaryCondition,
|
93 |
+
"CM_NumberBinaryOperation": NumberBinaryOperation,
|
94 |
+
"CM_NumberBinaryCondition": NumberBinaryCondition,
|
95 |
+
}
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/py.typed
ADDED
File without changes
|
ComfyUI/custom_nodes/ComfyMath/src/comfymath/vec.py
ADDED
@@ -0,0 +1,501 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy
|
2 |
+
|
3 |
+
from typing import Any, Callable, Mapping, TypeAlias
|
4 |
+
|
5 |
+
Vec2: TypeAlias = tuple[float, float]
|
6 |
+
VEC2_ZERO = (0.0, 0.0)
|
7 |
+
DEFAULT_VEC2 = ("VEC2", {"default": VEC2_ZERO})
|
8 |
+
|
9 |
+
Vec3: TypeAlias = tuple[float, float, float]
|
10 |
+
VEC3_ZERO = (0.0, 0.0, 0.0)
|
11 |
+
DEFAULT_VEC3 = ("VEC3", {"default": VEC3_ZERO})
|
12 |
+
|
13 |
+
Vec4: TypeAlias = tuple[float, float, float, float]
|
14 |
+
VEC4_ZERO = (0.0, 0.0, 0.0, 0.0)
|
15 |
+
DEFAULT_VEC4 = ("VEC4", {"default": VEC4_ZERO})
|
16 |
+
|
17 |
+
VEC_UNARY_OPERATIONS: Mapping[str, Callable[[numpy.ndarray], numpy.ndarray]] = {
|
18 |
+
"Neg": lambda a: -a,
|
19 |
+
"Normalize": lambda a: a / numpy.linalg.norm(a),
|
20 |
+
}
|
21 |
+
|
22 |
+
VEC_TO_SCALAR_UNARY_OPERATION: Mapping[str, Callable[[numpy.ndarray], float]] = {
|
23 |
+
"Norm": lambda a: numpy.linalg.norm(a).astype(float),
|
24 |
+
}
|
25 |
+
|
26 |
+
VEC_UNARY_CONDITIONS: Mapping[str, Callable[[numpy.ndarray], bool]] = {
|
27 |
+
"IsZero": lambda a: not numpy.any(a).astype(bool),
|
28 |
+
"IsNotZero": lambda a: numpy.any(a).astype(bool),
|
29 |
+
"IsNormalized": lambda a: numpy.allclose(a, a / numpy.linalg.norm(a)),
|
30 |
+
"IsNotNormalized": lambda a: not numpy.allclose(a, a / numpy.linalg.norm(a)),
|
31 |
+
}
|
32 |
+
|
33 |
+
VEC_BINARY_OPERATIONS: Mapping[
|
34 |
+
str, Callable[[numpy.ndarray, numpy.ndarray], numpy.ndarray]
|
35 |
+
] = {
|
36 |
+
"Add": lambda a, b: a + b,
|
37 |
+
"Sub": lambda a, b: a - b,
|
38 |
+
"Cross": lambda a, b: numpy.cross(a, b),
|
39 |
+
}
|
40 |
+
|
41 |
+
VEC_TO_SCALAR_BINARY_OPERATION: Mapping[
|
42 |
+
str, Callable[[numpy.ndarray, numpy.ndarray], float]
|
43 |
+
] = {
|
44 |
+
"Dot": lambda a, b: numpy.dot(a, b),
|
45 |
+
"Distance": lambda a, b: numpy.linalg.norm(a - b).astype(float),
|
46 |
+
}
|
47 |
+
|
48 |
+
VEC_BINARY_CONDITIONS: Mapping[str, Callable[[numpy.ndarray, numpy.ndarray], bool]] = {
|
49 |
+
"Eq": lambda a, b: numpy.allclose(a, b),
|
50 |
+
"Neq": lambda a, b: not numpy.allclose(a, b),
|
51 |
+
}
|
52 |
+
|
53 |
+
VEC_SCALAR_OPERATION: Mapping[str, Callable[[numpy.ndarray, float], numpy.ndarray]] = {
|
54 |
+
"Mul": lambda a, b: a * b,
|
55 |
+
"Div": lambda a, b: a / b,
|
56 |
+
}
|
57 |
+
|
58 |
+
|
59 |
+
def _vec2_from_numpy(a: numpy.ndarray) -> Vec2:
|
60 |
+
return (
|
61 |
+
float(a[0]),
|
62 |
+
float(a[1]),
|
63 |
+
)
|
64 |
+
|
65 |
+
|
66 |
+
def _vec3_from_numpy(a: numpy.ndarray) -> Vec3:
|
67 |
+
return (
|
68 |
+
float(a[0]),
|
69 |
+
float(a[1]),
|
70 |
+
float(a[2]),
|
71 |
+
)
|
72 |
+
|
73 |
+
|
74 |
+
def _vec4_from_numpy(a: numpy.ndarray) -> Vec4:
|
75 |
+
return (
|
76 |
+
float(a[0]),
|
77 |
+
float(a[1]),
|
78 |
+
float(a[2]),
|
79 |
+
float(a[3]),
|
80 |
+
)
|
81 |
+
|
82 |
+
|
83 |
+
class Vec2UnaryOperation:
|
84 |
+
@classmethod
|
85 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
86 |
+
return {
|
87 |
+
"required": {
|
88 |
+
"op": (list(VEC_UNARY_OPERATIONS.keys()),),
|
89 |
+
"a": DEFAULT_VEC2,
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
RETURN_TYPES = ("VEC2",)
|
94 |
+
FUNCTION = "op"
|
95 |
+
CATEGORY = "math/vec2"
|
96 |
+
|
97 |
+
def op(self, op: str, a: Vec2) -> tuple[Vec2]:
|
98 |
+
return (_vec2_from_numpy(VEC_UNARY_OPERATIONS[op](numpy.array(a))),)
|
99 |
+
|
100 |
+
|
101 |
+
class Vec2ToScalarUnaryOperation:
|
102 |
+
@classmethod
|
103 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
104 |
+
return {
|
105 |
+
"required": {
|
106 |
+
"op": (list(VEC_TO_SCALAR_UNARY_OPERATION.keys()),),
|
107 |
+
"a": DEFAULT_VEC2,
|
108 |
+
}
|
109 |
+
}
|
110 |
+
|
111 |
+
RETURN_TYPES = ("FLOAT",)
|
112 |
+
FUNCTION = "op"
|
113 |
+
CATEGORY = "math/vec2"
|
114 |
+
|
115 |
+
def op(self, op: str, a: Vec2) -> tuple[float]:
|
116 |
+
return (VEC_TO_SCALAR_UNARY_OPERATION[op](numpy.array(a)),)
|
117 |
+
|
118 |
+
|
119 |
+
class Vec2UnaryCondition:
|
120 |
+
@classmethod
|
121 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
122 |
+
return {
|
123 |
+
"required": {
|
124 |
+
"op": (list(VEC_UNARY_CONDITIONS.keys()),),
|
125 |
+
"a": DEFAULT_VEC2,
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
RETURN_TYPES = ("BOOL",)
|
130 |
+
FUNCTION = "op"
|
131 |
+
CATEGORY = "math/vec2"
|
132 |
+
|
133 |
+
def op(self, op: str, a: Vec2) -> tuple[bool]:
|
134 |
+
return (VEC_UNARY_CONDITIONS[op](numpy.array(a)),)
|
135 |
+
|
136 |
+
|
137 |
+
class Vec2BinaryOperation:
|
138 |
+
@classmethod
|
139 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
140 |
+
return {
|
141 |
+
"required": {
|
142 |
+
"op": (list(VEC_BINARY_OPERATIONS.keys()),),
|
143 |
+
"a": DEFAULT_VEC2,
|
144 |
+
"b": DEFAULT_VEC2,
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
RETURN_TYPES = ("VEC2",)
|
149 |
+
FUNCTION = "op"
|
150 |
+
CATEGORY = "math/vec2"
|
151 |
+
|
152 |
+
def op(self, op: str, a: Vec2, b: Vec2) -> tuple[Vec2]:
|
153 |
+
return (
|
154 |
+
_vec2_from_numpy(VEC_BINARY_OPERATIONS[op](numpy.array(a), numpy.array(b))),
|
155 |
+
)
|
156 |
+
|
157 |
+
|
158 |
+
class Vec2ToScalarBinaryOperation:
|
159 |
+
@classmethod
|
160 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
161 |
+
return {
|
162 |
+
"required": {
|
163 |
+
"op": (list(VEC_TO_SCALAR_BINARY_OPERATION.keys()),),
|
164 |
+
"a": DEFAULT_VEC2,
|
165 |
+
"b": DEFAULT_VEC2,
|
166 |
+
}
|
167 |
+
}
|
168 |
+
|
169 |
+
RETURN_TYPES = ("FLOAT",)
|
170 |
+
FUNCTION = "op"
|
171 |
+
CATEGORY = "math/vec2"
|
172 |
+
|
173 |
+
def op(self, op: str, a: Vec2, b: Vec2) -> tuple[float]:
|
174 |
+
return (VEC_TO_SCALAR_BINARY_OPERATION[op](numpy.array(a), numpy.array(b)),)
|
175 |
+
|
176 |
+
|
177 |
+
class Vec2BinaryCondition:
|
178 |
+
@classmethod
|
179 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
180 |
+
return {
|
181 |
+
"required": {
|
182 |
+
"op": (list(VEC_BINARY_CONDITIONS.keys()),),
|
183 |
+
"a": DEFAULT_VEC2,
|
184 |
+
"b": DEFAULT_VEC2,
|
185 |
+
}
|
186 |
+
}
|
187 |
+
|
188 |
+
RETURN_TYPES = ("BOOL",)
|
189 |
+
FUNCTION = "op"
|
190 |
+
CATEGORY = "math/vec2"
|
191 |
+
|
192 |
+
def op(self, op: str, a: Vec2, b: Vec2) -> tuple[bool]:
|
193 |
+
return (VEC_BINARY_CONDITIONS[op](numpy.array(a), numpy.array(b)),)
|
194 |
+
|
195 |
+
|
196 |
+
class Vec2ScalarOperation:
|
197 |
+
@classmethod
|
198 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
199 |
+
return {
|
200 |
+
"required": {
|
201 |
+
"op": (list(VEC_SCALAR_OPERATION.keys()),),
|
202 |
+
"a": DEFAULT_VEC2,
|
203 |
+
"b": ("FLOAT",),
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
RETURN_TYPES = ("VEC2",)
|
208 |
+
FUNCTION = "op"
|
209 |
+
CATEGORY = "math/vec2"
|
210 |
+
|
211 |
+
def op(self, op: str, a: Vec2, b: float) -> tuple[Vec2]:
|
212 |
+
return (_vec2_from_numpy(VEC_SCALAR_OPERATION[op](numpy.array(a), b)),)
|
213 |
+
|
214 |
+
|
215 |
+
class Vec3UnaryOperation:
|
216 |
+
@classmethod
|
217 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
218 |
+
return {
|
219 |
+
"required": {
|
220 |
+
"op": (list(VEC_UNARY_OPERATIONS.keys()),),
|
221 |
+
"a": DEFAULT_VEC3,
|
222 |
+
}
|
223 |
+
}
|
224 |
+
|
225 |
+
RETURN_TYPES = ("VEC3",)
|
226 |
+
FUNCTION = "op"
|
227 |
+
CATEGORY = "math/vec3"
|
228 |
+
|
229 |
+
def op(self, op: str, a: Vec3) -> tuple[Vec3]:
|
230 |
+
return (_vec3_from_numpy(VEC_UNARY_OPERATIONS[op](numpy.array(a))),)
|
231 |
+
|
232 |
+
|
233 |
+
class Vec3ToScalarUnaryOperation:
|
234 |
+
@classmethod
|
235 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
236 |
+
return {
|
237 |
+
"required": {
|
238 |
+
"op": (list(VEC_TO_SCALAR_UNARY_OPERATION.keys()),),
|
239 |
+
"a": DEFAULT_VEC3,
|
240 |
+
}
|
241 |
+
}
|
242 |
+
|
243 |
+
RETURN_TYPES = ("FLOAT",)
|
244 |
+
FUNCTION = "op"
|
245 |
+
CATEGORY = "math/vec3"
|
246 |
+
|
247 |
+
def op(self, op: str, a: Vec3) -> tuple[float]:
|
248 |
+
return (VEC_TO_SCALAR_UNARY_OPERATION[op](numpy.array(a)),)
|
249 |
+
|
250 |
+
|
251 |
+
class Vec3UnaryCondition:
|
252 |
+
@classmethod
|
253 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
254 |
+
return {
|
255 |
+
"required": {
|
256 |
+
"op": (list(VEC_UNARY_CONDITIONS.keys()),),
|
257 |
+
"a": DEFAULT_VEC3,
|
258 |
+
}
|
259 |
+
}
|
260 |
+
|
261 |
+
RETURN_TYPES = ("BOOL",)
|
262 |
+
FUNCTION = "op"
|
263 |
+
CATEGORY = "math/vec3"
|
264 |
+
|
265 |
+
def op(self, op: str, a: Vec3) -> tuple[bool]:
|
266 |
+
return (VEC_UNARY_CONDITIONS[op](numpy.array(a)),)
|
267 |
+
|
268 |
+
|
269 |
+
class Vec3BinaryOperation:
|
270 |
+
@classmethod
|
271 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
272 |
+
return {
|
273 |
+
"required": {
|
274 |
+
"op": (list(VEC_BINARY_OPERATIONS.keys()),),
|
275 |
+
"a": DEFAULT_VEC3,
|
276 |
+
"b": DEFAULT_VEC3,
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
RETURN_TYPES = ("VEC3",)
|
281 |
+
FUNCTION = "op"
|
282 |
+
CATEGORY = "math/vec3"
|
283 |
+
|
284 |
+
def op(self, op: str, a: Vec3, b: Vec3) -> tuple[Vec3]:
|
285 |
+
return (
|
286 |
+
_vec3_from_numpy(VEC_BINARY_OPERATIONS[op](numpy.array(a), numpy.array(b))),
|
287 |
+
)
|
288 |
+
|
289 |
+
|
290 |
+
class Vec3ToScalarBinaryOperation:
|
291 |
+
@classmethod
|
292 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
293 |
+
return {
|
294 |
+
"required": {
|
295 |
+
"op": (list(VEC_TO_SCALAR_BINARY_OPERATION.keys()),),
|
296 |
+
"a": DEFAULT_VEC3,
|
297 |
+
"b": DEFAULT_VEC3,
|
298 |
+
}
|
299 |
+
}
|
300 |
+
|
301 |
+
RETURN_TYPES = ("FLOAT",)
|
302 |
+
FUNCTION = "op"
|
303 |
+
CATEGORY = "math/vec3"
|
304 |
+
|
305 |
+
def op(self, op: str, a: Vec3, b: Vec3) -> tuple[float]:
|
306 |
+
return (VEC_TO_SCALAR_BINARY_OPERATION[op](numpy.array(a), numpy.array(b)),)
|
307 |
+
|
308 |
+
|
309 |
+
class Vec3BinaryCondition:
|
310 |
+
@classmethod
|
311 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
312 |
+
return {
|
313 |
+
"required": {
|
314 |
+
"op": (list(VEC_BINARY_CONDITIONS.keys()),),
|
315 |
+
"a": DEFAULT_VEC3,
|
316 |
+
"b": DEFAULT_VEC3,
|
317 |
+
}
|
318 |
+
}
|
319 |
+
|
320 |
+
RETURN_TYPES = ("BOOL",)
|
321 |
+
FUNCTION = "op"
|
322 |
+
CATEGORY = "math/vec3"
|
323 |
+
|
324 |
+
def op(self, op: str, a: Vec3, b: Vec3) -> tuple[bool]:
|
325 |
+
return (VEC_BINARY_CONDITIONS[op](numpy.array(a), numpy.array(b)),)
|
326 |
+
|
327 |
+
|
328 |
+
class Vec3ScalarOperation:
|
329 |
+
@classmethod
|
330 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
331 |
+
return {
|
332 |
+
"required": {
|
333 |
+
"op": (list(VEC_SCALAR_OPERATION.keys()),),
|
334 |
+
"a": DEFAULT_VEC3,
|
335 |
+
"b": ("FLOAT",),
|
336 |
+
}
|
337 |
+
}
|
338 |
+
|
339 |
+
RETURN_TYPES = ("VEC3",)
|
340 |
+
FUNCTION = "op"
|
341 |
+
CATEGORY = "math/vec3"
|
342 |
+
|
343 |
+
def op(self, op: str, a: Vec3, b: float) -> tuple[Vec3]:
|
344 |
+
return (_vec3_from_numpy(VEC_SCALAR_OPERATION[op](numpy.array(a), b)),)
|
345 |
+
|
346 |
+
|
347 |
+
class Vec4UnaryOperation:
|
348 |
+
@classmethod
|
349 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
350 |
+
return {
|
351 |
+
"required": {
|
352 |
+
"op": (list(VEC_UNARY_OPERATIONS.keys()),),
|
353 |
+
"a": DEFAULT_VEC4,
|
354 |
+
}
|
355 |
+
}
|
356 |
+
|
357 |
+
RETURN_TYPES = ("VEC4",)
|
358 |
+
FUNCTION = "op"
|
359 |
+
CATEGORY = "math/vec4"
|
360 |
+
|
361 |
+
def op(self, op: str, a: Vec4) -> tuple[Vec4]:
|
362 |
+
return (_vec4_from_numpy(VEC_UNARY_OPERATIONS[op](numpy.array(a))),)
|
363 |
+
|
364 |
+
|
365 |
+
class Vec4ToScalarUnaryOperation:
|
366 |
+
@classmethod
|
367 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
368 |
+
return {
|
369 |
+
"required": {
|
370 |
+
"op": (list(VEC_TO_SCALAR_UNARY_OPERATION.keys()),),
|
371 |
+
"a": DEFAULT_VEC4,
|
372 |
+
}
|
373 |
+
}
|
374 |
+
|
375 |
+
RETURN_TYPES = ("FLOAT",)
|
376 |
+
FUNCTION = "op"
|
377 |
+
CATEGORY = "math/vec4"
|
378 |
+
|
379 |
+
def op(self, op: str, a: Vec4) -> tuple[float]:
|
380 |
+
return (VEC_TO_SCALAR_UNARY_OPERATION[op](numpy.array(a)),)
|
381 |
+
|
382 |
+
|
383 |
+
class Vec4UnaryCondition:
|
384 |
+
@classmethod
|
385 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
386 |
+
return {
|
387 |
+
"required": {
|
388 |
+
"op": (list(VEC_UNARY_CONDITIONS.keys()),),
|
389 |
+
"a": DEFAULT_VEC4,
|
390 |
+
}
|
391 |
+
}
|
392 |
+
|
393 |
+
RETURN_TYPES = ("BOOL",)
|
394 |
+
FUNCTION = "op"
|
395 |
+
CATEGORY = "math/vec4"
|
396 |
+
|
397 |
+
def op(self, op: str, a: Vec4) -> tuple[bool]:
|
398 |
+
return (VEC_UNARY_CONDITIONS[op](numpy.array(a)),)
|
399 |
+
|
400 |
+
|
401 |
+
class Vec4BinaryOperation:
|
402 |
+
@classmethod
|
403 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
404 |
+
return {
|
405 |
+
"required": {
|
406 |
+
"op": (list(VEC_BINARY_OPERATIONS.keys()),),
|
407 |
+
"a": DEFAULT_VEC4,
|
408 |
+
"b": DEFAULT_VEC4,
|
409 |
+
}
|
410 |
+
}
|
411 |
+
|
412 |
+
RETURN_TYPES = ("VEC4",)
|
413 |
+
FUNCTION = "op"
|
414 |
+
CATEGORY = "math/vec4"
|
415 |
+
|
416 |
+
def op(self, op: str, a: Vec4, b: Vec4) -> tuple[Vec4]:
|
417 |
+
return (
|
418 |
+
_vec4_from_numpy(VEC_BINARY_OPERATIONS[op](numpy.array(a), numpy.array(b))),
|
419 |
+
)
|
420 |
+
|
421 |
+
|
422 |
+
class Vec4ToScalarBinaryOperation:
|
423 |
+
@classmethod
|
424 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
425 |
+
return {
|
426 |
+
"required": {
|
427 |
+
"op": (list(VEC_TO_SCALAR_BINARY_OPERATION.keys()),),
|
428 |
+
"a": DEFAULT_VEC4,
|
429 |
+
"b": DEFAULT_VEC4,
|
430 |
+
}
|
431 |
+
}
|
432 |
+
|
433 |
+
RETURN_TYPES = ("FLOAT",)
|
434 |
+
FUNCTION = "op"
|
435 |
+
CATEGORY = "math/vec4"
|
436 |
+
|
437 |
+
def op(self, op: str, a: Vec4, b: Vec4) -> tuple[float]:
|
438 |
+
return (VEC_TO_SCALAR_BINARY_OPERATION[op](numpy.array(a), numpy.array(b)),)
|
439 |
+
|
440 |
+
|
441 |
+
class Vec4BinaryCondition:
|
442 |
+
@classmethod
|
443 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
444 |
+
return {
|
445 |
+
"required": {
|
446 |
+
"op": (list(VEC_BINARY_CONDITIONS.keys()),),
|
447 |
+
"a": DEFAULT_VEC4,
|
448 |
+
"b": DEFAULT_VEC4,
|
449 |
+
}
|
450 |
+
}
|
451 |
+
|
452 |
+
RETURN_TYPES = ("BOOL",)
|
453 |
+
FUNCTION = "op"
|
454 |
+
CATEGORY = "math/vec4"
|
455 |
+
|
456 |
+
def op(self, op: str, a: Vec4, b: Vec4) -> tuple[bool]:
|
457 |
+
return (VEC_BINARY_CONDITIONS[op](numpy.array(a), numpy.array(b)),)
|
458 |
+
|
459 |
+
|
460 |
+
class Vec4ScalarOperation:
|
461 |
+
@classmethod
|
462 |
+
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
463 |
+
return {
|
464 |
+
"required": {
|
465 |
+
"op": (list(VEC_SCALAR_OPERATION.keys()),),
|
466 |
+
"a": DEFAULT_VEC4,
|
467 |
+
"b": ("FLOAT",),
|
468 |
+
}
|
469 |
+
}
|
470 |
+
|
471 |
+
RETURN_TYPES = ("VEC4",)
|
472 |
+
FUNCTION = "op"
|
473 |
+
CATEGORY = "math/vec4"
|
474 |
+
|
475 |
+
def op(self, op: str, a: Vec4, b: float) -> tuple[Vec4]:
|
476 |
+
return (_vec4_from_numpy(VEC_SCALAR_OPERATION[op](numpy.array(a), b)),)
|
477 |
+
|
478 |
+
|
479 |
+
NODE_CLASS_MAPPINGS = {
|
480 |
+
"CM_Vec2UnaryOperation": Vec2UnaryOperation,
|
481 |
+
"CM_Vec2UnaryCondition": Vec2UnaryCondition,
|
482 |
+
"CM_Vec2ToScalarUnaryOperation": Vec2ToScalarUnaryOperation,
|
483 |
+
"CM_Vec2BinaryOperation": Vec2BinaryOperation,
|
484 |
+
"CM_Vec2BinaryCondition": Vec2BinaryCondition,
|
485 |
+
"CM_Vec2ToScalarBinaryOperation": Vec2ToScalarBinaryOperation,
|
486 |
+
"CM_Vec2ScalarOperation": Vec2ScalarOperation,
|
487 |
+
"CM_Vec3UnaryOperation": Vec3UnaryOperation,
|
488 |
+
"CM_Vec3UnaryCondition": Vec3UnaryCondition,
|
489 |
+
"CM_Vec3ToScalarUnaryOperation": Vec3ToScalarUnaryOperation,
|
490 |
+
"CM_Vec3BinaryOperation": Vec3BinaryOperation,
|
491 |
+
"CM_Vec3BinaryCondition": Vec3BinaryCondition,
|
492 |
+
"CM_Vec3ToScalarBinaryOperation": Vec3ToScalarBinaryOperation,
|
493 |
+
"CM_Vec3ScalarOperation": Vec3ScalarOperation,
|
494 |
+
"CM_Vec4UnaryOperation": Vec4UnaryOperation,
|
495 |
+
"CM_Vec4UnaryCondition": Vec4UnaryCondition,
|
496 |
+
"CM_Vec4ToScalarUnaryOperation": Vec4ToScalarUnaryOperation,
|
497 |
+
"CM_Vec4BinaryOperation": Vec4BinaryOperation,
|
498 |
+
"CM_Vec4BinaryCondition": Vec4BinaryCondition,
|
499 |
+
"CM_Vec4ToScalarBinaryOperation": Vec4ToScalarBinaryOperation,
|
500 |
+
"CM_Vec4ScalarOperation": Vec4ScalarOperation,
|
501 |
+
}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/README.md
ADDED
@@ -0,0 +1,175 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Abandon this boat and jump on [this one!](https://github.com/Extraltodeus/Skimmed_CFG)
|
2 |
+
|
3 |
+
If you liked other functionnalities, I've re-created most in [this](https://github.com/Extraltodeus/pre_cfg_comfy_nodes_for_ComfyUI) repository.
|
4 |
+
|
5 |
+
# In short:
|
6 |
+
|
7 |
+
My own version "from scratch" of a self-rescaling CFG / anti-burn. It ain't much but it's honest work.
|
8 |
+
|
9 |
+
No more burns and 160% faster gens with the warp drive node.
|
10 |
+
|
11 |
+
Now includes custom attention modifiers and interesting presets as well as temperature scaling.
|
12 |
+
|
13 |
+
Also just tested and it works with pixart sigma.
|
14 |
+
|
15 |
+
Works with SD3 for as long as you don't use any boost feature / cutting the uncond (it's the same thing). 20 steps works nicely.
|
16 |
+
|
17 |
+
# Note:
|
18 |
+
|
19 |
+
The presets are interpreted with eval(). Make sure that you thrust whoever sent a preset to you as it may be used to execute malicious code.
|
20 |
+
|
21 |
+
# Update:
|
22 |
+
|
23 |
+
- Removed and perfected "Uncond Zero" node and moved it to it's [own repository](https://github.com/Extraltodeus/Uncond-Zero-for-ComfyUI/tree/main)
|
24 |
+
- Removed temperature nodes and set a [repository](https://github.com/Extraltodeus/Stable-Diffusion-temperature-settings) for these
|
25 |
+
|
26 |
+
# Usage:
|
27 |
+
|
28 |
+
![77889aa6-a2f6-48bf-8cde-17c9cbfda5fa](https://github.com/Extraltodeus/ComfyUI-AutomaticCFG/assets/15731540/c725a06c-8966-43de-ab1c-569e2ff5b151)
|
29 |
+
|
30 |
+
|
31 |
+
### That's it!
|
32 |
+
|
33 |
+
- The "boost" toggle will turn off the negative guidance when the sigmas are near 1. This doubles the inference speed.
|
34 |
+
- The negative strength lerp the cond and uncond. Now in normal times the way I do this would burn things to the ground. But since it is initialy an anti-burn it just works. This idea is inspired by the [negative prompt weight](https://github.com/muerrilla/stable-diffusion-NPW) repository.
|
35 |
+
- I leave the advanced node for those who are interested. It will not be beneficial to those who do not feel like experimenting.
|
36 |
+
|
37 |
+
For 100 steps this is where the sigma are reaching 1:
|
38 |
+
|
39 |
+
![image](https://github.com/Extraltodeus/ComfyUI-AutomaticCFG/assets/15731540/525199f1-2857-4027-a96e-105bc4b01860)
|
40 |
+
|
41 |
+
Note: the warp drive node improves the speed a lot more. The average speed is 160% the normal one if used with the AYS scheduler (check the workflow images).
|
42 |
+
|
43 |
+
There seem to be a slight improvement in quality when using the boost with my other node [CLIP Vector Sculptor text encode](https://github.com/Extraltodeus/Vector_Sculptor_ComfyUI) using the "mean" normalization option.
|
44 |
+
|
45 |
+
# Just a note:
|
46 |
+
|
47 |
+
Your CFG won't be your CFG anymore. It is turned into a way to guide the CFG/final intensity/brightness/saturation. So don't hesitate to change your habits while trying!
|
48 |
+
|
49 |
+
# The rest of the explaination:
|
50 |
+
|
51 |
+
While this node is connected, this will turn your sampler's CFG scale into something else.
|
52 |
+
This methods works by rescaling the CFG at each step by evaluating the potential average min/max values. Aiming at a desired output intensity (by intensity I mean overall brightness/saturation/sharpness).
|
53 |
+
The base intensity has been arbitrarily chosen by me and your sampler's CFG scale will make this target vary.
|
54 |
+
I have set the "central" CFG at 8. Meaning that at 4 you will aim at half of the desired range while at 16 it will be doubled. This makes it feel slightly like the usual when you're around the normal values.
|
55 |
+
|
56 |
+
The CFG behavior during the sampling being automatically set for each channel makes it behave differently and therefores gives different outputs than the usual.
|
57 |
+
From my observations by printing the results while testing, it seems to be going from around 16 at the beginning, to something like 4 near the middle and ends up near ~7.
|
58 |
+
These values might have changed since I've done a thousand tests with different ways but that's to give you an idea, it's just me eyeballing the CLI's output.
|
59 |
+
|
60 |
+
I use the upper and lower 25% topk mean value as a reference to have some margin of manoeuver.
|
61 |
+
|
62 |
+
It makes the sampling generate overall better quality images. I get much less if not any artifacts anymore and my more creative prompts also tends to give more random, in a good way, different results.
|
63 |
+
|
64 |
+
I attribute this more random yet positive behavior to the fact that it seems to be starting high and then since it becomes lower, it self-corrects and improvise, taking advantage of the sampling process a lot more.
|
65 |
+
|
66 |
+
It is dead simple to use and made sampling more fun from my perspective :)
|
67 |
+
|
68 |
+
You will find it in the model_patches category.
|
69 |
+
|
70 |
+
TLDR: set your CFG at 8 to try it. No burned images and artifacts anymore. CFG is also a bit more sensitive because it's a proportion around 8.
|
71 |
+
|
72 |
+
Low scale like 4 also gives really nice results since your CFG is not the CFG anymore.
|
73 |
+
|
74 |
+
# Updates:
|
75 |
+
|
76 |
+
Updated:
|
77 |
+
- Up to 28.5% faster generation speed than normal
|
78 |
+
- Negative weighting
|
79 |
+
|
80 |
+
05.04.24:
|
81 |
+
|
82 |
+
- Updated to latest ComfyUI version. If you get an error: update your ComfyUI
|
83 |
+
|
84 |
+
15.04.24
|
85 |
+
|
86 |
+
- ~~Added "no uncond" node which completely disable the negative and doubles the speed while rescaling the latent space in the post-cfg function up until the sigmas are at 1 (or really, 6.86%). By itself it is not perfect and I'm searching for solutions to improve the final result. It seems to work better with dpmpp3m_sde/exponential if you're not using anything else. If you are using the PAG node then you don't need to care about the sampler but will generate at a normal speed. Result will be simply different (I personally like them).~~ use the warp drive instead
|
87 |
+
- To use the [PAG node](https://github.com/pamparamm/sd-perturbed-attention/tree/master) ~~without the complete slow-down (if using the no-uncond node) or at least take advantage of the boost feature:~~
|
88 |
+
~~- in the "pag_nodes.py" file look for "disable_cfg1_optimization=True"~~
|
89 |
+
~~- set it to "disable_cfg1_optimization=False".~~ This is not necessary anymore because the dev modified it already :)
|
90 |
+
- For the negative lerp function in the other nodes the scale has been divided by two. So if you were using it at 10, set it to 5.
|
91 |
+
|
92 |
+
16.04.24
|
93 |
+
|
94 |
+
- Added "uncond_start_percentage" as an experimental feature. This allows to start the guidance later as a way to try [Applying Guidance in a Limited Interval Improves
|
95 |
+
Sample and Distribution Quality in Diffusion Models](https://arxiv.org/pdf/2404.07724.pdf). A more accurate implementation [can be found here](https://github.com/ericbeyer/guidance_interval) :)
|
96 |
+
|
97 |
+
17.04.24
|
98 |
+
|
99 |
+
- reworked the advanced node and cleaned up
|
100 |
+
- added timing on every options
|
101 |
+
- add a post-rescale node which allows to fight deep-frying images a bit more forr some special cases
|
102 |
+
- added a tweaked version of the Comfy SAG node with start/end sliders
|
103 |
+
- changed start/end sliders, they are related directly to the sigma values and not in percentage anymore. ⚠
|
104 |
+
|
105 |
+
01.05.24
|
106 |
+
|
107 |
+
- Actually working disabled uncond
|
108 |
+
- Added "warp drive" preset to test it out simply.
|
109 |
+
|
110 |
+
03.05.24
|
111 |
+
|
112 |
+
- Allows unpatch `turn off the negative` by removing or disconnecting the node.
|
113 |
+
- added the "Warp drive" node. It uses a new method of my own cooking which uses the previous step to determin a negative. Cutting the generation time by half for approx 3/4 of the steps.
|
114 |
+
- added example workflows with 10-12 steps but of course you can do more steps if needed. It is not a goal to do less steps in general but also to show it is compatible.
|
115 |
+
|
116 |
+
14.05.24:
|
117 |
+
- fix the little mem leak 😀
|
118 |
+
- temporarily disabled the timed SAG node because an update broke it.
|
119 |
+
- added node: **preset loader**. Can do what the other can and much more like modify the attention mechanisms! Mostly tested on SDXL 😀!
|
120 |
+
- Some presets are slower than others. Just like for the perturbed attention guidance for example. Most are just as fast.
|
121 |
+
- About some of the presets:
|
122 |
+
- For SD 1.5 "crossed conds customized 3" seems amazing!
|
123 |
+
- "Enhanced_details_and_tweaked_attention" works better on creative generations and less on characters.
|
124 |
+
- "Reinforced_style" does not regulates the CFG, gives MUCH MORE importance to your negative prompt, works with 12 steps and is slightly slower.
|
125 |
+
- "The red riding latent" only works with SDXL. It is an almost nonsensical mix of attention tweaks. Best with 12 steps and really nice with creative prompts. Has the tendency to give more red clothings to the characters. Hence the name.
|
126 |
+
- "Excellent_attention" is the default settings for the node described below. Don't delete it or the node won't work. 🙃
|
127 |
+
- "Potato Attention Guidance" is really nice for portraits of happy people...
|
128 |
+
- There are a bunch of others. I've generated examples which you can find in the example grids folder.
|
129 |
+
- Most of these have been tested on SDXL. I have very little idea of the effect on SD 1.5
|
130 |
+
- The presets are .json files and can contain a string which will go through eval(). ⚠
|
131 |
+
- Always check what is inside before running it when it comes from someone else! I hesitated to share a preset which would plan a shutdown in 60 seconds named "actually shut down the computer in one minute" to let you be aware but that would bother more than it would be helfpul.
|
132 |
+
- added node: "**Excellent attention**" developped by myself and based on this [astonishingly easy to understand research paper!](https://github.com/Extraltodeus/temp/blob/main/very_science.jpg) But in short:
|
133 |
+
- Just try it. [Do it](https://www.youtube.com/watch?v=ZXsQAXx_ao0).
|
134 |
+
- This node allows to disable the input layer 8 on self and cross attention.
|
135 |
+
- But also to apply a custom modification on cross attention middle layer 0. The "patch_cond" and "patch_uncond" toggles are about this modification.
|
136 |
+
- While the modification is definitely not very ressource costy, the light patch uses less VRAM.
|
137 |
+
- The multiplier influences the cross attention and reinforces prompt-following. But like for real. Works better with the "light patch" toggle ON.
|
138 |
+
- I have ~~only~~ mostly tested it with SDXL.
|
139 |
+
- You can find a grid example of this node's settings in the "grids_example" folder.
|
140 |
+
- For some reason the Juggernaut model does not work with it and I have no idea why.
|
141 |
+
- Customizable attention modifiers:
|
142 |
+
- Check the ["attention_modifiers_explainations"](https://github.com/Extraltodeus/ComfyUI-AutomaticCFG/blob/main/workflows/attention_modifiers_explainations.png) in the workflows. 👀 It is basically a tutorial.
|
143 |
+
- Experiment what each layer really do by using what is basically a bruteforcing node! (the Attention modifiers tester node)
|
144 |
+
- This is how you do a [Perturbed Attention Guidance](https://github.com/Extraltodeus/temp/blob/main/PAG.png) for example
|
145 |
+
|
146 |
+
|
147 |
+
|
148 |
+
# Examples
|
149 |
+
|
150 |
+
### 10 steps with only 2 having the negative enabled. So ~170% faster. 2.5 seconds on a RTX4070
|
151 |
+
|
152 |
+
![03640UI_00001_](https://github.com/Extraltodeus/ComfyUI-AutomaticCFG/assets/15731540/673cb47a-095f-4ebb-a186-2f6a49ffd2e1)
|
153 |
+
|
154 |
+
### cherry-picked 24 steps uncond fully disabled (these images are also workflows):
|
155 |
+
|
156 |
+
|
157 |
+
![03619UI_00001_](https://github.com/Extraltodeus/ComfyUI-AutomaticCFG/assets/15731540/19ee6edc-b039-4472-9ec2-c08ea15dd908)
|
158 |
+
|
159 |
+
![03621UI_00001_](https://github.com/Extraltodeus/ComfyUI-AutomaticCFG/assets/15731540/52695e1c-d28e-427f-9109-7ee4e4b3a5f6)
|
160 |
+
|
161 |
+
![03604UI_00001_](https://github.com/Extraltodeus/ComfyUI-AutomaticCFG/assets/15731540/ca391b46-f587-43da-98da-a87e4982e4ed)
|
162 |
+
|
163 |
+
|
164 |
+
|
165 |
+
# Pro tip:
|
166 |
+
|
167 |
+
Did you know that my first activity is to write creative model merging functions?
|
168 |
+
|
169 |
+
While the code is too much of a mess to be shared, I do expose and share my models. You can find them in this [gallery](https://github.com/Extraltodeus/shared_models_galleries)! 😁
|
170 |
+
|
171 |
+
|
172 |
+
-----
|
173 |
+
|
174 |
+
Thanks to ComfyUI for existing and making such things so simple!
|
175 |
+
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__init__.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .nodes import *
|
2 |
+
# from .experimental_temperature import ExperimentalTemperaturePatchSDXL,ExperimentalTemperaturePatchSD15,CLIPTemperaturePatch,CLIPTemperaturePatchDual
|
3 |
+
# from .nodes_sag_custom import *
|
4 |
+
|
5 |
+
NODE_CLASS_MAPPINGS = {
|
6 |
+
"Automatic CFG": simpleDynamicCFG,
|
7 |
+
"Automatic CFG - Negative": simpleDynamicCFGlerpUncond,
|
8 |
+
"Automatic CFG - Warp Drive": simpleDynamicCFGwarpDrive,
|
9 |
+
"Automatic CFG - Preset Loader": presetLoader,
|
10 |
+
"Automatic CFG - Excellent attention": simpleDynamicCFGExcellentattentionPatch,
|
11 |
+
"Automatic CFG - Advanced": advancedDynamicCFG,
|
12 |
+
"Automatic CFG - Post rescale only": postCFGrescaleOnly,
|
13 |
+
"Automatic CFG - Custom attentions": simpleDynamicCFGCustomAttentionPatch,
|
14 |
+
"Automatic CFG - Attention modifiers": attentionModifierParametersNode,
|
15 |
+
"Automatic CFG - Attention modifiers tester": attentionModifierBruteforceParametersNode,
|
16 |
+
"Automatic CFG - Unpatch function": simpleDynamicCFGunpatch,
|
17 |
+
# "Zero Uncond CFG - standalone patch (incompatible with the others)":uncondZeroNode,
|
18 |
+
# "Temperature settings SDXL": ExperimentalTemperaturePatchSDXL,
|
19 |
+
# "Temperature settings SD 1.5": ExperimentalTemperaturePatchSD15,
|
20 |
+
# "Temperature settings CLIP": CLIPTemperaturePatch,
|
21 |
+
# "Temperature separate settings CLIP SDXL": CLIPTemperaturePatchDual,
|
22 |
+
# "SAG delayed activation": SelfAttentionGuidanceCustom,
|
23 |
+
}
|
24 |
+
|
25 |
+
NODE_DISPLAY_NAME_MAPPINGS = {
|
26 |
+
"Automatic CFG - Unpatch function": "Automatic CFG - Unpatch function(Deprecated)",
|
27 |
+
}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (1 kB). View file
|
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__pycache__/experimental_temperature.cpython-310.pyc
ADDED
Binary file (7.42 kB). View file
|
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__pycache__/nodes.cpython-310.pyc
ADDED
Binary file (46.2 kB). View file
|
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/experimental_temperature.py
ADDED
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from torch import nn, einsum
|
3 |
+
from einops import rearrange, repeat
|
4 |
+
import torch.nn.functional as F
|
5 |
+
import math
|
6 |
+
from comfy import model_management
|
7 |
+
import types
|
8 |
+
import os
|
9 |
+
|
10 |
+
def exists(val):
|
11 |
+
return val is not None
|
12 |
+
|
13 |
+
# better than a division by 0 hey
|
14 |
+
abs_mean = lambda x: torch.where(torch.isnan(x) | torch.isinf(x), torch.zeros_like(x), x).abs().mean()
|
15 |
+
|
16 |
+
class temperature_patcher():
|
17 |
+
def __init__(self, temperature, layer_name="None"):
|
18 |
+
self.temperature = temperature
|
19 |
+
self.layer_name = layer_name
|
20 |
+
|
21 |
+
# taken from comfy.ldm.modules
|
22 |
+
def attention_basic_with_temperature(self, q, k, v, extra_options, mask=None, attn_precision=None):
|
23 |
+
if isinstance(extra_options, int):
|
24 |
+
heads = extra_options
|
25 |
+
else:
|
26 |
+
heads = extra_options['n_heads']
|
27 |
+
|
28 |
+
b, _, dim_head = q.shape
|
29 |
+
dim_head //= heads
|
30 |
+
scale = dim_head ** -0.5
|
31 |
+
|
32 |
+
h = heads
|
33 |
+
q, k, v = map(
|
34 |
+
lambda t: t.unsqueeze(3)
|
35 |
+
.reshape(b, -1, heads, dim_head)
|
36 |
+
.permute(0, 2, 1, 3)
|
37 |
+
.reshape(b * heads, -1, dim_head)
|
38 |
+
.contiguous(),
|
39 |
+
(q, k, v),
|
40 |
+
)
|
41 |
+
|
42 |
+
# force cast to fp32 to avoid overflowing
|
43 |
+
if attn_precision == torch.float32:
|
44 |
+
sim = einsum('b i d, b j d -> b i j', q.float(), k.float()) * scale
|
45 |
+
else:
|
46 |
+
sim = einsum('b i d, b j d -> b i j', q, k) * scale
|
47 |
+
|
48 |
+
del q, k
|
49 |
+
|
50 |
+
if exists(mask):
|
51 |
+
if mask.dtype == torch.bool:
|
52 |
+
mask = rearrange(mask, 'b ... -> b (...)')
|
53 |
+
max_neg_value = -torch.finfo(sim.dtype).max
|
54 |
+
mask = repeat(mask, 'b j -> (b h) () j', h=h)
|
55 |
+
sim.masked_fill_(~mask, max_neg_value)
|
56 |
+
else:
|
57 |
+
if len(mask.shape) == 2:
|
58 |
+
bs = 1
|
59 |
+
else:
|
60 |
+
bs = mask.shape[0]
|
61 |
+
mask = mask.reshape(bs, -1, mask.shape[-2], mask.shape[-1]).expand(b, heads, -1, -1).reshape(-1, mask.shape[-2], mask.shape[-1])
|
62 |
+
sim.add_(mask)
|
63 |
+
|
64 |
+
# attention, what we cannot get enough of
|
65 |
+
sim = sim.div(self.temperature if self.temperature > 0 else abs_mean(sim)).softmax(dim=-1)
|
66 |
+
|
67 |
+
out = einsum('b i j, b j d -> b i d', sim.to(v.dtype), v)
|
68 |
+
out = (
|
69 |
+
out.unsqueeze(0)
|
70 |
+
.reshape(b, heads, -1, dim_head)
|
71 |
+
.permute(0, 2, 1, 3)
|
72 |
+
.reshape(b, -1, heads * dim_head)
|
73 |
+
)
|
74 |
+
return out
|
75 |
+
|
76 |
+
layers_SD15 = {
|
77 |
+
"input":[1,2,4,5,7,8],
|
78 |
+
"middle":[0],
|
79 |
+
"output":[3,4,5,6,7,8,9,10,11],
|
80 |
+
}
|
81 |
+
|
82 |
+
layers_SDXL = {
|
83 |
+
"input":[4,5,7,8],
|
84 |
+
"middle":[0],
|
85 |
+
"output":[0,1,2,3,4,5],
|
86 |
+
}
|
87 |
+
|
88 |
+
class ExperimentalTemperaturePatch:
|
89 |
+
@classmethod
|
90 |
+
def INPUT_TYPES(s):
|
91 |
+
required_inputs = {f"{key}_{layer}": ("BOOLEAN", {"default": False}) for key, layers in s.TOGGLES.items() for layer in layers}
|
92 |
+
required_inputs["model"] = ("MODEL",)
|
93 |
+
required_inputs["Temperature"] = ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": 0.01})
|
94 |
+
required_inputs["Attention"] = (["both","self","cross"],)
|
95 |
+
return {"required": required_inputs}
|
96 |
+
|
97 |
+
TOGGLES = {}
|
98 |
+
RETURN_TYPES = ("MODEL","STRING",)
|
99 |
+
RETURN_NAMES = ("Model","String",)
|
100 |
+
FUNCTION = "patch"
|
101 |
+
|
102 |
+
CATEGORY = "model_patches/Automatic_CFG/Standalone_temperature_patches"
|
103 |
+
|
104 |
+
def patch(self, model, Temperature, Attention, **kwargs):
|
105 |
+
m = model.clone()
|
106 |
+
levels = ["input","middle","output"]
|
107 |
+
parameters_output = {level:[] for level in levels}
|
108 |
+
for key, toggle_enabled in kwargs.items():
|
109 |
+
current_level = key.split("_")[0]
|
110 |
+
if current_level in levels and toggle_enabled:
|
111 |
+
b_number = int(key.split("_")[1])
|
112 |
+
parameters_output[current_level].append(b_number)
|
113 |
+
patcher = temperature_patcher(Temperature,key)
|
114 |
+
|
115 |
+
if Attention in ["both","self"]:
|
116 |
+
m.set_model_attn1_replace(patcher.attention_basic_with_temperature, current_level, b_number)
|
117 |
+
if Attention in ["both","cross"]:
|
118 |
+
m.set_model_attn2_replace(patcher.attention_basic_with_temperature, current_level, b_number)
|
119 |
+
|
120 |
+
parameters_as_string = "\n".join(f"{k}: {','.join(map(str, v))}" for k, v in parameters_output.items())
|
121 |
+
parameters_as_string = f"Temperature: {Temperature}\n{parameters_as_string}\nAttention: {Attention}"
|
122 |
+
return (m, parameters_as_string,)
|
123 |
+
|
124 |
+
ExperimentalTemperaturePatchSDXL = type("ExperimentalTemperaturePatch_SDXL", (ExperimentalTemperaturePatch,), {"TOGGLES": layers_SDXL})
|
125 |
+
ExperimentalTemperaturePatchSD15 = type("ExperimentalTemperaturePatch_SD15", (ExperimentalTemperaturePatch,), {"TOGGLES": layers_SD15})
|
126 |
+
|
127 |
+
class CLIPTemperaturePatch:
|
128 |
+
@classmethod
|
129 |
+
def INPUT_TYPES(cls):
|
130 |
+
return {"required": { "clip": ("CLIP",),
|
131 |
+
"Temperature": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
|
132 |
+
}}
|
133 |
+
|
134 |
+
RETURN_TYPES = ("CLIP",)
|
135 |
+
FUNCTION = "patch"
|
136 |
+
CATEGORY = "model_patches/Automatic_CFG/Standalone_temperature_patches"
|
137 |
+
|
138 |
+
def patch(self, clip, Temperature):
|
139 |
+
def custom_optimized_attention(device, mask=None, small_input=True):
|
140 |
+
return temperature_patcher(Temperature).attention_basic_with_temperature
|
141 |
+
|
142 |
+
def new_forward(self, x, mask=None, intermediate_output=None):
|
143 |
+
optimized_attention = custom_optimized_attention(x.device, mask=mask is not None, small_input=True)
|
144 |
+
|
145 |
+
if intermediate_output is not None:
|
146 |
+
if intermediate_output < 0:
|
147 |
+
intermediate_output = len(self.layers) + intermediate_output
|
148 |
+
|
149 |
+
intermediate = None
|
150 |
+
for i, l in enumerate(self.layers):
|
151 |
+
x = l(x, mask, optimized_attention)
|
152 |
+
if i == intermediate_output:
|
153 |
+
intermediate = x.clone()
|
154 |
+
return x, intermediate
|
155 |
+
|
156 |
+
m = clip.clone()
|
157 |
+
|
158 |
+
clip_encoder_instance = m.cond_stage_model.clip_l.transformer.text_model.encoder
|
159 |
+
clip_encoder_instance.forward = types.MethodType(new_forward, clip_encoder_instance)
|
160 |
+
|
161 |
+
if getattr(m.cond_stage_model, f"clip_g", None) is not None:
|
162 |
+
clip_encoder_instance_g = m.cond_stage_model.clip_g.transformer.text_model.encoder
|
163 |
+
clip_encoder_instance_g.forward = types.MethodType(new_forward, clip_encoder_instance_g)
|
164 |
+
|
165 |
+
return (m,)
|
166 |
+
|
167 |
+
class CLIPTemperaturePatchDual:
|
168 |
+
@classmethod
|
169 |
+
def INPUT_TYPES(cls):
|
170 |
+
return {"required": { "clip": ("CLIP",),
|
171 |
+
"Temperature": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
|
172 |
+
"CLIP_Model": (["clip_g","clip_l","both"],),
|
173 |
+
}}
|
174 |
+
|
175 |
+
RETURN_TYPES = ("CLIP",)
|
176 |
+
FUNCTION = "patch"
|
177 |
+
CATEGORY = "model_patches/Automatic_CFG/Standalone_temperature_patches"
|
178 |
+
|
179 |
+
def patch(self, clip, Temperature, CLIP_Model):
|
180 |
+
def custom_optimized_attention(device, mask=None, small_input=True):
|
181 |
+
return temperature_patcher(Temperature, "CLIP").attention_basic_with_temperature
|
182 |
+
|
183 |
+
def new_forward(self, x, mask=None, intermediate_output=None):
|
184 |
+
optimized_attention = custom_optimized_attention(x.device, mask=mask is not None, small_input=True)
|
185 |
+
|
186 |
+
if intermediate_output is not None:
|
187 |
+
if intermediate_output < 0:
|
188 |
+
intermediate_output = len(self.layers) + intermediate_output
|
189 |
+
|
190 |
+
intermediate = None
|
191 |
+
for i, l in enumerate(self.layers):
|
192 |
+
x = l(x, mask, optimized_attention)
|
193 |
+
if i == intermediate_output:
|
194 |
+
intermediate = x.clone()
|
195 |
+
return x, intermediate
|
196 |
+
|
197 |
+
m = clip.clone()
|
198 |
+
|
199 |
+
if CLIP_Model in ["clip_l","both"]:
|
200 |
+
clip_encoder_instance = m.cond_stage_model.clip_l.transformer.text_model.encoder
|
201 |
+
clip_encoder_instance.forward = types.MethodType(new_forward, clip_encoder_instance)
|
202 |
+
|
203 |
+
if CLIP_Model in ["clip_g","both"]:
|
204 |
+
if getattr(m.cond_stage_model, f"clip_g", None) is not None:
|
205 |
+
clip_encoder_instance_g = m.cond_stage_model.clip_g.transformer.text_model.encoder
|
206 |
+
clip_encoder_instance_g.forward = types.MethodType(new_forward, clip_encoder_instance_g)
|
207 |
+
|
208 |
+
return (m,)
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/Enhanced_details_and_tweaked_attention.png
ADDED
Git LFS Details
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/Iris_Lux_v1051_base_image_vanilla_sampling.png
ADDED
Git LFS Details
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_a.jpg
ADDED
Git LFS Details
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_b.jpg
ADDED
Git LFS Details
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/presets.jpg
ADDED
Git LFS Details
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/nodes.py
ADDED
@@ -0,0 +1,1292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
from copy import deepcopy
|
3 |
+
from torch.nn import Upsample
|
4 |
+
import comfy.model_management as model_management
|
5 |
+
from comfy.model_patcher import set_model_options_patch_replace
|
6 |
+
from comfy.ldm.modules.attention import attention_basic, attention_xformers, attention_pytorch, attention_split, attention_sub_quad, optimized_attention_for_device
|
7 |
+
from .experimental_temperature import temperature_patcher
|
8 |
+
import comfy.samplers
|
9 |
+
import comfy.utils
|
10 |
+
import numpy as np
|
11 |
+
import torch
|
12 |
+
import torch.nn.functional as F
|
13 |
+
from colorama import Fore, Style
|
14 |
+
import json
|
15 |
+
import os
|
16 |
+
import random
|
17 |
+
import base64
|
18 |
+
|
19 |
+
original_sampling_function = None
|
20 |
+
current_dir = os.path.dirname(os.path.realpath(__file__))
|
21 |
+
json_preset_path = os.path.join(current_dir, 'presets')
|
22 |
+
attnfunc = optimized_attention_for_device(model_management.get_torch_device())
|
23 |
+
check_string = "UEFUUkVPTi50eHQ="
|
24 |
+
support_string = b'CgoKClRoYW5rIHlvdSBmb3IgdXNpbmcgbXkgbm9kZXMhCgpJZiB5b3UgZW5qb3kgaXQsIHBsZWFzZSBjb25zaWRlciBzdXBwb3J0aW5nIG1lIG9uIFBhdHJlb24gdG8ga2VlcCB0aGUgbWFnaWMgZ29pbmchCgpWaXNpdDoKCmh0dHBzOi8vd3d3LnBhdHJlb24uY29tL2V4dHJhbHRvZGV1cwoKCgo='
|
25 |
+
|
26 |
+
def support_function():
|
27 |
+
if base64.b64decode(check_string).decode('utf8') not in os.listdir(current_dir):
|
28 |
+
print(base64.b64decode(check_string).decode('utf8'))
|
29 |
+
print(base64.b64decode(support_string).decode('utf8'))
|
30 |
+
|
31 |
+
def sampling_function_patched(model, x, timestep, uncond, cond, cond_scale, model_options={}, seed=None, **kwargs):
|
32 |
+
|
33 |
+
cond_copy = cond
|
34 |
+
uncond_copy = uncond
|
35 |
+
|
36 |
+
for fn in model_options.get("sampler_patch_model_pre_cfg_function", []):
|
37 |
+
args = {"model": model, "sigma": timestep, "model_options": model_options}
|
38 |
+
model, model_options = fn(args)
|
39 |
+
|
40 |
+
if "sampler_pre_cfg_automatic_cfg_function" in model_options:
|
41 |
+
uncond, cond, cond_scale = model_options["sampler_pre_cfg_automatic_cfg_function"](
|
42 |
+
sigma=timestep, uncond=uncond, cond=cond, cond_scale=cond_scale
|
43 |
+
)
|
44 |
+
|
45 |
+
if math.isclose(cond_scale, 1.0) and model_options.get("disable_cfg1_optimization", False) == False:
|
46 |
+
uncond_ = None
|
47 |
+
else:
|
48 |
+
uncond_ = uncond
|
49 |
+
|
50 |
+
conds = [cond, uncond_]
|
51 |
+
|
52 |
+
out = comfy.samplers.calc_cond_batch(model, conds, x, timestep, model_options)
|
53 |
+
|
54 |
+
for fn in model_options.get("sampler_pre_cfg_function", []):
|
55 |
+
args = {"conds":conds, "conds_out": out, "cond_scale": cond_scale, "timestep": timestep,
|
56 |
+
"input": x, "sigma": timestep, "model": model, "model_options": model_options}
|
57 |
+
out = fn(args)
|
58 |
+
|
59 |
+
cond_pred = out[0]
|
60 |
+
uncond_pred = out[1]
|
61 |
+
|
62 |
+
if "sampler_cfg_function" in model_options:
|
63 |
+
args = {"cond": x - cond_pred, "uncond": x - uncond_pred, "cond_scale": cond_scale, "timestep": timestep, "input": x, "sigma": timestep,
|
64 |
+
"cond_denoised": cond_pred, "uncond_denoised": uncond_pred, "model": model, "model_options": model_options, "cond_pos": cond_copy, "cond_neg": uncond_copy}
|
65 |
+
cfg_result = x - model_options["sampler_cfg_function"](args)
|
66 |
+
else:
|
67 |
+
cfg_result = uncond_pred + (cond_pred - uncond_pred) * cond_scale
|
68 |
+
|
69 |
+
for fn in model_options.get("sampler_post_cfg_function", []):
|
70 |
+
args = {"denoised": cfg_result, "cond": cond_copy, "uncond": uncond_copy, "model": model, "uncond_denoised": uncond_pred, "cond_denoised": cond_pred,
|
71 |
+
"sigma": timestep, "model_options": model_options, "input": x}
|
72 |
+
cfg_result = fn(args)
|
73 |
+
|
74 |
+
return cfg_result
|
75 |
+
|
76 |
+
def monkey_patching_comfy_sampling_function():
|
77 |
+
global original_sampling_function
|
78 |
+
|
79 |
+
if original_sampling_function is None:
|
80 |
+
original_sampling_function = comfy.samplers.sampling_function
|
81 |
+
# Make sure to only patch once
|
82 |
+
if hasattr(comfy.samplers.sampling_function, '_automatic_cfg_decorated'):
|
83 |
+
return
|
84 |
+
comfy.samplers.sampling_function = sampling_function_patched
|
85 |
+
comfy.samplers.sampling_function._automatic_cfg_decorated = True # flag to check monkey patch
|
86 |
+
|
87 |
+
def make_sampler_pre_cfg_automatic_cfg_function(minimum_sigma_to_disable_uncond=0, maximum_sigma_to_enable_uncond=1000000, disabled_cond_start=10000,disabled_cond_end=10000):
|
88 |
+
def sampler_pre_cfg_automatic_cfg_function(sigma, uncond, cond, cond_scale, **kwargs):
|
89 |
+
if sigma[0] < minimum_sigma_to_disable_uncond or sigma[0] > maximum_sigma_to_enable_uncond:
|
90 |
+
uncond = None
|
91 |
+
if sigma[0] <= disabled_cond_start and sigma[0] > disabled_cond_end:
|
92 |
+
cond = None
|
93 |
+
return uncond, cond, cond_scale
|
94 |
+
return sampler_pre_cfg_automatic_cfg_function
|
95 |
+
|
96 |
+
def get_entropy(tensor):
|
97 |
+
hist = np.histogram(tensor.cpu(), bins=100)[0]
|
98 |
+
hist = hist / hist.sum()
|
99 |
+
hist = hist[hist > 0]
|
100 |
+
return -np.sum(hist * np.log2(hist))
|
101 |
+
|
102 |
+
def map_sigma(sigma, sigmax, sigmin):
|
103 |
+
return 1 + ((sigma - sigmax) * (0 - 1)) / (sigmin - sigmax)
|
104 |
+
|
105 |
+
def center_latent_mean_values(latent, per_channel, mult):
|
106 |
+
for b in range(len(latent)):
|
107 |
+
if per_channel:
|
108 |
+
for c in range(len(latent[b])):
|
109 |
+
latent[b][c] -= latent[b][c].mean() * mult
|
110 |
+
else:
|
111 |
+
latent[b] -= latent[b].mean() * mult
|
112 |
+
return latent
|
113 |
+
|
114 |
+
def get_denoised_ranges(latent, measure="hard", top_k=0.25):
|
115 |
+
chans = []
|
116 |
+
for x in range(len(latent)):
|
117 |
+
max_values = torch.topk(latent[x] - latent[x].mean() if measure == "range" else latent[x], k=int(len(latent[x])*top_k), largest=True).values
|
118 |
+
min_values = torch.topk(latent[x] - latent[x].mean() if measure == "range" else latent[x], k=int(len(latent[x])*top_k), largest=False).values
|
119 |
+
max_val = torch.mean(max_values).item()
|
120 |
+
min_val = abs(torch.mean(min_values).item()) if measure == "soft" else torch.mean(torch.abs(min_values)).item()
|
121 |
+
denoised_range = (max_val + min_val) / 2
|
122 |
+
chans.append(denoised_range**2 if measure == "hard_squared" else denoised_range)
|
123 |
+
return chans
|
124 |
+
|
125 |
+
def get_sigmin_sigmax(model):
|
126 |
+
model_sampling = model.model.model_sampling
|
127 |
+
sigmin = model_sampling.sigma(model_sampling.timestep(model_sampling.sigma_min))
|
128 |
+
sigmax = model_sampling.sigma(model_sampling.timestep(model_sampling.sigma_max))
|
129 |
+
return sigmin, sigmax
|
130 |
+
|
131 |
+
def gaussian_similarity(x, y, sigma=1.0):
|
132 |
+
diff = (x - y) ** 2
|
133 |
+
return torch.exp(-diff / (2 * sigma ** 2))
|
134 |
+
|
135 |
+
def check_skip(sigma, high_sigma_threshold, low_sigma_threshold):
|
136 |
+
return sigma > high_sigma_threshold or sigma < low_sigma_threshold
|
137 |
+
|
138 |
+
def max_abs(tensors):
|
139 |
+
shape = tensors.shape
|
140 |
+
tensors = tensors.reshape(shape[0], -1)
|
141 |
+
tensors_abs = torch.abs(tensors)
|
142 |
+
max_abs_idx = torch.argmax(tensors_abs, dim=0)
|
143 |
+
result = tensors[max_abs_idx, torch.arange(tensors.shape[1])]
|
144 |
+
return result.reshape(shape[1:])
|
145 |
+
|
146 |
+
def gaussian_kernel(size: int, sigma: float):
|
147 |
+
x = torch.arange(size) - size // 2
|
148 |
+
gauss = torch.exp(-x**2 / (2 * sigma**2))
|
149 |
+
kernel = gauss / gauss.sum()
|
150 |
+
return kernel.view(1, size) * kernel.view(size, 1)
|
151 |
+
|
152 |
+
def blur_tensor(tensor, kernel_size = 9, sigma = 2.0):
|
153 |
+
tensor = tensor.unsqueeze(0)
|
154 |
+
C = tensor.size(1)
|
155 |
+
kernel = gaussian_kernel(kernel_size, sigma)
|
156 |
+
kernel = kernel.expand(C, 1, kernel_size, kernel_size).to(tensor.device).to(dtype=tensor.dtype, device=tensor.device)
|
157 |
+
padding = kernel_size // 2
|
158 |
+
tensor = F.pad(tensor, (padding, padding, padding, padding), mode='reflect')
|
159 |
+
blurred_tensor = F.conv2d(tensor, kernel, groups=C)
|
160 |
+
return blurred_tensor.squeeze(0)
|
161 |
+
|
162 |
+
def smallest_distances(tensors):
|
163 |
+
if all(torch.equal(tensors[0], tensor) for tensor in tensors[1:]):
|
164 |
+
return tensors[0]
|
165 |
+
set_device = tensors.device
|
166 |
+
min_val = torch.full(tensors[0].shape, float("inf")).to(set_device)
|
167 |
+
result = torch.zeros_like(tensors[0])
|
168 |
+
for idx1, t1 in enumerate(tensors):
|
169 |
+
temp_diffs = torch.zeros_like(tensors[0])
|
170 |
+
for idx2, t2 in enumerate(tensors):
|
171 |
+
if idx1 != idx2:
|
172 |
+
temp_diffs += torch.abs(torch.sub(t1, t2))
|
173 |
+
min_val = torch.minimum(min_val, temp_diffs)
|
174 |
+
mask = torch.eq(min_val,temp_diffs)
|
175 |
+
result[mask] = t1[mask]
|
176 |
+
return result
|
177 |
+
|
178 |
+
def rescale(tensor, multiplier=2):
|
179 |
+
batch, seq_length, features = tensor.shape
|
180 |
+
H = W = int(seq_length**0.5)
|
181 |
+
tensor_reshaped = tensor.view(batch, features, H, W)
|
182 |
+
new_H = new_W = int(H * multiplier)
|
183 |
+
resized_tensor = F.interpolate(tensor_reshaped, size=(new_H, new_W), mode='bilinear', align_corners=False)
|
184 |
+
return resized_tensor.view(batch, new_H * new_W, features)
|
185 |
+
|
186 |
+
# from https://discuss.pytorch.org/t/help-regarding-slerp-function-for-generative-model-sampling/32475
|
187 |
+
def slerp(high, low, val):
|
188 |
+
dims = low.shape
|
189 |
+
|
190 |
+
#flatten to batches
|
191 |
+
low = low.reshape(dims[0], -1)
|
192 |
+
high = high.reshape(dims[0], -1)
|
193 |
+
|
194 |
+
low_norm = low/torch.norm(low, dim=1, keepdim=True)
|
195 |
+
high_norm = high/torch.norm(high, dim=1, keepdim=True)
|
196 |
+
|
197 |
+
# in case we divide by zero
|
198 |
+
low_norm[low_norm != low_norm] = 0.0
|
199 |
+
high_norm[high_norm != high_norm] = 0.0
|
200 |
+
|
201 |
+
omega = torch.acos((low_norm*high_norm).sum(1))
|
202 |
+
so = torch.sin(omega)
|
203 |
+
res = (torch.sin((1.0-val)*omega)/so).unsqueeze(1)*low + (torch.sin(val*omega)/so).unsqueeze(1) * high
|
204 |
+
return res.reshape(dims)
|
205 |
+
|
206 |
+
normalize_tensor = lambda x: x / x.norm()
|
207 |
+
|
208 |
+
def random_swap(tensors, proportion=1):
|
209 |
+
num_tensors = tensors.shape[0]
|
210 |
+
if num_tensors < 2: return tensors[0],0
|
211 |
+
tensor_size = tensors[0].numel()
|
212 |
+
if tensor_size < 100: return tensors[0],0
|
213 |
+
|
214 |
+
true_count = int(tensor_size * proportion)
|
215 |
+
mask = torch.cat((torch.ones(true_count, dtype=torch.bool, device=tensors[0].device),
|
216 |
+
torch.zeros(tensor_size - true_count, dtype=torch.bool, device=tensors[0].device)))
|
217 |
+
mask = mask[torch.randperm(tensor_size)].reshape(tensors[0].shape)
|
218 |
+
if num_tensors == 2 and proportion < 1:
|
219 |
+
index_tensor = torch.ones_like(tensors[0], dtype=torch.int64, device=tensors[0].device)
|
220 |
+
else:
|
221 |
+
index_tensor = torch.randint(1 if proportion < 1 else 0, num_tensors, tensors[0].shape, device=tensors[0].device)
|
222 |
+
for i, t in enumerate(tensors):
|
223 |
+
if i == 0: continue
|
224 |
+
merge_mask = index_tensor == i & mask
|
225 |
+
tensors[0][merge_mask] = t[merge_mask]
|
226 |
+
return tensors[0]
|
227 |
+
|
228 |
+
def multi_tensor_check_mix(tensors):
|
229 |
+
if tensors[0].numel() < 2 or len(tensors) < 2:
|
230 |
+
return tensors[0]
|
231 |
+
ref_tensor_shape = tensors[0].shape
|
232 |
+
sequence_tensor = torch.arange(tensors[0].numel(), device=tensors[0].device) % len(tensors)
|
233 |
+
reshaped_sequence = sequence_tensor.view(ref_tensor_shape)
|
234 |
+
for i in range(len(tensors)):
|
235 |
+
if i == 0: continue
|
236 |
+
mask = reshaped_sequence == i
|
237 |
+
tensors[0][mask] = tensors[i][mask]
|
238 |
+
return tensors[0]
|
239 |
+
|
240 |
+
def sspow(input_tensor, p=2):
|
241 |
+
return input_tensor.abs().pow(p) * input_tensor.sign()
|
242 |
+
|
243 |
+
def sspown(input_tensor, p=2):
|
244 |
+
abs_t = input_tensor.abs()
|
245 |
+
abs_t = (abs_t - abs_t.min()) / (abs_t.max() - abs_t.min())
|
246 |
+
return abs_t.pow(p) * input_tensor.sign()
|
247 |
+
|
248 |
+
def gradient_merge(tensor1, tensor2, start_value=0, dim=0):
|
249 |
+
if torch.numel(tensor1) <= 1: return tensor1
|
250 |
+
if dim >= tensor1.dim(): dim = 0
|
251 |
+
size = tensor1.size(dim)
|
252 |
+
alpha = torch.linspace(start_value, 1-start_value, steps=size, device=tensor1.device).view([-1 if i == dim else 1 for i in range(tensor1.dim())])
|
253 |
+
return tensor1 * alpha + tensor2 * (1 - alpha)
|
254 |
+
|
255 |
+
def save_tensor(input_tensor,name):
|
256 |
+
if "rndnum" in name:
|
257 |
+
rndnum = str(random.randint(100000,999999))
|
258 |
+
name = name.replace("rndnum", rndnum)
|
259 |
+
output_directory = os.path.join(current_dir, 'saved_tensors')
|
260 |
+
os.makedirs(output_directory, exist_ok=True)
|
261 |
+
output_file_path = os.path.join(output_directory, f"{name}.pt")
|
262 |
+
torch.save(input_tensor, output_file_path)
|
263 |
+
return input_tensor
|
264 |
+
|
265 |
+
def print_and_return(input_tensor, *args):
|
266 |
+
for what_to_print in args:
|
267 |
+
print(" ",what_to_print)
|
268 |
+
return input_tensor
|
269 |
+
|
270 |
+
# Experimental testings
|
271 |
+
def normal_attention(q, k, v, mask=None):
|
272 |
+
attention_scores = torch.matmul(q, k.transpose(-2, -1))
|
273 |
+
d_k = k.size(-1)
|
274 |
+
attention_scores = attention_scores / torch.sqrt(torch.tensor(d_k, dtype=torch.float32))
|
275 |
+
if mask is not None:
|
276 |
+
attention_scores = attention_scores.masked_fill(mask == 0, float('-inf'))
|
277 |
+
attention_weights = F.softmax(attention_scores, dim=-1)
|
278 |
+
output = torch.matmul(attention_weights, v)
|
279 |
+
return output
|
280 |
+
|
281 |
+
def split_heads(x, n_heads):
|
282 |
+
batch_size, seq_length, hidden_dim = x.size()
|
283 |
+
head_dim = hidden_dim // n_heads
|
284 |
+
x = x.view(batch_size, seq_length, n_heads, head_dim)
|
285 |
+
return x.permute(0, 2, 1, 3)
|
286 |
+
|
287 |
+
def combine_heads(x, n_heads):
|
288 |
+
batch_size, n_heads, seq_length, head_dim = x.size()
|
289 |
+
hidden_dim = n_heads * head_dim
|
290 |
+
x = x.permute(0, 2, 1, 3).contiguous()
|
291 |
+
return x.view(batch_size, seq_length, hidden_dim)
|
292 |
+
|
293 |
+
def sparsemax(logits):
|
294 |
+
logits_sorted, _ = torch.sort(logits, descending=True, dim=-1)
|
295 |
+
cumulative_sum = torch.cumsum(logits_sorted, dim=-1) - 1
|
296 |
+
rho = (logits_sorted > cumulative_sum / (torch.arange(logits.size(-1)) + 1).to(logits.device)).float()
|
297 |
+
tau = (cumulative_sum / rho.sum(dim=-1, keepdim=True)).gather(dim=-1, index=rho.sum(dim=-1, keepdim=True).long() - 1)
|
298 |
+
return torch.max(torch.zeros_like(logits), logits - tau)
|
299 |
+
|
300 |
+
def attnfunc_custom(q, k, v, n_heads, eval_string = ""):
|
301 |
+
q = split_heads(q, n_heads)
|
302 |
+
k = split_heads(k, n_heads)
|
303 |
+
v = split_heads(v, n_heads)
|
304 |
+
|
305 |
+
d_k = q.size(-1)
|
306 |
+
|
307 |
+
scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)
|
308 |
+
|
309 |
+
if eval_string == "":
|
310 |
+
attn_weights = F.softmax(scores, dim=-1)
|
311 |
+
else:
|
312 |
+
attn_weights = eval(eval_string)
|
313 |
+
|
314 |
+
output = torch.matmul(attn_weights, v)
|
315 |
+
output = combine_heads(output, n_heads)
|
316 |
+
return output
|
317 |
+
|
318 |
+
def min_max_norm(t):
|
319 |
+
return (t - t.min()) / (t.max() - t.min())
|
320 |
+
|
321 |
+
class attention_modifier():
|
322 |
+
def __init__(self, self_attn_mod_eval, conds = None):
|
323 |
+
self.self_attn_mod_eval = self_attn_mod_eval
|
324 |
+
self.conds = conds
|
325 |
+
|
326 |
+
def modified_attention(self, q, k, v, extra_options, mask=None):
|
327 |
+
|
328 |
+
"""extra_options contains: {'cond_or_uncond': [1, 0], 'sigmas': tensor([14.6146], device='cuda:0'),
|
329 |
+
'original_shape': [2, 4, 128, 128], 'transformer_index': 4, 'block': ('middle', 0),
|
330 |
+
'block_index': 3, 'n_heads': 20, 'dim_head': 64, 'attn_precision': None}"""
|
331 |
+
|
332 |
+
if "attnbc" in self.self_attn_mod_eval:
|
333 |
+
attnbc = attention_basic(q, k, v, extra_options['n_heads'], mask)
|
334 |
+
if "normattn" in self.self_attn_mod_eval:
|
335 |
+
normattn = normal_attention(q, k, v, mask)
|
336 |
+
if "attnxf" in self.self_attn_mod_eval:
|
337 |
+
attnxf = attention_xformers(q, k, v, extra_options['n_heads'], mask)
|
338 |
+
if "attnpy" in self.self_attn_mod_eval:
|
339 |
+
attnpy = attention_pytorch(q, k, v, extra_options['n_heads'], mask)
|
340 |
+
if "attnsp" in self.self_attn_mod_eval:
|
341 |
+
attnsp = attention_split(q, k, v, extra_options['n_heads'], mask)
|
342 |
+
if "attnsq" in self.self_attn_mod_eval:
|
343 |
+
attnsq = attention_sub_quad(q, k, v, extra_options['n_heads'], mask)
|
344 |
+
if "attnopt" in self.self_attn_mod_eval:
|
345 |
+
attnopt = attnfunc(q, k, v, extra_options['n_heads'], mask)
|
346 |
+
n_heads = extra_options['n_heads']
|
347 |
+
if self.conds is not None:
|
348 |
+
cond_pos_l = self.conds[0][..., :768].cuda()
|
349 |
+
cond_neg_l = self.conds[1][..., :768].cuda()
|
350 |
+
if self.conds[0].shape[-1] > 768:
|
351 |
+
cond_pos_g = self.conds[0][..., 768:2048].cuda()
|
352 |
+
cond_neg_g = self.conds[1][..., 768:2048].cuda()
|
353 |
+
return eval(self.self_attn_mod_eval)
|
354 |
+
|
355 |
+
def experimental_functions(cond_input, method, exp_value, exp_normalize, pcp, psi, sigma, sigmax, attention_modifiers_input, args, model_options_copy, eval_string = ""):
|
356 |
+
"""
|
357 |
+
There may or may not be an actual reasoning behind each of these methods.
|
358 |
+
Some like the sine value have interesting properties. Enabled for both cond and uncond preds it somehow make them stronger.
|
359 |
+
Note that there is a "normalize" toggle and it may change greatly the end result since some operation will totaly butcher the values.
|
360 |
+
"theDaRkNeSs" for example without normalizing seems to darken if used for cond/uncond (not with the cond as the uncond or something).
|
361 |
+
Maybe just with the positive. I don't remember. I leave it for now if you want to play around.
|
362 |
+
|
363 |
+
The eval_string can be used to create the uncond replacement.
|
364 |
+
I made it so it's split by semicolons and only the last split is the value in used.
|
365 |
+
What is before is added in an array named "v".
|
366 |
+
pcp is previous cond_pred
|
367 |
+
psi is previous sigma
|
368 |
+
args is the CFG function input arguments with the added cond/unconds (like the actual activation conditionings) named respectively "cond_pos" and "cond_neg"
|
369 |
+
|
370 |
+
So if you write:
|
371 |
+
|
372 |
+
pcp if sigma < 7 else -pcp;
|
373 |
+
print("it works too just don't use the output I guess");
|
374 |
+
v[0] if sigma < 14 else torch.zeros_like(cond);
|
375 |
+
v[-1]*2
|
376 |
+
|
377 |
+
Well the first line becomes v[0], second v[1] etc.
|
378 |
+
The last one becomes the result.
|
379 |
+
Note that it's just an example, I don't see much interest in that one.
|
380 |
+
|
381 |
+
Using comfy.samplers.calc_cond_batch(args["model"], [args["cond_pos"], None], args["input"], args["timestep"], args["model_options"])[0]
|
382 |
+
can work too.
|
383 |
+
|
384 |
+
This whole mess has for initial goal to attempt to find the best way (or have some bruteforcing fun) to replace the uncond pred for as much as possible.
|
385 |
+
Or simply to try things around :)
|
386 |
+
"""
|
387 |
+
if method == "cond_pred":
|
388 |
+
return cond_input
|
389 |
+
default_device = cond_input.device
|
390 |
+
# print()
|
391 |
+
# print(get_entropy(cond))
|
392 |
+
cond = cond_input.clone()
|
393 |
+
cond_norm = cond.norm()
|
394 |
+
if method == "amplify":
|
395 |
+
mask = torch.abs(cond) >= 1
|
396 |
+
cond_copy = cond.clone()
|
397 |
+
cond = torch.pow(torch.abs(cond), ( 1 / exp_value)) * cond.sign()
|
398 |
+
cond[mask] = torch.pow(torch.abs(cond_copy[mask]), exp_value) * cond[mask].sign()
|
399 |
+
elif method == "root":
|
400 |
+
cond = torch.pow(torch.abs(cond), ( 1 / exp_value)) * cond.sign()
|
401 |
+
elif method == "power":
|
402 |
+
cond = torch.pow(torch.abs(cond), exp_value) * cond.sign()
|
403 |
+
elif method == "erf":
|
404 |
+
cond = torch.erf(cond)
|
405 |
+
elif method == "exp_erf":
|
406 |
+
cond = torch.pow(torch.erf(cond), exp_value)
|
407 |
+
elif method == "root_erf":
|
408 |
+
cond = torch.erf(cond)
|
409 |
+
cond = torch.pow(torch.abs(cond), 1 / exp_value ) * cond.sign()
|
410 |
+
elif method == "erf_amplify":
|
411 |
+
cond = torch.erf(cond)
|
412 |
+
mask = torch.abs(cond) >= 1
|
413 |
+
cond_copy = cond.clone()
|
414 |
+
cond = torch.pow(torch.abs(cond), 1 / exp_value ) * cond.sign()
|
415 |
+
cond[mask] = torch.pow(torch.abs(cond_copy[mask]), exp_value) * cond[mask].sign()
|
416 |
+
elif method == "sine":
|
417 |
+
cond = torch.sin(torch.abs(cond)) * cond.sign()
|
418 |
+
elif method == "sine_exp":
|
419 |
+
cond = torch.sin(torch.abs(cond)) * cond.sign()
|
420 |
+
cond = torch.pow(torch.abs(cond), exp_value) * cond.sign()
|
421 |
+
elif method == "sine_exp_diff":
|
422 |
+
cond = torch.sin(torch.abs(cond)) * cond.sign()
|
423 |
+
cond = torch.pow(torch.abs(cond_input), exp_value) * cond.sign() - cond
|
424 |
+
elif method == "sine_exp_diff_to_sine":
|
425 |
+
cond = torch.sin(torch.abs(cond)) * cond.sign()
|
426 |
+
cond = torch.pow(torch.abs(cond), exp_value) * cond.sign() - cond
|
427 |
+
elif method == "sine_root":
|
428 |
+
cond = torch.sin(torch.abs(cond)) * cond.sign()
|
429 |
+
cond = torch.pow(torch.abs(cond), ( 1 / exp_value)) * cond.sign()
|
430 |
+
elif method == "sine_root_diff":
|
431 |
+
cond = torch.sin(torch.abs(cond)) * cond.sign()
|
432 |
+
cond = torch.pow(torch.abs(cond_input), 1 / exp_value) * cond.sign() - cond
|
433 |
+
elif method == "sine_root_diff_to_sine":
|
434 |
+
cond = torch.sin(torch.abs(cond)) * cond.sign()
|
435 |
+
cond = torch.pow(torch.abs(cond), 1 / exp_value) * cond.sign() - cond
|
436 |
+
elif method == "theDaRkNeSs":
|
437 |
+
cond = torch.sin(cond)
|
438 |
+
cond = torch.pow(torch.abs(cond), 1 / exp_value) * cond.sign() - cond
|
439 |
+
elif method == "cosine":
|
440 |
+
cond = torch.cos(torch.abs(cond)) * cond.sign()
|
441 |
+
elif method == "sign":
|
442 |
+
cond = cond.sign()
|
443 |
+
elif method == "zero":
|
444 |
+
cond = torch.zeros_like(cond)
|
445 |
+
elif method in ["attention_modifiers_input_using_cond","attention_modifiers_input_using_uncond","subtract_attention_modifiers_input_using_cond","subtract_attention_modifiers_input_using_uncond"]:
|
446 |
+
cond_to_use = args["cond_pos"] if method in ["attention_modifiers_input_using_cond","subtract_attention_modifiers_input_using_cond"] else args["cond_neg"]
|
447 |
+
tmp_model_options = deepcopy(model_options_copy)
|
448 |
+
for atm in attention_modifiers_input:
|
449 |
+
if sigma <= atm['sigma_start'] and sigma > atm['sigma_end']:
|
450 |
+
block_layers = {"input": atm['unet_block_id_input'], "middle": atm['unet_block_id_middle'], "output": atm['unet_block_id_output']}
|
451 |
+
for unet_block in block_layers:
|
452 |
+
for unet_block_id in block_layers[unet_block].split(","):
|
453 |
+
if unet_block_id != "":
|
454 |
+
unet_block_id = int(unet_block_id)
|
455 |
+
tmp_model_options = set_model_options_patch_replace(tmp_model_options, attention_modifier(atm['self_attn_mod_eval'], [args["cond_pos"][0]["cross_attn"], args["cond_neg"][0]["cross_attn"]]if "cond" in atm['self_attn_mod_eval'] else None).modified_attention, atm['unet_attn'], unet_block, unet_block_id)
|
456 |
+
|
457 |
+
cond = comfy.samplers.calc_cond_batch(args["model"], [cond_to_use], args["input"], args["timestep"], tmp_model_options)[0]
|
458 |
+
if method in ["subtract_attention_modifiers_input_using_cond","subtract_attention_modifiers_input_using_uncond"]:
|
459 |
+
cond = cond_input + (cond_input - cond) * exp_value
|
460 |
+
|
461 |
+
elif method == "previous_average":
|
462 |
+
if sigma > (sigmax - 1):
|
463 |
+
cond = torch.zeros_like(cond)
|
464 |
+
else:
|
465 |
+
cond = (pcp / psi * sigma + cond) / 2
|
466 |
+
elif method == "eval":
|
467 |
+
if "condmix" in eval_string:
|
468 |
+
def condmix(args, mult=2):
|
469 |
+
cond_pos_tmp = deepcopy(args["cond_pos"])
|
470 |
+
cond_pos_tmp[0]["cross_attn"] += (args["cond_pos"][0]["cross_attn"] - args["cond_neg"][0]["cross_attn"]*-1) * mult
|
471 |
+
return cond_pos_tmp
|
472 |
+
v = []
|
473 |
+
evals_strings = eval_string.split(";")
|
474 |
+
if len(evals_strings) > 1:
|
475 |
+
for i in range(len(evals_strings[:-1])):
|
476 |
+
v.append(eval(evals_strings[i]))
|
477 |
+
cond = eval(evals_strings[-1])
|
478 |
+
if exp_normalize and torch.all(cond != 0):
|
479 |
+
cond = cond * cond_norm / cond.norm()
|
480 |
+
# print(get_entropy(cond))
|
481 |
+
return cond.to(device=default_device)
|
482 |
+
|
483 |
+
class advancedDynamicCFG:
|
484 |
+
def __init__(self):
|
485 |
+
self.last_cfg_ht_one = 8
|
486 |
+
self.previous_cond_pred = None
|
487 |
+
|
488 |
+
@classmethod
|
489 |
+
def INPUT_TYPES(s):
|
490 |
+
return {"required": {
|
491 |
+
"model": ("MODEL",),
|
492 |
+
|
493 |
+
"automatic_cfg" : (["None", "soft", "hard", "hard_squared", "range"], {"default": "hard"},),
|
494 |
+
|
495 |
+
"skip_uncond" : ("BOOLEAN", {"default": True}),
|
496 |
+
"fake_uncond_start" : ("BOOLEAN", {"default": False}),
|
497 |
+
"uncond_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
498 |
+
"uncond_sigma_end": ("FLOAT", {"default": 1, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
499 |
+
|
500 |
+
"lerp_uncond" : ("BOOLEAN", {"default": False}),
|
501 |
+
"lerp_uncond_strength": ("FLOAT", {"default": 2, "min": 0.0, "max": 10.0, "step": 0.1, "round": 0.1}),
|
502 |
+
"lerp_uncond_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
503 |
+
"lerp_uncond_sigma_end": ("FLOAT", {"default": 1, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
504 |
+
|
505 |
+
"subtract_latent_mean" : ("BOOLEAN", {"default": False}),
|
506 |
+
"subtract_latent_mean_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
507 |
+
"subtract_latent_mean_sigma_end": ("FLOAT", {"default": 1, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
508 |
+
|
509 |
+
"latent_intensity_rescale" : ("BOOLEAN", {"default": False}),
|
510 |
+
"latent_intensity_rescale_method" : (["soft","hard","range"], {"default": "hard"},),
|
511 |
+
"latent_intensity_rescale_cfg": ("FLOAT", {"default": 8, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.1}),
|
512 |
+
"latent_intensity_rescale_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
513 |
+
"latent_intensity_rescale_sigma_end": ("FLOAT", {"default": 3, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
514 |
+
|
515 |
+
"cond_exp": ("BOOLEAN", {"default": False}),
|
516 |
+
"cond_exp_normalize": ("BOOLEAN", {"default": False}),
|
517 |
+
"cond_exp_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
518 |
+
"cond_exp_sigma_end": ("FLOAT", {"default": 1, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
519 |
+
"cond_exp_method": (["amplify", "root", "power", "erf", "erf_amplify", "exp_erf", "root_erf", "sine", "sine_exp", "sine_exp_diff", "sine_exp_diff_to_sine", "sine_root", "sine_root_diff", "sine_root_diff_to_sine", "theDaRkNeSs", "cosine", "sign", "zero", "previous_average", "eval",
|
520 |
+
"attention_modifiers_input_using_cond","attention_modifiers_input_using_uncond",
|
521 |
+
"subtract_attention_modifiers_input_using_cond","subtract_attention_modifiers_input_using_uncond"],),
|
522 |
+
"cond_exp_value": ("FLOAT", {"default": 2, "min": 0, "max": 100, "step": 0.1, "round": 0.01}),
|
523 |
+
|
524 |
+
"uncond_exp": ("BOOLEAN", {"default": False}),
|
525 |
+
"uncond_exp_normalize": ("BOOLEAN", {"default": False}),
|
526 |
+
"uncond_exp_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
527 |
+
"uncond_exp_sigma_end": ("FLOAT", {"default": 1, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
528 |
+
"uncond_exp_method": (["amplify", "root", "power", "erf", "erf_amplify", "exp_erf", "root_erf", "sine", "sine_exp", "sine_exp_diff", "sine_exp_diff_to_sine", "sine_root", "sine_root_diff", "sine_root_diff_to_sine", "theDaRkNeSs", "cosine", "sign", "zero", "previous_average", "eval",
|
529 |
+
"subtract_attention_modifiers_input_using_cond","subtract_attention_modifiers_input_using_uncond"],),
|
530 |
+
"uncond_exp_value": ("FLOAT", {"default": 2, "min": 0, "max": 100, "step": 0.1, "round": 0.01}),
|
531 |
+
|
532 |
+
"fake_uncond_exp": ("BOOLEAN", {"default": False}),
|
533 |
+
"fake_uncond_exp_normalize": ("BOOLEAN", {"default": False}),
|
534 |
+
"fake_uncond_exp_method" : (["cond_pred", "previous_average",
|
535 |
+
"amplify", "root", "power", "erf", "erf_amplify", "exp_erf", "root_erf", "sine", "sine_exp", "sine_exp_diff", "sine_exp_diff_to_sine", "sine_root", "sine_root_diff",
|
536 |
+
"sine_root_diff_to_sine", "theDaRkNeSs", "cosine", "sign", "zero", "eval",
|
537 |
+
"subtract_attention_modifiers_input_using_cond","subtract_attention_modifiers_input_using_uncond",
|
538 |
+
"attention_modifiers_input_using_cond","attention_modifiers_input_using_uncond"],),
|
539 |
+
"fake_uncond_exp_value": ("FLOAT", {"default": 2, "min": 0, "max": 1000, "step": 0.1, "round": 0.01}),
|
540 |
+
"fake_uncond_multiplier": ("INT", {"default": 1, "min": -1, "max": 1, "step": 1}),
|
541 |
+
"fake_uncond_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
542 |
+
"fake_uncond_sigma_end": ("FLOAT", {"default": 1, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
543 |
+
"auto_cfg_topk": ("FLOAT", {"default": 0.25, "min": 0.0, "max": 0.5, "step": 0.05, "round": 0.01}),
|
544 |
+
"auto_cfg_ref": ("FLOAT", {"default": 8, "min": 0.0, "max": 100, "step": 0.5, "round": 0.01}),
|
545 |
+
"attention_modifiers_global_enabled": ("BOOLEAN", {"default": False}),
|
546 |
+
"disable_cond": ("BOOLEAN", {"default": False}),
|
547 |
+
"disable_cond_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
548 |
+
"disable_cond_sigma_end": ("FLOAT", {"default": 0, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
549 |
+
"save_as_preset": ("BOOLEAN", {"default": False}),
|
550 |
+
"preset_name": ("STRING", {"multiline": False}),
|
551 |
+
},
|
552 |
+
"optional":{
|
553 |
+
"eval_string_cond": ("STRING", {"multiline": True}),
|
554 |
+
"eval_string_uncond": ("STRING", {"multiline": True}),
|
555 |
+
"eval_string_fake": ("STRING", {"multiline": True}),
|
556 |
+
"args_filter": ("STRING", {"multiline": True, "forceInput": True}),
|
557 |
+
"attention_modifiers_positive": ("ATTNMOD", {"forceInput": True}),
|
558 |
+
"attention_modifiers_negative": ("ATTNMOD", {"forceInput": True}),
|
559 |
+
"attention_modifiers_fake_negative": ("ATTNMOD", {"forceInput": True}),
|
560 |
+
"attention_modifiers_global": ("ATTNMOD", {"forceInput": True}),
|
561 |
+
}
|
562 |
+
}
|
563 |
+
RETURN_TYPES = ("MODEL","STRING",)
|
564 |
+
FUNCTION = "patch"
|
565 |
+
|
566 |
+
CATEGORY = "model_patches/Automatic_CFG"
|
567 |
+
|
568 |
+
def patch(self, model, automatic_cfg = "None",
|
569 |
+
skip_uncond = False, fake_uncond_start = False, uncond_sigma_start = 1000, uncond_sigma_end = 0,
|
570 |
+
lerp_uncond = False, lerp_uncond_strength = 1, lerp_uncond_sigma_start = 1000, lerp_uncond_sigma_end = 1,
|
571 |
+
subtract_latent_mean = False, subtract_latent_mean_sigma_start = 1000, subtract_latent_mean_sigma_end = 1,
|
572 |
+
latent_intensity_rescale = False, latent_intensity_rescale_sigma_start = 1000, latent_intensity_rescale_sigma_end = 1,
|
573 |
+
cond_exp = False, cond_exp_sigma_start = 1000, cond_exp_sigma_end = 1000, cond_exp_method = "amplify", cond_exp_value = 2, cond_exp_normalize = False,
|
574 |
+
uncond_exp = False, uncond_exp_sigma_start = 1000, uncond_exp_sigma_end = 1000, uncond_exp_method = "amplify", uncond_exp_value = 2, uncond_exp_normalize = False,
|
575 |
+
fake_uncond_exp = False, fake_uncond_exp_method = "amplify", fake_uncond_exp_value = 2, fake_uncond_exp_normalize = False, fake_uncond_multiplier = 1, fake_uncond_sigma_start = 1000, fake_uncond_sigma_end = 1,
|
576 |
+
latent_intensity_rescale_cfg = 8, latent_intensity_rescale_method = "hard",
|
577 |
+
ignore_pre_cfg_func = False, args_filter = "", auto_cfg_topk = 0.25, auto_cfg_ref = 8,
|
578 |
+
eval_string_cond = "", eval_string_uncond = "", eval_string_fake = "",
|
579 |
+
attention_modifiers_global_enabled = False,
|
580 |
+
attention_modifiers_positive = [], attention_modifiers_negative = [], attention_modifiers_fake_negative = [], attention_modifiers_global = [],
|
581 |
+
disable_cond=False, disable_cond_sigma_start=1000,disable_cond_sigma_end=1000, save_as_preset = False, preset_name = "", **kwargs
|
582 |
+
):
|
583 |
+
|
584 |
+
# support_function()
|
585 |
+
model_options_copy = deepcopy(model.model_options)
|
586 |
+
monkey_patching_comfy_sampling_function()
|
587 |
+
if args_filter != "":
|
588 |
+
args_filter = args_filter.split(",")
|
589 |
+
else:
|
590 |
+
args_filter = [k for k, v in locals().items()]
|
591 |
+
not_in_filter = ['self','model','args','args_filter','save_as_preset','preset_name','model_options_copy']
|
592 |
+
if fake_uncond_exp_method != "eval":
|
593 |
+
not_in_filter.append("eval_string")
|
594 |
+
|
595 |
+
if save_as_preset and preset_name != "":
|
596 |
+
preset_parameters = {key: value for key, value in locals().items() if key not in not_in_filter}
|
597 |
+
with open(os.path.join(json_preset_path, preset_name+".json"), 'w', encoding='utf-8') as f:
|
598 |
+
json.dump(preset_parameters, f)
|
599 |
+
print(f"Preset saved with the name: {Fore.GREEN}{preset_name}{Fore.RESET}")
|
600 |
+
print(f"{Fore.RED}Don't forget to turn the save toggle OFF to not overwrite!{Fore.RESET}")
|
601 |
+
|
602 |
+
args_str = '\n'.join(f'{k}: {v}' for k, v in locals().items() if k not in not_in_filter and k in args_filter)
|
603 |
+
|
604 |
+
sigmin, sigmax = get_sigmin_sigmax(model)
|
605 |
+
|
606 |
+
lerp_start, lerp_end = lerp_uncond_sigma_start, lerp_uncond_sigma_end
|
607 |
+
subtract_start, subtract_end = subtract_latent_mean_sigma_start, subtract_latent_mean_sigma_end
|
608 |
+
rescale_start, rescale_end = latent_intensity_rescale_sigma_start, latent_intensity_rescale_sigma_end
|
609 |
+
print(f"Model maximum sigma: {sigmax} / Model minimum sigma: {sigmin}")
|
610 |
+
m = model.clone()
|
611 |
+
|
612 |
+
if skip_uncond or disable_cond:
|
613 |
+
# set model_options sampler_pre_cfg_automatic_cfg_function
|
614 |
+
m.model_options["sampler_pre_cfg_automatic_cfg_function"] = make_sampler_pre_cfg_automatic_cfg_function(uncond_sigma_end if skip_uncond else 0, uncond_sigma_start if skip_uncond else 100000,\
|
615 |
+
disable_cond_sigma_start if disable_cond else 100000, disable_cond_sigma_end if disable_cond else 100000)
|
616 |
+
print(f"Sampling function patched. Uncond enabled from {round(uncond_sigma_start,2)} to {round(uncond_sigma_end,2)}")
|
617 |
+
elif not ignore_pre_cfg_func:
|
618 |
+
m.model_options.pop("sampler_pre_cfg_automatic_cfg_function", None)
|
619 |
+
uncond_sigma_start, uncond_sigma_end = 1000000, 0
|
620 |
+
|
621 |
+
top_k = auto_cfg_topk
|
622 |
+
previous_cond_pred = None
|
623 |
+
previous_sigma = None
|
624 |
+
def automatic_cfg_function(args):
|
625 |
+
nonlocal previous_sigma
|
626 |
+
cond_scale = args["cond_scale"]
|
627 |
+
input_x = args["input"]
|
628 |
+
cond_pred = args["cond_denoised"]
|
629 |
+
uncond_pred = args["uncond_denoised"]
|
630 |
+
sigma = args["sigma"][0]
|
631 |
+
model_options = args["model_options"]
|
632 |
+
if self.previous_cond_pred is None:
|
633 |
+
self.previous_cond_pred = cond_pred.clone().detach().to(device=cond_pred.device)
|
634 |
+
if previous_sigma is None:
|
635 |
+
previous_sigma = sigma.item()
|
636 |
+
reference_cfg = auto_cfg_ref if auto_cfg_ref > 0 else cond_scale
|
637 |
+
|
638 |
+
def fake_uncond_step():
|
639 |
+
return fake_uncond_start and skip_uncond and (sigma > uncond_sigma_start or sigma < uncond_sigma_end) and sigma <= fake_uncond_sigma_start and sigma >= fake_uncond_sigma_end
|
640 |
+
|
641 |
+
if fake_uncond_step():
|
642 |
+
uncond_pred = cond_pred.clone().detach().to(device=cond_pred.device) * fake_uncond_multiplier
|
643 |
+
|
644 |
+
if cond_exp and sigma <= cond_exp_sigma_start and sigma >= cond_exp_sigma_end:
|
645 |
+
cond_pred = experimental_functions(cond_pred, cond_exp_method, cond_exp_value, cond_exp_normalize, self.previous_cond_pred, previous_sigma, sigma.item(), sigmax, attention_modifiers_positive, args, model_options_copy, eval_string_cond)
|
646 |
+
if uncond_exp and sigma <= uncond_exp_sigma_start and sigma >= uncond_exp_sigma_end and not fake_uncond_step():
|
647 |
+
uncond_pred = experimental_functions(uncond_pred, uncond_exp_method, uncond_exp_value, uncond_exp_normalize, self.previous_cond_pred, previous_sigma, sigma.item(), sigmax, attention_modifiers_negative, args, model_options_copy, eval_string_uncond)
|
648 |
+
if fake_uncond_step() and fake_uncond_exp:
|
649 |
+
uncond_pred = experimental_functions(uncond_pred, fake_uncond_exp_method, fake_uncond_exp_value, fake_uncond_exp_normalize, self.previous_cond_pred, previous_sigma, sigma.item(), sigmax, attention_modifiers_fake_negative, args, model_options_copy, eval_string_fake)
|
650 |
+
self.previous_cond_pred = cond_pred.clone().detach().to(device=cond_pred.device)
|
651 |
+
|
652 |
+
if sigma >= sigmax or cond_scale > 1:
|
653 |
+
self.last_cfg_ht_one = cond_scale
|
654 |
+
target_intensity = self.last_cfg_ht_one / 10
|
655 |
+
|
656 |
+
if ((check_skip(sigma, uncond_sigma_start, uncond_sigma_end) and skip_uncond) and not fake_uncond_step()) or cond_scale == 1:
|
657 |
+
return input_x - cond_pred
|
658 |
+
|
659 |
+
if lerp_uncond and not check_skip(sigma, lerp_start, lerp_end) and lerp_uncond_strength != 1:
|
660 |
+
uncond_pred_norm = uncond_pred.norm()
|
661 |
+
uncond_pred = torch.lerp(cond_pred, uncond_pred, lerp_uncond_strength)
|
662 |
+
uncond_pred = uncond_pred * uncond_pred_norm / uncond_pred.norm()
|
663 |
+
cond = input_x - cond_pred
|
664 |
+
uncond = input_x - uncond_pred
|
665 |
+
|
666 |
+
if automatic_cfg == "None":
|
667 |
+
return uncond + cond_scale * (cond - uncond)
|
668 |
+
|
669 |
+
denoised_tmp = input_x - (uncond + reference_cfg * (cond - uncond))
|
670 |
+
|
671 |
+
for b in range(len(denoised_tmp)):
|
672 |
+
denoised_ranges = get_denoised_ranges(denoised_tmp[b], automatic_cfg, top_k)
|
673 |
+
for c in range(len(denoised_tmp[b])):
|
674 |
+
fixeds_scale = reference_cfg * target_intensity / denoised_ranges[c]
|
675 |
+
denoised_tmp[b][c] = uncond[b][c] + fixeds_scale * (cond[b][c] - uncond[b][c])
|
676 |
+
|
677 |
+
return denoised_tmp
|
678 |
+
|
679 |
+
def center_mean_latent_post_cfg(args):
|
680 |
+
denoised = args["denoised"]
|
681 |
+
sigma = args["sigma"][0]
|
682 |
+
if check_skip(sigma, subtract_start, subtract_end):
|
683 |
+
return denoised
|
684 |
+
denoised = center_latent_mean_values(denoised, False, 1)
|
685 |
+
return denoised
|
686 |
+
|
687 |
+
def rescale_post_cfg(args):
|
688 |
+
denoised = args["denoised"]
|
689 |
+
sigma = args["sigma"][0]
|
690 |
+
|
691 |
+
if check_skip(sigma, rescale_start, rescale_end):
|
692 |
+
return denoised
|
693 |
+
target_intensity = latent_intensity_rescale_cfg / 10
|
694 |
+
for b in range(len(denoised)):
|
695 |
+
denoised_ranges = get_denoised_ranges(denoised[b], latent_intensity_rescale_method)
|
696 |
+
for c in range(len(denoised[b])):
|
697 |
+
scale_correction = target_intensity / denoised_ranges[c]
|
698 |
+
denoised[b][c] = denoised[b][c] * scale_correction
|
699 |
+
return denoised
|
700 |
+
|
701 |
+
tmp_model_options = deepcopy(m.model_options)
|
702 |
+
if attention_modifiers_global_enabled:
|
703 |
+
# print(f"{Fore.GREEN}Sigma timings are ignored for global modifiers.{Fore.RESET}")
|
704 |
+
for atm in attention_modifiers_global:
|
705 |
+
block_layers = {"input": atm['unet_block_id_input'], "middle": atm['unet_block_id_middle'], "output": atm['unet_block_id_output']}
|
706 |
+
for unet_block in block_layers:
|
707 |
+
for unet_block_id in block_layers[unet_block].split(","):
|
708 |
+
if unet_block_id != "":
|
709 |
+
unet_block_id = int(unet_block_id)
|
710 |
+
tmp_model_options = set_model_options_patch_replace(tmp_model_options, attention_modifier(atm['self_attn_mod_eval']).modified_attention, atm['unet_attn'], unet_block, unet_block_id)
|
711 |
+
m.model_options = tmp_model_options
|
712 |
+
|
713 |
+
if not ignore_pre_cfg_func:
|
714 |
+
m.set_model_sampler_cfg_function(automatic_cfg_function, disable_cfg1_optimization = False)
|
715 |
+
if subtract_latent_mean:
|
716 |
+
m.set_model_sampler_post_cfg_function(center_mean_latent_post_cfg)
|
717 |
+
if latent_intensity_rescale:
|
718 |
+
m.set_model_sampler_post_cfg_function(rescale_post_cfg)
|
719 |
+
return (m, args_str, )
|
720 |
+
|
721 |
+
class attentionModifierParametersNode:
|
722 |
+
@classmethod
|
723 |
+
def INPUT_TYPES(s):
|
724 |
+
return {"required": {
|
725 |
+
"sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
726 |
+
"sigma_end": ("FLOAT", {"default": 0, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
727 |
+
"self_attn_mod_eval": ("STRING", {"multiline": True }, {"default": ""}),
|
728 |
+
"unet_block_id_input": ("STRING", {"multiline": False}, {"default": ""}),
|
729 |
+
"unet_block_id_middle": ("STRING", {"multiline": False}, {"default": ""}),
|
730 |
+
"unet_block_id_output": ("STRING", {"multiline": False}, {"default": ""}),
|
731 |
+
"unet_attn": (["attn1","attn2","both"],),
|
732 |
+
},
|
733 |
+
"optional":{
|
734 |
+
"join_parameters": ("ATTNMOD", {"forceInput": True}),
|
735 |
+
}}
|
736 |
+
|
737 |
+
RETURN_TYPES = ("ATTNMOD","STRING",)
|
738 |
+
RETURN_NAMES = ("Attention modifier", "Parameters as string")
|
739 |
+
FUNCTION = "exec"
|
740 |
+
CATEGORY = "model_patches/Automatic_CFG/experimental_attention_modifiers"
|
741 |
+
def exec(self, join_parameters=None, **kwargs):
|
742 |
+
info_string = "\n".join([f"{k}: {v}" for k,v in kwargs.items() if v != ""])
|
743 |
+
if kwargs['unet_attn'] == "both":
|
744 |
+
copy_kwargs = kwargs.copy()
|
745 |
+
kwargs['unet_attn'] = "attn1"
|
746 |
+
copy_kwargs['unet_attn'] = "attn2"
|
747 |
+
out_modifiers = [kwargs, copy_kwargs]
|
748 |
+
else:
|
749 |
+
out_modifiers = [kwargs]
|
750 |
+
return (out_modifiers if join_parameters is None else join_parameters + out_modifiers, info_string, )
|
751 |
+
|
752 |
+
class attentionModifierBruteforceParametersNode:
|
753 |
+
@classmethod
|
754 |
+
def INPUT_TYPES(s):
|
755 |
+
return {"required": {
|
756 |
+
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
757 |
+
"sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
758 |
+
"sigma_end": ("FLOAT", {"default": 0, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
759 |
+
"self_attn_mod_eval": ("STRING", {"multiline": True , "default": ""}),
|
760 |
+
"unet_block_id_input": ("STRING", {"multiline": False, "default": "4,5,7,8"}),
|
761 |
+
"unet_block_id_middle": ("STRING", {"multiline": False, "default": "0"}),
|
762 |
+
"unet_block_id_output": ("STRING", {"multiline": False, "default": "0,1,2,3,4,5"}),
|
763 |
+
"unet_attn": (["attn1","attn2","both"],),
|
764 |
+
},
|
765 |
+
"optional":{
|
766 |
+
"join_parameters": ("ATTNMOD", {"forceInput": True}),
|
767 |
+
}}
|
768 |
+
|
769 |
+
RETURN_TYPES = ("ATTNMOD","STRING",)
|
770 |
+
RETURN_NAMES = ("Attention modifier", "Parameters as string")
|
771 |
+
FUNCTION = "exec"
|
772 |
+
CATEGORY = "model_patches/Automatic_CFG/experimental_attention_modifiers"
|
773 |
+
|
774 |
+
def create_sequence_parameters(self, input_str, middle_str, output_str):
|
775 |
+
input_values = input_str.split(",") if input_str else []
|
776 |
+
middle_values = middle_str.split(",") if middle_str else []
|
777 |
+
output_values = output_str.split(",") if output_str else []
|
778 |
+
result = []
|
779 |
+
result.extend([{"unet_block_id_input": val, "unet_block_id_middle": "", "unet_block_id_output": ""} for val in input_values])
|
780 |
+
result.extend([{"unet_block_id_input": "", "unet_block_id_middle": val, "unet_block_id_output": ""} for val in middle_values])
|
781 |
+
result.extend([{"unet_block_id_input": "", "unet_block_id_middle": "", "unet_block_id_output": val} for val in output_values])
|
782 |
+
return result
|
783 |
+
|
784 |
+
def exec(self, seed, join_parameters=None, **kwargs):
|
785 |
+
sequence_parameters = self.create_sequence_parameters(kwargs['unet_block_id_input'],kwargs['unet_block_id_middle'],kwargs['unet_block_id_output'])
|
786 |
+
lenseq = len(sequence_parameters)
|
787 |
+
current_index = seed % lenseq
|
788 |
+
current_sequence = sequence_parameters[current_index]
|
789 |
+
kwargs["unet_block_id_input"] = current_sequence["unet_block_id_input"]
|
790 |
+
kwargs["unet_block_id_middle"] = current_sequence["unet_block_id_middle"]
|
791 |
+
kwargs["unet_block_id_output"] = current_sequence["unet_block_id_output"]
|
792 |
+
if current_sequence["unet_block_id_input"] != "":
|
793 |
+
current_block_string = f"unet_block_id_input: {current_sequence['unet_block_id_input']}"
|
794 |
+
elif current_sequence["unet_block_id_middle"] != "":
|
795 |
+
current_block_string = f"unet_block_id_middle: {current_sequence['unet_block_id_middle']}"
|
796 |
+
elif current_sequence["unet_block_id_output"] != "":
|
797 |
+
current_block_string = f"unet_block_id_output: {current_sequence['unet_block_id_output']}"
|
798 |
+
info_string = f"Progress: {current_index+1}/{lenseq}\n{kwargs['self_attn_mod_eval']}\n{kwargs['unet_attn']} {current_block_string}"
|
799 |
+
if kwargs['unet_attn'] == "both":
|
800 |
+
copy_kwargs = kwargs.copy()
|
801 |
+
kwargs['unet_attn'] = "attn1"
|
802 |
+
copy_kwargs['unet_attn'] = "attn2"
|
803 |
+
out_modifiers = [kwargs, copy_kwargs]
|
804 |
+
else:
|
805 |
+
out_modifiers = [kwargs]
|
806 |
+
return (out_modifiers if join_parameters is None else join_parameters + out_modifiers, info_string, )
|
807 |
+
|
808 |
+
class attentionModifierConcatNode:
|
809 |
+
@classmethod
|
810 |
+
def INPUT_TYPES(s):
|
811 |
+
return {"required": {
|
812 |
+
"parameters_1": ("ATTNMOD", {"forceInput": True}),
|
813 |
+
"parameters_2": ("ATTNMOD", {"forceInput": True}),
|
814 |
+
}}
|
815 |
+
|
816 |
+
RETURN_TYPES = ("ATTNMOD",)
|
817 |
+
FUNCTION = "exec"
|
818 |
+
CATEGORY = "model_patches/Automatic_CFG/experimental_attention_modifiers"
|
819 |
+
def exec(self, parameters_1, parameters_2):
|
820 |
+
output_parms = parameters_1 + parameters_2
|
821 |
+
return (output_parms, )
|
822 |
+
|
823 |
+
class simpleDynamicCFG:
|
824 |
+
@classmethod
|
825 |
+
def INPUT_TYPES(s):
|
826 |
+
return {"required": {
|
827 |
+
"model": ("MODEL",),
|
828 |
+
"hard_mode" : ("BOOLEAN", {"default": True}),
|
829 |
+
"boost" : ("BOOLEAN", {"default": True}),
|
830 |
+
}}
|
831 |
+
RETURN_TYPES = ("MODEL",)
|
832 |
+
FUNCTION = "patch"
|
833 |
+
|
834 |
+
CATEGORY = "model_patches/Automatic_CFG/presets"
|
835 |
+
|
836 |
+
def patch(self, model, hard_mode, boost):
|
837 |
+
advcfg = advancedDynamicCFG()
|
838 |
+
m = advcfg.patch(model,
|
839 |
+
skip_uncond = boost,
|
840 |
+
uncond_sigma_start = 1000, uncond_sigma_end = 1,
|
841 |
+
automatic_cfg = "hard" if hard_mode else "soft"
|
842 |
+
)[0]
|
843 |
+
return (m, )
|
844 |
+
|
845 |
+
class presetLoader:
|
846 |
+
@classmethod
|
847 |
+
def INPUT_TYPES(s):
|
848 |
+
presets_files = [pj.replace(".json","") for pj in os.listdir(json_preset_path) if ".json" in pj and pj not in ["Experimental_temperature.json","do_not_delete.json"]]
|
849 |
+
presets_files = sorted(presets_files, key=str.lower)
|
850 |
+
return {"required": {
|
851 |
+
"model": ("MODEL",),
|
852 |
+
"preset" : (presets_files, {"default": "Excellent_attention"}),
|
853 |
+
"uncond_sigma_end": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
854 |
+
"use_uncond_sigma_end_from_preset" : ("BOOLEAN", {"default": True}),
|
855 |
+
"automatic_cfg" : (["From preset","None", "soft", "hard", "hard_squared", "range"],),
|
856 |
+
},
|
857 |
+
"optional":{
|
858 |
+
"join_global_parameters": ("ATTNMOD", {"forceInput": True}),
|
859 |
+
}}
|
860 |
+
RETURN_TYPES = ("MODEL", "STRING", "STRING",)
|
861 |
+
RETURN_NAMES = ("Model", "Preset name", "Parameters as string",)
|
862 |
+
FUNCTION = "patch"
|
863 |
+
|
864 |
+
CATEGORY = "model_patches/Automatic_CFG"
|
865 |
+
|
866 |
+
def patch(self, model, preset, uncond_sigma_end, use_uncond_sigma_end_from_preset, automatic_cfg, join_global_parameters=None):
|
867 |
+
with open(os.path.join(json_preset_path, preset+".json"), 'r', encoding='utf-8') as f:
|
868 |
+
preset_args = json.load(f)
|
869 |
+
if not use_uncond_sigma_end_from_preset:
|
870 |
+
preset_args["uncond_sigma_end"] = uncond_sigma_end
|
871 |
+
preset_args["fake_uncond_sigma_end"] = uncond_sigma_end
|
872 |
+
preset_args["fake_uncond_exp_sigma_end"] = uncond_sigma_end
|
873 |
+
preset_args["uncond_exp_sigma_end"] = uncond_sigma_end
|
874 |
+
|
875 |
+
if join_global_parameters is not None:
|
876 |
+
preset_args["attention_modifiers_global"] = preset_args["attention_modifiers_global"] + join_global_parameters
|
877 |
+
preset_args["attention_modifiers_global_enabled"] = True
|
878 |
+
|
879 |
+
if automatic_cfg != "From preset":
|
880 |
+
preset_args["automatic_cfg"] = automatic_cfg
|
881 |
+
|
882 |
+
advcfg = advancedDynamicCFG()
|
883 |
+
m = advcfg.patch(model, **preset_args)[0]
|
884 |
+
info_string = ",\n".join([f"\"{k}\": {v}" for k,v in preset_args.items() if v != ""])
|
885 |
+
print(f"Preset {Fore.GREEN}{preset}{Fore.RESET} loaded successfully!")
|
886 |
+
return (m, preset, info_string,)
|
887 |
+
|
888 |
+
class simpleDynamicCFGlerpUncond:
|
889 |
+
@classmethod
|
890 |
+
def INPUT_TYPES(s):
|
891 |
+
return {"required": {
|
892 |
+
"model": ("MODEL",),
|
893 |
+
"boost" : ("BOOLEAN", {"default": True}),
|
894 |
+
"negative_strength": ("FLOAT", {"default": 1, "min": 0.0, "max": 5.0, "step": 0.1, "round": 0.1}),
|
895 |
+
}}
|
896 |
+
RETURN_TYPES = ("MODEL",)
|
897 |
+
FUNCTION = "patch"
|
898 |
+
|
899 |
+
CATEGORY = "model_patches/Automatic_CFG/presets"
|
900 |
+
|
901 |
+
def patch(self, model, boost, negative_strength):
|
902 |
+
advcfg = advancedDynamicCFG()
|
903 |
+
m = advcfg.patch(model=model,
|
904 |
+
automatic_cfg="hard", skip_uncond=boost,
|
905 |
+
uncond_sigma_start = 15, uncond_sigma_end = 1,
|
906 |
+
lerp_uncond=negative_strength != 1, lerp_uncond_strength=negative_strength,
|
907 |
+
lerp_uncond_sigma_start = 15, lerp_uncond_sigma_end = 1
|
908 |
+
)[0]
|
909 |
+
return (m, )
|
910 |
+
|
911 |
+
class postCFGrescaleOnly:
|
912 |
+
@classmethod
|
913 |
+
def INPUT_TYPES(s):
|
914 |
+
return {"required": {
|
915 |
+
"model": ("MODEL",),
|
916 |
+
"subtract_latent_mean" : ("BOOLEAN", {"default": True}),
|
917 |
+
"subtract_latent_mean_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.1}),
|
918 |
+
"subtract_latent_mean_sigma_end": ("FLOAT", {"default": 7.5, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.1}),
|
919 |
+
"latent_intensity_rescale" : ("BOOLEAN", {"default": True}),
|
920 |
+
"latent_intensity_rescale_method" : (["soft","hard","range"], {"default": "hard"},),
|
921 |
+
"latent_intensity_rescale_cfg" : ("FLOAT", {"default": 8, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.1}),
|
922 |
+
"latent_intensity_rescale_sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.1}),
|
923 |
+
"latent_intensity_rescale_sigma_end": ("FLOAT", {"default": 5, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.1}),
|
924 |
+
}}
|
925 |
+
RETURN_TYPES = ("MODEL",)
|
926 |
+
FUNCTION = "patch"
|
927 |
+
|
928 |
+
CATEGORY = "model_patches/Automatic_CFG/utils"
|
929 |
+
|
930 |
+
def patch(self, model,
|
931 |
+
subtract_latent_mean, subtract_latent_mean_sigma_start, subtract_latent_mean_sigma_end,
|
932 |
+
latent_intensity_rescale, latent_intensity_rescale_method, latent_intensity_rescale_cfg, latent_intensity_rescale_sigma_start, latent_intensity_rescale_sigma_end
|
933 |
+
):
|
934 |
+
advcfg = advancedDynamicCFG()
|
935 |
+
m = advcfg.patch(model=model,
|
936 |
+
subtract_latent_mean = subtract_latent_mean,
|
937 |
+
subtract_latent_mean_sigma_start = subtract_latent_mean_sigma_start, subtract_latent_mean_sigma_end = subtract_latent_mean_sigma_end,
|
938 |
+
latent_intensity_rescale = latent_intensity_rescale, latent_intensity_rescale_cfg = latent_intensity_rescale_cfg, latent_intensity_rescale_method = latent_intensity_rescale_method,
|
939 |
+
latent_intensity_rescale_sigma_start = latent_intensity_rescale_sigma_start, latent_intensity_rescale_sigma_end = latent_intensity_rescale_sigma_end,
|
940 |
+
ignore_pre_cfg_func = True
|
941 |
+
)[0]
|
942 |
+
return (m, )
|
943 |
+
|
944 |
+
class simpleDynamicCFGHighSpeed:
|
945 |
+
@classmethod
|
946 |
+
def INPUT_TYPES(s):
|
947 |
+
return {"required": {
|
948 |
+
"model": ("MODEL",),
|
949 |
+
}}
|
950 |
+
RETURN_TYPES = ("MODEL",)
|
951 |
+
FUNCTION = "patch"
|
952 |
+
|
953 |
+
CATEGORY = "model_patches/Automatic_CFG/presets"
|
954 |
+
|
955 |
+
def patch(self, model):
|
956 |
+
advcfg = advancedDynamicCFG()
|
957 |
+
m = advcfg.patch(model=model, automatic_cfg = "hard",
|
958 |
+
skip_uncond = True, uncond_sigma_start = 7.5, uncond_sigma_end = 1)[0]
|
959 |
+
return (m, )
|
960 |
+
|
961 |
+
class simpleDynamicCFGwarpDrive:
|
962 |
+
@classmethod
|
963 |
+
def INPUT_TYPES(s):
|
964 |
+
return {"required": {
|
965 |
+
"model": ("MODEL",),
|
966 |
+
"uncond_sigma_start": ("FLOAT", {"default": 5.5, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
967 |
+
"uncond_sigma_end": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
968 |
+
"fake_uncond_sigma_end": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
969 |
+
}}
|
970 |
+
RETURN_TYPES = ("MODEL",)
|
971 |
+
FUNCTION = "patch"
|
972 |
+
|
973 |
+
CATEGORY = "model_patches/Automatic_CFG/presets"
|
974 |
+
|
975 |
+
def patch(self, model, uncond_sigma_start, uncond_sigma_end, fake_uncond_sigma_end):
|
976 |
+
advcfg = advancedDynamicCFG()
|
977 |
+
print(f" {Fore.CYAN}WARP DRIVE MODE ENGAGED!{Style.RESET_ALL}\n Settings suggestions:\n"
|
978 |
+
f" {Fore.GREEN}1/1/1: {Fore.YELLOW}Maaaxxxiiimum speeeeeed.{Style.RESET_ALL} {Fore.RED}Uncond disabled.{Style.RESET_ALL} {Fore.MAGENTA}Fasten your seatbelt!{Style.RESET_ALL}\n"
|
979 |
+
f" {Fore.GREEN}3/1/1: {Fore.YELLOW}Risky space-time continuum distortion.{Style.RESET_ALL} {Fore.MAGENTA}Awesome for prompts with a clear subject!{Style.RESET_ALL}\n"
|
980 |
+
f" {Fore.GREEN}5.5/1/1: {Fore.YELLOW}Frameshift Drive Autopilot: {Fore.GREEN}Engaged.{Style.RESET_ALL} {Fore.MAGENTA}Should work with anything but do it better and faster!{Style.RESET_ALL}")
|
981 |
+
|
982 |
+
m = advcfg.patch(model=model, automatic_cfg = "hard",
|
983 |
+
skip_uncond = True, uncond_sigma_start = uncond_sigma_start, uncond_sigma_end = uncond_sigma_end,
|
984 |
+
fake_uncond_sigma_end = fake_uncond_sigma_end, fake_uncond_sigma_start = 1000, fake_uncond_start=True,
|
985 |
+
fake_uncond_exp=True,fake_uncond_exp_normalize=True,fake_uncond_exp_method="previous_average",
|
986 |
+
cond_exp = False, cond_exp_sigma_start = 9, cond_exp_sigma_end = uncond_sigma_start, cond_exp_method = "erf", cond_exp_normalize = True,
|
987 |
+
)[0]
|
988 |
+
return (m, )
|
989 |
+
|
990 |
+
class simpleDynamicCFGunpatch:
|
991 |
+
@classmethod
|
992 |
+
def INPUT_TYPES(s):
|
993 |
+
return {"required": {
|
994 |
+
"model": ("MODEL",),
|
995 |
+
}}
|
996 |
+
RETURN_TYPES = ("MODEL",)
|
997 |
+
FUNCTION = "unpatch"
|
998 |
+
|
999 |
+
CATEGORY = "model_patches/Automatic_CFG/utils"
|
1000 |
+
|
1001 |
+
def unpatch(self, model):
|
1002 |
+
m = model.clone()
|
1003 |
+
m.model_options.pop("sampler_pre_cfg_automatic_cfg_function", None)
|
1004 |
+
return (m, )
|
1005 |
+
|
1006 |
+
class simpleDynamicCFGExcellentattentionPatch:
|
1007 |
+
@classmethod
|
1008 |
+
def INPUT_TYPES(s):
|
1009 |
+
inputs = {"required": {
|
1010 |
+
"model": ("MODEL",),
|
1011 |
+
"Auto_CFG": ("BOOLEAN", {"default": True}),
|
1012 |
+
"patch_multiplier": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 1.0, "round": 0.01}),
|
1013 |
+
"patch_cond": ("BOOLEAN", {"default": True}),
|
1014 |
+
"patch_uncond": ("BOOLEAN", {"default": True}),
|
1015 |
+
"light_patch": ("BOOLEAN", {"default": False}),
|
1016 |
+
"mute_self_input_layer_8_cond": ("BOOLEAN", {"default": False}),
|
1017 |
+
"mute_cross_input_layer_8_cond": ("BOOLEAN", {"default": False}),
|
1018 |
+
"mute_self_input_layer_8_uncond": ("BOOLEAN", {"default": True}),
|
1019 |
+
"mute_cross_input_layer_8_uncond": ("BOOLEAN", {"default": False}),
|
1020 |
+
"uncond_sigma_end": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
1021 |
+
"bypass_layer_8_instead_of_mute": ("BOOLEAN", {"default": False}),
|
1022 |
+
"save_as_preset": ("BOOLEAN", {"default": False}),
|
1023 |
+
"preset_name": ("STRING", {"multiline": False}),
|
1024 |
+
},
|
1025 |
+
"optional":{
|
1026 |
+
"attn_mod_for_positive_operation": ("ATTNMOD", {"forceInput": True}),
|
1027 |
+
"attn_mod_for_negative_operation": ("ATTNMOD", {"forceInput": True}),
|
1028 |
+
},
|
1029 |
+
}
|
1030 |
+
if "dev_env.txt" in os.listdir(current_dir):
|
1031 |
+
inputs['optional'].update({"attn_mod_for_global_operation": ("ATTNMOD", {"forceInput": True})})
|
1032 |
+
return inputs
|
1033 |
+
|
1034 |
+
RETURN_TYPES = ("MODEL","STRING",)
|
1035 |
+
RETURN_NAMES = ("Model", "Parameters as string",)
|
1036 |
+
FUNCTION = "patch"
|
1037 |
+
|
1038 |
+
CATEGORY = "model_patches/Automatic_CFG"
|
1039 |
+
|
1040 |
+
def patch(self, model, Auto_CFG, patch_multiplier, patch_cond, patch_uncond, light_patch,
|
1041 |
+
mute_self_input_layer_8_cond, mute_cross_input_layer_8_cond,
|
1042 |
+
mute_self_input_layer_8_uncond, mute_cross_input_layer_8_uncond,
|
1043 |
+
uncond_sigma_end,bypass_layer_8_instead_of_mute, save_as_preset, preset_name,
|
1044 |
+
attn_mod_for_positive_operation = None, attn_mod_for_negative_operation = None, attn_mod_for_global_operation = None):
|
1045 |
+
|
1046 |
+
parameters_as_string = "Excellent attention:\n" + "\n".join([f"{k}: {v}" for k, v in locals().items() if k not in ["self", "model"]])
|
1047 |
+
|
1048 |
+
with open(os.path.join(json_preset_path, "Excellent_attention.json"), 'r', encoding='utf-8') as f:
|
1049 |
+
patch_parameters = json.load(f)
|
1050 |
+
|
1051 |
+
attn_patch = {"sigma_start": 1000, "sigma_end": 0,
|
1052 |
+
"self_attn_mod_eval": f"normalize_tensor(q+(q-attention_basic(attnbc, k, v, extra_options['n_heads'])))*attnbc.norm()*{patch_multiplier}",
|
1053 |
+
"unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn2"}
|
1054 |
+
attn_patch_light = {"sigma_start": 1000, "sigma_end": 0,
|
1055 |
+
"self_attn_mod_eval": f"q*{patch_multiplier}",
|
1056 |
+
"unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn2"}
|
1057 |
+
|
1058 |
+
kill_self_input_8 = {
|
1059 |
+
"sigma_start": 1000,
|
1060 |
+
"sigma_end": 0,
|
1061 |
+
"self_attn_mod_eval": "q" if bypass_layer_8_instead_of_mute else "torch.zeros_like(q)",
|
1062 |
+
"unet_block_id_input": "8",
|
1063 |
+
"unet_block_id_middle": "",
|
1064 |
+
"unet_block_id_output": "",
|
1065 |
+
"unet_attn": "attn1"}
|
1066 |
+
|
1067 |
+
kill_cross_input_8 = kill_self_input_8.copy()
|
1068 |
+
kill_cross_input_8['unet_attn'] = "attn2"
|
1069 |
+
|
1070 |
+
attention_modifiers_positive = []
|
1071 |
+
attention_modifiers_fake_negative = []
|
1072 |
+
|
1073 |
+
if patch_cond: attention_modifiers_positive.append(attn_patch) if not light_patch else attention_modifiers_positive.append(attn_patch_light)
|
1074 |
+
if mute_self_input_layer_8_cond: attention_modifiers_positive.append(kill_self_input_8)
|
1075 |
+
if mute_cross_input_layer_8_cond: attention_modifiers_positive.append(kill_cross_input_8)
|
1076 |
+
|
1077 |
+
if patch_uncond: attention_modifiers_fake_negative.append(attn_patch) if not light_patch else attention_modifiers_fake_negative.append(attn_patch_light)
|
1078 |
+
if mute_self_input_layer_8_uncond: attention_modifiers_fake_negative.append(kill_self_input_8)
|
1079 |
+
if mute_cross_input_layer_8_uncond: attention_modifiers_fake_negative.append(kill_cross_input_8)
|
1080 |
+
|
1081 |
+
patch_parameters['attention_modifiers_positive'] = attention_modifiers_positive
|
1082 |
+
patch_parameters['attention_modifiers_fake_negative'] = attention_modifiers_fake_negative
|
1083 |
+
|
1084 |
+
if attn_mod_for_positive_operation is not None:
|
1085 |
+
patch_parameters['attention_modifiers_positive'] = patch_parameters['attention_modifiers_positive'] + attn_mod_for_positive_operation
|
1086 |
+
if attn_mod_for_negative_operation is not None:
|
1087 |
+
patch_parameters['attention_modifiers_fake_negative'] = patch_parameters['attention_modifiers_fake_negative'] + attn_mod_for_negative_operation
|
1088 |
+
if attn_mod_for_global_operation is not None:
|
1089 |
+
patch_parameters["attention_modifiers_global_enabled"] = True
|
1090 |
+
patch_parameters['attention_modifiers_global'] = attn_mod_for_global_operation
|
1091 |
+
|
1092 |
+
patch_parameters["uncond_sigma_end"] = uncond_sigma_end
|
1093 |
+
patch_parameters["fake_uncond_sigma_end"] = uncond_sigma_end
|
1094 |
+
patch_parameters["automatic_cfg"] = "hard" if Auto_CFG else "None"
|
1095 |
+
|
1096 |
+
if save_as_preset:
|
1097 |
+
patch_parameters["save_as_preset"] = save_as_preset
|
1098 |
+
patch_parameters["preset_name"] = preset_name
|
1099 |
+
|
1100 |
+
advcfg = advancedDynamicCFG()
|
1101 |
+
m = advcfg.patch(model, **patch_parameters)[0]
|
1102 |
+
|
1103 |
+
return (m, parameters_as_string, )
|
1104 |
+
|
1105 |
+
class simpleDynamicCFGCustomAttentionPatch:
|
1106 |
+
@classmethod
|
1107 |
+
def INPUT_TYPES(s):
|
1108 |
+
return {"required": {
|
1109 |
+
"model": ("MODEL",),
|
1110 |
+
"Auto_CFG": ("BOOLEAN", {"default": True}),
|
1111 |
+
"cond_mode" : (["replace_by_custom","normal+(normal-custom_cond)*multiplier","normal+(normal-custom_uncond)*multiplier"],),
|
1112 |
+
"uncond_mode" : (["replace_by_custom","normal+(normal-custom_cond)*multiplier","normal+(normal-custom_uncond)*multiplier"],),
|
1113 |
+
"cond_diff_multiplier": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.1, "round": 0.01}),
|
1114 |
+
"uncond_diff_multiplier": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.1, "round": 0.01}),
|
1115 |
+
"uncond_sigma_end": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10000, "step": 0.1, "round": 0.01}),
|
1116 |
+
"save_as_preset": ("BOOLEAN", {"default": False}),
|
1117 |
+
"preset_name": ("STRING", {"multiline": False}),
|
1118 |
+
},
|
1119 |
+
"optional":{
|
1120 |
+
"attn_mod_for_positive_operation": ("ATTNMOD", {"forceInput": True}),
|
1121 |
+
"attn_mod_for_negative_operation": ("ATTNMOD", {"forceInput": True}),
|
1122 |
+
}}
|
1123 |
+
RETURN_TYPES = ("MODEL",)
|
1124 |
+
RETURN_NAMES = ("Model",)
|
1125 |
+
FUNCTION = "patch"
|
1126 |
+
|
1127 |
+
CATEGORY = "model_patches/Automatic_CFG/experimental_attention_modifiers"
|
1128 |
+
|
1129 |
+
def patch(self, model, Auto_CFG, cond_mode, uncond_mode, cond_diff_multiplier, uncond_diff_multiplier, uncond_sigma_end, save_as_preset, preset_name,
|
1130 |
+
attn_mod_for_positive_operation = [], attn_mod_for_negative_operation = []):
|
1131 |
+
|
1132 |
+
with open(os.path.join(json_preset_path, "do_not_delete.json"), 'r', encoding='utf-8') as f:
|
1133 |
+
patch_parameters = json.load(f)
|
1134 |
+
|
1135 |
+
patch_parameters["cond_exp_value"] = cond_diff_multiplier
|
1136 |
+
patch_parameters["uncond_exp_value"] = uncond_diff_multiplier
|
1137 |
+
|
1138 |
+
if cond_mode != "replace_by_custom":
|
1139 |
+
patch_parameters["disable_cond"] = False
|
1140 |
+
if cond_mode == "normal+(normal-custom_cond)*multiplier":
|
1141 |
+
patch_parameters["cond_exp_method"] = "subtract_attention_modifiers_input_using_cond"
|
1142 |
+
elif cond_mode == "normal+(normal-custom_uncond)*multiplier":
|
1143 |
+
patch_parameters["cond_exp_method"] = "subtract_attention_modifiers_input_using_uncond"
|
1144 |
+
|
1145 |
+
if uncond_mode != "replace_by_custom":
|
1146 |
+
patch_parameters["uncond_sigma_start"] = 1000.0
|
1147 |
+
patch_parameters["fake_uncond_exp"] = False
|
1148 |
+
patch_parameters["uncond_exp"] = True
|
1149 |
+
|
1150 |
+
if uncond_mode == "normal+(normal-custom_cond)*multiplier":
|
1151 |
+
patch_parameters["uncond_exp_method"] = "subtract_attention_modifiers_input_using_cond"
|
1152 |
+
elif uncond_mode == "normal+(normal-custom_uncond)*multiplier":
|
1153 |
+
patch_parameters["uncond_exp_method"] = "subtract_attention_modifiers_input_using_uncond"
|
1154 |
+
|
1155 |
+
if cond_mode != "replace_by_custom" and attn_mod_for_positive_operation != []:
|
1156 |
+
smallest_sigma = min([float(x['sigma_end']) for x in attn_mod_for_positive_operation])
|
1157 |
+
patch_parameters["disable_cond_sigma_end"] = smallest_sigma
|
1158 |
+
patch_parameters["cond_exp_sigma_end"] = smallest_sigma
|
1159 |
+
|
1160 |
+
if uncond_mode != "replace_by_custom" and attn_mod_for_negative_operation != []:
|
1161 |
+
smallest_sigma = min([float(x['sigma_end']) for x in attn_mod_for_negative_operation])
|
1162 |
+
patch_parameters["uncond_exp_sigma_end"] = smallest_sigma
|
1163 |
+
patch_parameters["fake_uncond_start"] = False
|
1164 |
+
# else:
|
1165 |
+
# biggest_sigma = max([float(x['sigma_start']) for x in attn_mod_for_negative_operation])
|
1166 |
+
# patch_parameters["fake_uncond_sigma_start"] = biggest_sigma
|
1167 |
+
|
1168 |
+
patch_parameters["automatic_cfg"] = "hard" if Auto_CFG else "None"
|
1169 |
+
patch_parameters['attention_modifiers_positive'] = attn_mod_for_positive_operation
|
1170 |
+
patch_parameters['attention_modifiers_negative'] = attn_mod_for_negative_operation
|
1171 |
+
patch_parameters['attention_modifiers_fake_negative'] = attn_mod_for_negative_operation
|
1172 |
+
patch_parameters["uncond_sigma_end"] = uncond_sigma_end
|
1173 |
+
patch_parameters["fake_uncond_sigma_end"] = uncond_sigma_end
|
1174 |
+
patch_parameters["save_as_preset"] = save_as_preset
|
1175 |
+
patch_parameters["preset_name"] = preset_name
|
1176 |
+
|
1177 |
+
advcfg = advancedDynamicCFG()
|
1178 |
+
m = advcfg.patch(model, **patch_parameters)[0]
|
1179 |
+
|
1180 |
+
return (m, )
|
1181 |
+
|
1182 |
+
|
1183 |
+
|
1184 |
+
|
1185 |
+
class attentionModifierSingleLayerBypassNode:
|
1186 |
+
@classmethod
|
1187 |
+
def INPUT_TYPES(s):
|
1188 |
+
return {"required": {
|
1189 |
+
"sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
1190 |
+
"sigma_end": ("FLOAT", {"default": 0, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
1191 |
+
"block_name": (["input","middle","output"],),
|
1192 |
+
"block_number": ("INT", {"default": 0, "min": 0, "max": 12, "step": 1}),
|
1193 |
+
"unet_attn": (["attn1","attn2","both"],),
|
1194 |
+
},
|
1195 |
+
"optional":{
|
1196 |
+
"join_parameters": ("ATTNMOD", {"forceInput": True}),
|
1197 |
+
}}
|
1198 |
+
|
1199 |
+
RETURN_TYPES = ("ATTNMOD","STRING",)
|
1200 |
+
RETURN_NAMES = ("Attention modifier", "Parameters as string")
|
1201 |
+
FUNCTION = "exec"
|
1202 |
+
CATEGORY = "model_patches/Automatic_CFG/experimental_attention_modifiers"
|
1203 |
+
|
1204 |
+
def exec(self, sigma_start, sigma_end, block_name, block_number, unet_attn, join_parameters=None):
|
1205 |
+
attn_modifier_dict = {
|
1206 |
+
"sigma_start": sigma_start, "sigma_end": sigma_end,
|
1207 |
+
"self_attn_mod_eval": "q",
|
1208 |
+
"unet_block_id_input": str(block_number) if block_name == "input" else "",
|
1209 |
+
"unet_block_id_middle": str(block_number) if block_name == "middle" else "",
|
1210 |
+
"unet_block_id_output": str(block_number) if block_name == "output" else "",
|
1211 |
+
"unet_attn": f"{unet_attn}"
|
1212 |
+
}
|
1213 |
+
|
1214 |
+
info_string = "\n".join([f"{k}: {v}" for k,v in attn_modifier_dict.items() if v != ""])
|
1215 |
+
|
1216 |
+
if unet_attn == "both":
|
1217 |
+
attn_modifier_dict['unet_attn'] = "attn1"
|
1218 |
+
copy_attn_modifier_dict = attn_modifier_dict.copy()
|
1219 |
+
copy_attn_modifier_dict['unet_attn'] = "attn2"
|
1220 |
+
out_modifiers = [attn_modifier_dict, copy_attn_modifier_dict]
|
1221 |
+
else:
|
1222 |
+
out_modifiers = [attn_modifier_dict]
|
1223 |
+
|
1224 |
+
return (out_modifiers if join_parameters is None else join_parameters + out_modifiers, info_string, )
|
1225 |
+
|
1226 |
+
class attentionModifierSingleLayerTemperatureNode:
|
1227 |
+
@classmethod
|
1228 |
+
def INPUT_TYPES(s):
|
1229 |
+
return {"required": {
|
1230 |
+
"sigma_start": ("FLOAT", {"default": 1000, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
1231 |
+
"sigma_end": ("FLOAT", {"default": 0, "min": 0.0, "max": 10000.0, "step": 0.1, "round": 0.01}),
|
1232 |
+
"block_name": (["input","middle","output"],),
|
1233 |
+
"block_number": ("INT", {"default": 0, "min": 0, "max": 12, "step": 1}),
|
1234 |
+
"unet_attn": (["attn1","attn2","both"],),
|
1235 |
+
"temperature": ("FLOAT", {"default": 1, "min": 0.0, "max": 10000.0, "step": 0.01, "round": 0.01}),
|
1236 |
+
},
|
1237 |
+
"optional":{
|
1238 |
+
"join_parameters": ("ATTNMOD", {"forceInput": True}),
|
1239 |
+
}}
|
1240 |
+
|
1241 |
+
RETURN_TYPES = ("ATTNMOD","STRING",)
|
1242 |
+
RETURN_NAMES = ("Attention modifier", "Parameters as string")
|
1243 |
+
FUNCTION = "exec"
|
1244 |
+
CATEGORY = "model_patches/Automatic_CFG/experimental_attention_modifiers"
|
1245 |
+
|
1246 |
+
def exec(self, sigma_start, sigma_end, block_name, block_number, unet_attn, temperature, join_parameters=None):
|
1247 |
+
attn_modifier_dict = {
|
1248 |
+
"sigma_start": sigma_start, "sigma_end": sigma_end,
|
1249 |
+
"self_attn_mod_eval": f"temperature_patcher({temperature}).attention_basic_with_temperature(q, k, v, extra_options)",
|
1250 |
+
"unet_block_id_input": str(block_number) if block_name == "input" else "",
|
1251 |
+
"unet_block_id_middle": str(block_number) if block_name == "middle" else "",
|
1252 |
+
"unet_block_id_output": str(block_number) if block_name == "output" else "",
|
1253 |
+
"unet_attn": f"{unet_attn}"
|
1254 |
+
}
|
1255 |
+
|
1256 |
+
info_string = "\n".join([f"{k}: {v}" for k,v in attn_modifier_dict.items() if v != ""])
|
1257 |
+
|
1258 |
+
if unet_attn == "both":
|
1259 |
+
attn_modifier_dict['unet_attn'] = "attn1"
|
1260 |
+
copy_attn_modifier_dict = attn_modifier_dict.copy()
|
1261 |
+
copy_attn_modifier_dict['unet_attn'] = "attn2"
|
1262 |
+
out_modifiers = [attn_modifier_dict, copy_attn_modifier_dict]
|
1263 |
+
else:
|
1264 |
+
out_modifiers = [attn_modifier_dict]
|
1265 |
+
|
1266 |
+
return (out_modifiers if join_parameters is None else join_parameters + out_modifiers, info_string, )
|
1267 |
+
|
1268 |
+
class uncondZeroNode:
|
1269 |
+
@classmethod
|
1270 |
+
def INPUT_TYPES(s):
|
1271 |
+
return {"required": {
|
1272 |
+
"model": ("MODEL",),
|
1273 |
+
"scale": ("FLOAT", {"default": 1.2, "min": 0.0, "max": 10.0, "step": 0.01, "round": 0.01}),
|
1274 |
+
}}
|
1275 |
+
RETURN_TYPES = ("MODEL",)
|
1276 |
+
FUNCTION = "patch"
|
1277 |
+
|
1278 |
+
CATEGORY = "model_patches/Automatic_CFG"
|
1279 |
+
|
1280 |
+
def patch(self, model, scale):
|
1281 |
+
def custom_patch(args):
|
1282 |
+
cond_pred = args["cond_denoised"]
|
1283 |
+
input_x = args["input"]
|
1284 |
+
if args["sigma"][0] <= 1:
|
1285 |
+
return input_x - cond_pred
|
1286 |
+
cond = input_x - cond_pred
|
1287 |
+
uncond = input_x - torch.zeros_like(cond)
|
1288 |
+
return uncond + scale * (cond - uncond)
|
1289 |
+
|
1290 |
+
m = model.clone()
|
1291 |
+
m.set_model_sampler_cfg_function(custom_patch)
|
1292 |
+
return (m, )
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/nodes_sag_custom.py
ADDED
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from torch import einsum
|
3 |
+
import torch.nn.functional as F
|
4 |
+
import math
|
5 |
+
|
6 |
+
from einops import rearrange, repeat
|
7 |
+
import os
|
8 |
+
from comfy.ldm.modules.attention import optimized_attention, _ATTN_PRECISION
|
9 |
+
import comfy.samplers
|
10 |
+
|
11 |
+
# from comfy/ldm/modules/attention.py
|
12 |
+
# but modified to return attention scores as well as output
|
13 |
+
def attention_basic_with_sim(q, k, v, heads, mask=None):
|
14 |
+
b, _, dim_head = q.shape
|
15 |
+
dim_head //= heads
|
16 |
+
scale = dim_head ** -0.5
|
17 |
+
|
18 |
+
h = heads
|
19 |
+
q, k, v = map(
|
20 |
+
lambda t: t.unsqueeze(3)
|
21 |
+
.reshape(b, -1, heads, dim_head)
|
22 |
+
.permute(0, 2, 1, 3)
|
23 |
+
.reshape(b * heads, -1, dim_head)
|
24 |
+
.contiguous(),
|
25 |
+
(q, k, v),
|
26 |
+
)
|
27 |
+
|
28 |
+
# force cast to fp32 to avoid overflowing
|
29 |
+
if _ATTN_PRECISION =="fp32":
|
30 |
+
sim = einsum('b i d, b j d -> b i j', q.float(), k.float()) * scale
|
31 |
+
else:
|
32 |
+
sim = einsum('b i d, b j d -> b i j', q, k) * scale
|
33 |
+
|
34 |
+
del q, k
|
35 |
+
|
36 |
+
if mask is not None:
|
37 |
+
mask = rearrange(mask, 'b ... -> b (...)')
|
38 |
+
max_neg_value = -torch.finfo(sim.dtype).max
|
39 |
+
mask = repeat(mask, 'b j -> (b h) () j', h=h)
|
40 |
+
sim.masked_fill_(~mask, max_neg_value)
|
41 |
+
|
42 |
+
# attention, what we cannot get enough of
|
43 |
+
sim = sim.softmax(dim=-1)
|
44 |
+
|
45 |
+
out = einsum('b i j, b j d -> b i d', sim.to(v.dtype), v)
|
46 |
+
out = (
|
47 |
+
out.unsqueeze(0)
|
48 |
+
.reshape(b, heads, -1, dim_head)
|
49 |
+
.permute(0, 2, 1, 3)
|
50 |
+
.reshape(b, -1, heads * dim_head)
|
51 |
+
)
|
52 |
+
return (out, sim)
|
53 |
+
|
54 |
+
def create_blur_map(x0, attn, sigma=3.0, threshold=1.0):
|
55 |
+
# reshape and GAP the attention map
|
56 |
+
_, hw1, hw2 = attn.shape
|
57 |
+
b, _, lh, lw = x0.shape
|
58 |
+
attn = attn.reshape(b, -1, hw1, hw2)
|
59 |
+
# Global Average Pool
|
60 |
+
mask = attn.mean(1, keepdim=False).sum(1, keepdim=False) > threshold
|
61 |
+
ratio = 2**(math.ceil(math.sqrt(lh * lw / hw1)) - 1).bit_length()
|
62 |
+
mid_shape = [math.ceil(lh / ratio), math.ceil(lw / ratio)]
|
63 |
+
|
64 |
+
# Reshape
|
65 |
+
mask = (
|
66 |
+
mask.reshape(b, *mid_shape)
|
67 |
+
.unsqueeze(1)
|
68 |
+
.type(attn.dtype)
|
69 |
+
)
|
70 |
+
# Upsample
|
71 |
+
mask = F.interpolate(mask, (lh, lw))
|
72 |
+
|
73 |
+
blurred = gaussian_blur_2d(x0, kernel_size=9, sigma=sigma)
|
74 |
+
blurred = blurred * mask + x0 * (1 - mask)
|
75 |
+
return blurred
|
76 |
+
|
77 |
+
def gaussian_blur_2d(img, kernel_size, sigma):
|
78 |
+
ksize_half = (kernel_size - 1) * 0.5
|
79 |
+
|
80 |
+
x = torch.linspace(-ksize_half, ksize_half, steps=kernel_size)
|
81 |
+
|
82 |
+
pdf = torch.exp(-0.5 * (x / sigma).pow(2))
|
83 |
+
|
84 |
+
x_kernel = pdf / pdf.sum()
|
85 |
+
x_kernel = x_kernel.to(device=img.device, dtype=img.dtype)
|
86 |
+
|
87 |
+
kernel2d = torch.mm(x_kernel[:, None], x_kernel[None, :])
|
88 |
+
kernel2d = kernel2d.expand(img.shape[-3], 1, kernel2d.shape[0], kernel2d.shape[1])
|
89 |
+
|
90 |
+
padding = [kernel_size // 2, kernel_size // 2, kernel_size // 2, kernel_size // 2]
|
91 |
+
|
92 |
+
img = F.pad(img, padding, mode="reflect")
|
93 |
+
img = F.conv2d(img, kernel2d, groups=img.shape[-3])
|
94 |
+
return img
|
95 |
+
|
96 |
+
def get_denoised_ranges(latent, measure="hard", top_k=0.25):
|
97 |
+
chans = []
|
98 |
+
for x in range(len(latent)):
|
99 |
+
max_values = torch.topk(latent[x] - latent[x].mean() if measure == "range" else latent[x], k=int(len(latent[x])*top_k), largest=True).values
|
100 |
+
min_values = torch.topk(latent[x] - latent[x].mean() if measure == "range" else latent[x], k=int(len(latent[x])*top_k), largest=False).values
|
101 |
+
max_val = torch.mean(max_values).item()
|
102 |
+
min_val = torch.mean(torch.abs(min_values)).item() if (measure == "hard" or measure == "range") else abs(torch.mean(min_values).item())
|
103 |
+
denoised_range = (max_val + min_val) / 2
|
104 |
+
chans.append(denoised_range)
|
105 |
+
return chans
|
106 |
+
|
107 |
+
class SelfAttentionGuidanceCustom:
|
108 |
+
@classmethod
|
109 |
+
def INPUT_TYPES(s):
|
110 |
+
return {"required": { "model": ("MODEL",),
|
111 |
+
"scale": ("FLOAT", {"default": 0.5, "min": -2.0, "max": 100.0, "step": 0.1}),
|
112 |
+
"blur_sigma": ("FLOAT", {"default": 2.0, "min": 0.0, "max": 10.0, "step": 0.1}),
|
113 |
+
"sigma_start": ("FLOAT", {"default": 15.0, "min": 0.0, "max": 1000.0, "step": 0.1, "round": 0.1}),
|
114 |
+
"sigma_end": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1000.0, "step": 0.1, "round": 0.1}),
|
115 |
+
"auto_scale" : ("BOOLEAN", {"default": False}),
|
116 |
+
}}
|
117 |
+
RETURN_TYPES = ("MODEL",)
|
118 |
+
FUNCTION = "patch"
|
119 |
+
|
120 |
+
CATEGORY = "model_patches"
|
121 |
+
|
122 |
+
def patch(self, model, scale, blur_sigma, sigma_start, sigma_end, auto_scale):
|
123 |
+
m = model.clone()
|
124 |
+
|
125 |
+
attn_scores = None
|
126 |
+
|
127 |
+
# TODO: make this work properly with chunked batches
|
128 |
+
# currently, we can only save the attn from one UNet call
|
129 |
+
def attn_and_record(q, k, v, extra_options):
|
130 |
+
nonlocal attn_scores
|
131 |
+
# if uncond, save the attention scores
|
132 |
+
heads = extra_options["n_heads"]
|
133 |
+
cond_or_uncond = extra_options["cond_or_uncond"]
|
134 |
+
b = q.shape[0] // len(cond_or_uncond)
|
135 |
+
if 1 in cond_or_uncond:
|
136 |
+
uncond_index = cond_or_uncond.index(1)
|
137 |
+
# do the entire attention operation, but save the attention scores to attn_scores
|
138 |
+
(out, sim) = attention_basic_with_sim(q, k, v, heads=heads)
|
139 |
+
# when using a higher batch size, I BELIEVE the result batch dimension is [uc1, ... ucn, c1, ... cn]
|
140 |
+
n_slices = heads * b
|
141 |
+
attn_scores = sim[n_slices * uncond_index:n_slices * (uncond_index+1)]
|
142 |
+
return out
|
143 |
+
else:
|
144 |
+
return optimized_attention(q, k, v, heads=heads)
|
145 |
+
|
146 |
+
def post_cfg_function(args):
|
147 |
+
nonlocal attn_scores
|
148 |
+
uncond_attn = attn_scores
|
149 |
+
|
150 |
+
sag_scale = scale
|
151 |
+
sag_sigma = blur_sigma
|
152 |
+
sag_threshold = 1.0
|
153 |
+
model = args["model"]
|
154 |
+
uncond_pred = args["uncond_denoised"]
|
155 |
+
uncond = args["uncond"]
|
156 |
+
cfg_result = args["denoised"]
|
157 |
+
sigma = args["sigma"]
|
158 |
+
model_options = args["model_options"]
|
159 |
+
x = args["input"]
|
160 |
+
if uncond_pred is None or uncond is None or uncond_attn is None:
|
161 |
+
return cfg_result
|
162 |
+
if min(cfg_result.shape[2:]) <= 4: #skip when too small to add padding
|
163 |
+
return cfg_result
|
164 |
+
if sigma[0] > sigma_start or sigma[0] < sigma_end:
|
165 |
+
return cfg_result
|
166 |
+
# create the adversarially blurred image
|
167 |
+
degraded = create_blur_map(uncond_pred, uncond_attn, sag_sigma, sag_threshold)
|
168 |
+
degraded_noised = degraded + x - uncond_pred
|
169 |
+
# call into the UNet
|
170 |
+
(sag, _) = comfy.samplers.calc_cond_batch(model, [uncond, None], degraded_noised, sigma, model_options)
|
171 |
+
# comfy.samplers.calc_cond_uncond_batch(model, uncond, None, degraded_noised, sigma, model_options)
|
172 |
+
|
173 |
+
if auto_scale:
|
174 |
+
denoised_tmp = cfg_result + (degraded - sag) * 8
|
175 |
+
for b in range(len(denoised_tmp)):
|
176 |
+
denoised_ranges = get_denoised_ranges(denoised_tmp[b])
|
177 |
+
for c in range(len(denoised_tmp[b])):
|
178 |
+
fixed_scale = (sag_scale / 10) / denoised_ranges[c]
|
179 |
+
denoised_tmp[b][c] = cfg_result[b][c] + (degraded[b][c] - sag[b][c]) * fixed_scale
|
180 |
+
return denoised_tmp
|
181 |
+
|
182 |
+
return cfg_result + (degraded - sag) * sag_scale
|
183 |
+
|
184 |
+
m.set_model_sampler_post_cfg_function(post_cfg_function, disable_cfg1_optimization=False)
|
185 |
+
|
186 |
+
# from diffusers:
|
187 |
+
# unet.mid_block.attentions[0].transformer_blocks[0].attn1.patch
|
188 |
+
m.set_model_attn1_replace(attn_and_record, "middle", 0, 0)
|
189 |
+
|
190 |
+
return (m, )
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/A subtle touch.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 1000.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 1000.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 1000.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": true, "attention_modifiers_global": [{"sigma_start": 15, "sigma_end": 0, "self_attn_mod_eval": "q.sin()", "unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn2"}], "disable_cond": false, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "model_options_copy": {"transformer_options": {}}, "attention_modifiers_fake_negative": [], "attention_modifiers_negative": [], "attention_modifiers_positive": [], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": false, "cond_exp_method": "attention_modifiers_input_using_cond", "cond_exp_normalize": false, "cond_exp_sigma_end": 0.0, "cond_exp_sigma_start": 1000.0, "cond_exp_value": 1.0, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": false, "fake_uncond_exp_method": "attention_modifiers_input_using_uncond", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 1.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 1.0, "fake_uncond_sigma_start": 1000.0, "fake_uncond_start": true, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "eval_string"], "skip_uncond": true, "uncond_exp": false, "uncond_exp_method": "subtract_attention_modifiers_input_using_uncond", "uncond_exp_normalize": false, "uncond_exp_sigma_end": 0.0, "uncond_exp_sigma_start": 1000.0, "uncond_exp_value": 1.0, "uncond_sigma_end": 1.0, "uncond_sigma_start": 15.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Crossed conds customized 1.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 15.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 15.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 15.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": true, "attention_modifiers_global": [], "disable_cond": false, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "attention_modifiers_fake_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "k", "unet_block_id_input": "7,8", "unet_block_id_middle": "", "unet_block_id_output": "0", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "4", "unet_block_id_middle": "0", "unet_block_id_output": "3", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "attention_modifiers_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "k", "unet_block_id_input": "7,8", "unet_block_id_middle": "", "unet_block_id_output": "0", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "4", "unet_block_id_middle": "0", "unet_block_id_output": "3", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "attention_modifiers_positive": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "k", "unet_block_id_input": "7,8", "unet_block_id_middle": "", "unet_block_id_output": "0", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "4", "unet_block_id_middle": "0", "unet_block_id_output": "3", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": true, "cond_exp_method": "subtract_attention_modifiers_input_using_uncond", "cond_exp_normalize": false, "cond_exp_sigma_end": 1.0, "cond_exp_sigma_start": 1000.0, "cond_exp_value": 0.3333333333333333, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": false, "fake_uncond_exp_method": "cond_pred", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 1.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 0.0, "fake_uncond_sigma_start": 1000.0, "fake_uncond_start": false, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "model_options_copy", "eval_string"], "skip_uncond": true, "uncond_exp": true, "uncond_exp_method": "subtract_attention_modifiers_input_using_cond", "uncond_exp_normalize": false, "uncond_exp_sigma_end": 1.0, "uncond_exp_sigma_start": 1000.0, "uncond_exp_value": 0.3333333333333333, "uncond_sigma_end": 1.0, "uncond_sigma_start": 150.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Crossed conds customized 2.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 15.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 15.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 15.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": true, "attention_modifiers_global": [], "disable_cond": false, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "attention_modifiers_fake_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "k", "unet_block_id_input": "7,8", "unet_block_id_middle": "", "unet_block_id_output": "0", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "4", "unet_block_id_middle": "0", "unet_block_id_output": "3", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "attention_modifiers_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "k", "unet_block_id_input": "7,8", "unet_block_id_middle": "", "unet_block_id_output": "0", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "4", "unet_block_id_middle": "0", "unet_block_id_output": "3", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "attention_modifiers_positive": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "k", "unet_block_id_input": "7,8", "unet_block_id_middle": "", "unet_block_id_output": "0", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "4", "unet_block_id_middle": "0", "unet_block_id_output": "3", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": true, "cond_exp_method": "subtract_attention_modifiers_input_using_uncond", "cond_exp_normalize": false, "cond_exp_sigma_end": 3.0, "cond_exp_sigma_start": 1000.0, "cond_exp_value": 0.3333333333333333, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": false, "fake_uncond_exp_method": "cond_pred", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 1.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 0.0, "fake_uncond_sigma_start": 1000.0, "fake_uncond_start": false, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "model_options_copy", "eval_string"], "skip_uncond": true, "uncond_exp": true, "uncond_exp_method": "subtract_attention_modifiers_input_using_cond", "uncond_exp_normalize": false, "uncond_exp_sigma_end": 3.0, "uncond_exp_sigma_start": 1000.0, "uncond_exp_value": 0.3333333333333333, "uncond_sigma_end": 1.0, "uncond_sigma_start": 150.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Crossed conds customized 3.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 15.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 15.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 15.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": true, "attention_modifiers_global": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn1"}], "disable_cond": false, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "attention_modifiers_fake_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "k", "unet_block_id_input": "7", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "attention_modifiers_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "k", "unet_block_id_input": "7", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "attention_modifiers_positive": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "k", "unet_block_id_input": "7", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": true, "cond_exp_method": "subtract_attention_modifiers_input_using_uncond", "cond_exp_normalize": false, "cond_exp_sigma_end": 0.0, "cond_exp_sigma_start": 1000.0, "cond_exp_value": 1.0, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": false, "fake_uncond_exp_method": "cond_pred", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 1.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 0.0, "fake_uncond_sigma_start": 1000.0, "fake_uncond_start": false, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "model_options_copy", "eval_string"], "skip_uncond": true, "uncond_exp": true, "uncond_exp_method": "subtract_attention_modifiers_input_using_cond", "uncond_exp_normalize": false, "uncond_exp_sigma_end": 0.0, "uncond_exp_sigma_start": 1000.0, "uncond_exp_value": 1.0, "uncond_sigma_end": 1.0, "uncond_sigma_start": 150.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Enhanced_details_and_tweaked_attention
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 15.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 15.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 15.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": true, "attention_modifiers_global": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "disable_cond": false, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "attention_modifiers_fake_negative": [], "attention_modifiers_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "-q", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "attention_modifiers_positive": [{"sigma_start": 15, "sigma_end": 0, "self_attn_mod_eval": "v", "unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn1"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "q", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn1"}], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": true, "cond_exp_method": "subtract_attention_modifiers_input_using_cond", "cond_exp_normalize": true, "cond_exp_sigma_end": 0.0, "cond_exp_sigma_start": 15.0, "cond_exp_value": 0.5, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": false, "fake_uncond_exp_method": "cond_pred", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 1.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 1.0, "fake_uncond_sigma_start": 15.0, "fake_uncond_start": false, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "model_options_copy", "eval_string"], "skip_uncond": true, "uncond_exp": true, "uncond_exp_method": "subtract_attention_modifiers_input_using_uncond", "uncond_exp_normalize": true, "uncond_exp_sigma_end": 0.4, "uncond_exp_sigma_start": 15.0, "uncond_exp_value": 0.5, "uncond_sigma_end": 0.4, "uncond_sigma_start": 15.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Excellent_attention.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 15.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 15.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 15.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": false, "attention_modifiers_global": [], "disable_cond": true, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "attention_modifiers_fake_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "normalize_tensor(q+(q-attention_basic(attnbc, k, v, extra_options['n_heads'])))*attnbc.norm()", "unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn2"}, {"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn1"}], "attention_modifiers_negative": [], "attention_modifiers_positive": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "normalize_tensor(q+(q-attention_basic(attnbc, k, v, extra_options['n_heads'])))*attnbc.norm()", "unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn2"}], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": true, "cond_exp_method": "attention_modifiers_input_using_cond", "cond_exp_normalize": false, "cond_exp_sigma_end": 0.0, "cond_exp_sigma_start": 1000.0, "cond_exp_value": 1.0, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": true, "fake_uncond_exp_method": "attention_modifiers_input_using_uncond", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 1000.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 0.0, "fake_uncond_sigma_start": 1000.0, "fake_uncond_start": true, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "model_options_copy", "eval_string"], "skip_uncond": true, "uncond_exp": false, "uncond_exp_method": "amplify", "uncond_exp_normalize": false, "uncond_exp_sigma_end": 0.0, "uncond_exp_sigma_start": 1000.0, "uncond_exp_value": 1.0, "uncond_sigma_end": 0.0, "uncond_sigma_start": 0.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/For magic.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 1000.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 1000.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 1000.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": true, "attention_modifiers_global": [{"sigma_start": 15, "sigma_end": 0, "self_attn_mod_eval": "q.sin()", "unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn2"}], "disable_cond": false, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "model_options_copy": {"transformer_options": {}}, "attention_modifiers_fake_negative": [], "attention_modifiers_negative": [], "attention_modifiers_positive": [{"sigma_start": 15, "sigma_end": 0, "self_attn_mod_eval": "q/2", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}, {"sigma_start": 15, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "", "unet_block_id_middle": "0", "unet_block_id_output": "", "unet_attn": "attn2"}], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": true, "cond_exp_method": "subtract_attention_modifiers_input_using_uncond", "cond_exp_normalize": false, "cond_exp_sigma_end": 1.0, "cond_exp_sigma_start": 1000.0, "cond_exp_value": 0.5, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": false, "fake_uncond_exp_method": "attention_modifiers_input_using_uncond", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 2.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 1.0, "fake_uncond_sigma_start": 1000.0, "fake_uncond_start": false, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "eval_string"], "skip_uncond": true, "uncond_exp": false, "uncond_exp_method": "subtract_attention_modifiers_input_using_uncond", "uncond_exp_normalize": false, "uncond_exp_sigma_end": 1.0, "uncond_exp_sigma_start": 1000.0, "uncond_exp_value": 1.0, "uncond_sigma_end": 1.0, "uncond_sigma_start": 15.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Kickstart.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 15.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 15.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 15.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": false, "attention_modifiers_global": [], "disable_cond": true, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "attention_modifiers_fake_negative": [{"sigma_start": 1000, "sigma_end": 7, "self_attn_mod_eval": "attnbc*2", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn1"}, {"sigma_start": 7, "sigma_end": 2, "self_attn_mod_eval": "attnbc*2", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "attention_modifiers_negative": [], "attention_modifiers_positive": [{"sigma_start": 1000, "sigma_end": 7, "self_attn_mod_eval": "attnbc*2", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn1"}, {"sigma_start": 7, "sigma_end": 2, "self_attn_mod_eval": "attnbc*2", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": true, "cond_exp_method": "attention_modifiers_input_using_cond", "cond_exp_normalize": false, "cond_exp_sigma_end": 0.0, "cond_exp_sigma_start": 1000.0, "cond_exp_value": 0.3333333333333333, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": true, "fake_uncond_exp_method": "attention_modifiers_input_using_uncond", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 1000.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 0.0, "fake_uncond_sigma_start": 1000.0, "fake_uncond_start": true, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "model_options_copy", "eval_string"], "skip_uncond": true, "uncond_exp": false, "uncond_exp_method": "amplify", "uncond_exp_normalize": false, "uncond_exp_sigma_end": 0.0, "uncond_exp_sigma_start": 1000.0, "uncond_exp_value": 0.3333333333333333, "uncond_sigma_end": 0.0, "uncond_sigma_start": 150.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Mute input layer 8 attn1 and attn2 for uncond.json
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 15.0,
|
2 |
+
"lerp_uncond_sigma_end": 1.0,
|
3 |
+
"subtract_latent_mean": false,
|
4 |
+
"subtract_latent_mean_sigma_start": 15.0,
|
5 |
+
"subtract_latent_mean_sigma_end": 1.0,
|
6 |
+
"latent_intensity_rescale": false,
|
7 |
+
"latent_intensity_rescale_sigma_start": 15.0,
|
8 |
+
"latent_intensity_rescale_sigma_end": 3.0,
|
9 |
+
"ignore_pre_cfg_func": false,
|
10 |
+
"auto_cfg_topk": 0.25,
|
11 |
+
"attention_modifiers_global_enabled": false,
|
12 |
+
"attention_modifiers_global": [],
|
13 |
+
"disable_cond": false,
|
14 |
+
"disable_cond_sigma_start": 1000.0,
|
15 |
+
"disable_cond_sigma_end": 0.0,
|
16 |
+
"kwargs": {},
|
17 |
+
"attention_modifiers_fake_negative": [{"sigma_start": 1000,
|
18 |
+
"sigma_end": 0,
|
19 |
+
"self_attn_mod_eval": "torch.zeros_like(q)",
|
20 |
+
"unet_block_id_input": "8",
|
21 |
+
"unet_block_id_middle": "",
|
22 |
+
"unet_block_id_output": "",
|
23 |
+
"unet_attn": "attn1"},
|
24 |
+
{"sigma_start": 1000,
|
25 |
+
"sigma_end": 0,
|
26 |
+
"self_attn_mod_eval": "torch.zeros_like(q)",
|
27 |
+
"unet_block_id_input": "8",
|
28 |
+
"unet_block_id_middle": "",
|
29 |
+
"unet_block_id_output": "",
|
30 |
+
"unet_attn": "attn2"}],
|
31 |
+
"attention_modifiers_negative": [],
|
32 |
+
"attention_modifiers_positive": [],
|
33 |
+
"auto_cfg_ref": 8.0,
|
34 |
+
"automatic_cfg": "hard",
|
35 |
+
"cond_exp": false,
|
36 |
+
"cond_exp_method": "attention_modifiers_input_using_cond",
|
37 |
+
"cond_exp_normalize": false,
|
38 |
+
"cond_exp_sigma_end": 0.0,
|
39 |
+
"cond_exp_sigma_start": 1000.0,
|
40 |
+
"cond_exp_value": 0.3333333333333333,
|
41 |
+
"eval_string_cond": "",
|
42 |
+
"eval_string_fake": "",
|
43 |
+
"eval_string_uncond": "",
|
44 |
+
"fake_uncond_exp": true,
|
45 |
+
"fake_uncond_exp_method": "attention_modifiers_input_using_uncond",
|
46 |
+
"fake_uncond_exp_normalize": false,
|
47 |
+
"fake_uncond_exp_value": 1000.0,
|
48 |
+
"fake_uncond_multiplier": 1,
|
49 |
+
"fake_uncond_sigma_end": 0.0,
|
50 |
+
"fake_uncond_sigma_start": 1000.0,
|
51 |
+
"fake_uncond_start": true,
|
52 |
+
"latent_intensity_rescale_cfg": 8.0,
|
53 |
+
"latent_intensity_rescale_method": "hard",
|
54 |
+
"lerp_uncond": false,
|
55 |
+
"lerp_uncond_strength": 2.0,
|
56 |
+
"not_in_filter": ["self",
|
57 |
+
"model",
|
58 |
+
"args",
|
59 |
+
"args_filter",
|
60 |
+
"save_as_preset",
|
61 |
+
"preset_name",
|
62 |
+
"model_options_copy",
|
63 |
+
"eval_string"],
|
64 |
+
"skip_uncond": true,
|
65 |
+
"uncond_exp": false,
|
66 |
+
"uncond_exp_method": "amplify",
|
67 |
+
"uncond_exp_normalize": false,
|
68 |
+
"uncond_exp_sigma_end": 0.0,
|
69 |
+
"uncond_exp_sigma_start": 1000.0,
|
70 |
+
"uncond_exp_value": 0.3333333333333333,
|
71 |
+
"uncond_sigma_end": 0.0,
|
72 |
+
"uncond_sigma_start": 0.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Mute input layer 8 attn1 for uncond.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 15.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 15.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 15.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": false, "attention_modifiers_global": [], "disable_cond": false, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "attention_modifiers_fake_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn1"}], "attention_modifiers_negative": [], "attention_modifiers_positive": [], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": false, "cond_exp_method": "attention_modifiers_input_using_cond", "cond_exp_normalize": false, "cond_exp_sigma_end": 0.0, "cond_exp_sigma_start": 1000.0, "cond_exp_value": 0.3333333333333333, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": true, "fake_uncond_exp_method": "attention_modifiers_input_using_uncond", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 1000.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 0.0, "fake_uncond_sigma_start": 1000.0, "fake_uncond_start": true, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "model_options_copy", "eval_string"], "skip_uncond": true, "uncond_exp": false, "uncond_exp_method": "amplify", "uncond_exp_normalize": false, "uncond_exp_sigma_end": 0.0, "uncond_exp_sigma_start": 1000.0, "uncond_exp_value": 0.3333333333333333, "uncond_sigma_end": 0.0, "uncond_sigma_start": 0.0}
|
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Mute input layer 8 attn2 for uncond.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"lerp_uncond_sigma_start": 15.0, "lerp_uncond_sigma_end": 1.0, "subtract_latent_mean": false, "subtract_latent_mean_sigma_start": 15.0, "subtract_latent_mean_sigma_end": 1.0, "latent_intensity_rescale": false, "latent_intensity_rescale_sigma_start": 15.0, "latent_intensity_rescale_sigma_end": 3.0, "ignore_pre_cfg_func": false, "auto_cfg_topk": 0.25, "attention_modifiers_global_enabled": false, "attention_modifiers_global": [], "disable_cond": false, "disable_cond_sigma_start": 1000.0, "disable_cond_sigma_end": 0.0, "kwargs": {}, "attention_modifiers_fake_negative": [{"sigma_start": 1000, "sigma_end": 0, "self_attn_mod_eval": "torch.zeros_like(q)", "unet_block_id_input": "8", "unet_block_id_middle": "", "unet_block_id_output": "", "unet_attn": "attn2"}], "attention_modifiers_negative": [], "attention_modifiers_positive": [], "auto_cfg_ref": 8.0, "automatic_cfg": "hard", "cond_exp": false, "cond_exp_method": "attention_modifiers_input_using_cond", "cond_exp_normalize": false, "cond_exp_sigma_end": 0.0, "cond_exp_sigma_start": 1000.0, "cond_exp_value": 0.3333333333333333, "eval_string_cond": "", "eval_string_fake": "", "eval_string_uncond": "", "fake_uncond_exp": true, "fake_uncond_exp_method": "attention_modifiers_input_using_uncond", "fake_uncond_exp_normalize": false, "fake_uncond_exp_value": 1000.0, "fake_uncond_multiplier": 1, "fake_uncond_sigma_end": 0.0, "fake_uncond_sigma_start": 1000.0, "fake_uncond_start": true, "latent_intensity_rescale_cfg": 8.0, "latent_intensity_rescale_method": "hard", "lerp_uncond": false, "lerp_uncond_strength": 2.0, "not_in_filter": ["self", "model", "args", "args_filter", "save_as_preset", "preset_name", "model_options_copy", "eval_string"], "skip_uncond": true, "uncond_exp": false, "uncond_exp_method": "amplify", "uncond_exp_normalize": false, "uncond_exp_sigma_end": 0.0, "uncond_exp_sigma_start": 1000.0, "uncond_exp_value": 0.3333333333333333, "uncond_sigma_end": 0.0, "uncond_sigma_start": 0.0}
|