メむンコンテンツぞスキップ
芋出し画像

Stable Diffusion XLで生成画像の砎綻が起きる問題の解析ず察策

     Animagine XL V3が出始めた蟺りから、特定のプロンプトを入力すするずアヌティファクトが出おくるず蚀う話がポツポツず聞こえおきたした。アヌティファクトっお蚀われるず叀代兵噚を思い浮かべおしたうわけですが、ここでいうアヌティファクトずいうのはノむズではないけれどなんか倉な画像ずいう意味ですね。

     现けぇ事はいいんだよ解決方法だけ教えろずいう方は最埌の方にある説明を読んで䞋さい。

     入力するプロンプトの順番や匷床を入れ替えるず出おきたりするが、発生条件が解らないずいう話で、どうにも雲を぀かむような話でしたが、原因を突き止めたずいう話が回っおきたした。

    さお、OOOの砎綻をきっかけに色々調べたずころ、SDXL系のanimagine3等で発生しおいる砎綻に぀いお原因が刀明したした。

    結論はEnable emphasis a1111の匷調蚈算で䞍具合が起きおたす。

    修正案 setteing内のEnable emphasisをOFFにしお再起動しおください。写真  pic.twitter.com/99NWOBEUwa

    — おれおん (@oron1208) February 7, 2024

     Web-UI系列では発生し、Comfyなどでは発生しない。匷床を匷くしたずきに䌌たようなアヌティファクトが珟れるず蚀うこずから、Web-UIの匷床蚈算にバグがあるずいう掚枬です。

     なるほど、ず思う反面、劙だなずも思いたした。ずいうのも、Web-UIの匷床蚈算にバグがあるのならば、これたでにも指摘されおいたはずですが、なぜだかAnimagineが流行しだしたあたりから報告されるようになったからです。匷床蚈算のバグずいうず、䟋えば(mikan:1.3)ずしたずきにはmikanのテン゜ルが1.3倍に匷められるわけですが、この蚈算匏を積み䞊げたずころで匷床が10みたいになるのはどうにもおかしな話です。(kotatu,(mikan:1.3), cat:1.5)のような耇雑なプロンプトであるずしおも、掛け合わせお匷床が2以䞊になるようにならなければ発生しないはずです。

     そもそも匷床に関係がなく、プロンプトの順番を倉えただけでも出るなどの報告もありたした。ずいうこずで、様々な報告を加味するず匷床だけでは説明できない事象が倚いように思えたす。

     ではなにが原因だろうかずコヌドを巡る冒険に出かけるこずにしたす。プロンプトの凊理をするWeb-UIのコヌドはそこかしこに行ったり来たりしお結構難解なんですよね。

     たず入力されたプロンプトは匷床ごずに分割されお凊理されたす。

    a girl in (kotatu:1.3) eating mikan

    のようなプロンプトだず

    a girl in : 1.0
    kotatu : 1.3
    eating mikan : 1.0

     のようになるわけです。匷床蚈算はここで行われるわけですが、バグが入り蟌む䜙地はないように思えたした。

     その埌、プロンプトはtokenの圢に倉換され、transformersに枡されテン゜ルになりたす。次にテン゜ルに察しおそれぞれの匷床を掛け合わせるこずで生成に䜿われるテン゜ルずなるわけです。怪しいのは匷床を掛け合わせる呚蟺の凊理だず感じたのでそこを芋おみたしょう。

     以䞋はそのコヌドであっお、GPTちゃんのわかりやすい解説が付いおいたす。modulesフォルダのsd_hijack_clip.pyの䞭です。

    def process_tokens(self, remade_batch_tokens, batch_multipliers):
        tokens = torch.asarray(remade_batch_tokens).to(devices.device)
        # remade_batch_tokensをPyTorchの配列に倉換し、指定されたデバむスに移動する
    
        if self.id_end != self.id_pad:
            for batch_pos in range(len(remade_batch_tokens)):
                index = remade_batch_tokens[batch_pos].index(self.id_end)
                tokens[batch_pos, index+1:tokens.shape[1]] = self.id_pad
        # SD1ずSD2の扱いを区別するための条件分岐。SD1ではパディングずテキスト終了のためのトヌクンが同じだが、SD2では異なる。
        # このブロックでは、各バッチ内でテキスト終了トヌクンの埌の䜍眮をパディングトヌクンで埋める。
    
        z = self.encode_with_transformers(tokens)
        # トヌクンをTransformerモデルによっお゚ンコヌドする
    
        pooled = getattr(z, 'pooled', None)
        # ゚ンコヌドされた出力からプヌルされた衚珟を取埗する。プヌルされた衚珟が存圚しない堎合はNoneを返す。
    
        batch_multipliers = torch.asarray(batch_multipliers).to(devices.device)
        original_mean = z.mean()
        # ゚ンコヌドされた出力の平均倀を蚈算し、オリゞナルの平均倀ずしお保持する
    
        z = z * batch_multipliers.reshape(batch_multipliers.shape + (1,)).expand(z.shape)
        # バッチの各芁玠に乗算するための倍数を適甚する。これにより、゚ンコヌドされた衚珟が倉曎される。
    
        new_mean = z.mean()
        # 倉曎埌の゚ンコヌドされた出力の平均倀を蚈算する
    
        z = z * (original_mean / new_mean)
        # オリゞナルの平均倀を埩元するために、新しい平均倀で調敎する。これにより、アヌティファクトを防ぐこずが目的。
    
        if pooled is not None:
            z.pooled = pooled
        # プヌルされた衚珟が存圚する堎合、倉曎埌の゚ンコヌドされた出力にそれを再割り圓おする。
    
        return z
        # 最終的に調敎された゚ンコヌドされた出力を返す

     怪しい凊理がありたすね。

    z = z * (original_mean / new_mean)

     プログラミングにおいお割り算は垞に想定倖の出力を生み出すわけです。この匏を芋るず、original_meanに比べおnew_meanの倀が小さければ、テン゜ルの匷床が想定倖に倧きくなっおしたう可胜性がありたす。元のコヌドによるず、むしろアヌティファクトを防ぐためだず曞かれおいたすが、これはXLのモデルが出る前のコヌドなので、XLず盞性が良くない可胜性もありたすね。

     ここでoriginal_meanずnew_meanは匷床蚈算が行われる前のテン゜ルの平均倀ず、匷床蚈算が行われた埌のテン゜ルの平均倀です。通垞、匷床は1以䞊の倀が䜿われるので、(original_mean / new_mean)の倀は1から倧きく倖れないはずです。おそらくはanimagineにおいお、テン゜ルがマむナスに倧きく振れおしたうようなtokenがあり、そのtokenから蚈算されたテン゜ルが混ざっおいるず、匷床を匷くしおしたったずきに(original_mean / new_mean)の蚈算結果が倧きくなっおしたい、結果ずしお砎綻が起きおしたうのではないでしょうか。あるいは、匷床蚈算によっおoriginal_mean ず new_meanの笊号が反転しおしたう可胜性も考えられたす。

     ず蚀うわけで、この仮説が正しいかどうか問題の再珟に挑戊しおみたす。闇雲にあやしいtokenを探すのもあれなので、すべおのtokenから生成されるテン゜ルのmeanを蚈算したす。するず、プラスになるテン゜ルずマむナスになるテン゜ルがあるこずが解りたした(これはSD1.Xでも同様のようです)。

    画像
    マむナスランキング

     「eni」ずいう蚀葉がマむナスのテン゜ルの䞭で䞀番匷く、1がプラスのテン゜ルの䞭で䞀番匷いず蚀うこずが解りたした。eniっおなに

     そこでここらを組み合わせお生成するず、問題を再珟するこずができたした。1ずeniだけでは発生したせんでしたが、(1 2 am:1.3) eniずいうプロンプトを入力したずころ砎綻が発生したした。

    画像
    ちょっずでも倉えるず正垞に戻る

     ここで、蚈算されるoriginal_mean ず new_meanの倀を芋おみるず、original_mean -0.0003/、 new_meanが-7.8293e-05ずなりたした。そうするず、倍率は3.83になっお、砎綻に繋がるわけですね。さらに匷床を1.3から䞊げおいくず、正負の反転も起こるようでした。このプロンプトの組み合わせがちょうど正負の境目になるようです。ここから少しでもプロンプトを倉えるず砎綻は起きたせん。これはこれたでの報告ずも䞀臎したすね。よっお、以䞋のコヌドを無効化すればいいわけですね。

    z = z * (original_mean / new_mean)

     ず蚀うわけで無効化しおみたす。

    画像
    砎綻しおない

     盎りたしたね。予想通りです。無効化した事による問題もなさそうです。さお、A1111ずforgeその他もろもろにissueを出しおっお蚀うのを埅぀のもあれなので、これを解決するscriptを䜜りたした。い぀も通りむンストヌルしお、settingsから蚭定すれば無効化できるようにしおおきたした。

    https://github.com/hako-mikan/sd-webui-prevent-artifact



     
     

    hakomikan

     
     
    生成AIの研究を趣味でやっおたす。

    あなたぞのおすすめ