ConditioningSetArea の動作詳細

現在の ComfyUI で特に理解しにくい機能の筆頭は、ConditioningSetArea でしょう。 Stable Diffusion の根幹に近い部分に影響を与える機能の上、名前から想像されるのとは違う動作をするからです。

このページでは、ConditioningSetArea の実機能を担当する KSampler の中で何が行われているのかを解説します。 例によって数式は最小限で、義務教育レベルの数学のみを使います。 また用語に関しては、大元の diffusion model や画像生成界隈で使われているものではなく、ComfyUI のユーザから見たものを使用します。

重要なポイント
  1. ConditioningSetArea は、『conditioning の効果範囲を、指定したサイズ・位置の矩形内に限定するもの』ではなく、『指定したサイズ・位置の矩形内でノイズ推定 (画像生成) を行うように指示するもの』である。
  2. 範囲内で複数のノイズ推定 (画像生成) が行われた場合は、結果は重み付き平均される。

目次

復習: ConditioningSetArea 無しの場合

まずは前提の復習から始めます。 ConditioningSetAreaConditioningCombine を使わずに、単純に positive と negative を CLIPTextEncode でエンコードしたものだけを使う基本的な txt2img の場合は、サンプリングは以下の図のように行われます。

  • positive と negative で一回ずつ、U-Net を使ってノイズを推定する。 推定されたノイズをステップ開始時の画像から除去して、positive と negative の中間画像を作る。
  • cfg scale を使って 2 つの中間画像を混ぜ、ガイダンス効果を高めた画像を作る。 通常は cfg scale は 4 〜 12 あたりの値で 1 より大きいので、negative を原点にして、positive を延長するようなイメージです。

これが毎ステップごとに 1回以上実行されます。

本題: ConditioningSetArea ありの場合

本題です。positive 側のプロンプト 3個を CLIPTextEncode でエンコードし、その内 2つに ConditioningSetArea で領域を割り当て、ConditioningCombine で結合するとしましょう。 例えば、以下のグラフのような例です。

サンプリングは以下の図のように行われます。

  1. positive と negative を比較する。 同一 area の conditioning が相手側に無ければ作る。
  2. 個別の conditioning それぞれについて、それぞれの area 内に限定してノイズを推定して中間画像を作る。
  3. positive と negative それぞれで、latent 画素単位で中間画像の重み付け平均を求める。
  4. cfg scale を使って、ガイダンス効果を高めた画像を作る。

以下、順番に見ていきます。

1. positive と negative を比較する。同一 area の conditioning が相手側に無ければ作る。

positive と negative の全ての conditioning について、相手側に同一領域を対象とする conditioning があるかを確認し、無ければ新たに追加します。 このときプロンプトは、相手側 conditioning で対象領域を完全に含み、かつ最小面積のものをコピーして使います。

図の例では、positive の area1 と area2 に対応する negative が無いので、新たに作って追加しています。 area1、area2 のどちらついても、negative 側でそれを含む領域なのは {en0, {}} しかないので、en0 を新たに作る conditioning のプロンプトとして使います。

(現時点で、このペア作りの動作仕様には穴があり、生成画像が発散してしまうことがあります。 positive または negative に領域指定された conditioning しか無く、 領域に隙間があって画像全体をカバーしていない場合です。)

2. 個別の conditioning それぞれについて、それぞれの area 内に限定してノイズを推定して中間画像を作る。

positive、negative それぞれの個別の conditioning について、それぞれのプロンプトを使って、『それぞれの領域の中で』ノイズ推定を行い、それぞれの中間画像を作ります。

図の例では、positive の 3個、negative の 3個の合計 6個の conditioning について、それぞれ別々にノイズ推定を行い、6個の中間画像を得ています。

  • ep0 を使って画像全体で推定したノイズ、を除去した画像
  • ep1 を使って area1 の中で推定したノイズ、を除去した画像
  • ep2 を使って area2 の中で推定したノイズ、を除去した画像
  • en0 を使って画像全体で推定したノイズ、を除去した画像
  • en0 を使って area1 の中で推定したノイズ、を除去した画像
  • en0 を使って area2 の中で推定したノイズ、を除去した画像

『それぞれの領域の中で』というのが重要です。 例えば、ep1 を使ったノイズ推定の時に U-Net の入力となる画像は、area1 で切り取ったものだけです。 area1 の外に何かがあることすら知らずにノイズを推定するわけです。

3. positive と negative それぞれで、latent 画素単位で中間画像の重み付け平均を求める。

前過程で得られた個別の中間画像を、positive 側と negative 側とに分け、それぞれの結果を統合します。 ここで用いられるのが latent 画素単位での重み付き平均です。 area と strength がマスクのように働いて結果が加算された後、strength の合計 (マスク値の合計) で正規化されます。 strength が指定されていない conditioning に関しては、デフォルトの strength (= 1) が使用されます。

4. cfg scale を使って、ガイダンス効果を高めた画像に変換する。

これに関しては、ConditioningSetArea を使わない基本形と同じです。