ジャコ Lab

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

IP-Adapter FaceID に再チャレンジ!

id:touch-sp さん、ご助言ありがとうございました!
どうしてエラーが発生するのか理解に繋がりました 🙇

早速、 IP-Adapter FaceID に再チャレンジしてみようと思います。

はじめに振り返り

過去にチャレンジして動かせなかった記事はこちらです。

エラー記事1
エラー記事2

原因

自分は pip install diffusers を使って PyPI に公開されている最新 diffusers を使用してました。この時、インストールされるバージョンは現時点で v0.27.2 です。

一方で、参照しているドキュメントは MAIN のものだったのが原因です。

つまり v0.27.2 では実装されていない機能を試そうとしていたわけです。

そりゃ動かんわい

ドキュメント(MAIN)のキャプチャドキュメント(v0.27.2)のキャプチャ
ドキュメントのキャプチャ

ドキュメントを v0.27.2 の版にすると IP-Adapter FaceID のブロックがごっそりとありません。

よって、main ブランチの機能を動かすために以下のご助言になったわけですね。

mainブランチをインストールすれば前回のスクリプトは動作すると思います。 pip install git+https://github.com/huggingface/diffusers

感謝!

早速 pip install のところを見直して試してみる!

実行結果!

Image Embedding に使用した画像
Image Embedding に使用した画像

生成された画像1生成された画像2生成された画像3生成された画像4
生成された画像

キターーーーー

FaceAnalysis の部分をわからないなりに理解してみる!

今回、この部分が全然わかりません。
最終的に pipeline に渡すid_embedsが出来ていれば良いのだが。。。
ref_images_embeds = []
app = FaceAnalysis(name="buffalo_l", providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
app.prepare(ctx_id=0, det_size=(640, 640))
image = cv2.cvtColor(np.asarray(image), cv2.COLOR_BGR2RGB)
faces = app.get(image)
image = torch.from_numpy(faces[0].normed_embedding)
ref_images_embeds.append(image.unsqueeze(0))
ref_images_embeds = torch.stack(ref_images_embeds, dim=0).unsqueeze(0)
neg_ref_images_embeds = torch.zeros_like(ref_images_embeds)
id_embeds = torch.cat([neg_ref_images_embeds, ref_images_embeds]).to(dtype=torch.float16, device="cuda")

わからないなりにコメントを入れてみた

# 入れ物
ref_images_embeds = []

# FaceAnalysis を準備する
app = FaceAnalysis(name="buffalo_l", providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
app.prepare(ctx_id=0, det_size=(640, 640))

# OpenCV で扱えるように色空間を RGB -> BGR 変換する
image = cv2.cvtColor(np.asarray(image), cv2.COLOR_BGR2RGB)

# 顔情報を取得
faces = app.get(image)

# 顔情報から埋め込みパラメータ?を作成する
image = torch.from_numpy(faces[0].normed_embedding)
ref_images_embeds.append(image.unsqueeze(0))
ref_images_embeds = torch.stack(ref_images_embeds, dim=0).unsqueeze(0)
neg_ref_images_embeds = torch.zeros_like(ref_images_embeds)
id_embeds = torch.cat([neg_ref_images_embeds, ref_images_embeds]).to(dtype=torch.float16, device="cuda")
全然よくわからんけどこんな感じ??凄い適当です。

BGRな画像
BGRな画像

途中で RGB2BGR をしているので出力してみた
OpenCV 使い慣れてないから物珍しい。稀に良く色反転している!ってのを見たことがある気がします

スクリプト全体

モジュール群をインストールする

!pip install git+https://github.com/huggingface/diffusers
!pip install -U transformers accelerate peft controlnet_aux onnxruntime-gpu insightface

モデル群をロードする

import torch
import cv2
import numpy as np
from diffusers import StableDiffusionPipeline, DDIMScheduler

# ベースもデールをロードする
pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16,
).to("cuda")

# スケジューラを設定する
pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)

# IP-Adapter FaceID をロードする
pipe.load_ip_adapter(
    "h94/IP-Adapter-FaceID",
    subfolder=None,
    weight_name="ip-adapter-faceid_sd15.bin",
    image_encoder_folder=None
)
# IP-Adapter のスケールを設定する
pipe.set_ip_adapter_scale(0.6)

画像埋め込み情報?を作る

import cv2
import numpy as np
from insightface.app import FaceAnalysis
from diffusers.utils import load_image

# Image Embedding に使用する画像をロードする
image_url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/ip_mask_girl1.png"
image = load_image(image_url)

# FaceAnalysis を準備する
app = FaceAnalysis(name="buffalo_l", providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
app.prepare(ctx_id=0, det_size=(640, 640))

# OpenCV で扱えるように色空間を RGB -> BGR 変換する
image = cv2.cvtColor(np.asarray(image), cv2.COLOR_BGR2RGB)

# 顔情報を取得
faces = app.get(image)

# 顔情報から埋め込みパラメータ?を作成する
image = torch.from_numpy(faces[0].normed_embedding)
ref_images_embeds = []
ref_images_embeds.append(image.unsqueeze(0))
ref_images_embeds = torch.stack(ref_images_embeds, dim=0).unsqueeze(0)
neg_ref_images_embeds = torch.zeros_like(ref_images_embeds)
id_embeds = torch.cat([neg_ref_images_embeds, ref_images_embeds]).to(dtype=torch.float16, device="cuda")

パイプラインを実行する

import torch

# シードを設定する
generator = torch.Generator(device="cpu").manual_seed(42)

# パイプラインを実行する
prompt = "A photo of a girl"
negative_prompt = "monochrome, lowres, bad anatomy, worst quality, low quality"
images = pipe(
    prompt,
    negative_prompt=negative_prompt,
    ip_adapter_image_embeds=[id_embeds],
    num_inference_steps=20,
    num_images_per_prompt=4,
    generator=generator
).images

生成された画像を出力

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")

for idx, image in enumerate(images):
    # 実行結果
    image.save(f"image_{formattedNow}_{idx}_{generator.initial_seed()}.png")

まとめ

自分が使用している diffusers のバージョンはわかっていましたが、
まさか参照しているドキュメントが 新しすぎる とは思いませんでした。。。

しかし、まだ疑問が残るところがありますね。

main ブランチの diffusers では、 IP-Adapter FaceIDコミュニティパイプライン から Core に移動したのは良いとして、移動する前の v0.27.2 で出来ないのはなんでなんでしょうね。

謎!

まぁしかし、何にせよ、IP-Adapter FaceID が動いたので OK ですね!