Stable Diffusionのプロンプト処理の新手法の簡単な解説

この記事は、"ShiftEncoding to overcome position bias in Stable Diffusion prompts"という記事の内容を要約したものです。

背景

Stable Diffusionでは () や [] を使ってプロンプト内の一部の単語やフレーズを強調することがよく行われていますが、これは実は素のStable Diffusionの機能ではなく、"Stable Diffusion web UI"や"Long Prompt Weighting Stable Diffusion"という非公式ツールで独自に提供されている機能です。

この機能は便利ですが、素のStable Diffusionのプロンプト処理方法にある、単語やフレーズの出現位置で出力画像が大きく変わるという問題をそのまま引き継いでしまう実装となっています。

例えば、"black dog, white cat, blue sky and mountain, near a big tree"(黒犬、白猫、青空と山、大きな木の近く)というプロンプトでは次のような画像が生成されます。

black dog, white cat, blue sky and mountain, near a big tree

しかし、順序を入れ替えて、"blue sky and mountain, near a big tree, black dog, white cat"(青空と山、大きな木の近く、黒犬、白猫)とすると、次のようになります。(シード値は共通)

blue sky and mountain, near a big tree, black dog, white cat

新手法は、このような単語の出現位置による差異(ポジションバイアス)を避けながら、長文プロンプトや単語・フレーズの強調ができるプロンプト処理方法です。

シフトエンコーディング

新手法の名前はシフトエンコーディングと言います。

並列プロンプト

シフトエンコーディングでは、シフト・反転・回転という手法を用いて、プロンプト中の単語位置を入れ替えた並列プロンプトをいくつも作り、その意味ベクトルの平均値を使って画像生成を行います。

例えば、入力プロンプトが "A, B, C" であった場合、テキストをカンマ区切りで分割した上で、次のような並列プロンプトを生成します。

  • "A B C"

  • "B C A"

  • "C A B"

  • "C B A"

  • "B A C"

  • "A C B"

これらの平均値を取ることで、単語やフレーズの出現位置が1か所に偏ることがなくなり、ポジションバイアスが軽減されることが期待されます。

強調構文

次に単語やフレーズの強調ですが、これはカンマ区切りで分割した部分ごとに、重みづけ、繰り返し、位置固定という3つの手法で行うことができます。

重みづけは、プロンプト中に ":1.5" のように記述することで、並列プロンプトの平均値を計算する際に、該当する部分の意味ベクトルに対して重み分だけ掛け算します。

繰り返しは、プロンプト中に "*2" のように記述することで、並列プロンプトを作る前に、該当部分を指定回数繰り返してプロンプトを拡張します。"A, B *2, C" というプロンプトの場合、"A, B, B, C" のようになります。

位置固定は、並列プロンプトを作る時、指定した部分をプロンプトの前方に固定します。固定部分と非固定部分の境は ">>>" という記号で分割します。">>>" がなければ、すべて非固定部分として扱われます。例えば "A >>> B, C" というプロンプトの場合、次のような並列プロンプトが作られます。

  • "A B C"

  • "A C B"

さらに、プロンプト中の改行は空白として扱われるため、次のようなプロンプトを記述することが可能になります。

black dog :1.5,
white cat *2,
>>>
blue sky and mountain :3 *2,
near a big tree,

シフトエンコーディングを用いたプロンプトの例

使い方

シフトエンコーディングは、Unstable Diffusion v2.0 以降でサポートされています。ライブラリの一般的な使い方は "Unstable Diffusion : Stable Diffusionを簡単にGoogle Colabで使う方法" で解説されています。(注:他の同名のプロジェクトと混同しないようにしてください。)

シフトエンコーディングを使う場合は、例に含まれる StandardEncoding を ShiftEncoding で置き換えます。例えば、テキストから画像を生成(Text to Image)する場合は、次のようになります。

prompt = "1girl, 1boy"
negative_prompt = "1girl"
guidance_scale = 7.5
num_steps = 50
image_size = (512, 512)  # width, height
symmetric = False

image = pipe(
    pipeline_type=Txt2Img(
        initialize=Randomly(symmetric=symmetric),
        size=image_size,
    ),
    text_input=ShiftEncoding(
        prompt=prompt,
        negative_prompt=negative_prompt,
    ),
    guidance_scale=guidance_scale,
    num_inference_steps=num_steps,
  )[0]
display(image)

画像生成例

以下の画像は、すべて同一シード値を用いて、シフトエンコーディングを使って生成した画像です。

black dog, white cat, blue sky and mountain, near a big tree
black dog :2.5, white cat, blue sky and mountain, near a big tree
black dog *3, white cat, blue sky and mountain, near a big tree
black dog, >>> white cat, blue sky and mountain, near a big tree
プロンプトは下記参照
プロンプト: 
high quality,
photorealistic,
>>>
black dog :1.5, white cat :1.3, blue sky and mountain *2, near a big tree

ネガティブプロンプト: 
low quality,
malformed,
>>>
blue sky and mountain, near a big tree

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