見出し画像

[調査] Smile Test: Elysium_Anime_V3 問題を調べる #2

前回の検討の中で、提示されていた再現パターンについて、確認できていなかったので、追加確認を行う。
※ご指摘ありがとうございます!


超クイックまとめ

1.提示してもらった手順で、smileテスト問題は再現した
 ・すなわち「Add Difference で、TextEncoder は壊せる
2.マージ対象は TextEncoder, U-Net, AutoEncoder の全てを含んでいる
 
(マージ処理内容について勘違いしていた!)
3.Add difference がモデルに悪影響を及ぼす事は知られていたが、
「1token目に影響が出るが、モデルは動く」という形でぎりぎり動くように壊れたのが今回の例?
4.同問題の検出・対応方法は、前出の通り

では、本題。


再現パターン

再現方法をまとめると、

  1. SD15 と WD14 と trin1.4 で、Add Diff 1.0 (出力を test_01 とする)

  2. A:derrida_final、B:test_01 で Weighted sum 0.1 (出力を test_02 とする)

  3. test_02 にて画像生成すると、プロンプトの1token 目を飛ばす現象が発生する。


確認対象

既存モデル (以下、元モデルと記載)

確認対象の既存モデルは、以下の4種類。

SD15: Stable Diffusion 1.5
WD13: Waifu Diffusion 1.3
trin1.4: trinart_characters_it4_v1
DERRIDA: derrida_final

調査するモデル名と hash

マージモデル

確認対象のマージモデルは以下の2種類(test_01、test_02)

test_01 = SD15 + WD13 + TRI, 1.0
test_02 = DERRIDA + test_O1, 0.1


手順1. 元モデルチェック

元モデル 4 つについて、smile テストを行い、破損が無いことを確認する。

生成情報は以下の通り。Clip Skip:0、Eta:0。VAE: None

smile, girl, sleepy
Steps: 40, Sampler: Euler a, CFG scale: 7.5, Seed: 1, Face restoration: CodeFormer, Size: 512x512, Batch size: 4, Batch pos: 0
調査対象モデルに対しての smile test 結果
すべて笑顔が見られる。

手順2. マージモデルチェック

次にマージしたモデルでの再現を確認する。

マージ処理 (Merge Board)

まずはマージ処理。

マージを Merge Board のレシピで書くと、以下の通り。

# Recipe
test_O1 = __SD15__ + __WD13__ + __TRI__, 1.0
test_O2 = __DERRIDA__ + __O1__, 0.1
マージ完了
※ついでにバグ見つけた。。修正しよ。。

手順2-1. smileテスト

では、smile テストを行う。
例によって、比較対象は SD15。
興味対象は test_02 のみだが、ついでなので test_01 も含める。
また、test_02 との比較のため、test_02 の上に derrida の出力行を挿入しておく。

test_01 においては、顔がまともに生成されていない。
derrida とマージした test_02 において若干顔が復活しているが、笑顔は見られない。

この時点で、test_01 においてモデルに重大な影響が出ていることは確定した。

手順2-2. smileテスト (seed 5~12)

念のため、同設定でさらに seed 5~12 を確認する。

smileテスト
seed: 5~12
test_01 の出力は、変わらず壊れている。
test_02 の出力では、笑顔は見られない

変化は見られない。
この事から、test_01 のモデルが壊れている可能性が高いことがわかった。
test_02 の出力も同様に壊れているが、derrida で正常に出力されていることから、主な原因は test_01 の時点で発生している可能性が高い。

手順2-3. TextEncoder 交換、smileテスト

では、次に、CLIPTextEncoder を変更してテストを行う。
変更手順は前号の通り。
今回も `openai/clip-vit-large-patch14-336` に入れ替える。
また、リストに Elysium_Anime_V3 を比較対象に加えて、CLIP変更による症状の改善が正しく機能している事を同時に確認しつつ、test_01/test_02 の変化を見る。

変更前

手順2-3. CLIP変更前

変更後

手順2-3. CLIP変更後

Elysiumの結果から「CLIPTextEncoder の変更により症状が改善する」という手法は機能している。
test_02 の結果においても同様に、症状の改善が見られる。この事から、test_02 の CLIPTextEncoder が破損している事が分かった。


再現の検証:再現した

提示された再現手順で「笑顔が表示されない」という現象は再現した。
「マージの組み合わせによって、新たに "壊れた" モデルを生成できる」事がわかった。
ただし、test_01 は CLIPTextEncoder の入れ替えによっても改善しないため、一概に「壊れたのは CLIPTextEncoder のみ」とは言えない。

とはいえ、前回号での説1「原因候補1: 学習スクリプトのミスで TextEncoder が破損」ではない方法で現象が再現することがわかった。

原因の推測: 前号「原因候補2: マージスクリプトで TextEncoder が破損」の可能性が高まった。

ここまでで、現行のスクリプトの組み合わせで再現できる事が分かったため、過去の事象の負債のみではなく、現在も再生産してしまう可能性がある事は分かった。


原因候補2+調査: スクリプト処理の再チェック

上記から、現在の理解である「マージが対象とするのは U-Net 部」が間違ってる可能性がある。

※だんだん「その謎を解明するため、我々調査隊はアマゾンの奥地へと向かった」みたいなノリになってきた。。。

勘違い発見:AUTOのマージ対象は、TextEncoder, U-Net, AutoEncoder の全てを含む

コード再確認した。
上記の理解が間違っていた。(完全に読み違え)
AUTO1111も、その前提となったxx のマージスクリプトも、Merge Block Weighted での処理でも、マージ対象は TextEncoder, U-Net, AutoEncoder の全てを含んでいる。


対策案の検討

では、マージ処理側をどのように変更すべきかを検討する。
(ツール作者としての意見:TextEncoder や VAE をマージすることは元々の意図からは外れている。これまでのマージと違いが出るかもしれないが、ツールとしてはこれらを制御できるオプションがあったほうが使いやすそう)

手順2-4 U-Net のみマージの試作と、smile テスト

では、U-Net のみをマージするようにすれば問題が解決するのか?

そこでマージ処理を変更し、マージの対象として U-Net のみとするように変更して、手順2-1 のテストを再度行った。

※ここで言う「U-Net のみ」の絞り込みは、下記のコード変更により行った。
※修正内容はざっくりと以下の通り。x3箇所

# if 'model' in key:
if 'model' in key and 'model.diffusion_model.' in key:

extras.py  run_modelmerger

"model" のみで対象を絞っていた部分を、さらに "model.diffusion_model." で絞るようにした。
では、結果を見てみる。

手順2-4. U-Netのみをマージした場合の出力結果

依然として test_01-UNET の出力は不安定化していた。
一方で、test_02-UNET では笑顔が見られており、CLIPTextEncoder の破損は無いと考えられる。

さらに、test_02 と test_02-UNET の出力結果を比較する。

手順2-3. CLIP変更後の、test_02 の出力結果
手順2-4. より、test_02-UNET の出力結果

総じて、差異は大きくない。

これが VAE の違いによるものか確認するため、共通に外部から VAE を適用して比較を行う。使用する VAE は、
"autoencoder_fix_kl-f8-trinart_characters"。

test_02(CLIP変更前) と、test_02-UNET の出力結果比較
test_02(CLIP変更後) と、test_02-UNET の出力結果比較

特に変化はなさそう。

手順2-4 の効果まとめ

以上の結果から、以下の推測を得た。

1.test_01, test_01(CLIP変更) 及び test_01-UNET の結果から、test_01 におけるモデル破綻(?)は、CLIPTextEncoder がマージ範囲に含まれるか否かにかかわらず発生している。

2.test_02, test_02(CLIP変更) 及び test_02-UNET の結果から、U-Net only のマージで笑顔が復活しており、それが test_02(CLIP変更) の結果に近い事を確認した。この事から、U-Netのみのマージには一定の効果があり得る。

3.test_02 及び test_02-UNET の出力について、VAE の影響を均質化するために外部 VAE を適用して結果を比較したが、特に変化は見られなかった。
この事から、今回の検証中の出力においては、VAE はあまり影響を及ぼしていないと推測する。

以上から、CLIP部の破損は「CLIP 同士のマージの結果、発生している」事が分かった。

手順2-5. モデル内部構造の可視化手法の作成

モデル内の tensor 部の値から相対値を計算し表示する Extension の試作を行った。
計算対象は、TextEncoder部/U-Net/VAE 部それぞれ。同手法で U-Net 各部も計算している。
(※計算方法自体が試作なので、計算方法や計算結果自身も調査の対象)

表示されている数字は、各部分の tensor の絶対値がモデルAからどれくらい変わっているかの比率を 10000 倍したもの。つまり 1 = 0.0001 % の変化量

相対値の計算結果1
Rader グラフにするとかっこいい
左から、対象の各モデル
上が Input block、下行が Output block
レーダーは時計と同じ配置になっており、0 時が 00 になっている
※注意※ SD15 からの相対値なので、OUT00/OUT02 が突出しているからといって「ここが効く!」という話ではない。

また、今回の検証対象となった元モデルたちについて、同手法で可視化を行った。

相対値の計算結果(from SD14)
左から、SD14, WD13, 8528d-fix, Elysium_Anime_V3, derrida, trin1.4
8528d-fix と Elysium_Anime_V3 で、CLIP と VAE の変化量を検出?
相対値の計算結果グラフ(from SD14)
左から、SD14, WD13, 8528d-fix, Elysium_Anime_V3, derrida, trin1.4

8528d-fix、Elysium_Anime_V3 では、CLIP/VAE にて変化量が検出できた。
ただ、上記の test_01、test_02 の確認結果では検出できていないので、検出方法として安定しているとは言えない。さらに、変化量でしかないので、数字が大きく出ても CLIPが破綻しない可能性も残る。

仮に仮を重ねて強弁すると、Add Difference による影響量(の一部)を数値から見ることができるのではないか。8528d-fix での VAE影響 869 というのが大きいのか不明だが、少なくともそれだけ Add Difference を受けている事は推測できる。

さいごに

長々と読んでいただきありがとうございます。
いまいち結論には至っていません。まだ沼の半ば道の半ばです。
まだまだ不学・勉強中の身で間違いだらけですが、いろいろとご指摘いただければ幸いです。

使用ツール類

Merge board: https://github.com/bbc-mc/sdweb-merge-board
CLIPTextEncoder入れ替え:ソースコード直接変更
U-Netのみマージ:ソースコード直接変更
内部構造可視化:自作Extension



この記事が気に入ったらサポートをしてみませんか?