本記事では、AnimateDiffと呼ばれる機械学習手法を用いてテキストから動画を生成する方法をご紹介します。
AnimateDiff
概要
AnimateDiffは、Stable Diffusionなどをベースとした、テキストからアニメーションを生成するImage Animation技術です。
AnimateDiffでは、DreamBoothやLoRAなどのを用いて、パーソナライズされたText to Imageモデルを使用することでモデル固有のチューニングの労力を節約する実用的なフレームワークです。
このフレームワークは、新しく初期化されたMotion Modeling Moduleを挿入するだけで、Text to Imageモデルをアニメーション画像を生成するtext drive modelに変更することができます。
これにより、モデルの出力の領域と多様性を維持しながら時間的に滑らかなアニメーションクリップを生成することが可能となっています。
詳細はこちらの論文をご参照ください。
本記事では上記手法を用いて、テキストからアニメーションクリップを生成していきます。
デモ(Colaboratory)
それでは、実際に動かしながらImage Animationタスクを実行します。
ソースコードは本記事にも記載していますが、下記のGitHubでも取得可能です。
GitHub - Colaboratory demo
また、下記から直接Google Colaboratoryで開くこともできます。
なお、このデモはPythonで実装しています。
Pythonの実装に不安がある方、Pythonを使った機械学習について詳しく勉強したい方は、以下の書籍やオンライン講座などがおすすめです。
環境セットアップ
それではセットアップしていきます。
Colaboratoryを開いたら下記を設定しGPUを使用するようにしてください。
「ランタイムのタイプを変更」→「ハードウェアアクセラレータ」をGPUに変更
初めにGithubからソースコードを取得します。
%cd /content
!git clone https://github.com/guoyww/AnimateDiff.git
%cd /content/AnimateDiff
# Commits on Jul 21, 2023
!git checkout 53c63ad8391d7095ab5364c13b4aa3a7d183dac5
次にライブラリをインストールします。
%cd /content/AnimateDiff
!pip install omegaconf einops omegaconf safetensors diffusers[torch]==0.11.1 transformers xformers==0.0.20 triton==2.0.0
!pip install --upgrade gdown
以上で環境セットアップは完了です。
学習済みモデルのセットアップ
続いて、Stable Diffusionや、Motion Module、T2Iモデルなどをダウンロードしていきます。
%cd /content/AnimateDiff
# download StableDiffusion
!rm -rf ./models/StableDiffusion/
!git clone -b fp16 https://huggingface.co/runwayml/stable-diffusion-v1-5 ./models/StableDiffusion/stable-diffusion-v1-5
# download base T2I
!rm -rf ./models/Motion_Module/*
# !bash download_bashscripts/0-MotionModule.sh
!wget -c https://huggingface.co/camenduru/AnimateDiff/resolve/main/mm_sd_v14.ckpt \
-O ./models/Motion_Module/mm_sd_v14.ckpt
!wget -c https://huggingface.co/camenduru/AnimateDiff/resolve/main/mm_sd_v15.ckpt \
-O ./models/Motion_Module/mm_sd_v15.ckpt
続いて、パーソナライズされたT2Iモデルをダウンロードします。
それぞれのモデルの出力についてはこちらをご参照ください。
T2I_TYPE = "1-ToonYou" #@param ["1-ToonYou", "2-Lyriel", "3-RcnzCartoon", "4-MajicMix", "5-RealisticVision", "6-Tusun", "7-FilmVelvia", "8-GhibliBackground"]
!bash download_bashscripts/{T2I_TYPE}.sh
Image Animation
それでは、テキストからアニメーションを生成していきます。
初めに一部ソースコードを修正します。
%cd /content/AnimateDiff
# fix codes
!sed -i ./animatediff/utils/convert_from_ckpt.py \
-e "s/load_state_dict(text_model_dict)/load_state_dict(text_model_dict, strict=False)/g"
!sed -i ./animatediff/utils/util.py \
-e "s/fps=fps/duration=1000\/fps/g"
次にライブラリをインポートします。
%cd /content/AnimateDiff
import argparse
import datetime
import inspect
import os
from omegaconf import OmegaConf
import torch
import diffusers
from diffusers import AutoencoderKL, DDIMScheduler
from tqdm.auto import tqdm
from transformers import CLIPTextModel, CLIPTokenizer
from animatediff.models.unet import UNet3DConditionModel
from animatediff.pipelines.pipeline_animation import AnimationPipeline
from animatediff.utils.util import save_videos_grid
from animatediff.utils.convert_from_ckpt import convert_ldm_unet_checkpoint, convert_ldm_clip_checkpoint, convert_ldm_vae_checkpoint
from animatediff.utils.convert_lora_safetensor_to_diffusers import convert_lora
from diffusers.utils.import_utils import is_xformers_available
from einops import rearrange, repeat
import csv, pdb, glob
from safetensors import safe_open
import math
from pathlib import Path
続いて、テキストプロンプトなどを設定します。
%cd /content/AnimateDiff
# set args
args = argparse.ArgumentParser()
args.pretrained_model_path = 'models/StableDiffusion/stable-diffusion-v1-5'
args.inference_config = 'configs/inference/inference.yaml'
args.config = f'configs/prompts/{T2I_TYPE}.yaml'
args.L = 16
args.W = 512
args.H = 512
args.prompt = 'cherry blossoms, woman, 4k, definition, colorful'
args.n_prompt = ''
args.random_seed = 12
*_, func_args = inspect.getargvalues(inspect.currentframe())
func_args = dict(func_args)
time_str = datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S")
savedir = f"samples/{Path(args.config).stem}-{time_str}"
os.makedirs(savedir)
inference_config = OmegaConf.load(args.inference_config)
config = OmegaConf.load(args.config)
samples = []
テキストプロンプトからアニメーションを生成します。
sample_idx = 0
for model_idx, (config_key, model_config) in enumerate(list(config.items())[:1]):
print(model_idx, (config_key, model_config))
motion_modules = model_config.motion_module
motion_modules = [motion_modules] if isinstance(motion_modules, str) else list(motion_modules)
for motion_module in motion_modules[:1]:
print(motion_module)
### >>> create validation pipeline >>> ###
tokenizer = CLIPTokenizer.from_pretrained(args.pretrained_model_path, subfolder="tokenizer")
text_encoder = CLIPTextModel.from_pretrained(args.pretrained_model_path, subfolder="text_encoder")
vae = AutoencoderKL.from_pretrained(args.pretrained_model_path, subfolder="vae")
unet = UNet3DConditionModel.from_pretrained_2d(args.pretrained_model_path, subfolder="unet", unet_additional_kwargs=OmegaConf.to_container(inference_config.unet_additional_kwargs))
if is_xformers_available(): unet.enable_xformers_memory_efficient_attention()
else: assert False
pipeline = AnimationPipeline(
vae=vae, text_encoder=text_encoder, tokenizer=tokenizer, unet=unet,
scheduler=DDIMScheduler(**OmegaConf.to_container(inference_config.noise_scheduler_kwargs)),
).to("cuda")
# 1. unet ckpt
# 1.1 motion module
motion_module_state_dict = torch.load(motion_module, map_location="cpu")
if "global_step" in motion_module_state_dict: func_args.update({"global_step": motion_module_state_dict["global_step"]})
missing, unexpected = pipeline.unet.load_state_dict(motion_module_state_dict, strict=False)
assert len(unexpected) == 0
# 1.2 T2I
if model_config.path != "":
if model_config.path.endswith(".ckpt"):
state_dict = torch.load(model_config.path)
pipeline.unet.load_state_dict(state_dict)
elif model_config.path.endswith(".safetensors"):
state_dict = {}
if T2I_TYPE == "5-RealisticVision":
model_config.path = './models/DreamBooth_LoRA/realisticVisionV40_v20Novae.safetensors'
with safe_open(model_config.path, framework="pt", device="cpu") as f:
for key in f.keys():
state_dict[key] = f.get_tensor(key)
is_lora = all("lora" in k for k in state_dict.keys())
if not is_lora:
base_state_dict = state_dict
else:
base_state_dict = {}
with safe_open(model_config.base, framework="pt", device="cpu") as f:
for key in f.keys():
base_state_dict[key] = f.get_tensor(key)
# vae
converted_vae_checkpoint = convert_ldm_vae_checkpoint(base_state_dict, pipeline.vae.config)
pipeline.vae.load_state_dict(converted_vae_checkpoint)
# unet
converted_unet_checkpoint = convert_ldm_unet_checkpoint(base_state_dict, pipeline.unet.config)
pipeline.unet.load_state_dict(converted_unet_checkpoint, strict=False)
# text_model
pipeline.text_encoder = convert_ldm_clip_checkpoint(base_state_dict)
# import pdb
# pdb.set_trace()
if is_lora:
pipeline = convert_lora(pipeline, state_dict, alpha=model_config.lora_alpha)
pipeline.to("cuda")
### <<< create validation pipeline <<< ###
config[config_key].random_seed = []
prompt, n_prompt, random_seed = args.prompt, args.n_prompt, args.random_seed
# manually set random seed for reproduction
if random_seed != -1: torch.manual_seed(random_seed)
else: torch.seed()
config[config_key].random_seed.append(torch.initial_seed())
print(f"current seed: {torch.initial_seed()}")
print(f"sampling {prompt} ...")
sample = pipeline(
prompt,
negative_prompt = n_prompt,
num_inference_steps = model_config.steps,
guidance_scale = model_config.guidance_scale,
width = args.W,
height = args.H,
video_length = args.L).videos
samples.append(sample)
prompt = "-".join((prompt.replace("/", "").split(" ")[:10]))
save_videos_grid(sample, f"{savedir}/sample/{sample_idx}-{prompt}.gif")
print(f"save to {savedir}/sample/{prompt}.gif")
出力結果は以下の通りです。
テキストから16フレームのアニメーションが生成されています。
from IPython.display import Image
Image(open(f"{savedir}/sample/{sample_idx}-{prompt}.gif", 'rb').read())
まとめ
本記事では、AnimateDiffを用いてテキストからアニメーションを生成する方法をご紹介しました。
Stable Diffusionから端を発し、益々の発展を見せています。
また本記事では、機械学習を動かすことにフォーカスしてご紹介しました。
もう少し学術的に体系立てて学びたいという方には以下の書籍などがお勧めです。ぜひご一読下さい。
リンク
リンク
また動かせるだけから理解して応用できるエンジニアの足掛かりに下記のUdemyなどもお勧めです。
参考文献
1.
論文 - AnimateDiff: Animate Your Personalized Text-to-Image Diffusion Models without Specific Tuning
2. GitHub - guoyww/animatediff
0 件のコメント :
コメントを投稿