NovelAI提出的训练方法、自动标注、标签化、Windows + VRAM 12GB(对于SD v1.x)环境等所对应的fine tuning。在这里,fine tuning指的是用图像和标注训练模型(不包括LoRA、Textual Inversion和Hypernetworks)。

请同时参考关于训练的共同文档

概要

使用Diffusers对Stable Diffusion的U-Net进行fine tuning。对应了NovelAI的文章中的以下改进(虽然Aspect Ratio Bucketing参考了NovelAI的代码,但最终的代码都是原创的)。

  • 使用CLIP(Text Encoder)的倒数第二层的输出,而不是最后一层的输出。
  • 以非正方形分辨率进行训练(Aspect Ratio Bucketing)。
  • 将标记长度从75扩展到225。
  • 使用BLIP进行标注(自动创建标注)、使用DeepDanbooru或WD14Tagger进行自动标签化。
  • 支持Hypernetwork的训练。
  • 支持Stable Diffusion v2.0(base以及768/v)。
  • 提前获取VAE的输出并保存到磁盘,以减少训练时的内存使用量并提高速度。

默认情况下,不训练Text Encoder。在整体模型的fine tuning中,通常只训练U-Net(NovelAI似乎也是如此)。可以通过选项指定来训练Text Encoder。

关于追加功能

更改CLIP的输出

为了将提示反映到图像中,CLIP(Text Encoder)将文本转换为特征量。Stable Diffusion使用CLIP的最后一层的输出,但可以更改为使用倒数第二层的输出。据NovelAI说,这样可以更准确地反映提示。 也可以保持原样,使用最后一层的输出。

*注意:Stable Diffusion 2.0默认使用倒数第二层。请不要指定clip_skip选项。

以非正方形分辨率进行训练

Stable Diffusion是在512512的分辨率下训练的,但除了这个分辨率以外,还会在2561024或384*640等分辨率下进行训练。这样可以减少裁剪的部分,更准确地学习提示和图像之间的关系。 训练分辨率会在不超过作为参数给出的分辨率的面积(=内存使用量)的范围内,以64像素为单位进行调整。

在机器学习中,通常将输入大小统一起来,但并不是特别有约束,实际上只要在同一个批次中统一即可。NovelAI所说的bucketing是指预先根据长宽比将训练数据分类到不同的训练分辨率中,然后在每个bucket内创建批次,以统一批次内的图像大小。

将标记长度从75扩展到225

Stable Diffusion的最大标记长度是75(包括开始和结束标记是77),这里将其扩展到225。 但是,由于CLIP的最大接受长度是75,因此在标记长度为225时,会简单地将其分成三部分,分别调用CLIP,然后将结果连接起来。

*注意:这种实现方式是否合适尚不明确。目前看来是可以正常工作的。特别是在2.0版本中,没有可以参考的实现方式,因此采用了独自的实现方式。

*注意:在Automatic1111的Web UI中,似乎会根据逗号进行分割,但这里只是进行了简单的分割。

训练步骤

请预先参考本仓库的README,进行环境设置。

数据准备

请参考关于训练数据的准备。fine tuning仅支持使用元数据的fine tuning方式。

执行训练

例如,可以通过以下命令执行训练。以下是一个为了减少内存使用的设置示例。请根据需要修改每一行。

accelerate launch --num_cpu_threads_per_process 1 fine_tune.py 
    --pretrained_model_name_or_path=<.ckpt或.safetensors或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 
    --in_json meta_lat.json 
    --train_data_dir=train_data 
    --output_dir=fine_tuned 
    --shuffle_caption 
    --train_batch_size=1 --learning_rate=5e-6 --max_train_steps=10000 
    --use_8bit_adam --xformers --gradient_checkpointing
    --mixed_precision=bf16
    --save_every_n_epochs=4

fine tuning特有的其他主要选项

关于所有选项,请参考其他文档。

train_text_encoder

将Text Encoder也作为训练对象。内存使用量会略微增加。

在通常的fine tuning中,不将Text Encoder作为训练对象(可能是因为U-Net是根据Text Encoder的输出进行训练的),但在训练数据较少的情况下,像DreamBooth一样对Text Encoder进行训练似乎也是有效的。

diffusers_xformers

使用Diffusers的xformers功能,而不是脚本自有的xformers替换功能。这样就无法进行Hypernetwork的训练。