[FateZero] AIでテキストを用いて動画を編集する [ゼロショット]

2023年3月23日木曜日

Artificial Intelligence

本記事では、FateZeroと呼ばれる機械学習手法を用いて任意の動画をテキストプロンプトで編集する方法をご紹介します。

アイキャッチ
出典: chenyangqiqi/fatezero

FateZero

概要

FateZeroは、テキストで動画を編集可能なゼロショットのVideo Editing手法です。

従来の拡散モデルは、テキストベースの画像生成において素晴らしい成功を収めている一方で、生成には膨大なランダム性が含まれており、現実世界のコンテンツ編集に適用することは依然として困難です。

FateZeroでは、DDIM inversionではなく、反転中に中間アテンションマップをキャプチャし、構造情報と運動情報の両方を保持し、編集プロセスでこれらのマップを融合させています。

またフレーム一貫性を確保するため、時空間アテンション(spatial-temporal attention)を導入し、Unetのノイズ除去におけるself-attenntionを改善しています。

これらにより、テキストからビデオに対し、優れたゼロショット編集機能を実現しています。

Architecture
出典: FateZero: Fusing Attentions for Zero-shot Text-based Video Editing

詳細はこちらの論文をご参照ください。

本記事では上記手法を用いて、テキストから動画を編集する方法をご紹介します。

デモ(Colaboratory)

それでは、実際に動かしながら動画を編集していきます。
ソースコードは本記事にも記載していますが、下記のGitHubでも取得可能です。
GitHub - Colaboratory demo

また、下記から直接Google Colaboratoryで開くこともできます。
Open In Colab

なお、このデモはPythonで実装しています。
Pythonの実装に不安がある方、Pythonを使った機械学習について詳しく勉強したい方は、以下の書籍やオンライン講座などがおすすめです。

環境セットアップ

それではセットアップしていきます。 Colaboratoryを開いたら下記を設定しGPUを使用するようにしてください。

「ランタイムのタイプを変更」→「ハードウェアアクセラレータ」をGPUに変更

初めにGithubからソースコードを取得します。

%cd /content

!git clone https://github.com/ChenyangQiQi/FateZero

%cd /content/FateZero
# Commits on Mar 22, 2023
!git checkout 37a321f04a41c0c342e78b2dca0f02183d2ba1de

次にライブラリをインストールします。

%cd /content/FateZero

!pip install -q -U --pre triton
!pip install -q diffusers[torch]==0.11.1 transformers==4.26.0 bitsandbytes==0.35.4 \
decord accelerate omegaconf einops ftfy gradio imageio-ffmpeg xformers

!pip install moviepy yt-dlp
!pip install imageio==2.4.1

最後にライブラリをインポートします。

%cd /content/FateZero

import os
import glob

import torch
import cv2

from yt_dlp import YoutubeDL
from moviepy.video.fx.resize import resize
from moviepy.editor import VideoFileClip

from omegaconf import OmegaConf

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('using device is', device)

以上で環境セットアップは完了です。

学習済みモデルのセットアップ

ここでは、Stable Diffusion v1.4をダウンロードします。

%cd /content/FateZero

MODEL_NAME = "CompVis/stable-diffusion-v1-4"

!git lfs install
!git clone https://huggingface.co/$MODEL_NAME ckpt/$MODEL_NAME
MODEL_NAME = f"./ckpt/{MODEL_NAME}"
print(f"[*] MODEL_NAME={MODEL_NAME}")

動画のダウンロード

ここでは、Youtube上から動画をダウンロードしていきます。

初めにURLと切り抜き区間を設定します。

%cd /content/FateZero

video_url = 'https://www.youtube.com/watch?v=YAWt-gktZqM' #@param {type:"string"}

#@markdown 動画の切り抜き範囲(秒)を指定してください。\
#@markdown 30秒以上の場合OOM発生の可能性が高いため注意
start_sec =  77#@param {type:"integer"}
end_sec =  78#@param {type:"integer"}

(start_pt, end_pt) = (start_sec, end_sec)

設定に従い、動画をダウンロードします。

download_resolution = 720
full_video_path = './data/full_video02.mp4'
input_clip_path = './data/clip_video02.mp4'

# 動画ダウンロード
ydl_opts = {'format': f'best[height<={download_resolution}]', 'overwrites': True, 'outtmpl': full_video_path}
with YoutubeDL(ydl_opts) as ydl:
    ydl.download([video_url])

# 指定区間切り抜き
with VideoFileClip(full_video_path) as video:
    subclip = video.subclip(start_pt, end_pt)
    subclip.write_videofile(input_clip_path)

フレーム画像取得

動画をフレーム画像に変換します。

# load video
video = cv2.VideoCapture(input_clip_path)
# get video info
w = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
frames_per_second = video.get(cv2.CAP_PROP_FPS)
num_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
print('video width:', w, ', height:', h, ', fps:', frames_per_second, ', frames:', num_frames)

# create out directory
out_path = './data/frames'
os.makedirs(out_path, exist_ok=True)

# Get only 8frames due to OOM
interval = int(num_frames/8)

for i in range(num_frames):
  if i % interval == 0:
    success, frame = video.read()
    cv2.imwrite( os.path.join(out_path, f'{i:06}.jpg'), frame)

Video Editing

それでは、動画をテキストで編集していきます。

まず出力先などを設定します。

#@markdown frame image directory
VIDEO_FILE = './data/frames'
VIDEO_ID = VIDEO_FILE.split('/')[-1] # directory name
RESULT_DIR = 'result/'+VIDEO_ID # output directory
CONFIG_NAME = "config/"+VIDEO_ID+".yaml" # config path

#@markdown source prompt
source_prompt = "a black car driving down a curvy road in the countryside" #@param {type:"string"}
#@markdown edit prompt
edit_prompt = "watercolor painting of a black car driving down a curvy road in the countryside"  #@param {type:"string"}
EMPHYSIS_WORD = "watercolor" #@param {type:"string"}
EMPHYSIS_VALUE = 10 #@param {type:"number"}
INVERSION_STEP = 8 #@param {type:"number"}
REPLACE_STRENGTH = 0.8 #@param {type:"slider", min:0, max:1, step:0.1}
STORE_ATTENTION_ON_disk = False #@param {type:"boolean"}

# OOM avoidance
# video_length = num_frames
video_length = 8
# width = w
# height = h
width = 512 
height = 288


config = {
  "pretrained_model_path": MODEL_NAME,
  "logdir": RESULT_DIR,
  "train_dataset": {
    "path": VIDEO_FILE,
    "prompt": source_prompt,
    "n_sample_frame": video_length,
    "sampling_rate": 1,
    "stride": 80,
    "offset": 
    {
        "left": 0,
        "right": 0,
        "top": 0,
        "bottom": 0,
    }
  },
  "validation_sample_logger_config":{
      "use_train_latents": True,
      "use_inversion_attention": True,
      "guidance_scale": 7.5,
      "prompts":[
          source_prompt,
          edit_prompt,
      ],
      "p2p_config":[ 
          {
          "cross_replace_steps":{
              "default_":0.8
              },
          "self_replace_steps": 0.8,
          "masked_self_attention": True,
           "bend_th": [2, 2],
          "is_replace_controller": False 
          },
          {
          "cross_replace_steps":{
              "default_":0.8
              },
          "self_replace_steps": 0.8,
          "eq_params":{
              "words":[EMPHYSIS_WORD],
              "values": [EMPHYSIS_VALUE]
            },
          "use_inversion_attention": True,
          "is_replace_controller": False 
          }]
          ,
    "clip_length": "${..train_dataset.n_sample_frame}",
    "sample_seeds": [0],
    "num_inference_steps": INVERSION_STEP,
    "prompt2prompt_edit": True
     },
  "disk_store": STORE_ATTENTION_ON_disk,
  "model_config":{
      "lora": 160,
      "SparseCausalAttention_index": ['mid'],
      "least_sc_channel": 640
  },
  "test_pipeline_config":{
    "target": "video_diffusion.pipelines.p2pDDIMSpatioTemporalPipeline.p2pDDIMSpatioTemporalPipeline",
    "num_inference_steps": "${..validation_sample_logger.num_inference_steps}"
  },
  "epsilon": 1e-5,
  "train_steps": 10,
  "seed": 0,
  "learning_rate": 1e-5,
  "train_temporal_conv": False,
  "guidance_scale": "${validation_sample_logger_config.guidance_scale}"
}

OmegaConf.save(config, CONFIG_NAME)
print('save new configue to ', CONFIG_NAME)

それでは、設定に従い推論を実行します。

%cd /content/FateZero

!python test_fatezero.py --config=$CONFIG_NAME

出力結果は以下の通りです。

水墨画風に変換されています。

result

まとめ

本記事では、FateZeroでテキストで動画を編集する方法をご紹介しました。

今後さらに高精細で汎用性の高いモデルが開発されそうです。

また本記事では、機械学習を動かすことにフォーカスしてご紹介しました。
もう少し学術的に体系立てて学びたいという方には以下の書籍などがお勧めです。ぜひご一読下さい。


また動かせるだけから理解して応用できるエンジニアの足掛かりに下記のUdemyなどもお勧めです。

参考文献

1.  論文 - FateZero: Fusing Attentions for Zero-shot Text-based Video Editing

2. GitHub - chenyangqiqi/fatezero

AIで副業ならココから!

まずは無料会員登録

プロフィール

メーカーで研究開発を行う現役エンジニア
組み込み機器開発や機会学習モデル開発に従事しています

本ブログでは最新AI技術を中心にソースコード付きでご紹介します


Twitter

カテゴリ

このブログを検索

ブログ アーカイブ

TeDokology