前回 runwayml/stable-diffusion-inpainting
を使って Inpainting をしました。
今回は ControlNet 版で試してみます
はじめに
ControlNet is a type of model for controlling image diffusion models by conditioning the model with an additional input image. There are many types of conditioning inputs (canny edge, user sketching, human pose, depth, and more) you can use to control a diffusion model.
ControlNet とは、 追加の入力画像を使用して調整することで、出力画像を制御するモデルの一種で、制御に使用できる入力には様々なタイプがある とのことです。diffusers では v0.14.0 で登場し、 v0.16.0 でパワーアップした模様です。
今回は、その中でも、前々回から触っている Inpaint をやってみようと思います。
ControlNet 版 Inpaint
投入画像の準備
from diffusers.utils import load_image import numpy as np import torch # 投入画像の準備 init_image_url = "https://huggingface.co/datasets/diffusers/test-arrays/resolve/main/stable_diffusion_inpaint/boy.png" init_image = load_image(init_image_url).resize((512, 512)) mask_image_url = "https://huggingface.co/datasets/diffusers/test-arrays/resolve/main/stable_diffusion_inpaint/boy_mask.png" mask_image = load_image(mask_image_url).resize((512, 512)) # コントロールイメージを作成するメソッド def make_inpaint_condition(image, image_mask): image = np.array(image.convert("RGB")).astype(np.float32) / 255.0 image_mask = np.array(image_mask.convert("L")).astype(np.float32) / 255.0 assert image.shape[0:1] == image_mask.shape[0:1], "image and image_mask must have the same image size" image[image_mask > 0.5] = -1.0 # set as masked pixel image = np.expand_dims(image, 0).transpose(0, 3, 1, 2) image = torch.from_numpy(image) return image control_image = make_inpaint_condition(init_image, mask_image)
まずは、入力画像の準備です。 make_inpaint_condition
メソッドについては詳しくは何をやっているかわからないですが、 入力画像 と マスク画像 から ControlNet で使用するイメージを作成しているようです。
ControlNetModel の準備
# ControlNet の準備 controlnet = ControlNetModel.from_pretrained( "lllyasviel/control_v11p_sd15_inpaint", torch_dtype=torch.float16 ) # パイプラインの準備 pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained( "runwayml/stable-diffusion-v1-5", torch_dtype=torch.float16, controlnet=controlnet, ).to("cuda") pipe.enable_model_cpu_offload() # スケジューラの設定 pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)
お次は、ControlNetModel の準備です。
"lllyasviel/control_v11p_sd15_inpaint"
を使用します。
パイプラインには StableDiffusionControlNetInpaintPipeline
を使用して、 controlnet 引数 を設定します。
パイプライン実行
# パイプライン実行 prompt = "a handsome man with ray-ban sunglasses" image = pipe( prompt, num_inference_steps=20, generator=torch.Generator(device="cuda").manual_seed(1), eta=1.0, image=init_image, mask_image=mask_image, control_image=control_image, ).images[0]
最後にパイプラインの実行です。
image 引数 に入力画像
mask_image 引数 にマスク画像
control_image 引数 に先程作成した control_image を設定します。
eta とはなんでしょうね?初見です。
ハンサムな男性が、レイバンのサングラスをかけたハンサムな男性になりました。
eta 引数とは?
eta (float, optional, defaults to 0.0) — Corresponds to parameter eta (η) from the DDIM paper. Only applies to the DDIMScheduler, and is ignored in other schedulers.
ということで DDIMScheduler に使われるパラメータでした。DDIM 以外の Scheduler では無視されるパラメータのようです。
通常版?(runwayml/stable-diffusion-inpainting
) でもやってみよう
上手く行きました!
コード全文 (折りたたみ)
import torch from diffusers import AutoPipelineForInpainting, DDIMScheduler # パイプラインの準備 pipeline = AutoPipelineForInpainting.from_pretrained( "runwayml/stable-diffusion-inpainting", torch_dtype=torch.float16, variant="fp16" ).to("cuda") pipeline.enable_model_cpu_offload() # スケジューラの設定 pipeline.scheduler = DDIMScheduler.from_config(pipeline.scheduler.config) # 投入画像の準備 init_image_url = "https://huggingface.co/datasets/diffusers/test-arrays/resolve/main/stable_diffusion_inpaint/boy.png" init_image = load_image(init_image_url).resize((512, 512)) mask_image_url = "https://huggingface.co/datasets/diffusers/test-arrays/resolve/main/stable_diffusion_inpaint/boy_mask.png" mask_image = load_image(mask_image_url).resize((512, 512)) # パイプライン実行 prompt = "a handsome man with ray-ban sunglasses" image = pipeline( "a handsome man with ray-ban sunglasses", num_inference_steps=20, generator=torch.Generator(device="cuda").manual_seed(1), eta=1.0, image=init_image, mask_image=mask_image, ).images[0]
まとめ
ControlNet 版 Inpaint も diffusers でお手軽に使用できました。
runwayml/stable-diffusion-inpainting
との違いはわかりませんが、ControlNet は同じノリで他にも色々できるようなので、「Inpaint だけ別のやり方」というよりは ControlNet に統一しても良さそうな気がしました。