見出し画像

Layered Diffusion Pipeline の使い方

この記事は、GitHubに置かれているLayered Diffusion Pipelineのトップページの翻訳です。なお、この説明はライブラリの基本的な使い方のみをカバーしていて、発展的な使い方は記述されていないことを留意してください。


これは、Stable Diffusionパイプラインをより柔軟に使用するためのラッパーライブラリです。このパイプラインの主要な考え方は、Layerと呼ばれる概念で、一個の画像生成にさまざまなプロンプトを層のように積み重ねて適用することです。

以前のライブラリとは異なり、この新しいライブラリはゼロから書き直されましたが、ライセンスは現時点では元のStable Diffusionパイプラインに従っています。ライセンスの詳細については、Stable Diffusionパイプラインのコードベースを確認してください。

基本の使用方法

Layered Diffusion Pipelineは、元のStable Diffusion Pipelineと同様のタスクを実行できます(v2以降に導入された新しいinpaintingモデルやdepth to imageモデルなど、特別にチューニングされたモデルを除く)。このセクションでは、次の3つの使用例についてライブラリの使用方法を説明します。

  • text to image(テキストから画像)

  • image to image(画像から画像)

  • 古いinpainting

初期化

まず、ライブラリを使用するには、本体のPythonファイルをカレントディレクトリに配置し、次のようにインポートする必要があります。

from pipeline_layered_diffusion import *

Google Colabを使う場合は次のようになります。

!pip install diffusers transformers scipy accelerate xformers safetensors omegaconf pytorch_lightning opencv-python
# Original code: https://github.com/nanashi161382/unstable_diffusion/blob/main/pipeline_layered_diffusion.py
!wget 'https://raw.githubusercontent.com/nanashi161382/unstable_diffusion/main/pipeline_layered_diffusion.py'
from pipeline_layered_diffusion import *

次に、パイプラインを初期化します。diffusers形式のモデルデータをHuggingFaceのリポジトリからダウンロードして初期化するには、次のようにします。

dataset = "stabilityai/stable-diffusion-2"
auth_token = "" # auth token for HuggingFace if needed
pipe = LayeredDiffusionPipeline().Connect(dataset, auth_token=auth_token)

diffusers形式のモデルデータをローカルに保存したものがあれば、それを用いて次のように初期化します。

model_name = "stabilityai/stable-diffusion-2"  # ここはどんな文字列でもよい。
model_path = "/path/to/model/directory"
pipe = LayeredDiffusionPipeline().Connect(model_name, cache_path=model_path)

Stable Diffusion形式のモデルデータがあれば、それがckpt形式でもsafetensors形式でも同様に、次のように記述できます。

model_name = "stabilityai/stable-diffusion-2"  # ここはどんな文字列でもよい。
model_path = "/path/to/model/directory/model_name.ckpt"
pipe = LayeredDiffusionPipeline().ConnectCkpt(
    model_name, checkpoint_path=model_path
)

この場合、VAEだけを置き換えることもできます。VAEデータは、diffusers形式でも、ptファイル形式でも使用可能です。

model_name = "stabilityai/stable-diffusion-2"  # ここはどんな文字列でもよい。
model_path = "/path/to/model/directory/model_name.ckpt"
vae_path = "/path/to/vae/model/directory/vae_name.vae.pt"
pipe = LayeredDiffusionPipeline().ConnectCkpt(
    model_name, checkpoint_path=model_path, vae_path=vae_path
)

注)利用可能な画像生成モデルデータやVAEデータについては、こちらの記事も参考にしてください。

注2)ControlNetとTextual Inversionについては、以下の記事を参考にしてください。

注3)LoRAについては、以下の記事を参考にしてください。

画像生成

これでパイプラインの準備ができました。以下、3つのタスクのサンプルコードとサンプル画像です。

text to image

image_size = (512, 512)  # width, height
image = pipe(
    num_steps=30,
    size=image_size,
    iterate=Layer(
        prompt="photo of orange pomeranian dog running in the park >>> cute face, fluffy",
        negative_prompt="bad quality, blur",
        cfg_scale=4.0
    ),
)[0]
display(image)
text to image

image to image

image_size = (512, 512)  # width, height
image = pipe(
    num_steps=30,
    size=image_size,
    initialize=ByImage(
        image="init_image.png",
        strength=0.7,
    ),
    iterate=Layer(
        prompt="photo of orange pomeranian dog running in the park >>> cute face, fluffy",
        negative_prompt="bad quality, blur",
        cfg_scale=4.0
    ),
)[0]
display(image)
image to image

古いinpainting

image_size = (512, 512)  # width, height
image = pipe(
    num_steps=30,
    size=image_size,
    initialize=ByImage(
        image="init_image.png",
        strength=0.95,
    ),
    iterate=Layer(
        prompt="photo of orange tabby norwegian forest cat >>> cute face, fluffy",
        negative_prompt="bad quality, blur",
        cfg_scale=4.0
        mask_by="mask_image.png",
    ),
)[0]
display(image)
古いinpainting

ShiftEncoding

デフォルトでは、プロンプトとネガティブプロンプトはShiftEncodingによって解釈されます。ShiftEncodingは、以下の機能をStable Diffusionで可能にするために新しく提案されたプロンプトの処理方法です。

  • 位置バイアスの除去

  • 長いプロンプトの処理

  • 単語/フレーズの強調

詳細については、「Stable Diffusionのプロンプト処理の新手法の簡単な解説」をお読みください。

オリジナルのStable Diffusionパイプラインと同じプロンプト処理をさせるには、以下のようにパイプラインに default_encoding=StandardEncoding() を追加する必要があります。

image_size = (512, 512)  # width, height
image = pipe(
    num_steps=30,
    size=image_size,
    default_encoding=StandardEncoding(),
    initialize=Randomly(),
    iterate=Layer(
        prompt="black dog",
        negative_prompt="white cat",
        cfg_scale=7.5,
    ),
)[0]
display(image)

レイヤー機能の例

もっと複雑な指示をレイヤー機能を使うことで実現できます。以下に例を挙げます。

2つ以上の対象物を異なるプロンプトでinpaintする

inpaintingは、単一のプロンプトとネガティブプロンプトの組み合わせを使用して、元の画像の一部を再描画します。しかし、一度に元の画像の複数の部分を再描画したい場合があります。Layered Diffusion Pipelineで複数のレイヤーを使用して、それぞれの対象物をレイヤーごとに指定することができます。以下に例を示します。

image_size = (512, 512)  # width, height
image = pipe(
    num_steps=30,
    size=image_size,
    initialize=ByImage(
        image="init_image.png",
        strength=0.9,
    ),
    iterate=[
      Layer(
        prompt="orange puppy sitting on sofa",
        negative_prompt="bad quality",
        cfg_scale=4.0,
        mask_by="mask_image_left.png",
      ),
      Layer(
        prompt="red tulip flower in brown planter",
        negative_prompt="bad quality",
        cfg_scale=4.0,
        mask_by="mask_image_right.png",
      ),
    ]
)[0]
display(image)
2つ同時にinpaintする

これは大体のケースでうまくいきますが、2つのレイヤーのプロンプトが似ている場合、レイヤー同士で影響し合うことがあります。そのような場合には、干渉を避けるためにレイヤーを distinct として指定することができます。以下に例を示します。

image_size = (512, 512)  # width, height
image = pipe(
    num_steps=30,
    size=image_size,
    initialize=ByImage(
        image="init_image.png",
        strength=0.9,
    ),
    iterate=[
      Layer(
        prompt="orange puppy sitting on sofa",
        negative_prompt="bad quality",
        cfg_scale=4.0,
        mask_by="mask_image_left.png",
        is_distinct=True,
      ),
      Layer(
        prompt="orange puppy sitting on sofa",
        negative_prompt="bad quality",
        cfg_scale=4.0,
        mask_by="mask_image_right.png",
        is_distinct=True,
      ),
    ]
)[0]
display(image)
distinctを使う

複数のプロンプトを使ってtext to image

Layersは他にも、背景と前景など、画像の異なる部分に異なるプロンプトを適用することに使うことができます。これは、inpaintingと概念的に類似していますが、背景として提供された画像を使用する代わりに、text to imageを背景画像を生成するためにも使用します。以下に例を示します。

image_size = (512, 512)  # width, height
image = pipe(
    num_steps=30,
    size=image_size,
    initialize=Randomly(),
    iterate=[
      Layer(
        prompt="photo of >>> green grass field, blue sky, mountain on horizon",
        negative_prompt="blur",
        cfg_scale=4.0,
      ),
      Layer(
        prompt="white persian cat >>> round face, blue eyes",
        negative_prompt="bad quality, malformed",
        cfg_scale=4.0,
        mask_by="mask_rect.png",
      ),
    ]
)[0]
display(image)
2つのプロンプトから画像生成

前節の複数レイヤーを使ったinpaintingと同様に、前景オブジェクトに2つ以上のレイヤーを使用することができ、また、is_distinct=True も使用できます。is_distinct=True は前景のレイヤーにのみ適用する必要があります。以下に、is_distinct=True を使用した例を示します。これにより、各レイヤーがより明確になりますが、統合度が低くなる場合があります。

is_distinct=True を使用

複数のプロンプトとstrengthを使ってimage to image

(この節の内容は、少し古くなったため省略します)

おまけ

この節は、元の記事にはない内容です。

冒頭の画像はStable Diffusion v1.5を使ってやや超現実的な雰囲気の画像を作成しようと考えて作ったものです。以下に、使用したスクリプトを掲載します。

image = pipe(
    num_steps=30,
    size=(512, 512),
    iterate=[
        Layer(
            prompt=("surrealistic image of layers of many oil painting canvases "
                    "randomly piled up on top of each other on a desk"),
            negative_prompt="best quality",
            cfg_scale=7.0,
        ),
    ],
    negative_prompt_scale=0.6,
)
display(image[0])

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