From 4396350271ef24f361ac10966f3213bc8e8db322 Mon Sep 17 00:00:00 2001 From: Isotr0py <2037008807@qq.com> Date: Sat, 4 Mar 2023 13:59:22 +0800 Subject: [PATCH 01/15] Add network_args to meta if using another network --- train_network.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/train_network.py b/train_network.py index 7aee6514..ba2f4464 100644 --- a/train_network.py +++ b/train_network.py @@ -427,9 +427,9 @@ def train(args): "ss_bucket_info": json.dumps(dataset.bucket_info), } - # uncomment if another network is added - # for key, value in net_kwargs.items(): - # metadata["ss_arg_" + key] = value + if args.network_args: + for key, value in net_kwargs.items(): + metadata["ss_arg_" + key] = value if args.pretrained_model_name_or_path is not None: sd_model_name = args.pretrained_model_name_or_path From fe4f4446f1b16de54fd87bbc02ccdd3779e60b33 Mon Sep 17 00:00:00 2001 From: Kohya S Date: Sat, 4 Mar 2023 18:03:11 +0900 Subject: [PATCH 02/15] Add region control for LoRA --- gen_img_diffusers.py | 28 ++++++++++++++++------ networks/lora.py | 56 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/gen_img_diffusers.py b/gen_img_diffusers.py index 6bab0bb8..8a185170 100644 --- a/gen_img_diffusers.py +++ b/gen_img_diffusers.py @@ -1649,10 +1649,11 @@ def get_unweighted_text_embeddings( if pad == eos: # v1 text_input_chunk[:, -1] = text_input[0, -1] else: # v2 - if text_input_chunk[:, -1] != eos and text_input_chunk[:, -1] != pad: # 最後に普通の文字がある - text_input_chunk[:, -1] = eos - if text_input_chunk[:, 1] == pad: # BOSだけであとはPAD - text_input_chunk[:, 1] = eos + for j in range(len(text_input_chunk)): + if text_input_chunk[j, -1] != eos and text_input_chunk[j, -1] != pad: # 最後に普通の文字がある + text_input_chunk[j, -1] = eos + if text_input_chunk[j, 1] == pad: # BOSだけであとはPAD + text_input_chunk[j, 1] = eos if clip_skip is None or clip_skip == 1: text_embedding = pipe.text_encoder(text_input_chunk)[0] @@ -2276,13 +2277,26 @@ def main(args): mask_images = l # 画像サイズにオプション指定があるときはリサイズする - if init_images is not None and args.W is not None and args.H is not None: - print(f"resize img2img source images to {args.W}*{args.H}") - init_images = resize_images(init_images, (args.W, args.H)) + if args.W is not None and args.H is not None: + if init_images is not None: + print(f"resize img2img source images to {args.W}*{args.H}") + init_images = resize_images(init_images, (args.W, args.H)) if mask_images is not None: print(f"resize img2img mask images to {args.W}*{args.H}") mask_images = resize_images(mask_images, (args.W, args.H)) + if networks and mask_images: + # mask を領域情報として流用する、現在は1枚だけ対応 + # TODO 複数のnetwork classの混在時の考慮 + print("use mask as region") + # import cv2 + # for i in range(3): + # cv2.imshow("msk", np.array(mask_images[0])[:,:,i]) + # cv2.waitKey() + # cv2.destroyAllWindows() + networks[0].__class__.set_regions(networks, np.array(mask_images[0])) + mask_images = None + prev_image = None # for VGG16 guided if args.guide_image_path is not None: print(f"load image for CLIP/VGG16/ControlNet guidance: {args.guide_image_path}") diff --git a/networks/lora.py b/networks/lora.py index 24b107ba..2318605a 100644 --- a/networks/lora.py +++ b/networks/lora.py @@ -6,6 +6,7 @@ import math import os from typing import List +import numpy as np import torch from library import train_util @@ -45,14 +46,50 @@ class LoRAModule(torch.nn.Module): self.multiplier = multiplier self.org_module = org_module # remove in applying + self.region = None + self.region_mask = None def apply_to(self): self.org_forward = self.org_module.forward self.org_module.forward = self.forward del self.org_module + def set_region(self, region): + self.region = region + def forward(self, x): - return self.org_forward(x) + self.lora_up(self.lora_down(x)) * self.multiplier * self.scale + if self.region is None: + return self.org_forward(x) + self.lora_up(self.lora_down(x)) * self.multiplier * self.scale + + # reginal LoRA + if x.size()[1] % 77 == 0: + # print(f"LoRA for context: {self.lora_name}") + self.region = None + return self.org_forward(x) + self.lora_up(self.lora_down(x)) * self.multiplier * self.scale + + if self.region_mask is None: + if len(x.size()) == 4: + h, w = x.size()[2:4] + else: + seq_len = x.size()[1] + ratio = math.sqrt((self.region.size()[0] * self.region.size()[1]) / seq_len) + h = int(self.region.size()[0] / ratio + .5) + w = seq_len // h + + r = self.region.to(x.device) + if r.dtype == torch.bfloat16: + r = r.to(torch.float) + r = r.unsqueeze(0).unsqueeze(1) + # print(self.lora_name, self.region.size(), x.size(), r.size(), h, w) + r = torch.nn.functional.interpolate(r, (h, w), mode='bilinear') + r = r.to(x.dtype) + + if len(x.size()) == 3: + r = torch.reshape(r, (1, x.size()[1], -1)) + + self.region_mask = r + + return self.org_forward(x) + self.lora_up(self.lora_down(x)) * self.multiplier * self.scale * self.region_mask def create_network(multiplier, network_dim, network_alpha, vae, text_encoder, unet, **kwargs): @@ -130,7 +167,7 @@ class LoRANetwork(torch.nn.Module): self.multiplier = multiplier for lora in self.text_encoder_loras + self.unet_loras: lora.multiplier = self.multiplier - + def load_weights(self, file): if os.path.splitext(file)[1] == '.safetensors': from safetensors.torch import load_file, safe_open @@ -240,3 +277,18 @@ class LoRANetwork(torch.nn.Module): save_file(state_dict, file, metadata) else: torch.save(state_dict, file) + + @staticmethod + def set_regions(networks, image): + image = image.astype(np.float32) / 255.0 + for i, network in enumerate(networks[:3]): + # NOTE: consider averaging overwrapping area + region = image[:, :, i] + if region.max() == 0: + continue + region = torch.tensor(region) + network.set_region(region) + + def set_region(self, region): + for lora in self.unet_loras: + lora.set_region(region) From db8c79c46332c2e3e4b25f84aa98078b73609859 Mon Sep 17 00:00:00 2001 From: Kohya S Date: Sun, 5 Mar 2023 19:51:05 +0900 Subject: [PATCH 03/15] Update documentation --- train_README-ja.md | 321 ++++++++++++++++++++++++++++++++++++++---- train_db_README-ja.md | 291 ++++++++++---------------------------- 2 files changed, 371 insertions(+), 241 deletions(-) diff --git a/train_README-ja.md b/train_README-ja.md index bf0d9f9c..5e9a6282 100644 --- a/train_README-ja.md +++ b/train_README-ja.md @@ -1,4 +1,6 @@ -当リポジトリではモデルのfine tuning、DreamBooth、およびLoRAとTextual Inversionの学習をサポートします。この文書ではそれらに共通する、学習データの準備方法やスクリプトオプションについて説明します。 +# 学習データの準備について + +当リポジトリではモデルのfine tuning、DreamBooth、およびLoRAとTextual Inversionの学習をサポートします。この文書ではそれらに共通する、学習データの準備方法について説明します。 # 概要 @@ -8,15 +10,14 @@ 以下について説明します。 1. 学習データの準備について(設定ファイルを用いる新形式) -1. Aspect Ratio Bucketingについて +1. 学習で使われる用語のごく簡単な解説 1. 以前の指定形式(設定ファイルを用いずコマンドラインから指定) +1. 学習途中のサンプル画像生成 +1. 各スクリプトで共通の、よく使われるオプション 1. fine tuning 方式のメタデータ準備:キャプションニングなど 1.だけ実行すればとりあえず学習は可能です(学習については各スクリプトのドキュメントを参照)。2.以降は必要に応じて参照してください。 - # 学習データの準備について @@ -36,7 +37,7 @@ 1. fine tuning方式(正則化画像使用不可) - あらかじめキャプションをメタデータファイルにまとめます。タグとキャプションを分けて管理したり、学習を高速化するためlatentsを事前キャッシュしたりなどの機能をサポートします(いずれも別文書で説明しています)。 + あらかじめキャプションをメタデータファイルにまとめます。タグとキャプションを分けて管理したり、学習を高速化するためlatentsを事前キャッシュしたりなどの機能をサポートします(いずれも別文書で説明しています)。(fine tuning方式という名前ですが fine tuning 以外でも使えます。) 学習したいものと使用できる指定方法の組み合わせは以下の通りです。 @@ -124,7 +125,7 @@ batch_size = 4 # バッチサイズ num_repeats = 1 # 正則化画像の繰り返し回数、基本的には1でよい ``` -基本的には以下を場所のみ書き換えれば学習できます。 +基本的には以下の場所のみ書き換えれば学習できます。 1. 学習解像度 @@ -132,7 +133,7 @@ batch_size = 4 # バッチサイズ 1. バッチサイズ - 同時に何件のデータを学習するかを指定します。GPUのVRAMサイズ、学習解像度によって変わってきます。またfine tuning/DreamBooth/LoRA等でも変わってきますので、詳しくは各スクリプトの説明をご覧ください。 + 同時に何件のデータを学習するかを指定します。GPUのVRAMサイズ、学習解像度によって変わってきます。詳しくは後述します。またfine tuning/DreamBooth/LoRA等でも変わってきますので各スクリプトの説明もご覧ください。 1. フォルダ指定 @@ -248,7 +249,41 @@ batch_size = 4 # バッチサイズ それぞれのドキュメントを参考に学習を行ってください。 -# Aspect Ratio Bucketing について +# 学習で使われる用語のごく簡単な解説 + +細かいことは省略していますし私も完全には理解していないため、詳しくは各自お調べください。 + +## ステップ + +ざっくりいうと学習データで1回計算すると1ステップです。「学習データのキャプションを今のモデルに流してみて、出てくる画像を学習データの画像と比較し、学習データに近づくようにモデルをわずかに変更する」のが1ステップです。 + +## バッチサイズ + +バッチサイズは1ステップで何件のデータをまとめて計算するかを指定する値です。まとめて計算するため速度は相対的に向上します。また一般的には精度も高くなるといわれています。 + +`バッチサイズ×ステップ数` が学習に使われるデータの件数になります。そのため、バッチサイズを増やした分だけステップ数を減らすとよいでしょう。 + +(ただし、たとえば「バッチサイズ1で1600ステップ」と「バッチサイズ4で400ステップ」は同じ結果にはなりません。同じ学習率の場合、一般的には後者のほうが学習不足になります。学習率を多少大きくするか(たとえば `2e-6` など)、ステップ数をたとえば500ステップにするなどして工夫してください。) + +バッチサイズを大きくするとその分だけGPUメモリを消費します。メモリが足りなくなるとエラーになりますし、エラーにならないギリギリでは学習速度が低下します。タスクマネージャーや `nvidia-smi` コマンドで使用メモリ量を確認しながら調整するとよいでしょう。 + +なお、バッチは「一塊のデータ」位の意味です。 + +## 学習率 + +ざっくりいうと1ステップごとにどのくらい変化させるかを表します。大きな値を指定するとそれだけ速く学習が進みますが、変化しすぎてモデルが壊れたり、最適な状態にまで至れない場合があります。小さい値を指定すると学習速度は遅くなり、また最適な状態にやはり至れない場合があります。 + +fine tuning、DreamBoooth、LoRAそれぞれで大きく異なり、また学習データや学習させたいモデル、バッチサイズやステップ数によっても変わってきます。一般的な値から初めて学習状態を見ながら増減してください。 + +デフォルトでは学習全体を通して学習率は固定です。スケジューラの指定で学習率をどう変化させるか決められますので、それらによっても結果は変わってきます。 + +## エポック(epoch) + +学習データが一通り学習されると(データが一周すると)1 epochです。繰り返し回数を指定した場合は、その繰り返し後のデータが一周すると1 epochです。 + +1 epochのステップ数は、基本的には `データ件数÷バッチサイズ` ですが、Aspect Ratio Bucketing を使うと微妙に増えます(異なるbucketのデータは同じバッチにできないため、ステップ数が増えます)。 + +## Aspect Ratio Bucketing Stable Diffusion のv1は512\*512で学習されていますが、それに加えて256\*1024や384\*640といった解像度でも学習します。これによりトリミングされる部分が減り、より正しくキャプションと画像の関係が学習されることが期待されます。 @@ -260,11 +295,15 @@ Stable Diffusion のv1は512\*512で学習されていますが、それに加 機械学習では入力サイズをすべて統一するのが一般的ですが、特に制約があるわけではなく、実際は同一のバッチ内で統一されていれば大丈夫です。NovelAIの言うbucketingは、あらかじめ教師データを、アスペクト比に応じた学習解像度ごとに分類しておくことを指しているようです。そしてバッチを各bucket内の画像で作成することで、バッチの画像サイズを統一します。 -# 以前のデータ指定方法 +# 以前の指定形式(設定ファイルを用いずコマンドラインから指定) -フォルダ名で繰り返し回数を指定する方法です。 +`.toml` ファイルを指定せずコマンドラインオプションで指定する方法です。DreamBooth class+identifier方式、DreamBooth キャプション方式、fine tuning方式があります。 -## step 1. 学習用画像の準備 +## DreamBooth、class+identifier方式 + +フォルダ名で繰り返し回数を指定します。また `train_data_dir` オプションと `reg_data_dir` オプションを用います。 + +### step 1. 学習用画像の準備 学習用画像を格納するフォルダを作成します。 __さらにその中に__ 、以下の名前でディレクトリを作成します。 @@ -294,15 +333,7 @@ classがひとつで対象が複数の場合、正則化画像フォルダはひ - reg_girls - 1_1girl -### DreamBoothでキャプションを使う - -学習用画像、正則化画像のフォルダに、画像と同じファイル名で、拡張子.caption(オプションで変えられます)のファイルを置くと、そのファイルからキャプションを読み込みプロンプトとして学習します。 - -※それらの画像の学習に、フォルダ名(identifier class)は使用されなくなります。 - -キャプションファイルの拡張子はデフォルトで.captionです。学習スクリプトの `--caption_extension` オプションで変更できます。`--shuffle_caption` オプションで学習時のキャプションについて、カンマ区切りの各部分をシャッフルしながら学習します。 - -## step 2. 正則化画像の準備 +### step 2. 正則化画像の準備 正則化画像を使う場合の手順です。 @@ -313,16 +344,256 @@ classがひとつで対象が複数の場合、正則化画像フォルダはひ ![image](https://user-images.githubusercontent.com/52813779/210770897-329758e5-3675-49f1-b345-c135f1725832.png) -## step 3. 学習の実行 +### step 3. 学習の実行 各学習スクリプトを実行します。 `--train_data_dir` オプションで前述の学習用データのフォルダを(__画像を含むフォルダではなく、その親フォルダ__)、`--reg_data_dir` オプションで正則化画像のフォルダ(__画像を含むフォルダではなく、その親フォルダ__)を指定してください。 - # メタデータファイルの作成 diff --git a/train_db_README-ja.md b/train_db_README-ja.md index 85ae35aa..903f214c 100644 --- a/train_db_README-ja.md +++ b/train_db_README-ja.md @@ -1,75 +1,92 @@ -DreamBoothのガイドです。LoRA等の追加ネットワークの学習にも同じ手順を使います。 +DreamBoothのガイドです。 # 概要 +DreamBoothとは、画像生成モデルに特定の主題を追加学習し、それを特定の識別子で生成する技術です。[論文はこちら](https://arxiv.org/abs/2208.12242)。 + +具体的には、Stable Diffusionのモデルにキャラや画風などを学ばせ、それを `shs` のような特定の単語で呼び出せる(生成画像に出現させる)ことができます。 + +スクリプトは[DiffusersのDreamBooth](https://github.com/huggingface/diffusers/tree/main/examples/dreambooth)を元にしていますが、以下のような機能追加を行っています(いくつかの機能は元のスクリプト側もその後対応しています)。 + スクリプトの主な機能は以下の通りです。 -- 8bit Adam optimizerおよびlatentのキャッシュによる省メモリ化(ShivamShrirao氏版と同様)。 +- 8bit Adam optimizerおよびlatentのキャッシュによる省メモリ化([Shivam Shrirao氏版](https://github.com/ShivamShrirao/diffusers/tree/main/examples/dreambooth)と同様)。 - xformersによる省メモリ化。 - 512x512だけではなく任意サイズでの学習。 - augmentationによる品質の向上。 - DreamBoothだけではなくText Encoder+U-Netのfine tuningに対応。 -- StableDiffusion形式でのモデルの読み書き。 +- Stable Diffusion形式でのモデルの読み書き。 - Aspect Ratio Bucketing。 - Stable Diffusion v2.0対応。 # 学習の手順 -## step 1. 環境整備 +## データの準備 -このリポジトリのREADMEを参照してください。 +[学習データの準備について](./train_README-ja.md) を参照してください。 +## 学習の実行 -## step 2. identifierとclassを決める - -学ばせたい対象を結びつける単語identifierと、対象の属するclassを決めます。 - -(instanceなどいろいろな呼び方がありますが、とりあえず元の論文に合わせます。) - -以下ごく簡単に説明します(詳しくは調べてください)。 - -classは学習対象の一般的な種別です。たとえば特定の犬種を学ばせる場合には、classはdogになります。アニメキャラならモデルによりboyやgirl、1boyや1girlになるでしょう。 - -identifierは学習対象を識別して学習するためのものです。任意の単語で構いませんが、元論文によると「tokinizerで1トークンになる3文字以下でレアな単語」が良いとのことです。 - -identifierとclassを使い、たとえば「shs dog」などでモデルを学習することで、学習させたい対象をclassから識別して学習できます。 - -画像生成時には「shs dog」とすれば学ばせた犬種の画像が生成されます。 - -(identifierとして私が最近使っているものを参考までに挙げると、``shs sts scs cpc coc cic msm usu ici lvl cic dii muk ori hru rik koo yos wny`` などです。) - -## step 3. 学習用画像の準備 -学習用画像を格納するフォルダを作成します。 __さらにその中に__ 、以下の名前でディレクトリを作成します。 +スクリプトを実行します。最大限、メモリを節約したコマンドは以下のようになります(実際には1行で入力します)。`< >` 内を書き換えてください。12GB程度のVRAMで動作するようです。 ``` -<繰り返し回数>_ +accelerate launch --num_cpu_threads_per_process 1 train_db.py + --pretrained_model_name_or_path=<.ckptまたは.safetensordまたはDiffusers版モデルのディレクトリ> + --dataset_config=<データ準備で作成した.tomlファイル> + --output_dir=<学習したモデルの出力先フォルダ> + --output_name=<学習したモデル出力時のファイル名> + --save_model_as=safetensors + --prior_loss_weight=1.0 + --max_train_steps=1600 + --learning_rate=1e-6 + --optimizer_type="AdamW8bit" + --xformers + --mixed_precision="fp16" + --cache_latents + --gradient_checkpointing ``` -間の``_``を忘れないでください。 +`num_cpu_threads_per_process` には通常は1を指定するとよいようです。 -繰り返し回数は、正則化画像と枚数を合わせるために指定します(後述します)。 +`pretrained_model_name_or_path` に追加学習を行う元となるモデルを指定します。Stable Diffusionのcheckpointファイル(.ckptまたは.safetensors)、Diffusersのローカルディスクにあるモデルディレクトリ、DiffusersのモデルID("stabilityai/stable-diffusion-2"など)が指定できます。 -たとえば「sls frog」というプロンプトで、データを20回繰り返す場合、「20_sls frog」となります。以下のようになります。 +`output_dir` に学習後のモデルを保存するフォルダを指定します。`output_name` にモデルのファイル名を拡張子を除いて指定します。`save_model_as` でsafetensors形式での保存を指定しています。 -![image](https://user-images.githubusercontent.com/52813779/210770636-1c851377-5936-4c15-90b7-8ac8ad6c2074.png) +`dataset_config` に `.toml` ファイルを指定します。ファイル内でのバッチサイズ指定は、メモリ消費を抑えるために `1` としてください。 -## step 4. 正則化画像の準備 -正則化画像を使う場合の手順です。使わずに学習することもできます(正則化画像を使わないと区別ができなくなるので対象class全体が影響を受けます)。 +`prior_loss_weight` は正則化画像のlossの重みです。通常は1.0を指定します。 -正則化画像を格納するフォルダを作成します。 __さらにその中に__ ``<繰り返し回数>_`` という名前でディレクトリを作成します。 +学習させるステップ数 `max_train_steps` を1600とします。学習率 `learning_rate` はここでは1e-6を指定しています。 -たとえば「frog」というプロンプトで、データを繰り返さない(1回だけ)場合、以下のようになります。 +省メモリ化のため `mixed_precision="fp16"` を指定します(RTX30 シリーズ以降では `bf16` も指定できます。環境整備時にaccelerateに行った設定と合わせてください)。また `gradient_checkpointing` を指定します。 -![image](https://user-images.githubusercontent.com/52813779/210770897-329758e5-3675-49f1-b345-c135f1725832.png) +オプティマイザ(モデルを学習データにあうように最適化=学習させるクラス)にメモリ消費の少ない 8bit AdamW を使うため、 `optimizer_type="AdamW8bit"` を指定します。 -繰り返し回数は「 __学習用画像の繰り返し回数×学習用画像の枚数≧正則化画像の繰り返し回数×正則化画像の枚数__ 」となるように指定してください。 +xformersオプションを指定し、xformersのCrossAttentionを用います。xformersをインストールしていない場合やエラーとなる場合(環境にもよりますが `mixed_precision="no"` の場合など)、代わりに `mem_eff_attn` オプションを指定すると省メモリ版CrossAttentionを使用します(速度は遅くなります)。 -(1 epochのデータ数が「学習用画像の繰り返し回数×学習用画像の枚数」となります。正則化画像の枚数がそれより多いと、余った部分の正則化画像は使用されません。) +省メモリ化のため `cache_latents` オプションを指定してVAEの出力をキャッシュします。 -## step 5. 学習の実行 -スクリプトを実行します。最大限、メモリを節約したコマンドは以下のようになります(実際には1行で入力します)。 +ある程度メモリがある場合は、`.toml` ファイルを編集してバッチサイズをたとえば `4` くらいに増やしてください(高速化と精度向上の可能性があります)。また `cache_latents` を外すことで augmentation が可能になります。 -※LoRA等の追加ネットワークを学習する場合のコマンドは ``train_db.py`` ではなく ``train_network.py`` となります。また追加でnetwork_\*オプションが必要となりますので、LoRAのガイドを参照してください。 +### DreamBoothでのステップ数について + +当スクリプトでは省メモリ化のため、ステップ当たりの学習回数が元のスクリプトの半分になっています(対象の画像と正則化画像を同一のバッチではなく別のバッチに分割して学習するため)。 + +元のDiffusers版やXavierXiao氏のStable Diffusion版とほぼ同じ学習を行うには、ステップ数を倍にしてください。 + +(学習画像と正則化画像をまとめてから shuffle するため厳密にはデータの順番が変わってしまいますが、学習には大きな影響はないと思います。) + +### DreamBoothでのバッチサイズについて + +モデル全体を学習するためLoRA等の学習に比べるとメモリ消費量は多くなります(fine tuningと同じ)。 + +### 学習率について + +Diffusers版では5e-6ですがStable Diffusion版は1e-6ですので、上のサンプルでは1e-6を指定しています。 + +### 以前の形式のデータセット指定をした場合のコマンドライン + +解像度やバッチサイズをオプションで指定します。コマンドラインの例は以下の通りです。 ``` accelerate launch --num_cpu_threads_per_process 1 train_db.py @@ -77,6 +94,7 @@ accelerate launch --num_cpu_threads_per_process 1 train_db.py --train_data_dir=<学習用データのディレクトリ> --reg_data_dir=<正則化画像のディレクトリ> --output_dir=<学習したモデルの出力先ディレクトリ> + --output_name=<学習したモデル出力時のファイル名> --prior_loss_weight=1.0 --resolution=512 --train_batch_size=1 @@ -89,43 +107,33 @@ accelerate launch --num_cpu_threads_per_process 1 train_db.py --gradient_checkpointing ``` -num_cpu_threads_per_processには通常は1を指定するとよいようです。 +## 学習したモデルで画像生成する -pretrained_model_name_or_pathに追加学習を行う元となるモデルを指定します。Stable Diffusionのcheckpointファイル(.ckptまたは.safetensors)、Diffusersのローカルディスクにあるモデルディレクトリ、DiffusersのモデルID("stabilityai/stable-diffusion-2"など)が指定できます。学習後のモデルの保存形式はデフォルトでは元のモデルと同じになります(save_model_asオプションで変更できます)。 +学習が終わると指定したフォルダに指定した名前でsafetensorsファイルが出力されます。 -prior_loss_weightは正則化画像のlossの重みです。通常は1.0を指定します。 +v1.4/1.5およびその他の派生モデルの場合、このモデルでAutomatic1111氏のWebUIなどで推論できます。models\Stable-diffusionフォルダに置いてください。 -resolutionは画像のサイズ(解像度、幅と高さ)になります。bucketing(後述)を用いない場合、学習用画像、正則化画像はこのサイズとしてください。 +v2.xモデルでWebUIで画像生成する場合、モデルの仕様が記述された.yamlファイルが別途必要になります。v2.x baseの場合はv2-inference.yamlを、768/vの場合はv2-inference-v.yamlを、同じフォルダに置き、拡張子の前の部分をモデルと同じ名前にしてください。 -train_batch_sizeは学習時のバッチサイズです。max_train_stepsを1600とします。学習率learning_rateは、diffusers版では5e-6ですがStableDiffusion版は1e-6ですのでここでは1e-6を指定しています。 +![image](https://user-images.githubusercontent.com/52813779/210776915-061d79c3-6582-42c2-8884-8b91d2f07313.png) -省メモリ化のためmixed_precision="bf16"(または"fp16")、およびgradient_checkpointing を指定します。 +各yamlファイルは[Stability AIのSD2.0のリポジトリ](https://github.com/Stability-AI/stablediffusion/tree/main/configs/stable-diffusion)にあります。 -xformersオプションを指定し、xformersのCrossAttentionを用います。xformersをインストールしていない場合、エラーとなる場合(mixed_precisionなしの場合、私の環境ではエラーとなりました)、代わりにmem_eff_attnオプションを指定すると省メモリ版CrossAttentionを使用します(速度は遅くなります)。 +# DreamBooth特有のその他の主なオプション -省メモリ化のためcache_latentsオプションを指定してVAEの出力をキャッシュします。 +すべてのオプションについては別文書を参照してください。 -ある程度メモリがある場合はたとえば以下のように指定します。 +## Text Encoderの学習を途中から行わない --stop_text_encoder_training -``` -accelerate launch --num_cpu_threads_per_process 8 train_db.py - --pretrained_model_name_or_path=<.ckptまたは.safetensordまたはDiffusers版モデルのディレクトリ> - --train_data_dir=<学習用データのディレクトリ> - --reg_data_dir=<正則化画像のディレクトリ> - --output_dir=<学習したモデルの出力先ディレクトリ> - --prior_loss_weight=1.0 - --resolution=512 - --train_batch_size=4 - --learning_rate=1e-6 - --max_train_steps=400 - --use_8bit_adam - --xformers - --mixed_precision="bf16" - --cache_latents -``` +stop_text_encoder_trainingオプションに数値を指定すると、そのステップ数以降はText Encoderの学習を行わずU-Netだけ学習します。場合によっては精度の向上が期待できるかもしれません。 -gradient_checkpointingを外し高速化します(メモリ使用量は増えます)。バッチサイズを増やし、高速化と精度向上を図ります。 +(恐らくText Encoderだけ先に過学習することがあり、それを防げるのではないかと推測していますが、詳細な影響は不明です。) +## Tokenizerのパディングをしない --no_token_padding +no_token_paddingオプションを指定するとTokenizerの出力をpaddingしません(Diffusers版の旧DreamBoothと同じ動きになります)。 + + + From 1c00764d01e6183811ae7f8d6f6a5ef23d184e6a Mon Sep 17 00:00:00 2001 From: Kohya S Date: Sun, 5 Mar 2023 22:32:26 +0900 Subject: [PATCH 04/15] updating documents --- fine_tune_README_ja.md | 477 +++++++---------------------------------- train_README-ja.md | 48 ++++- train_db_README-ja.md | 18 +- train_ti_README-ja.md | 80 +++++-- 4 files changed, 195 insertions(+), 428 deletions(-) diff --git a/fine_tune_README_ja.md b/fine_tune_README_ja.md index 9dcd34af..686947c9 100644 --- a/fine_tune_README_ja.md +++ b/fine_tune_README_ja.md @@ -1,6 +1,9 @@ -NovelAIの提案した学習手法、自動キャプションニング、タグ付け、Windows+VRAM 12GB(v1.4/1.5の場合)環境等に対応したfine tuningです。 +NovelAIの提案した学習手法、自動キャプションニング、タグ付け、Windows+VRAM 12GB(SD v1.xの場合)環境等に対応したfine tuningです。ここでfine tuningとは、モデルを画像とキャプションで学習することを指します(LoRAやTextual Inversion、Hypernetworksは含みません) + +[学習についての共通ドキュメント](./train_README-ja.md) もあわせてご覧ください。 + +# 概要 -## 概要 Diffusersを用いてStable DiffusionのU-Netのfine tuningを行います。NovelAIの記事にある以下の改善に対応しています(Aspect Ratio BucketingについてはNovelAIのコードを参考にしましたが、最終的なコードはすべてオリジナルです)。 * CLIP(Text Encoder)の最後の層ではなく最後から二番目の層の出力を用いる。 @@ -13,19 +16,24 @@ Diffusersを用いてStable DiffusionのU-Netのfine tuningを行います。Nov デフォルトではText Encoderの学習は行いません。モデル全体のfine tuningではU-Netだけを学習するのが一般的なようです(NovelAIもそのようです)。オプション指定でText Encoderも学習対象とできます。 -## 追加機能について -### CLIPの出力の変更 +# 追加機能について + +## CLIPの出力の変更 + プロンプトを画像に反映するため、テキストの特徴量への変換を行うのがCLIP(Text Encoder)です。Stable DiffusionではCLIPの最後の層の出力を用いていますが、それを最後から二番目の層の出力を用いるよう変更できます。NovelAIによると、これによりより正確にプロンプトが反映されるようになるとのことです。 元のまま、最後の層の出力を用いることも可能です。 + ※Stable Diffusion 2.0では最後から二番目の層をデフォルトで使います。clip_skipオプションを指定しないでください。 -### 正方形以外の解像度での学習 +## 正方形以外の解像度での学習 + Stable Diffusionは512\*512で学習されていますが、それに加えて256\*1024や384\*640といった解像度でも学習します。これによりトリミングされる部分が減り、より正しくプロンプトと画像の関係が学習されることが期待されます。 学習解像度はパラメータとして与えられた解像度の面積(=メモリ使用量)を超えない範囲で、64ピクセル単位で縦横に調整、作成されます。 機械学習では入力サイズをすべて統一するのが一般的ですが、特に制約があるわけではなく、実際は同一のバッチ内で統一されていれば大丈夫です。NovelAIの言うbucketingは、あらかじめ教師データを、アスペクト比に応じた学習解像度ごとに分類しておくことを指しているようです。そしてバッチを各bucket内の画像で作成することで、バッチの画像サイズを統一します。 -### トークン長の75から225への拡張 +## トークン長の75から225への拡張 + Stable Diffusionでは最大75トークン(開始・終了を含むと77トークン)ですが、それを225トークンまで拡張します。 ただしCLIPが受け付ける最大長は75トークンですので、225トークンの場合、単純に三分割してCLIPを呼び出してから結果を連結しています。 @@ -33,296 +41,67 @@ Stable Diffusionでは最大75トークン(開始・終了を含むと77トー ※Automatic1111氏のWeb UIではカンマを意識して分割、といったこともしているようですが、私の場合はそこまでしておらず単純な分割です。 -## 環境整備 +# 学習の手順 -このリポジトリの[README](./README-ja.md)を参照してください。 +あらかじめこのリポジトリのREADMEを参照し、環境整備を行ってください。 -## 教師データの用意 - -学習させたい画像データを用意し、任意のフォルダに入れてください。リサイズ等の事前の準備は必要ありません。 -ただし学習解像度よりもサイズが小さい画像については、超解像などで品質を保ったまま拡大しておくことをお勧めします。 - -複数の教師データフォルダにも対応しています。前処理をそれぞれのフォルダに対して実行する形となります。 - -たとえば以下のように画像を格納します。 - -![教師データフォルダのスクショ](https://user-images.githubusercontent.com/52813779/208907739-8e89d5fa-6ca8-4b60-8927-f484d2a9ae04.png) - -## 自動キャプショニング -キャプションを使わずタグだけで学習する場合はスキップしてください。 - -また手動でキャプションを用意する場合、キャプションは教師データ画像と同じディレクトリに、同じファイル名、拡張子.caption等で用意してください。各ファイルは1行のみのテキストファイルとします。 - -### BLIPによるキャプショニング - -最新版ではBLIPのダウンロード、重みのダウンロード、仮想環境の追加は不要になりました。そのままで動作します。 - -finetuneフォルダ内のmake_captions.pyを実行します。 - -``` -python finetune\make_captions.py --batch_size <バッチサイズ> <教師データフォルダ> -``` - -バッチサイズ8、教師データを親フォルダのtrain_dataに置いた場合、以下のようになります。 - -``` -python finetune\make_captions.py --batch_size 8 ..\train_data -``` - -キャプションファイルが教師データ画像と同じディレクトリに、同じファイル名、拡張子.captionで作成されます。 - -batch_sizeはGPUのVRAM容量に応じて増減してください。大きいほうが速くなります(VRAM 12GBでももう少し増やせると思います)。 -max_lengthオプションでキャプションの最大長を指定できます。デフォルトは75です。モデルをトークン長225で学習する場合には長くしても良いかもしれません。 -caption_extensionオプションでキャプションの拡張子を変更できます。デフォルトは.captionです(.txtにすると後述のDeepDanbooruと競合します)。 - -複数の教師データフォルダがある場合には、それぞれのフォルダに対して実行してください。 - -なお、推論にランダム性があるため、実行するたびに結果が変わります。固定する場合には--seedオプションで「--seed 42」のように乱数seedを指定してください。 - -その他のオプションは--helpでヘルプをご参照ください(パラメータの意味についてはドキュメントがまとまっていないようで、ソースを見るしかないようです)。 - -デフォルトでは拡張子.captionでキャプションファイルが生成されます。 - -![captionが生成されたフォルダ](https://user-images.githubusercontent.com/52813779/208908845-48a9d36c-f6ee-4dae-af71-9ab462d1459e.png) - -たとえば以下のようなキャプションが付きます。 - -![キャプションと画像](https://user-images.githubusercontent.com/52813779/208908947-af936957-5d73-4339-b6c8-945a52857373.png) - -## DeepDanbooruによるタグ付け -danbooruタグのタグ付け自体を行わない場合は「キャプションとタグ情報の前処理」に進んでください。 - -タグ付けはDeepDanbooruまたはWD14Taggerで行います。WD14Taggerのほうが精度が良いようです。WD14Taggerでタグ付けする場合は、次の章へ進んでください。 - -### 環境整備 -DeepDanbooru https://github.com/KichangKim/DeepDanbooru を作業フォルダにcloneしてくるか、zipをダウンロードして展開します。私はzipで展開しました。 -またDeepDanbooruのReleasesのページ https://github.com/KichangKim/DeepDanbooru/releases の「DeepDanbooru Pretrained Model v3-20211112-sgd-e28」のAssetsから、deepdanbooru-v3-20211112-sgd-e28.zipをダウンロードしてきてDeepDanbooruのフォルダに展開します。 - -以下からダウンロードします。Assetsをクリックして開き、そこからダウンロードします。 - -![DeepDanbooruダウンロードページ](https://user-images.githubusercontent.com/52813779/208909417-10e597df-7085-41ee-bd06-3e856a1339df.png) - -以下のようなこういうディレクトリ構造にしてください - -![DeepDanbooruのディレクトリ構造](https://user-images.githubusercontent.com/52813779/208909486-38935d8b-8dc6-43f1-84d3-fef99bc471aa.png) - -Diffusersの環境に必要なライブラリをインストールします。DeepDanbooruのフォルダに移動してインストールします(実質的にはtensorflow-ioが追加されるだけだと思います)。 - -``` -pip install -r requirements.txt -``` - -続いてDeepDanbooru自体をインストールします。 - -``` -pip install . -``` - -以上でタグ付けの環境整備は完了です。 - -### タグ付けの実施 -DeepDanbooruのフォルダに移動し、deepdanbooruを実行してタグ付けを行います。 - -``` -deepdanbooru evaluate <教師データフォルダ> --project-path deepdanbooru-v3-20211112-sgd-e28 --allow-folder --save-txt -``` - -教師データを親フォルダのtrain_dataに置いた場合、以下のようになります。 - -``` -deepdanbooru evaluate ../train_data --project-path deepdanbooru-v3-20211112-sgd-e28 --allow-folder --save-txt -``` - -タグファイルが教師データ画像と同じディレクトリに、同じファイル名、拡張子.txtで作成されます。1件ずつ処理されるためわりと遅いです。 - -複数の教師データフォルダがある場合には、それぞれのフォルダに対して実行してください。 - -以下のように生成されます。 - -![DeepDanbooruの生成ファイル](https://user-images.githubusercontent.com/52813779/208909855-d21b9c98-f2d3-4283-8238-5b0e5aad6691.png) - -こんな感じにタグが付きます(すごい情報量……)。 - -![DeepDanbooruタグと画像](https://user-images.githubusercontent.com/52813779/208909908-a7920174-266e-48d5-aaef-940aba709519.png) - -## WD14Taggerによるタグ付け -DeepDanbooruの代わりにWD14Taggerを用いる手順です。 - -Automatic1111氏のWebUIで使用しているtaggerを利用します。こちらのgithubページ(https://github.com/toriato/stable-diffusion-webui-wd14-tagger#mrsmilingwolfs-model-aka-waifu-diffusion-14-tagger )の情報を参考にさせていただきました。 - -最初の環境整備で必要なモジュールはインストール済みです。また重みはHugging Faceから自動的にダウンロードしてきます。 - -### タグ付けの実施 -スクリプトを実行してタグ付けを行います。 -``` -python tag_images_by_wd14_tagger.py --batch_size <バッチサイズ> <教師データフォルダ> -``` - -教師データを親フォルダのtrain_dataに置いた場合、以下のようになります。 -``` -python tag_images_by_wd14_tagger.py --batch_size 4 ..\train_data -``` - -初回起動時にはモデルファイルがwd14_tagger_modelフォルダに自動的にダウンロードされます(フォルダはオプションで変えられます)。以下のようになります。 - -![ダウンロードされたファイル](https://user-images.githubusercontent.com/52813779/208910447-f7eb0582-90d6-49d3-a666-2b508c7d1842.png) - -タグファイルが教師データ画像と同じディレクトリに、同じファイル名、拡張子.txtで作成されます。 - -![生成されたタグファイル](https://user-images.githubusercontent.com/52813779/208910534-ea514373-1185-4b7d-9ae3-61eb50bc294e.png) - -![タグと画像](https://user-images.githubusercontent.com/52813779/208910599-29070c15-7639-474f-b3e4-06bd5a3df29e.png) - -threshオプションで、判定されたタグのconfidence(確信度)がいくつ以上でタグをつけるかが指定できます。デフォルトはWD14Taggerのサンプルと同じ0.35です。値を下げるとより多くのタグが付与されますが、精度は下がります。 -batch_sizeはGPUのVRAM容量に応じて増減してください。大きいほうが速くなります(VRAM 12GBでももう少し増やせると思います)。caption_extensionオプションでタグファイルの拡張子を変更できます。デフォルトは.txtです。 -model_dirオプションでモデルの保存先フォルダを指定できます。 -またforce_downloadオプションを指定すると保存先フォルダがあってもモデルを再ダウンロードします。 - -複数の教師データフォルダがある場合には、それぞれのフォルダに対して実行してください。 - -## キャプションとタグ情報の前処理 - -スクリプトから処理しやすいようにキャプションとタグをメタデータとしてひとつのファイルにまとめます。 - -### キャプションの前処理 - -キャプションをメタデータに入れるには、作業フォルダ内で以下を実行してください(キャプションを学習に使わない場合は実行不要です)(実際は1行で記述します、以下同様)。 - -``` -python merge_captions_to_metadata.py <教師データフォルダ> -  --in_json <読み込むメタデータファイル名> - <メタデータファイル名> -``` - -メタデータファイル名は任意の名前です。 -教師データがtrain_data、読み込むメタデータファイルなし、メタデータファイルがmeta_cap.jsonの場合、以下のようになります。 - -``` -python merge_captions_to_metadata.py train_data meta_cap.json -``` - -caption_extensionオプションでキャプションの拡張子を指定できます。 - -複数の教師データフォルダがある場合には、full_path引数を指定してください(メタデータにフルパスで情報を持つようになります)。そして、それぞれのフォルダに対して実行してください。 - -``` -python merge_captions_to_metadata.py --full_path - train_data1 meta_cap1.json -python merge_captions_to_metadata.py --full_path --in_json meta_cap1.json - train_data2 meta_cap2.json -``` - -in_jsonを省略すると書き込み先メタデータファイルがあるとそこから読み込み、そこに上書きします。 - -__※in_jsonオプションと書き込み先を都度書き換えて、別のメタデータファイルへ書き出すようにすると安全です。__ - -### タグの前処理 - -同様にタグもメタデータにまとめます(タグを学習に使わない場合は実行不要です)。 -``` -python merge_dd_tags_to_metadata.py <教師データフォルダ> - --in_json <読み込むメタデータファイル名> - <書き込むメタデータファイル名> -``` - -先と同じディレクトリ構成で、meta_cap.jsonを読み、meta_cap_dd.jsonに書きだす場合、以下となります。 -``` -python merge_dd_tags_to_metadata.py train_data --in_json meta_cap.json meta_cap_dd.json -``` - -複数の教師データフォルダがある場合には、full_path引数を指定してください。そして、それぞれのフォルダに対して実行してください。 - -``` -python merge_dd_tags_to_metadata.py --full_path --in_json meta_cap2.json - train_data1 meta_cap_dd1.json -python merge_dd_tags_to_metadata.py --full_path --in_json meta_cap_dd1.json - train_data2 meta_cap_dd2.json -``` - -in_jsonを省略すると書き込み先メタデータファイルがあるとそこから読み込み、そこに上書きします。 - -__※in_jsonオプションと書き込み先を都度書き換えて、別のメタデータファイルへ書き出すようにすると安全です。__ - -### キャプションとタグのクリーニング -ここまででメタデータファイルにキャプションとDeepDanbooruのタグがまとめられています。ただ自動キャプショニングにしたキャプションは表記ゆれなどがあり微妙(※)ですし、タグにはアンダースコアが含まれていたりratingが付いていたりしますので(DeepDanbooruの場合)、エディタの置換機能などを用いてキャプションとタグのクリーニングをしたほうがいいでしょう。 - -※たとえばアニメ絵の少女を学習する場合、キャプションにはgirl/girls/woman/womenなどのばらつきがあります。また「anime girl」なども単に「girl」としたほうが適切かもしれません。 - -クリーニング用のスクリプトが用意してありますので、スクリプトの内容を状況に応じて編集してお使いください。 - -(教師データフォルダの指定は不要になりました。メタデータ内の全データをクリーニングします。) - -``` -python clean_captions_and_tags.py <読み込むメタデータファイル名> <書き込むメタデータファイル名> -``` - ---in_jsonは付きませんのでご注意ください。たとえば次のようになります。 - -``` -python clean_captions_and_tags.py meta_cap_dd.json meta_clean.json -``` - -以上でキャプションとタグの前処理は完了です。 - -## latentsの事前取得 - -学習を高速に進めるためあらかじめ画像の潜在表現を取得しディスクに保存しておきます。あわせてbucketing(教師データをアスペクト比に応じて分類する)を行います。 - -作業フォルダで以下のように入力してください。 -``` -python prepare_buckets_latents.py <教師データフォルダ> - <読み込むメタデータファイル名> <書き込むメタデータファイル名> - - --batch_size <バッチサイズ> - --max_resolution <解像度 幅,高さ> - --mixed_precision <精度> -``` - -モデルがmodel.ckpt、バッチサイズ4、学習解像度は512\*512、精度no(float32)で、meta_clean.jsonからメタデータを読み込み、meta_lat.jsonに書き込む場合、以下のようになります。 - -``` -python prepare_buckets_latents.py - train_data meta_clean.json meta_lat.json model.ckpt - --batch_size 4 --max_resolution 512,512 --mixed_precision no -``` - -教師データフォルダにnumpyのnpz形式でlatentsが保存されます。 - -Stable Diffusion 2.0のモデルを読み込む場合は--v2オプションを指定してください(--v_parameterizationは不要です)。 - -解像度の最小サイズを--min_bucket_resoオプションで、最大サイズを--max_bucket_resoで指定できます。デフォルトはそれぞれ256、1024です。たとえば最小サイズに384を指定すると、256\*1024や320\*768などの解像度は使わなくなります。 -解像度を768\*768のように大きくした場合、最大サイズに1280などを指定すると良いでしょう。 - ---flip_augオプションを指定すると左右反転のaugmentation(データ拡張)を行います。疑似的にデータ量を二倍に増やすことができますが、データが左右対称でない場合に指定すると(例えばキャラクタの外見、髪型など)学習がうまく行かなくなります。 -(反転した画像についてもlatentsを取得し、\*\_flip.npzファイルを保存する単純な実装です。fline_tune.pyには特にオプション指定は必要ありません。\_flip付きのファイルがある場合、flip付き・なしのファイルを、ランダムに読み込みます。) - -バッチサイズはVRAM 12GBでももう少し増やせるかもしれません。 -解像度は64で割り切れる数字で、"幅,高さ"で指定します。解像度はfine tuning時のメモリサイズに直結します。VRAM 12GBでは512,512が限界と思われます(※)。16GBなら512,704や512,768まで上げられるかもしれません。なお256,256等にしてもVRAM 8GBでは厳しいようです(パラメータやoptimizerなどは解像度に関係せず一定のメモリが必要なため)。 - -※batch size 1の学習で12GB VRAM、640,640で動いたとの報告もありました。 - -以下のようにbucketingの結果が表示されます。 - -![bucketingの結果](https://user-images.githubusercontent.com/52813779/208911419-71c00fbb-2ce6-49d5-89b5-b78d7715e441.png) - -複数の教師データフォルダがある場合には、full_path引数を指定してください。そして、それぞれのフォルダに対して実行してください。 -``` -python prepare_buckets_latents.py --full_path - train_data1 meta_clean.json meta_lat1.json model.ckpt - --batch_size 4 --max_resolution 512,512 --mixed_precision no - -python prepare_buckets_latents.py --full_path - train_data2 meta_lat1.json meta_lat2.json model.ckpt - --batch_size 4 --max_resolution 512,512 --mixed_precision no - -``` -読み込み元と書き込み先を同じにすることも可能ですが別々の方が安全です。 - -__※引数を都度書き換えて、別のメタデータファイルに書き込むと安全です。__ +## データの準備 +[学習データの準備について](./train_README-ja.md) を参照してください。fine tuningではメタデータを用いるfine tuning方式のみ対応しています。 ## 学習の実行 -たとえば以下のように実行します。以下は省メモリ化のための設定です。 +たとえば以下のように実行します。以下は省メモリ化のための設定です。それぞれの行を必要に応じて書き換えてください。 + +``` +accelerate launch --num_cpu_threads_per_process 1 fine_tune.py + --pretrained_model_name_or_path=<.ckptまたは.safetensordまたはDiffusers版モデルのディレクトリ> + --output_dir=<学習したモデルの出力先フォルダ> + --output_name=<学習したモデル出力時のファイル名> + --dataset_config=<データ準備で作成した.tomlファイル> + --save_model_as=safetensors + --learning_rate=5e-6 --max_train_steps=10000 + --use_8bit_adam --xformers --gradient_checkpointing + --mixed_precision=fp16 +``` + +`num_cpu_threads_per_process` には通常は1を指定するとよいようです。 + +`pretrained_model_name_or_path` に追加学習を行う元となるモデルを指定します。Stable Diffusionのcheckpointファイル(.ckptまたは.safetensors)、Diffusersのローカルディスクにあるモデルディレクトリ、DiffusersのモデルID("stabilityai/stable-diffusion-2"など)が指定できます。 + +`output_dir` に学習後のモデルを保存するフォルダを指定します。`output_name` にモデルのファイル名を拡張子を除いて指定します。`save_model_as` でsafetensors形式での保存を指定しています。 + +`dataset_config` に `.toml` ファイルを指定します。ファイル内でのバッチサイズ指定は、当初はメモリ消費を抑えるために `1` としてください。 + +学習させるステップ数 `max_train_steps` を10000とします。学習率 `learning_rate` はここでは5e-6を指定しています。 + +省メモリ化のため `mixed_precision="fp16"` を指定します(RTX30 シリーズ以降では `bf16` も指定できます。環境整備時にaccelerateに行った設定と合わせてください)。また `gradient_checkpointing` を指定します。 + +オプティマイザ(モデルを学習データにあうように最適化=学習させるクラス)にメモリ消費の少ない 8bit AdamW を使うため、 `optimizer_type="AdamW8bit"` を指定します。 + +`xformers` オプションを指定し、xformersのCrossAttentionを用います。xformersをインストールしていない場合やエラーとなる場合(環境にもよりますが `mixed_precision="no"` の場合など)、代わりに `mem_eff_attn` オプションを指定すると省メモリ版CrossAttentionを使用します(速度は遅くなります)。 + +ある程度メモリがある場合は、`.toml` ファイルを編集してバッチサイズをたとえば `4` くらいに増やしてください(高速化と精度向上の可能性があります)。 + +### よく使われるオプションについて + +以下の場合にはオプションに関するドキュメントを参照してください。 + +- Stable Diffusion 2.xまたはそこからの派生モデルを学習する +- clip skipを2以上を前提としたモデルを学習する +- 75トークンを超えたキャプションで学習する + +### バッチサイズについて + +モデル全体を学習するためLoRA等の学習に比べるとメモリ消費量は多くなります(DreamBoothと同じ)。 + +### 学習率について + +1e-6から5e-6程度が一般的なようです。他のfine tuningの例なども参照してみてください。 + +### 以前の形式のデータセット指定をした場合のコマンドライン + +解像度やバッチサイズをオプションで指定します。コマンドラインの例は以下の通りです。 + ``` accelerate launch --num_cpu_threads_per_process 1 fine_tune.py --pretrained_model_name_or_path=model.ckpt @@ -336,76 +115,7 @@ accelerate launch --num_cpu_threads_per_process 1 fine_tune.py --save_every_n_epochs=4 ``` -accelerateのnum_cpu_threads_per_processには通常は1を指定するとよいようです。 - -pretrained_model_name_or_pathに学習対象のモデルを指定します(Stable DiffusionのcheckpointかDiffusersのモデル)。Stable Diffusionのcheckpointは.ckptと.safetensorsに対応しています(拡張子で自動判定)。 - -in_jsonにlatentをキャッシュしたときのメタデータファイルを指定します。 - -train_data_dirに教師データのフォルダを、output_dirに学習後のモデルの出力先フォルダを指定します。 - -shuffle_captionを指定すると、キャプション、タグをカンマ区切りされた単位でシャッフルして学習します(Waifu Diffusion v1.3で行っている手法です)。 -(先頭のトークンのいくつかをシャッフルせずに固定できます。その他のオプションのkeep_tokensをご覧ください。) - -train_batch_sizeにバッチサイズを指定します。VRAM 12GBでは1か2程度を指定してください。解像度によっても指定可能な数は変わってきます。 -学習に使用される実際のデータ量は「バッチサイズ×ステップ数」です。バッチサイズを増やした時には、それに応じてステップ数を下げることが可能です。 - -learning_rateに学習率を指定します。たとえばWaifu Diffusion v1.3は5e-6のようです。 -max_train_stepsにステップ数を指定します。 - -use_8bit_adamを指定すると8-bit Adam Optimizerを使用します。省メモリ化、高速化されますが精度は下がる可能性があります。 - -xformersを指定するとCrossAttentionを置換して省メモリ化、高速化します。 -※11/9時点ではfloat32の学習ではxformersがエラーになるため、bf16/fp16を使うか、代わりにmem_eff_attnを指定して省メモリ版CrossAttentionを使ってください(速度はxformersに劣ります)。 - -gradient_checkpointingで勾配の途中保存を有効にします。速度は遅くなりますが使用メモリ量が減ります。 - -mixed_precisionで混合精度を使うか否かを指定します。"fp16"または"bf16"を指定すると省メモリになりますが精度は劣ります。 -"fp16"と"bf16"は使用メモリ量はほぼ同じで、bf16の方が学習結果は良くなるとの話もあります(試した範囲ではあまり違いは感じられませんでした)。 -"no"を指定すると使用しません(float32になります)。 - -※bf16で学習したcheckpointをAUTOMATIC1111氏のWeb UIで読み込むとエラーになるようです。これはデータ型のbfloat16がWeb UIのモデルsafety checkerでエラーとなるためのようです。save_precisionオプションを指定してfp16またはfloat32形式で保存してください。またはsafetensors形式で保管しても良さそうです。 - -save_every_n_epochsを指定するとそのエポックだけ経過するたびに学習中のモデルを保存します。 - -### Stable Diffusion 2.0対応 -Hugging Faceのstable-diffusion-2-baseを使う場合は--v2オプションを、stable-diffusion-2または768-v-ema.ckptを使う場合は--v2と--v_parameterizationの両方のオプションを指定してください。 - -### メモリに余裕がある場合に精度や速度を上げる -まずgradient_checkpointingを外すと速度が上がります。ただし設定できるバッチサイズが減りますので、精度と速度のバランスを見ながら設定してください。 - -バッチサイズを増やすと速度、精度が上がります。メモリが足りる範囲で、1データ当たりの速度を確認しながら増やしてください(メモリがぎりぎりになるとかえって速度が落ちることがあります)。 - -### 使用するCLIP出力の変更 -clip_skipオプションに2を指定すると、後ろから二番目の層の出力を用います。1またはオプション省略時は最後の層を用います。 -学習したモデルはAutomatic1111氏のWeb UIで推論できるはずです。 - -※SD2.0はデフォルトで後ろから二番目の層を使うため、SD2.0の学習では指定しないでください。 - -学習対象のモデルがもともと二番目の層を使うように学習されている場合は、2を指定するとよいでしょう。 - -そうではなく最後の層を使用していた場合はモデル全体がそれを前提に学習されています。そのため改めて二番目の層を使用して学習すると、望ましい学習結果を得るにはある程度の枚数の教師データ、長めの学習が必要になるかもしれません。 - -### トークン長の拡張 -max_token_lengthに150または225を指定することでトークン長を拡張して学習できます。 -学習したモデルはAutomatic1111氏のWeb UIで推論できるはずです。 - -clip_skipと同様に、モデルの学習状態と異なる長さで学習するには、ある程度の教師データ枚数、長めの学習時間が必要になると思われます。 - -### 学習ログの保存 -logging_dirオプションにログ保存先フォルダを指定してください。TensorBoard形式のログが保存されます。 - -たとえば--logging_dir=logsと指定すると、作業フォルダにlogsフォルダが作成され、その中の日時フォルダにログが保存されます。 -また--log_prefixオプションを指定すると、日時の前に指定した文字列が追加されます。「--logging_dir=logs --log_prefix=fine_tune_style1」などとして識別用にお使いください。 - -TensorBoardでログを確認するには、別のコマンドプロンプトを開き、作業フォルダで以下のように入力します(tensorboardはDiffusersのインストール時にあわせてインストールされると思いますが、もし入っていないならpip install tensorboardで入れてください)。 -``` -tensorboard --logdir=logs -``` - -### Hypernetworkの学習 -別の記事で解説予定です。 - + -### その他のオプション +# fine tuning特有のその他の主なオプション -#### keep_tokens -数値を指定するとキャプションの先頭から、指定した数だけのトークン(カンマ区切りの文字列)をシャッフルせず固定します。 +すべてのオプションについては別文書を参照してください。 -キャプションとタグが両方ある場合、学習時のプロンプトは「キャプション,タグ1,タグ2……」のように連結されますので、「--keep_tokens=1」とすれば、学習時にキャプションが必ず先頭に来るようになります。 - -#### dataset_repeats -データセットの枚数が極端に少ない場合、epochがすぐに終わってしまうため(epochの区切りで少し時間が掛かります)、数値を指定してデータを何倍かしてepochを長めにしてください。 - -#### train_text_encoder +## `train_text_encoder` Text Encoderも学習対象とします。メモリ使用量が若干増加します。 通常のfine tuningではText Encoderは学習対象としませんが(恐らくText Encoderの出力に従うようにU-Netを学習するため)、学習データ数が少ない場合には、DreamBoothのようにText Encoder側に学習させるのも有効的なようです。 -#### save_precision -checkpoint保存時のデータ形式をfloat、fp16、bf16から指定できます(未指定時は学習中のデータ形式と同じ)。ディスク容量が節約できますがモデルによる生成結果は変わってきます。またfloatやfp16を指定すると、1111氏のWeb UIでも読めるようになるはずです。 - -※VAEについては元のcheckpointのデータ形式のままになりますので、fp16でもモデルサイズが2GB強まで小さくならない場合があります。 - -#### save_model_as -モデルの保存形式を指定します。ckpt、safetensors、diffusers、diffusers_safetensorsのいずれかを指定してください。 - -Stable Diffusion形式(ckptまたはsafetensors)を読み込み、Diffusers形式で保存する場合、不足する情報はHugging Faceからv1.5またはv2.1の情報を落としてきて補完します。 - -#### use_safetensors -このオプションを指定するとsafetensors形式でcheckpointを保存します。保存形式はデフォルト(読み込んだ形式と同じ)になります。 - -#### save_stateとresume -save_stateオプションで、途中保存時および最終保存時に、checkpointに加えてoptimizer等の学習状態をフォルダに保存します。これにより中断してから学習再開したときの精度低下が避けられます(optimizerは状態を持ちながら最適化をしていくため、その状態がリセットされると再び初期状態から最適化を行わなくてはなりません)。なお、Accelerateの仕様でステップ数は保存されません。 - -スクリプト起動時、resumeオプションで状態の保存されたフォルダを指定すると再開できます。 - -学習状態は一回の保存あたり5GB程度になりますのでディスク容量にご注意ください。 - -#### gradient_accumulation_steps -指定したステップ数だけまとめて勾配を更新します。バッチサイズを増やすのと同様の効果がありますが、メモリを若干消費します。 - -※Accelerateの仕様で学習モデルが複数の場合には対応していないとのことですので、Text Encoderを学習対象にして、このオプションに2以上の値を指定するとエラーになるかもしれません。 - -#### lr_scheduler / lr_warmup_steps -lr_schedulerオプションで学習率のスケジューラをlinear, cosine, cosine_with_restarts, polynomial, constant, constant_with_warmupから選べます。デフォルトはconstantです。 - -lr_warmup_stepsでスケジューラのウォームアップ(だんだん学習率を変えていく)ステップ数を指定できます。詳細については各自お調べください。 - -#### diffusers_xformers +## `diffusers_xformers` スクリプト独自のxformers置換機能ではなくDiffusersのxformers機能を利用します。Hypernetworkの学習はできなくなります。 diff --git a/train_README-ja.md b/train_README-ja.md index 5e9a6282..479f9604 100644 --- a/train_README-ja.md +++ b/train_README-ja.md @@ -1,6 +1,8 @@ -# 学習データの準備について +__ドキュメント更新中のため記述に誤りがあるかもしれません。__ -当リポジトリではモデルのfine tuning、DreamBooth、およびLoRAとTextual Inversionの学習をサポートします。この文書ではそれらに共通する、学習データの準備方法について説明します。 +# 学習について、共通編 + +当リポジトリではモデルのfine tuning、DreamBooth、およびLoRAとTextual Inversionの学習をサポートします。この文書ではそれらに共通する、学習データの準備方法やオプション等について説明します。 # 概要 @@ -253,6 +255,10 @@ batch_size = 4 # バッチサイズ 細かいことは省略していますし私も完全には理解していないため、詳しくは各自お調べください。 +## fine tuning(ファインチューニング) + +モデルを学習して微調整することを指します。使われ方によって意味が異なってきますが、狭義のfine tuningはStable Diffusionの場合、モデルを画像とキャプションで学習することです。DreamBoothは狭義のfine tuningのひとつの特殊なやり方と言えます。広義のfine tuningは、LoRAやTextual Inversion、Hypernetworksなどを含み、モデルを学習することすべてを含みます。 + ## ステップ ざっくりいうと学習データで1回計算すると1ステップです。「学習データのキャプションを今のモデルに流してみて、出てくる画像を学習データの画像と比較し、学習データに近づくようにモデルをわずかに変更する」のが1ステップです。 @@ -407,7 +413,7 @@ masterpiece, best quality, 1boy, in business suit, standing at street, looking b - `--v2` / `--v_parameterization` - Hugging Faceのstable-diffusion-2-baseを使う場合はv2オプションを、stable-diffusion-2または768-v-ema.ckptを使う場合はv2とv_parameterizationの両方のオプションを指定してください。 + 学習対象モデルとしてHugging Faceのstable-diffusion-2-base、またはそこからのfine tuningモデルを使う場合(推論時に `v2-inference.yaml` を使うように指示されているモデルの場合)は `--v2` オプションを、stable-diffusion-2や768-v-ema.ckpt、およびそれらのfine tuningモデルを使う場合(推論時に `v2-inference-v.yaml` を使うモデルの場合)は `--v2` と `--v_parameterization` の両方のオプションを指定してください。 Stable Diffusion 2.0では大きく以下の点が変わっています。 @@ -535,8 +541,18 @@ masterpiece, best quality, 1boy, in business suit, standing at street, looking b ## オプティマイザ関係 - `--optimizer_type` - - オプティマイザの種類を次から指定します: AdamW (default), AdamW8bit, Lion, SGDNesterov, SGDNesterov8bit, DAdaptation, AdaFactor + --オプティマイザの種類を指定します。以下が指定できます。 + - AdamW : [torch.optim.AdamW](https://pytorch.org/docs/stable/generated/torch.optim.AdamW.html) + - 過去のバージョンのオプション未指定時と同じ + - AdamW8bit : 引数は同上 + - 過去のバージョンの--use_8bit_adam指定時と同じ + - Lion : https://github.com/lucidrains/lion-pytorch + - 過去のバージョンの--use_lion_optimizer指定時と同じ + - SGDNesterov : [torch.optim.SGD](https://pytorch.org/docs/stable/generated/torch.optim.SGD.html), nesterov=True + - SGDNesterov8bit : 引数は同上 + - DAdaptation : https://github.com/facebookresearch/dadaptation + - AdaFactor : [Transformers AdaFactor](https://huggingface.co/docs/transformers/main_classes/optimizer_schedules) + - 任意のオプティマイザ - `--learning_rate` @@ -554,6 +570,28 @@ masterpiece, best quality, 1boy, in business suit, standing at street, looking b 詳細については各自お調べください。 +### オプティマイザの指定について + +オプティマイザのオプション引数は--optimizer_argsオプションで指定してください。key=valueの形式で、複数の値が指定できます。また、valueはカンマ区切りで複数の値が指定できます。たとえばAdamWオプティマイザに引数を指定する場合は、``--optimizer_args weight_decay=0.01 betas=.9,.999``のようになります。 + +オプション引数を指定する場合は、それぞれのオプティマイザの仕様をご確認ください。 + +一部のオプティマイザでは必須の引数があり、省略すると自動的に追加されます(SGDNesterovのmomentumなど)。コンソールの出力を確認してください。 + +D-Adaptationオプティマイザは学習率を自動調整します。学習率のオプションに指定した値は学習率そのものではなくD-Adaptationが決定した学習率の適用率になりますので、通常は1.0を指定してください。Text EncoderにU-Netの半分の学習率を指定したい場合は、``--text_encoder_lr=0.5 --unet_lr=1.0``と指定します。 + +AdaFactorオプティマイザはrelative_step=Trueを指定すると学習率を自動調整できます(省略時はデフォルトで追加されます)。自動調整する場合は学習率のスケジューラにはadafactor_schedulerが強制的に使用されます。またscale_parameterとwarmup_initを指定するとよいようです。 + +自動調整する場合のオプション指定はたとえば ``--optimizer_args "relative_step=True" "scale_parameter=True" "warmup_init=True"`` のようになります。 + +学習率を自動調整しない場合はオプション引数 ``relative_step=False`` を追加してください。その場合、学習率のスケジューラにはconstant_with_warmupが、また勾配のclip normをしないことが推奨されているようです。そのため引数は ``--optimizer_type=adafactor --optimizer_args "relative_step=False" --lr_scheduler="constant_with_warmup" --max_grad_norm=0.0`` のようになります。 + +### 任意のオプティマイザを使う + +``torch.optim`` のオプティマイザを使う場合にはクラス名のみを(``--optimizer_type=RMSprop``など)、他のモジュールのオプティマイザを使う時は「モジュール名.クラス名」を指定してください(``--optimizer_type=bitsandbytes.optim.lamb.LAMB``など)。 + +(内部でimportlibしているだけで動作は未確認です。必要ならパッケージをインストールしてください。) +