見出し画像

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

「プロンプトの一つ目のトークン無視」問題が発生!という話を聞いたので調査してみる。

念のため。現在主に利用されているマージ手法では TextEncoder部は破損しない

現時点では、
「Add Difference を行うと、TextEncoder が壊れる」は誤り
で、
「破損した TextEncoder を持つモデルを A としてマージを行うと、破損部分が引き継がれる」
が正しいと考えられる。
理由は、現在利用されているマージは、AUTO1111 のもの、その基とされる eyriewow 氏のもの(※1)、diffusers のものなどがあるが、
U-Net 部のみをマージの対象としているため。 

23/01/02: あけましておめでとうございます。
指摘をもらった追加検証で、Add Difference を用いて同症状を発生させる事ができたので、上記の主張は誤りです。
現時点での修正主張は、
「Add Difference によるモデルを壊すことができ、TextEncoder も壊す事ができる」
「破損した TextEncoder を持つモデルを A または B (または C) としてマージを行うと、破損部が(いくばくか) 引き継がれる」

追加検証はこちら https://note.com/bbcmc/n/nd8aab5f5119f


では、本題。
修正方法のみ知りたい方は、「念のため(その2)修正方法」参照


この記事について

調査を進めていく必要があるが、一気に簡単に終わらない可能性がある。
結論が出たら記事の頭に乗せるべきと思うが、無い場合は調査中なのでそのつもりで読んでほしい。
どこまで調査していて、どこまで分かっているかが分かるはず。
逆にどこらへんが見えてないとか透けて見えれば良いな、と思う。

※各大項目の中で「xx結果」に、その項目のだいたいのまとめを記載する
※気力が続かなければ、調査が続かない可能性も。。。


現状確認

発生する現象

発生する現象は、「プロンプトの一つめのトークンが無視されている」というもの。巷で実行されている sleepy girl チェックは、手軽で良い確認方法だと思う。

確認されている対象モデル

配布されているモデルで、発生が確認されているのは、以下2つ。
・Elysium_Anime_V3
・8528d-fix

Elysium_Anime_V3 については、かなり以前から報告例があったが、ユーザー側で捨てトークンを入れるなどで回避していた模様。

各モデルの先祖確認

モデルのご先祖が何モデルかを調べた。

  • Elysiumについては、配布サイトでは明言されていない。
    使用する VAE について記載があり、Waifu Diffusion で配布されている kl-f8-anime2.ckpt を指定している事から、Waifu 由来?もしくは SD 系列とは思われる。仮に Stable Diffusion 1.4 と仮定する。

  • 8528d-fix については、配布サイトに「SD1.4 からファインチューンした」と記載されている。

以上の結果から、比較対象は Stable Diffusion 1.4 (以下 SD14)とする。


再現確認:Smile テスト

まずは、現象の再現確認を行う。
再現確認として、sleepy テストからちょっと弄って、smile テストを行う。
また、内部トークン処理が 75 token で分断されている事を加味し、1token目、76 token 目、151 token目の確認を行う(以下、smileテスト、smile76テスト、smile151テスト、と呼ぶ)

※なお、smile にしたのは、テストしていて溜まっていく画像が全部笑顔だと、なんとなく気分が良いから。
最終的に本検証で生成した画像は、497枚でした。

笑顔

smile テスト

使用プロンプトと生成情報は以下の通り。
VAEなし。Clip:2、Eta:31337。seed: 1-4

smile, girl, sleepy
Steps: 40, Sampler: Euler a, CFG scale: 7.5, Seed: 1, Face restoration: CodeFormer, Size: 512x512, Clip skip: 2, ENSD: 31337


smile テスト

SD1.4 では、笑顔が見られる。
一方で、8528d-fix や Elysium_Anime_V3 には、笑顔が見られない。


smile76テスト

token 76個目周辺による影響を調べる。
まずは token 76 周辺に文字プロンプトを振ったプロンプト文字列を決める。
token のカウントは AUTO1111 の t2i 画面に表示される数字 token_count に依った。

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

これで 74/75

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,smile

75/75

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,smile, girl

77/150

・・・どうやって 76 token目入れれば良いんだ。

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,smile
girl

76/150

smile の後を改行にしたところ、無事 76 になった。もう一声。

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,smile
girl sleepy

77/150

これくらいで良さそう。
これで、
 75: girl
 76: smile
 77: sleepy
になった。

使用プロンプトと生成情報は以下の通り。
VAEなし。Clip:2、Eta:31337。seed: 1-4


,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,smile
girl sleepy
Steps: 40, Sampler: Euler a, CFG scale: 7.5, Seed: 1, Face restoration: CodeFormer, Size: 512x512, Clip skip: 2, ENSD: 31337


smile76 テスト
,,,(中略),,,smile girl sleepy

問題なさそうにみえる。
SD14の seed1が若干寝苦しそうだが、8528d-fix、Elysium_Anime_V3 ともに、にっこりしているようにも見える。


追試として、プロンプトの girl を boy へ変更して実行。

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,smile
boy sleepy
Steps: 40, Sampler: Euler a, CFG scale: 7.5, Seed: 1, Size: 512x512, Clip skip: 2, ENSD: 31337
smail76テスト
girl -> boy へ入れ替えた

SD14は反応して、girl だったところが boy に変わった。
他 2 モデルについては、boy が効いていない可能性がある。
再度追試する。


ここでテストのミスに気がついた。
調査対象は 76 token 目なのに、76 token 目が girl になっている。
追試のため、トークン位置を入れ替え、smile が 76 token目に来るようにした。

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,sleepy
smile girl
Steps: 40, Sampler: Euler a, CFG scale: 7.5, Seed: 1, Size: 512x512, Model hash: 7460a6fa, Batch size: 4, Batch pos: 0, Clip skip: 2, ENSD: 31337


smile76テスト
smile と girl を入れ替え、token76が smile になっている

SD14 では依然として笑顔が見られる。
下2モデルからは、笑顔が消えた!
この事から、token 76 目が無視されていると考えられる。


smile151テスト

さらに影響範囲を推測するため、151 token目まで影響が及んでいるかを調べる。
※ 1, 76, 151 と影響があれば、周期的な再現性がありそう。

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,sleepy
smile girl

152/225
… ちょっとプロンプトを準備するのに慣れてきた

これで、対応するトークンは、以下の通り。
150: sleepy
151: smile
152: girl


smile151テスト
また笑顔が失われた…

smile151 テストでも、下2モデルでの笑顔の消失を確認した。


再現確認の結果:「再現する」

対象のモデルにおいて、1 token目の文字列が無視されている事がわかった。
また、76 token目、151 token目の文字列も無視されている事がわかった。
以上からの仮説として、$$75n +1 (n=0…)$$ 番目のトークンについて、上手く適用されていないと考えられる。

余談1:75 token 切り分けの理由

AUTO1111 では、この 75token 切り分けを行わないようにする提案もあったが、退けられている。(※いつだったか定かではないが、token制限が無くなった時期だったはず)
理由として、token 列が長くなるにつれて後ろの影響力は弱まるため、非常に長い token 列を(実装として)許容しても実際的に効果が出ないために意味がない。
一方で、現在の実装であれば 75 token ごとに切り分けて文字の効果量を判定するために、1 token 目と 76 token 目の影響力が同じにできる。
この特徴が、実際の絵作りに有用だと考える、とのこと。


破損箇所の確定

対処法はいくつか公開されていたので、そちらへおまかせする。
ここでは破損箇所の確定を行う。
(原因の究明は、さらにその先)


手法1: TextEncoder を入れ替えてみる

今回、75 という数字がついて回っているが、この数字については token が 75 token で切り分けられている事が知られている。実装上も 75 token で切り分けて処理している。
※AUTO1111では、さらに切り分け位置の調整機能がある。

Stable Diffusion のモデルデータ形式には、TextEncoder 部が含まれている事が知られている。

第一容疑者は、この「モデルデータに含まれている TextEncoder」だ。

この疑惑の確認のため、モデルを読み込んだ後に TextEncoder を別のものに変更して処理を行った。参考資料は以下。

https://zenn.dev/discus0434/articles/7ada798c5cc87d

従来使用されているものは "openai/clip-vit-large-patch14" だが、この記事に従って "openai/clip-vit-large-patch14-336" に入れ替える。
また、入れ替え処理は モデルを読み込んだ後 に行われている事を AUTO側の実装で確認した。


smileテスト:smile OK


smileテスト、CLIP入れ替え済み

smile76テスト:smile OK

smile76 テスト、CLIP入れ替え済み

smile151テスト:smile OK

smile151 テスト、CLIP入れ替え済み

結果:笑顔を取り戻した

TextEncoder を入れ替えた結果、笑顔を取り戻すことに成功した 
1token目、76token目、151token目のプロンプトの影響を取り戻すことに成功した。
この結果から、同2モデルでは、TextEncoder 部のデータが破損していること、その部分の修復が出来ればモデルの能力を復活させられることが判明した。


手法2: 問題点をもう一段切り分ける

TextEncoder 部に問題があることはわかった。
次に、TextEncoder のうち、CLIPTokenizer/CLIPTextModel のどちらに問題があるか切り分ける。

手法2-1: CLIPTokenizer

CLIPTokenizer のみを入れ替えて、smile テストを行った。

smileテスト
CLIPTokenizer のみを入れ替えた。
下2モデルに笑顔は無い。

結果では、下2モデルについて、笑顔は見られなかった。

手法2-2: CLIPTextModel

次に、CLIPTextModel のみを入れ替えて、smile テストを行った。

smileテスト
CLIPTextModel のみを入れ替えた。
下2モデルにも笑顔が見られる。

笑顔 …… !!
ようやく笑顔が見られた。

結果: CLIPTextModel に問題あり

これで、モデル内のデータのうち、CLIPTokenizer には問題がなく、CLIPTextModel に問題がある事がわかった。


原因の究明:To Be Continue ……?

現時点での調査結果はここまで。
破損を TextEncoder 部と特定できたので、次に原因を探るならば過去の調査だが、ちょっとシンドい。。。

原因候補1: 学習スクリプトのミスで TextEncoder が破損

可能性はある。
ただ、調査も確定も難しい。
非公開のコードで学習されていた場合、辿る手段が無い。

原因候補2: マージスクリプトのミスで TextEncoder が破損

一応、無いとは言えないが、あくまで技術者的表現であり、実質ほぼないと思う。特に 8528d-fix の事例は直近に発生しており、マージに関するプログラムはある程度落ち着いていた。
(※ 8528d-fix が発表された時期には自分は既に活動していたので、マージスクリプト周りはウォッチしているつもり)


念のため(その2)修正方法

修正方法(副作用注意)

MBW で、下記設定で処理すれば良い。

Model_A: 大丈夫なモデル
Model_B: 修正したいモデル
preset: ALL_B
base_alpha: 0

修正結果(例)

念のため(その2)の修正方法適用済み
ファイル名の頭に fix が付いているのが、修正したモデル。
上から、SD、8528d-fix、同修正モデル、Elysium_Anime_V3、同修正モデル。
修正により、笑顔を取り戻せている事がわかる

注意事項:TextEncoder部の入れ替えの注意事項

モデルによっては、TextEncoder部が学習されている可能性がある。
上記の修正で、移し元のモデルによってはそれが消えてしまうので、その点は注意のこと。(作画に影響が出る可能性あり)


Elysium_anime_V3 における、モデルロードミス疑惑 -> 解決・別件。無罪

検証中、X/Y Plot に同じ画像が発生する事があり、困惑した。
後から見返してみると、Elysium_anime_V3 のモデルをロードしたはずが、前のモデルの画像を出力している事がわかった。

ケース1
SD14 -> Elysium_Anime_V3 -> 8528d-fix の順番でモデルを変更している。
SD14 -> Elysium_Anime_V3 で、変化していないことがわかる。
ケース2
SD14 -> 8528d-fix -> Elysium_Anime_V3 の順番でモデルを変更している。
8528d-fix -> Elysium_Anime_V3 で、変化していないことがわかる。

ここで「Elysium_Anime_V3 破損発見!ロードできません!」と騒ぐのは簡単だが、ちゃんと考える必要がある。
まず、単独で Elysium_Anime_V3 はロードできる。(出力は別途確認済)
また、上記の他の検討では正しくロード出来ている
上記検討と、提示した問題発見の出力の差は、モデルの指定方法の違いだ。
上記検討では「Elysium_Anime_V3.safetensors」と指定しているが、問題が発生した場所では「Elysium_Anime_V3」と指定している。

この事と実装の調査から、「X/Y Plot に短い名前でモデル名を伝えると、特にたくさんのモデルを持っている人の場合は、検索に失敗する事がある」事が疑われる。検索時にロンゲストマッチしているらしく、同じ名前を含む・より長いモデル名があると、間違えている。。ぽい

(再現テストまでしてません。めんd)


リンク等

AUTOMATIC1111/stable-diffusion-webui

https://github.com/AUTOMATIC1111/stable-diffusion-webui

MBW: Merge Block Weighted GUI 

https://github.com/bbc-mc/sdweb-merge-block-weighted-gui



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