見出し画像

ComfyUIのSDXLのテキストエンコーダー処理について@CLIP-Gのパティング問題!?

T5Gemmaの記事を書いている際に、テキストエンコーダーに関連した内容で気になることがあったので、SDXLのテキストエンコーダー処理について調べてみたところ、CLIP-Gのパティング問題で、「隠れノイズ」的なものがあるのではということが判明しました。

ただ、この内容を修正することで画像生成がよりよくなるのかは不明です。

文章だけでは分かりにくいのでGeminiに作成してもらったインフォグラフィックを入れていきます。

SDXLの場合は、テキストエンコーダーはCLIP-LとCLIP-Gという2つのテキストエンコーダーが使用されています。

我々が入力したプロンプトをテキストエンコーダーが処理して、モデルに渡してが増生するという流れになっています。

スクリプトにデバッグ出力させることで、プロンプトがどのように処理されるのかを見る事が出来ます。

すると、CLIP-Lの処理は問題なかったのですが、CLIP-Gの処理に問題があるのでは?という話になりました。

通常の処理だと、75トークンの文字で区切られ、それより短い場合にCLIP-Lの様にプロンプト入力部だけが認識されるのが、CLIP-Gだと、その後の部分が「!」で穴埋めされるということが起きていました。

画像品質にどれぐらい関連するかは不明ですが、「!」が多く出力され、他のプロンプトを差し置いて「重要用語」的な扱いを受けていることが判明しました。

これらについて、ComfyUIのスクリプトを修正することで改善する事が可能です。

この修正を行うスクリプトは以下の1つだけになります。
パス:comfy/sdxl_clip.py
具体的な修正内容は以下
対応①: sdxl_clip.pyのSDXLClipGクラスの初期化部分を修正し、enable_attention_masks=Trueを設定
⇒この修正により、エンコーダがパディング領域を無視できるようになりました。結果として、!トークンの影響力は大幅に低減されましたが、トークン自体は依然として生成されるため、問題は部分的にしか解決しませんでした。しかし、これによりアテンションマスクの無効化が問題の一因であったことが確定しました。

対応②:正しいパディングトークンIDの指定
対応: sdxl_clip.pyのSDXLClipGTokenizerクラスの初期化部分を修正し、pad_with_end=Falseを削除。代わりにpad_token=49407(<|endoftext|>のID)を明示的に指定しました。⇒結果: この修正により、ノイズの発生源であった!トークンが生成されなくなりました。 CLIP-GのパディングはCLIP-Lと同様に<|endoftext|>で正しく行われるようになり、パディングノイズ問題は根本的に解決されました。

修正を加えたスクリプトは上のものです。

この修正を行う際に、修正後のログ内容を提示しておきます。
SDXLの場合はトークン数が77なので、それを超える場合は「チャンク」を作成して対応しています。
以下はCLIP-LとCLIP-Gのチャンクです。
プロンプトがどのような処理がされれているのか分かりやすいかと思います。
下の「Weighted Token」はトークンの重要視しているものを上位15個上げるというものです。
先程の「!」は、この上位に多く入り込んでいました。

--- [CLIP Encoder Debug] ---
Original Prompt: '1girl, leaning forward, hair flip, legs crossed, sitting on chair, open-mouth smile, gentle gaze, sleepy eyes, raised brows, tiny mouth corner lift, cheerful, chair, big breasts, red eyes, blonde hair, bra, long hair, solo, panties, breasts, black pantyhose, lingerie, underwear, cleavage, underwear only, navel, best quality, masterpiece'

--- Tokenized Chunks (G) ---
Chunk 1/2:  <|startoftext|> | 1</w> | girl</w> | ,</w> | leaning</w> | forward</w> | ,</w> | hair</w> | flip</w> | ,</w> | legs</w> | crossed</w> | ,</w> | sitting</w> | on</w> | chair</w> | ,</w> | open</w> | -</w> | mouth</w> | smile</w> | ,</w> | gentle</w> | gaze</w> | ,</w> | sleepy</w> | eyes</w> | ,</w> | raised</w> | brows</w> | ,</w> | tiny</w> | mouth</w> | corner</w> | lift</w> | ,</w> | cheerful</w> | ,</w> | chair</w> | ,</w> | big</w> | breasts</w> | ,</w> | red</w> | eyes</w> | ,</w> | blonde</w> | hair</w> | ,</w> | bra</w> | ,</w> | long</w> | hair</w> | ,</w> | solo</w> | ,</w> | panties</w> | ,</w> | breasts</w> | ,</w> | black</w> | panty | hose</w> | ,</w> | lingerie</w> | ,</w> | underwear</w> | ,</w> | cleavage</w> | ,</w> | underwear</w> | only</w> | ,</w> | na | vel</w> | ,</w> | <|endoftext|>
Chunk 2/2:  <|startoftext|> | best</w> | quality</w> | ,</w> | masterpiece</w> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|>

--- Tokenized Chunks (L) ---
Chunk 1/2:  <|startoftext|> | 1</w> | girl</w> | ,</w> | leaning</w> | forward</w> | ,</w> | hair</w> | flip</w> | ,</w> | legs</w> | crossed</w> | ,</w> | sitting</w> | on</w> | chair</w> | ,</w> | open</w> | -</w> | mouth</w> | smile</w> | ,</w> | gentle</w> | gaze</w> | ,</w> | sleepy</w> | eyes</w> | ,</w> | raised</w> | brows</w> | ,</w> | tiny</w> | mouth</w> | corner</w> | lift</w> | ,</w> | cheerful</w> | ,</w> | chair</w> | ,</w> | big</w> | breasts</w> | ,</w> | red</w> | eyes</w> | ,</w> | blonde</w> | hair</w> | ,</w> | bra</w> | ,</w> | long</w> | hair</w> | ,</w> | solo</w> | ,</w> | panties</w> | ,</w> | breasts</w> | ,</w> | black</w> | panty | hose</w> | ,</w> | lingerie</w> | ,</w> | underwear</w> | ,</w> | cleavage</w> | ,</w> | underwear</w> | only</w> | ,</w> | na | vel</w> | ,</w> | <|endoftext|>
Chunk 2/2:  <|startoftext|> | best</w> | quality</w> | ,</w> | masterpiece</w> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|> | <|endoftext|>

Final Conditioning Shape: torch.Size([1, 154, 2048])
Conditioning Stats: Mean=-0.0049, Std=0.7476, Min=-128.1443, Max=134.7522
Pooled Output Shape: torch.Size([1, 1280])

--- Top 15 Weighted Tokens (by Vector Magnitude) ---
Index: 0    | Token: '<|startoftext|>     ' | Magnitude: 205.1065
Index: 77   | Token: '<|startoftext|>     ' | Magnitude: 205.1065
Index: 57   | Token: ',</w>               ' | Magnitude: 50.5395
Index: 53   | Token: ',</w>               ' | Magnitude: 49.1383
Index: 25   | Token: 'sleepy</w>          ' | Magnitude: 43.3358
Index: 26   | Token: 'eyes</w>            ' | Magnitude: 40.5302
Index: 32   | Token: 'mouth</w>           ' | Magnitude: 40.0989
Index: 20   | Token: 'smile</w>           ' | Magnitude: 39.9337
Index: 29   | Token: 'brows</w>           ' | Magnitude: 39.5146
Index: 8    | Token: 'flip</w>            ' | Magnitude: 39.0118
Index: 44   | Token: 'eyes</w>            ' | Magnitude: 37.6642
Index: 19   | Token: 'mouth</w>           ' | Magnitude: 37.2483
Index: 11   | Token: 'crossed</w>         ' | Magnitude: 36.7929
Index: 21   | Token: ',</w>               ' | Magnitude: 36.6435
Index: 43   | Token: 'red</w>             ' | Magnitude: 36.5826
--- [CLIP Encoder Debug End] ---

タグ出力にすると、必然的に「カンマ」が増えるわけですが、これもWeighted Tokensに入ってきます。そのため「カンマの使いすぎ」も重要な部分が省かれるリスクが出るということが想定されます。

個人的には自作のタグノードとかに依存していましたので、この部分にまさにはまってしまっていましたので、今後対応策を考えていければと思いました。

いいなと思ったら応援しよう!