【text2video】ModelScopeモデルの追加学習【fine-tuning】

概要

動画生成を行うAIが注目を集めています。生成を行う拡散モデルの一つにはModelScopeによるモデルがあり、追加学習を行って新しい概念を与えたり上書き、強化したりできます。
以下は追加学習によってアニメ調の動画を作成できるようにしたモデルによる動画の例です。(元のModelScopeモデルは写実的な表現が得意ですがイラスト系は不得手)

この記事ではそれを実現する以下の追加学習ツールについて簡単に学習実行までの流れを記載します。専門的なことは書けないので書きません。学習の要点だけ。

動作環境

  • GPU
    256x256で学習するならVRAM16GB、512x512なら24GB搭載しているものが必要です。

  • Git
    ツール取得のためgitと、また大規模モデルをダウンロードするためgit lfsを導入します。

  • Python
    Python仮想環境構築のため、Anacondaをインストールしておきます。

環境構築

学習ツールと学習元モデルのダウンロード

2023年6月11日現在、実写系モデルではpotao1というModelScope派生モデルが結構出来が良いと注目されています。ですのでModelScopeオリジナルではなくそちらを追加学習するのもいいかもしれません。現状ModelScope派生モデルの一覧が載っているURLを記載しておきます。

モデルを実際にダウンロードしていきます。Windowsであればpowershell等を開き、ツールを導入したいフォルダ下で以下のコマンドを順に実行します。モデル取得が結構時間かかります。

git clone https://github.com/ExponentialML/Text-To-Video-Finetuning.git
cd Text-To-Video-Finetuning
git lfs install

# git clone <モデルのリポジトリ名> <モデルを配置するディレクトリ>
# ModelScopeオリジナルから追加学習する場合は以下
git clone https://huggingface.co/damo-vilab/text-to-video-ms-1.7b ./models/model_scope_diffusers/

Python仮想環境

グローバルPython環境と切り離すため仮想環境を作り、その環境を有効化します。正常に仮想環境に入れればコマンドラインが「(text2video-finetune) PS C:\path\to\your\dir>」というような形になるかと思います。

conda create -n text2video-finetune python=3.10
conda activate text2video-finetune

Pythonモジュールのインストール

gitでダウンロードしたText-To-Video-Finetuningフォルダ下に入り、以下を実行します。

pip install -r requirements.txt
pip install --force-reinstall torch torchvision --index-url https://download.pytorch.org/whl/cu118

また追加Torch2.0未満を使用する場合、xformersを導入するとVRAM使用量が抑えられるようです。

学習の前処理

この学習ツールには大きく分けて2種類の学習方法があります。複数の動画、画像を学習データとする方法と、単一の動画を学習する方法です。ここでは前者の方法について記載します。

学習動画、画像の用意

  • 動画
    学習対象となる動画を用意します。mp4形式。現状、学習結果は16フレーム程度あたりを超えると同じ内容を繰り返す仕様のようなのでそれを念頭に置いてデータを探しましょう。
    また、あまり激しく複雑な動きをしている内容のものはおそらく学習が難しいです。経験的には静的で滑らかに動くもののほうが学習結果の出力が崩壊しづらいようです。

  • 画像
    また画像も学習対象として設定できます。学習対象の細微な部分を表現しているものを選ぶとよいのではないかと思います。
    というより、画像だけでもわりと学習できる場合もあります。とある対象の画像を十数枚用意してそれだけで学習を試みたところ、トリガーとなるタグ+一緒に覚えさせた頻出のタグ3個程度をプロンプトに含めたら結構再現できてしまいました。似た概念がすでに学習済の場合は画像だけでもいいかもしれません。

動画、画像どちらについても、後に設定する学習サイズに合わせたものを選ぶとより良い結果になるでしょう。

動画内容の抽出 (実写系)

学習する動画の内容を説明(キャプショニング、タギング)するファイルを用意します。実写系の場合はVideo-BLIP2-Preprocessorを使うとよいかと思います(このスクリプトの作成者さんが作ってます)。特定の概念を覚えさせたい場合は、タガーが作成した結果ファイル内のそれぞれの動画/画像のタグ一覧にそのタグを追加する必要があります。

対象動画の動画内容をテキストとして抽出して学習に使用するため以下のようにツールを取得し、仮想環境作成、その仮想環境に入ります。text2video-finetune仮想環境にいる場合はconda deactivateで退出しておきます。

git clone https://github.com/ExponentialML/Video-BLIP2-Preprocessor.git
cd Video-BLIP2-Preprocessor
conda create -n Video-BLIP2-Preprocessor python=3.9
conda activate Video-BLIP2-Preprocessor
pip install -r requirements.txt

#私の環境では別途以下も必要でした
pip install git+https://github.com/huggingface/transformers 
pip install torch==1.13.1+cu116 torchvision==0.14.1+cu116 torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu116

以下コマンドを実行してJSONファイルを作成します。

python preprocess.py --video_directory <your path of videos> --config_name "My Videos" --config_save_name "my_videos" --prompt_amount 25

コマンドの説明:

  • ---video_directoryに対象動画のあるフォルダを指定します。

  • --config_nameは文字通り設定の名前ですが、たぶん重要じゃないので適当でいいと思います。

  • --config_save_nameで出力jsonファイル名を指定します。

  • --prompt_amountはランダムなフレームから内容を抽出する回数です。デフォルト値が25ですが、16フレーム程度の動画なら16以下で8とかでよいんではないかと個人的には思ってます。

他にも隠し引数があるようですがよくわかってません。

動画内容の抽出 (アニメ系)

アニメ系についてはwd14taggerを使用したKohya氏の画像タギング用スクリプトをちょっと改造して動画に対応したスクリプトを作成しました。
こちらのほうがイラスト系に沿ったより詳細な内容が抽出できるのではないかと思います。
なおこのスクリプトは抽出結果ファイルをCSV形式とJSON形式で選べますがJSONを選んでください。CSVは1つの動画の各フレームの内容をすべて1つにまとめるので、表現力が落ちます。JSON形式ならフレーム単位でタギングできます。
詳細はリンク先を参照ください。

抽出データの確認

上記も場合によって結構時間がかかります。
完了後、出力されたJSONを確認します。問題がなければ以下のような形になっているはずです。

{
    "name": "My Videos",
    "data": [
        {
            "video_path": "./videos/rider.mp4",
            "num_frames": 100,
            "data": [
                {
                    "frame_index": 14,
                    "prompt": "a person is riding a bike on a busy street."
                },
                {
                    "frame_index": 45,
                    "prompt": "a person is wearing a blue shirt and riding a bike on grass."
                },
                ...
            ]
        },
        ...
    ]
}

画像内容の抽出

それぞれの画像ファイルと一対一の(拡張子を除いた)同名の.txtファイルが同じフォルダ下に必要です。こちらについてはStableDiffusion学習に関する他の記事を参照するといいでしょう。アニメ系の学習の場合は先ほどのスクリプト(または元のKohya氏のもの)を使用できます。

学習設定の変更

設定を調整するため、Text-To-Video-Finetuningフォルダ下に戻り、configs/my_config.yamlをテキストエディタで開き、編集します。色々と項目がありますが、特に重要なもの(私が理解しているもの)は日本語コメントを加えておきます。ちなみに以下の設定は512x512の学習で私が使っていたものです。

### ./configs/my_config.yaml ###

# 学習元モデルのパス。以下は実写系モデルの場合
pretrained_model_path: "./models/model_scope_diffusers/"

# 学習途中のサンプル画像や学習結果モデルの保存先パス
output_dir: "./outputs/"

# 1つ以上の学習方法を組み合わせることができます。不要なものは単に行削除します。
# 以下では'single_video', 'folder'を削除しています。
# 'image': A folder of images and captions (.txt)
# 'folder': A folder a videos and captions (.txt)
# 'json': The JSON file created with automatic BLIP2 captions using https://github.com/ExponentialML/Video-BLIP2-Preprocessor
# 'single_video': A single video file.mp4 and text prompt
dataset_types: 
  - 'json'
  - 'image'

# Adds offset noise to training. See https://www.crosslabs.org/blog/diffusion-with-offset-noise
offset_noise_strength: 0.1
use_offset_noise: False

# When True, this extends all items in all enabled datasets to the highest length. 
# For example, if you have 200 videos and 10 images, 10 images will be duplicated to the length of 200. 
extend_dataset: False

# Caches the latents (Frames-Image -> VAE -> Latent) to a HDD or SDD. 
# The latents will be saved under your training folder, and loaded automatically for training.
# This both saves memory and speeds up training and takes very little disk space.
cache_latents: True

# If you have cached latents set to `True` and have a directory of cached latents,
# you can skip the caching process and load previously saved ones. 
cached_latent_dir: null #/path/to/cached_latents

# Train the text encoder. Leave at false to use LoRA only (Recommended).
train_text_encoder: False

# https://github.com/cloneofsimo/lora
# Use LoRA to train extra layers whilst saving memory. It trains both a LoRA & the model itself.
# This works slightly different than vanilla LoRA and DOES NOT save a separate file.
# It is simply used as a mechanism for saving memory by keeping layers frozen and training the residual.

# Use LoRA for the UNET model.
use_unet_lora: True

# Use LoRA for the Text Encoder.
use_text_lora: True

# The modules to use for LoRA. Different from 'trainable_modules'.
unet_lora_modules:
  - "ResnetBlock2D"

# The modules to use for LoRA. Different from `trainable_text_modules`.
text_encoder_lora_modules:
  - "CLIPEncoderLayer"

# Loraのランク。上記のようにLoraを使用する設定にした場合は値を下げればVRAMを節約できる。
# The rank for LoRA training. With ModelScope, the maximum should be 1024. 
# VRAM increases with higher rank, lower when decreased.
lora_rank: 25

# Training data parameters
train_data:

  # 学習サイズ。一致しない学習データはリサイズされる。大きいほどVRAMが必要。
  width: 512      
  height: 512

  # This will find the closest aspect ratio to your input width and height. 
  # For example, 512x512 width and height with a video of resolution 1280x720 will be resized to 512x256
  use_bucketing: True

  # The start frame index where your videos should start (Leave this at one for json and folder based training).
  sample_start_idx: 1

  # Used for 'folder'. The rate at which your frames are sampled. Does nothing for 'json' and 'single_video' dataset.
  fps: 24

  # For 'single_video' and 'json'. The number of frames to "step" (1,2,3,4) (frame_step=2) -> (1,3,5,7, ...).  
  frame_step: 5

  # 値を下げるとVRAM節約可能
  # The number of frames to sample. The higher this number, the higher the VRAM (acts similar to batch size).
  n_sample_frames: 45
  
  # 'single_video'
  single_video_path: ""

  # The prompt when using a a single video file
  single_video_prompt: ""

  # Fallback prompt if caption cannot be read. Enabled for 'image' and 'folder'.
  fallback_prompt: ''
  
  # 動画と対応するキャプションファイル(.txt)が存在するフォルダへのパス(今回未使用)
  path: 'C:/trainning/videos/'

  # 動画内容を説明しているJSONファイルへのパス
  json_path: './json/caption.json'

  # 画像と対応するキャプションファイル(.txt)が存在するフォルダへのパス
  image_dir: 'C:/trainning/Pictures/'

  # The prompt for all image files. Leave blank to use caption files (.txt) 
  single_img_prompt: ""

# 学習中のサンプル動画等に関する設定。
validation_data:

  # A custom prompt that is different from your training dataset. 
  prompt: ""

  # 学習過程のサンプル動画を生成するか否か (Requires more VRAM).
  sample_preview: True

  # サンプル動画の生成フレーム数
  num_frames: 16

  # サンプル動画のサイズ
  width: 512
  height: 512

  # Number of inference steps when generating the video.
  num_inference_steps: 25

  # CFG scale
  guidance_scale: 9

# 学習率 for AdamW
learning_rate: 5e-6

# Weight decay. Higher = more regularization. Lower = closer to dataset.
adam_weight_decay: 1e-2

# Optimizer parameters for the UNET. Overrides base learning rate parameters.
extra_unet_params: null
  #learning_rate: 1e-5
  #adam_weight_decay: 1e-4

# Optimizer parameters for the Text Encoder. Overrides base learning rate parameters.
extra_text_encoder_params: null
  #learning_rate: 5e-6
  #adam_weight_decay: 0.2

# How many batches to train. Not to be confused with video frames.
train_batch_size: 1

# モデルの学習ステップ数
max_train_steps: 10000

# 学習中途結果のモデルの保存頻度
checkpointing_steps: 2500

# サンプル画像を出力する頻度
validation_steps: 100

# Which modules we want to unfreeze for the UNET. Advanced usage.
trainable_modules:

  # If you want to ignore temporal attention entirely, remove "attn1-2" and replace with ".attentions"
  # This is for self attetion. Activates for spatial and temporal dimensions if n_sample_frames > 1
  - "attn1"
  
  # This is for cross attention (image & text data). Activates for spatial and temporal dimensions if n_sample_frames > 1
  - "attn2"
  
  #  Convolution networks that hold temporal information. Activates for spatial and temporal dimensions if n_sample_frames > 1
  - 'temp_conv'


# Which modules we want to unfreeze for the Text Encoder. Advanced usage.
trainable_text_modules:
  - "all"

# Seed for validation.
seed: 64

# Whether or not we want to use mixed precision with accelerate
mixed_precision: "fp16"

# This seems to be incompatible at the moment.
use_8bit_adam: False 

# Trades VRAM usage for speed. You lose roughly 20% of training speed, but save a lot of VRAM.
# If you need to save more VRAM, it can also be enabled for the text encoder, but reduces speed x2.
gradient_checkpointing: True
text_encoder_gradient_checkpointing: False

# Xformers must be installed for best memory savings and performance (< Pytorch 2.0)
enable_xformers_memory_efficient_attention: False

# Use scaled dot product attention (Only available with >= Torch 2.0)
enable_torch_2_attn: True

学習の実行

設定完了後、仮想環境を変更して学習を実行します。

# 別の環境にいたなら仮想環境を変更
conda deactivate  
conda activate text2video-finetune 

python train.py --config ./configs/my_config.yaml

学習サイズやステップ数によっては何時間もかかります。気長に待ちましょう。

結果の確認

学習が正常に完了していれば、output_dirで設定したフォルダに結果も出るが出力されているはずです。以下のスクリプトを実装したpythonファイルを実行すれば学習結果モデルから動画を生成できます。

### gen.py ###

import torch
from diffusers import DiffusionPipeline, DPMSolverMultistepScheduler
from diffusers.utils import export_to_video
import sys
import time
import math

args = sys.argv

my_trained_model_path = "./path/to/your/output/dir/"    # 学習結果モデルの場所(model_index.jsonを含むフォルダ)
output_path = "./outputs/t2v/"  # 動画の出力先
prompt = "your prompt"  # プロンプト
ng_prompt = "your negative prompt"  # ネガティブプロンプト
num = 1  # 出力動画数
num_frame = 16  # 動画フレーム数
num_inference_step = 40  # 動画の精度

pipe = DiffusionPipeline.from_pretrained(my_trained_model_path, torch_dtype=torch.float16, variant="fp16")
pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
pipe.enable_model_cpu_offload()

for i in range(num):
    video_frames = pipe(prompt, num_inference_steps=num_inference_step, negative_prompt=ng_prompt, width=320, height=256, num_frames=num_frame).frames
    out_file = output_path + str(math.floor(time.time())) + "_" + prompt[0:64] + ".mp4"
    video_path = export_to_video(video_frames, out_file)

diffusersパイプラインによる動画生成の詳細については以下。https://huggingface.co/docs/diffusers/main/en/api/pipelines/text_to_video

その他

utilsフォルダにAutomatic1111上で使用可能にするための変換スクリプトがあります。それによりModelScopeオリジナルフォーマットのunetが作成されます。それをModelScopeのtext2video_pytorch_model.pthと置き換えれば動作するようです。

まとめ

もっと動画学習勢が増えるとうれしいです。


この記事が気に入ったらサポートをしてみませんか?