ジャコ Lab

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

AnimateLCM を使ってみた

この記事では AnimateLCM に触れていきます。

LCM は初めて登場するキーワードですが、併せて調べていきます。

リリースノートの一番上にあったけど既読スルーしてたやつ

LCM (Latent Consistency Models) とは

AnimateDiff が対応したリリースノート(v0.22.0) にも記載されていた Latent Consistency Models の略です。リリースノートを見る限りだと、4ステップでかなり品質の高い画像が出力されています。

つまり AnimateLCMAnimateDiff 向けの Latent Consistency Models で、僅かなステップで高品質な動画が出力される感じがします。

やってみる

huggingface.co

こちらのドキュメントを参考に進めていきます。

まず、はじめに

ドキュメント通りに進めると以下のエラーになります。

OSError: wangfuyun/AnimateLCM does not appear to have a file named sd15_lora_beta.safetensors.
sd15_lora_beta.safetensors が NotFound!!

これは wangfuyun/AnimateLCM リポジトリ上の構成が変わったものと思われます。

どうやら AnimateLCM_sd15_t2v_lora.safetensors というファイル名にリネームされたのが原因のようです。

よって、以下のように変更を加える必要があります。

- "sd15_lora_beta.safetensors"
+ "AnimateLCM_sd15_t2v_lora.safetensors"

改めてやってみる

モデルのロード等(MotionAdapter, AnimateDiffPipeline, LCMScheduler)

from diffusers import AnimateDiffPipeline, LCMScheduler, MotionAdapter

# モーションアダプターのロード
adapter = MotionAdapter.from_pretrained(
    "wangfuyun/AnimateLCM"
)

# AnimateDiffPipeline 用のモデルのロード
pipe = AnimateDiffPipeline.from_pretrained(
    "emilianJR/epiCRealism",
    motion_adapter=adapter
)

# AnimateLCM (LoRA) のロード
pipe.load_lora_weights(
    "wangfuyun/AnimateLCM",
    weight_name="AnimateLCM_sd15_t2v_lora.safetensors",
    adapter_name="lcm-lora"
)

# スケジューラーの設定
pipe.scheduler = LCMScheduler.from_config(
    pipe.scheduler.config,
    beta_schedule="linear"
)

# メモリ関連
pipe.enable_vae_slicing()
pipe.enable_model_cpu_offload()
今までの AnimateDiff との違いは、MotionAdapter のモデルが異なるところ!

パイプライン実行

import torch

# パイプラインの実行
frames = pipe(
    prompt="A space rocket with trails of smoke behind it launching into space from the desert, 4k, high resolution",
    negative_prompt="bad quality, worse quality, low resolution",
    num_frames=16,
    guidance_scale=1.5,
    num_inference_steps=6,
    generator=torch.Generator("cpu").manual_seed(0),
).frames[0]

実行結果

from datetime import datetime
from zoneinfo import ZoneInfo
from diffusers.utils import export_to_gif

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

# 実行結果
export_to_gif(frames, f"animation_{formattedNow}.gif")

AnimateLCM で出力した結果
AnimateLCM で出力した結果

うんうん、出力できてる!

Motion LoRA と AnimateLCM LoRA の併用

from diffusers import AnimateDiffPipeline, LCMScheduler, MotionAdapter

# モーションアダプターのロード
adapter = MotionAdapter.from_pretrained(
    "wangfuyun/AnimateLCM"
)

# AnimateDiffPipeline 用のモデルのロード
pipe = AnimateDiffPipeline.from_pretrained(
    "emilianJR/epiCRealism",
    motion_adapter=adapter
)

# AnimateLCM LoRA のロード
pipe.load_lora_weights(
    "wangfuyun/AnimateLCM",
    weight_name="AnimateLCM_sd15_t2v_lora.safetensors",
    adapter_name="lcm-lora"
)
# Motion LoRA のロード
pipe.load_lora_weights(
    "guoyww/animatediff-motion-lora-tilt-up",
    adapter_name="tilt-up"
)
pipe.set_adapters(["lcm-lora", "tilt-up"], [1.0, 0.8])

# スケジューラーの設定
pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config, beta_schedule="linear")

# メモリ関連
pipe.enable_vae_slicing()
pipe.enable_model_cpu_offload()
なるほど、モーション LoRA を複数使うときと一緒のやり方ね!

パイプライン実行

import torch

# パイプラインの実行
frames = pipe(
    prompt="A space rocket with trails of smoke behind it launching into space from the desert, 4k, high resolution",
    negative_prompt="bad quality, worse quality, low resolution",
    num_frames=16,
    guidance_scale=1.5,
    num_inference_steps=6,
    generator=torch.Generator("cpu").manual_seed(0),
).frames[0]

実行結果

from datetime import datetime
from zoneinfo import ZoneInfo
from diffusers.utils import export_to_gif

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

# 実行結果
export_to_gif(frames, f"animation_{formattedNow}.gif")

AnimateLCM LoRA + Motion LoRA
AnimateLCM LoRA + Motion LoRA

まとめ

無事 LCM 使えました。

よく登場しそうなキーワードだから覚えておこう。LCM。