flatcherlee commited on
Commit
3d5837a
1 Parent(s): 932ae62

Upload 2334 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +30 -0
  2. ComfyUI/custom_nodes/ComfyMath/LICENSE +201 -0
  3. ComfyUI/custom_nodes/ComfyMath/README.md +19 -0
  4. ComfyUI/custom_nodes/ComfyMath/__init__.py +31 -0
  5. ComfyUI/custom_nodes/ComfyMath/__pycache__/__init__.cpython-310.pyc +0 -0
  6. ComfyUI/custom_nodes/ComfyMath/pyproject.toml +19 -0
  7. ComfyUI/custom_nodes/ComfyMath/requirements.txt +1 -0
  8. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__init__.py +0 -0
  9. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/__init__.cpython-310.pyc +0 -0
  10. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/bool.cpython-310.pyc +0 -0
  11. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/control.cpython-310.pyc +0 -0
  12. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/convert.cpython-310.pyc +0 -0
  13. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/float.cpython-310.pyc +0 -0
  14. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/graphics.cpython-310.pyc +0 -0
  15. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/int.cpython-310.pyc +0 -0
  16. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/number.cpython-310.pyc +0 -0
  17. ComfyUI/custom_nodes/ComfyMath/src/comfymath/__pycache__/vec.cpython-310.pyc +0 -0
  18. ComfyUI/custom_nodes/ComfyMath/src/comfymath/bool.py +59 -0
  19. ComfyUI/custom_nodes/ComfyMath/src/comfymath/control.py +3 -0
  20. ComfyUI/custom_nodes/ComfyMath/src/comfymath/convert.py +273 -0
  21. ComfyUI/custom_nodes/ComfyMath/src/comfymath/float.py +159 -0
  22. ComfyUI/custom_nodes/ComfyMath/src/comfymath/graphics.py +77 -0
  23. ComfyUI/custom_nodes/ComfyMath/src/comfymath/int.py +129 -0
  24. ComfyUI/custom_nodes/ComfyMath/src/comfymath/number.py +95 -0
  25. ComfyUI/custom_nodes/ComfyMath/src/comfymath/py.typed +0 -0
  26. ComfyUI/custom_nodes/ComfyMath/src/comfymath/vec.py +501 -0
  27. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/README.md +175 -0
  28. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__init__.py +27 -0
  29. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__pycache__/__init__.cpython-310.pyc +0 -0
  30. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__pycache__/experimental_temperature.cpython-310.pyc +0 -0
  31. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/__pycache__/nodes.cpython-310.pyc +0 -0
  32. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/experimental_temperature.py +208 -0
  33. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/Enhanced_details_and_tweaked_attention.png +3 -0
  34. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/Iris_Lux_v1051_base_image_vanilla_sampling.png +3 -0
  35. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_a.jpg +3 -0
  36. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_b.jpg +3 -0
  37. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/presets.jpg +3 -0
  38. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/nodes.py +1292 -0
  39. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/nodes_sag_custom.py +190 -0
  40. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/A subtle touch.json +1 -0
  41. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Crossed conds customized 1.json +1 -0
  42. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Crossed conds customized 2.json +1 -0
  43. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Crossed conds customized 3.json +1 -0
  44. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Enhanced_details_and_tweaked_attention +1 -0
  45. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Excellent_attention.json +1 -0
  46. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/For magic.json +1 -0
  47. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Kickstart.json +1 -0
  48. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Mute input layer 8 attn1 and attn2 for uncond.json +72 -0
  49. ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/presets/Mute input layer 8 attn1 for uncond.json +1 -0
  50. 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 <evan@spearman.mb.ca>"]
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

  • SHA256: 23dbd409ff9526382892b0395c8889bce4afb4f16b2df8a4918abfcb375b2f3a
  • Pointer size: 132 Bytes
  • Size of remote file: 1.32 MB
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/Iris_Lux_v1051_base_image_vanilla_sampling.png ADDED

Git LFS Details

  • SHA256: f36c78b64e07f85975e9dcb57e6a17787a3c95ffddc89b393c01c70864ed95e4
  • Pointer size: 132 Bytes
  • Size of remote file: 1.16 MB
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_a.jpg ADDED

Git LFS Details

  • SHA256: c54fad2902563d00fc5f8529a22bff7e85f82f787578cfb787b729e4f64040e3
  • Pointer size: 132 Bytes
  • Size of remote file: 1.66 MB
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/excellent_patch_b.jpg ADDED

Git LFS Details

  • SHA256: 317817674e6b2a8754c953a1adc403cc43793098e8316367b7e9db66653034ee
  • Pointer size: 132 Bytes
  • Size of remote file: 1.61 MB
ComfyUI/custom_nodes/ComfyUI-AutomaticCFG/grids_example/presets.jpg ADDED

Git LFS Details

  • SHA256: 9afb639bf225151a4c4c9dc5a349b83c56d21fc88a43303e37b611579680f125
  • Pointer size: 132 Bytes
  • Size of remote file: 1.42 MB
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}