見出し画像

CLIP Text Deprojectorを使って画像生成してみる ~データ増強~

前回、CLIP Text Deprojectorというものを作ったという記事を書きましたが、今回はそれをデータ増強(data augmentation)を用いて改良したという記事です。

前回の記事

他のStable Diffusionの関連記事

Layered Diffusion Pipelineを使うためのリンク集

前回の問題点

前回、CLIP Text Modelの最終embeddingから、Stable Diffusionの入力に使うlast hidden stateに変換することに、一定程度の成功を収めましたが、最終embeddingを足し算したり平均を取ったりすることはうまくできませんでした。

例えば、下の絵は、「cat」と「maid」のembeddingの平均を取って、Deprojectorを掛けてStable Diffusionに入力してできた画像です。

cat + maid

「cat」の意味はなんとか残っていますが、「maid」の意味は失われてしまい、また、画像自体も鮮明さを失っています。

そこで、次の目標を、最終embeddingの平均を取って画像生成ができるようにすることとしました。

モデルの改良方針

平均のembeddingから画像生成がうまくいかない理由として、そのようなembeddingをモデルが学習していないことにあるだろうと考えました。そこで、トレーニングデータに平均のembeddingを含むようなデータ増強(data augmentation)を行うことにしました。

データ増強の方法には、いくつかのやり方が考えられますが、予備実験と考察の結果、次の方法で行うことにしました。

トレーニングデータのデータ増強

上図はデータ増強方法の模式図です。以下にステップ毎に説明します。

  1. 入力テキストを2つ用意します。(Text #1, Text #2)

  2. 2つのテキストをスペースを空けて文字列結合します。

  3. 以上3つのテキスト全てをCLIP Text Modelに掛けて、それぞれにembeddingとlast hidden stateを計算します。

  4. トレーニングデータの入力データとして、Text #1, #2に対応するembedding #1, #2のベクトルを要素ごと足し合わせて正規化したものを取ります。

  5. トレーニングデータの正解データとして、2.で文字列結合したテキストに対応するlast hidden state #3を取ります。

また、はじめの2つの入力テキストの作り方として、次の2通りの方法を半々で採用しています。

  • LAION 400Bから取った1つのテキストを2つに分割する

  • LAION 400Bから2つのテキストを取る

トレーニングデータに含まれる元データと増強データの割合は、およそ一対一となるように調整しました。

生成画像 - 単一のembeddingから

まずは、単一のテキストから生成した単一のembeddingを元に、Stable Diffusionで画像を生成してみます。前回の記事で行ったものと同様の実験なので、比較のため、前回の結果と並べて掲載します。

使用したプロンプトは、前回と同様、次のテキストに画質調整用のタグをいくつか追加したものを使用しています。

  • cat maid (猫耳メイド)

  • 1girl red hair blue eye black skirt(赤髪 青目 黒スカート)

  • 1boy 1girl in class room(少年 少女 教室)

上から順に、Deprojectorなし、LAION 400Mのテキスト1万件でトレーニング、2万件、3万件、4万件、5万件と並んでいます。左が前回のモデルで、右が今回のモデルです。

「猫耳メイド」
「赤髪 青目 黒スカート」
「少年 少女 教室」

全体として、今回のモデル(右)は、前回のモデル(左)と同等か、それよりも元のプロンプトの意味をより正確に再現しています。特に、「少年 少女 教室」の画像では、今回のモデルの方が「教室」をより正確に画像に反映させています。

また、今回のモデルの方が、背景のディテールが細かく書き込まれる傾向にあるようです。

全体として、今回行ったデータ増強は、単一embeddingに対して、同等かそれ以上の効果があったと言えると思われます。

なお、さらに細かいチェックポイントで生成画像をチェックしてみたところ、3万~4万件を境に、画像生成の出力が不安定になり、過学習の可能性が懸念されたことを追記しておきます。

生成画像 - 複数のembeddingを合成

次に、今回の主眼である、複数のembeddingの合成を試してみました。この実験のため、PooledEncodingというクラスが新たにLayered Diffusion Pipelineに追加されています。

PooledEncodingは、カンマ区切りのプロンプトを受け取って、カンマで分割してそれぞれの部分ごとにembeddingを計算し、ベクトルの要素ごとに合計して正規化し、Deprojectorを適用するEncodingクラスです。

使用したスクリプトは、次のようなものになります。

prompt = "cat, maid"
encoding = PooledEncoding(normalize=True)
deprojector = CLIPTextDeprojector.from_pretrained("/path/to/model").to("cuda")

pipe.text_model.SetDeprojector(deprojector)
image = pipe(
    num_steps=30,
    size=(512, 512),
    iterate=Layer(
        prompt = (prompt, encoding),
        negative_prompt = "EasyNegative",
        cfg_scale=9,
    ),
    default_encoding=StandardEncoding(),
)

プロンプトには、次の3種類を使用しました。

  • cat, maid (猫 メイド)

  • 1girl, red hair, blue eye, black skirt (赤髪 青目 黒スカート)

  • 1boy, 1girl, in class room (少年 少女 教室)

「cat, maid」については、分割されることで「猫耳メイド」ではなく「猫、メイド」というように、ニュアンスが少し変化していることにも注目してください。

Deprojectorモデルについては、15000件のデータでトレーニングしたもの、25000件でトレーニングしたもの、40000件でトレーニングしたものの3種類を用意しました。さらに比較用に、標準エンコーディングを使ったものを最上段に配置しました。

以下が生成画像です。左と右は、同じモデルとスクリプトで、別の乱数シードを使って生成した画像です。

「猫 メイド」
「赤髪 青目 黒スカート」
「少年 少女 教室」

前回のモデルとは異なり、今回は明らかにプロンプトに対応した画像が生成されやすくなっています。また、完全に無関係な画像は1つも生成されませんでした。

全体として、25000件のデータでトレーニングしたモデルが最もよく、15000件では学習不足の様子が感じられます。これは、単一embeddingの結果に比べて、学習速度が遅いことを示唆している可能性があり、データ増強の配分割合の見直しが必要ではないかと思われます。

また、「少年 少女 教室」については、他のプロンプトと比べて、生成画像とプロンプトの意味の乖離が大きいように思われます。「猫 メイド」「赤髪 青目 黒スカート」は単一の対象の異なる属性であるのに対し、「少年 少女 教室」は3つの独立した対象であることが影響している可能性があると考えています。

まとめ

CLIP Text Deprojectorをデータ増強を用いて改良する取り組みは、一定の成果を得ました。

単一embeddingからの画像生成の質は、データ増強をする前とした後で、若干の向上が見られました。

複数のembeddingを合成して画像生成する場合は、データ増強前と比べて著しい改善が見られました。

今後の改良点として、増強データの配分割合の見直しと、過学習を抑えるデータ増強方法の調査の2点を挙げておきたいと思います。

追記

最新版のモデルデータは、Hugging Faceリポジトリに登録済みです。LAION 400Bの25000件のテキストと、それを元にした増強データでトレーニングしたモデルです。

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