ジャコ Lab

プログラミング関連のメモ帳的ブログです

ピッコロ記念日なのでピッコロ大魔王を生成したかったけど LoRA が見つからなかったので結局 IP-Adapter の記事になった件

とりあえず、昨日の記事同様、タイトルはすごい長いラノベ風にできたのは良いとして、、、

前回の IP-Adapter の記事に引き続き diffusers v0.24.0 のリリースノート に沿って IP-Adapter を使ってみる回になります。

前回は、 IP-Adapter を差し込んで LCM LoRA を併用していました。

今回は、 ControlNet を併用する形になります。

ControlNet とは?

ControlNet とは、 追加の入力画像を使用して調整することで、出力画像を制御するモデルの一種で、制御に使用できる入力には様々なタイプがある とのことで、以下で調べていました。

zako-lab929.hatenablog.com

IP-Adapter と ControlNet を併用する

diffusers v0.24.0 のリリースノート によると IP-AdapterControlNet の Depth を併用するサンプルのようです。

ControlNet の Depth 単体を試している記事は以下になります。

zako-lab929.hatenablog.com

ControlNet (Depth) のときには image= プロパティに control_image (depth_image) を渡しており、
「プロンプト」 + 「コントロール画像」 になります。

IP-Adapter を用いることで入力が 「画像」 「プロンプト」 「コントロール画像」 の3つになります。

モデルのロード等 (ControlNet(Depth), StableDiffusion1.5, IP-Adapter)

from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
import torch

# ControlNetモデルのロード (Depth)
controlnet = ControlNetModel.from_pretrained(
    "lllyasviel/control_v11f1p_sd15_depth",
    torch_dtype=torch.float16
)

# SD 系モデルのロード
pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    controlnet=controlnet,
    torch_dtype=torch.float16)
pipe.to("cuda")

# IP-Adapter のロード
pipe.load_ip_adapter(
    "h94/IP-Adapter",
    subfolder="models",
    weight_name="ip-adapter_sd15.bin"
)

# enable memory savings
pipe.enable_vae_slicing()
pipe.enable_model_cpu_offload()

入力画像等のロード

from diffusers.utils import load_image

# インプット画像のロード
input_image_url = "https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/statue.png"
input_image = load_image(input_image_url)

# コントロール画像のロード
control_image_url = "https://huggingface.co/datasets/YiYiXu/testing-images/resolve/main/depth.png"
control_image = load_image(control_image_url)

パイプライン実行

import torch

generator = torch.Generator(device="cpu").manual_seed(33)

prompt = "best quality, high quality"
negative_prompt = "monochrome, lowres, bad anatomy, worst quality, low quality"
image = pipe(
    prompt, 
    negative_prompt=negative_prompt, 
    image=control_image,
    ip_adapter_image=input_image,
    num_inference_steps=50,
    generator=generator,
).images[0]

実行結果

from datetime import datetime
from zoneinfo import ZoneInfo

# Asia/Tokyo タイムゾーンの現在時刻を YYYYMMDDhhmmss 形式で得る
formattedNow = datetime.now(tz=ZoneInfo("Asia/Tokyo")).strftime("%Y%m%d%H%M%S")

# 実行結果
image.save(f"image_{formattedNow}_{generator.initial_seed()}.png")

インプット画像となる石像コントロール画像となる Depth 画像アウトプット画像
(左から) インプット画像 | コントロール画像(Depth) | アウトプット画像

まとめ

ControlNet のときは、pix2pix や inpaint のようなインプット画像を用いるものもありましたが、
ほぼ「コントロール画像」と「プロンプト」を用いて実行するものでした。

IP-Adapter を差し込むことで、更に「インプット画像」を追加することができることがわかりました。