240627 - ComfyUI Conditioning
Spis Treści #
- Dwa słowa teorii
- Koncept: Conditioning
- Co próbujemy i da się zrobić?
- Wyjaśnienie kluczowych węzłów
- KSampler
- Parametr CFG
- Samplery i schedulery - jak z nimi pracować i jakie mają reguły
- Węzły Strategii Conditioning
- Czym są te węzły?
- Conditioning Concat
- Conditioning Combine
- Conditioning Average
- Conditioning SetTimestep Range
- KSampler
- Linki powiązane
![[.]](/img/49UBuuFGb3-2263.png)
1. Dwa słowa teorii #
1.1. Koncept: Conditioning #
- Definicja 'Conditioning'
- In ComfyUI Conditionings are used to guide the diffusion model to generate certain outputs.
- znaczy: prompt
- All conditionings start with a text prompt embedded by CLIP using a Clip Text Encode node.
- In ComfyUI Conditionings are used to guide the diffusion model to generate certain outputs.
- There is a 77 token limit per prompt (or it seems so)
2. Co próbujemy i da się zrobić #
Zacznijmy wizualnie (wszystkie rysunki niżej są na tym samym seedzie):
Mamy węzeł CLIP Text Encoding, czyli prompt. Ten prompt (zielony) mówi: "crystal mushroom statue on top of a beautiful, sleepy ocean, nebula in the background".
To ten rysunek który widać po prawej.
![[.]](/img/TpvhWTMZox-2110.png)
Mamy inny węzeł CLIP Text Encoding. Ten prompt (żółty) mówi: "glittering, iridescent, red green yellow reflective crystals sparkling with light".
Znowu widać rysunek po prawej.
![[.]](/img/Z4-sWZR2yn-2101.png)
Chcemy połączyć conditioning. Dodać w jakiś sposób aspekty "odbijających się kryształów" na naszego grzyba. Do tego służą węzły Conditioning.
Tutaj nakładamy aspekt odbijających się kryształów na grzyba - popatrzcie na kolejność węzłów w niebieskim (conditioning_to i conditioning_from):
![[.]](/img/Prn7_fy0tx-2110.png)
A tutaj mamy efekt na odwrót:
![[.]](/img/AH8yb2kItt-2101.png)
Czyli te węzły pozwalają na łączenie aspektów różnych rzeczy.
3. Wyjaśnienie kluczowych węzłów #
3.1. KSampler #
3.1.1. Parametr CFG #
- Cfg: classifier free guidance
- How aggressive the sampler should be in realizing the content of the prompts in the final image.
- Lower values: MODEL decides, higher values: PROMPT decides
- Higher scales force the image to better represent the prompt
- but a scale that is set too high will negatively impact the quality of the image.
To implikuje, że np. ten sam rysunek na wyższym cfg zachowa się inaczej niż na niższym. Znowu, demonstracja niżej:
CFG 2, czyli "model decyduje jak to ma wyglądać, prompt jest mniej istotny":
![[.]](/img/SCYXlkKt87-2145.png)
CFG 12, czyli "prompt absolutnie dominuje":
![[.]](/img/SCYXlkKt87-2145.png)
CFG 20 (ZDECYDOWANIE za dużo, tak wysoko się nie robi, bo się "przegrzewa" / "przepala"):
![[.]](/img/iDs-SHzGbr-2145.png)
3.1.2. Samplery i schedulery - jak z nimi pracować i jakie mają reguły #
Tu ważne jest to, by wiedzieć 2 rzeczy:
Sampler - scheduler
- mamy dwa typy:
- Converging, predictable noise
- np. sampler: Euler + scheduler: Normal
- Dobrze denoisuje na niskiej ilości stepów
- Dla niskiego cfg daje rozmyte odpowiedzi przy małych stepach
- co ważne: similar compositions no matter amount of steps (20 stepów i 120 stepów to różnice detali)
- należą do nich:
Euler, DPMPP_2M, DDIM, UNI_PC
- Stochastic, non-converging, more randomness
- np. sampler: Dpmpp + scheduler: Karras
- Dla niskiego cfg daje dobre odpowiedzi przy małych stepach
- OGÓLNIE używać warto dla niskiego cfg
- co ważne: 20 stepów i 120 stepów to INNE KOMPOZYCJE
- należą do nich:
*_ANCESTRAL, *_SDE, DDPM
- Converging, predictable noise
- W zależności co chcemy, możemy wybrać inne kombinacje sampler - scheduler
Znowu, popatrzmy na wyniki.
Wychodzimy od tego (sampler: heun, scheduler: normal, cfg: 8):
![[.]](/img/Prn7_fy0tx-2110.png)
Tu jest różnica między Heun a Euler; Euler jest "smoother", bardziej rozmyte.
![[.]](/img/jyK84JFC4e-2166.png)
Tu jest większa różnica (dpm_2_ancestral vs hein):
![[.]](/img/y-rXQbMMRs-2139.png)
A tu zmieniłem jedynie scheduler na ddim_uniform:
![[.]](/img/opGDAd3W0M-2129.png)
A tu, by pokazać, zmieniłem ilość iteracji (steps) z 30 do 80. Kompozycja zmieniła się bardziej niż w wypadku euler - normal.
![[.]](/img/AKWG7AHyO5-2180.png)
Punkt odniesienia: Euler - normal, 80 steps (powinno być podobne do referencji Heun - normal):
![[.]](/img/pvqRFUaWDG-2180.png)
Oki. To już wszystko jasne :-). Możemy przejść do akcji.
3.2. Węzły Strategii Conditioning #
3.2.1. Czym są te węzły? #
Najpierw wyjaśnijmy koncept Clip Conditioning:
![[.]](/img/A1j5-bWJJk-1393.png)
To, co nazywamy "Checkpoint" jest agregatem na 3 byty:
- UNet Model: wytrenowana sieć / model
- węzeł: UNETLoader
- Clip: text encoder, konwertujący tekst w embeddings
- węzeł: Load CLIP
- Variational Autoencoder
- węzeł: Load VAE
- wyjaśnienie:
- An autoencoder is a model (or part of a model) that is trained to produce its input as output.
- By giving the model less information to represent the data than the input contains, it's forced to learn about the input distribution and compress the information.
CLIP Text Encode bierze tekst i generuje z tego odpowiedni conditioning do generowania rysunku "kierowanego".
Teraz - możemy użyć specjalnych węzłów, by w odpowiedni sposób manipulować tymi wektorami embeddingowymi.
![[Conditioning concat REF_001]](/img/4JhjXWYdLI-1776.png)
Idealny prompt (pogrubienie moje):
- 1: closeup of an antropomorphic panda WEARING RED SCARF in an enchanted forest
- 2: closeup of an antropomorphic panda IN HEAVY ARMOUR in an enchanted forest
Różnice są trafiają do różnych strategii na tym samym seedzie.
Jakie mamy więc strategie?
3.2.2. Conditioning Concat #
Normalnie leci jeden wektor o długości 77 tokenów.
Ten węzeł działa tak:
- Concatenates the tensors together (77 + 77 = 154)
- MUCH less bleed between elements
![[.]](/img/fN_cQZ-m5n-1886.png)
Więc mamy następujący wynik (dla Euler Exponential 30 iteracji cfg 12 (by wzmocnić prompt)):
![[.]](/img/TRkTHCyMC5-1562.png)
Lub dla prostszego promptu:
![[.]](/img/B_I9yxAoPs-2065.png)
A teraz zrobimy porównanie dla spójnej sceny. Czyli:
- Prompt 1: "scared kitten in the dark forest full of eyes and spiderwebs, illustration"
- Prompt 2: "iridescent and beautiful scared kitten in the dark forest, illustration"
- Cfg: 3, 12
![[.]](/img/rMxNqbgMNv-1631.png)
Co ważne, jeśli to "ta sama scena", jesteśmy w stanie zachować wysoką spójność kompozycji między różnymi cfg. A jeśli scena jest różna, czasem nie wie co i jak dodać.
3.2.3. Conditioning Combine #
Normalnie leci jeden wektor o długości 77 tokenów.
- Conditioning Combine can be used to combine multiple conditionings by averaging the predicted noise of the diffusion model
- Adds tensors (mamy 4 a nie 2); more tensors sent to the model, denoising comes for TWO DIFF pictures and then averaged
- Stąd kontekst się robi z "osobnych promptów"
![[.]](/img/B373gpeafI-1870.png)
To też sprawia, że w tym wypadku nie mówimy "co nakładamy na co" - po prostu nakładamy potem na siebie określone szumy.
Jak widać, to FAKTYCZNIE wygląda jak "płaskie inteligentne połączenie obu światów".
![[.]](/img/tu7wdi_jWM-2143.png)
Dla niskiego cfg (3) mamy... coś, gdzie się pogubił:
![[.]](/img/Sy46F6UdCM-2171.png)
To jeszcze lepiej widać dla prostszego promptu. Tu mamy taki wynik (cfg 12):
![[.]](/img/xpC90O8ME7-2063.png)
A przy niższym cfg się CAŁKOWICIE pogubił (cfg 3):
![[.]](/img/Sy46F6UdCM-2171.png)
To pokazuje, że jeśli chcemy robić niskie cfg, WAŻNE jest by prompt miał ten sam kształt w obu połączeniach jeśli robimy Combine.
Zmieńmy ten prompt by to sprawdzić - powinien opisywać dość podobną scenę, ale w inny sposób:
- Prompt 1: "scared kitten in the dark forest full of eyes and spiderwebs, illustration"
- Prompt 2: "iridescent and beautiful scared kitten in the dark forest, illustration"
- Cfg: 3, 12
![[.]](/img/_V0q8a4Txp-1651.png)
Przy '3' utraciliśmy trochę strachu i aspekt ilustracji, ale jak widać - obecność "spójnej sceny" zdecydowanie pomogła w zachowaniu spójności logicznej.
3.2.4. Conditioning Average #
NO TEN TO JUŻ W OGÓLE DZIAŁA ZUPEŁNIE INACZEJ.
- Prompt embeddings are averaged (tensor size: 77) with the conditioning_to strength
![[.]](/img/aZxMPFWsVO-1365.png)
Ten węzeł ma nie tylko conditioning_to i conditioning_from, ale do tego jeszcze siłę sygnału (conditioning_to_strength).
Jak to wygląda - wpierw zbadajmy SKRAJNOŚCI:
Dla: siła sygnału 100% from: mushroom statue to: crystals
![[.]](/img/1PSR21Hot9-1472.png)
Dla: siła sygnału 0% from: mushroom statue to: crystals
![[.]](/img/N4j0xNLolY-1493.png)
Dla: siła sygnału 100% from: crystals to: mushroom statue
![[.]](/img/BuKiyzb1h4-1806.png)
Jak widać, rysunek 1 i rysunek 3 są identyczne. Czyli kolejność "nie ma znaczenia" jeśli da się 50% :-). Chodzi o to które wektory embeddingów mają mieć jaką wagę per iteracja.
Spójrzmy na 50% (ważne: patrzcie na cfg!):
![[.]](/img/yCzgztZFgG-2027.png)
70%, czyli "from CRYSTAL MUSHROOMS... nakładamy na GLITTERING CRYSTALS" gdzie kryształy mają wagę 70% a grzyby tylko 30%:
![[.]](/img/8O2XOQtGZE-1625.png)
30%, czyli całkowicie na odwrót. Nakładamy kryształowość na grzyby:
![[.]](/img/xMuAQ-DnYm-1634.png)
I na 10% - pomniejszy kryształowy aspekt nałożony na grzyby:
![[.]](/img/AhyCwS9riZ-2035.png)
Widać mniej więcej jak działa ten węzeł.
Sprawdźmy go na kotach, na mocy 20%.
![[.]](/img/8gihg4sgZa-1662.png)
A teraz na mocy 50%
![[.]](/img/olzZollXxj-1637.png)
I na mocy 80%.
![[.]](/img/yGoXejOt8a-1643.png)
Jak widać, przy niskim cfg ten węzeł niewiele robi, wszystkie rysunki są podobne. Nie jest to dziwne - cfg określa jak dużą moc ma prompt a niski cfg mówi, że KSampler robi "po swojemu", prompt nie jest dlań aż tak ważny.
Wynik więc nie dziwi - Conditioning Average działa na przestrzeni modyfikacji Embeddings (wektorów).
3.2.5. Conditioning SetTimestep Range #
TEN TO JUŻ JEST W OGÓLE Z INNEGO ŚWIATA.
Oki - wiecie, że gdy obrazek się generuje, to on się odszumia.
![[.]](/img/QCh0RW5UB8-896.png)
Czyli mamy serię kroków (iteracji), które sukcesywnie robią szum. PIERWSZE kroki są ważniejsze niż późniejsze kroki, bo budują kształt tego, co jest generowane.
Wiedząc to co wiemy, popatrzmy na te węzły i przejdźmy przez to:
![[.]](/img/mjMXsO0jRZ-1739.png)
Popatrzcie na NIEBIESKIE węzły:
- Prompt: "mushroom in the forest with fireflies" wchodzi do węzła
Conditioning SetTimestep Rangeod iteracji 0 do 10% iteracji (czyli 0->3 przy naszym KSamplerze).- to buduje podstawowy "las", ale nie ma dość detali
- Prompt: "mushroom in the cybernetic city, with the nebula background" wchodzi do tego węzła od iteracji 0.9 do 100% iteracji (czyli 3 włącznie do 30 przy naszym KSamplerze)
Ale mamy teraz dwa "zestawy" szumów. Musimy je połączyć. Dlatego łączymy je techniką COMBINE, która polega na łączeniu szumów.
Popatrzcie na jeszcze jeden wariant powyższego:
![[.]](/img/iyzXc1Dlck-1610.png)
NAWET przy nędznym 30% - 70% mamy bardzo dużo lasu i bardzo mało miasta. Jeśli mamy rzeczy, które są "sprzeczne", zwykle to co jest wcześniej będzie dominować.
Wróćmy do problemu promptu z grzybami, gdzie nakładamy kryształy na grzyby:
Tu mamy zamknięcie jednego i otwarcie drugiego:
![[.]](/img/1scylT7kIp-1761.png)
A tu zaczynamy od kształtu, ale od pewnego momentu generujemy oba obrazy jednocześnie:
![[.]](/img/GOkgSu5vEm-1764.png)
Największą siłą jest możliwość zbudowania KSZTAŁTU i nałożenie na to czegoś nowego. Popatrzcie co się dzieje, jeśli dam pierwotny grzyb na pierwsze 20% a potem nakładam na to "obcy" kształt diamentów (w czym cfg 3 jest, jak zwykle, specyficzne):
![[.]](/img/nffZjUKjSN-2165.png)