SDXLを使ったキャラクターLoraの作り方メモ
- 投稿日:
SDXLでキャラクターLoraをいい感じに作る方法。学習には教師画像のみを用いる。
必要なもの
- AUTOMATIC1111/stable-diffusion-webui
- Kohya_LoRA_param_GUI
- ベースとなるSDXLチェックポイントモデル
やり方
1. 学習用の素材となる画像を集める
学習画像の枚数・パターン
多ければ多いほどいいが、多すぎると学習に時間がかかりすぎるので、ある程度選別する。
例えば3Dキャラクターを学習する場合は、1ポーズ当たり正面・斜め前・横・斜め後ろ・真後ろの流れで一周八面の画像をいくつかのポーズ分作っておくと再現性が高くなる。
奇麗な画像があまりとれない場合は、極力そのキャラクターの特徴が出ている画像を数枚集める。4枚とかでもいい。1枚は試したことないのでどうなるのか不明。
学習素材となる画像の選定
学習元画像には背景が入っていてもいいが、そのキャラクターだけが映り込んでいるものを選ぶ。ほかのキャラクターが入っていたらトリミングするなどで消したほうが良い。
2. 学習用の素材画像にタグを打つ
- AUTOMATIC1111を起動し、Tagger→Batch from directoryを開く
- Additional tagsにキャラクターを出すためのトリガーワードを設定
- 既存のタグと衝突するとぶれるはずなので、一意な名前にする。例えば今井リサなら
imls
みたいに、とりあえず自分で識別できそうな適当な文字列を当てておく
- 既存のタグと衝突するとぶれるはずなので、一意な名前にする。例えば今井リサなら
3. タグファイルを整理する
前項で1画像ファイルに対して1タグファイルができているので、このファイルの内容を整理していく。
まずはゴミワードを探して取り除く。大抵複数ファイルに跨っているので一括置換するのがいい。
次に固定要素を取り除く。例えば髪型や髪の色、瞳の色、アクセサリーの特徴みたいな、何があっても変わらない部分は消す。例えば紫目のキャラクターならpurple eyes
を、ヘアアクセサリが特徴的なキャラクターであればhair ornament
を消すといった感じだ。残したい特徴をタグから取り除くことで、その特徴が固定化されやすくなる。
逆に変動させたい部分、逆に服装やポーズ、体の向き、メガネの有無など、変動しうる場所は残しておく。そうすると、いい感じに特徴をとらえたキャラクターが出やすくなる上、プロンプトにそれらを含めなくても出るようになるためトークンの節約にもなる。
但し、この細工は教師画像が少ないとあまり効果がない気がしている。
参考:LoRA/学習方法 - としあきdiffusion Wiki*
4. 学習とモデルの作成
以下のコードをNew Preset.xmlora
とか適当な名前で保存し、Kohya_LoRA_param_GUIで読み込み、チェックポイントモデルと教師画像、モデルの出力先を適当に指定して実行するとモデルが生成される。
体感ではponyDiffusionV6XL_v6StartWithThisOne.safetensorsが無難な気がしている。
<?xml version="1.0" encoding="utf-8"?>
<TrainParams xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ModelPath></ModelPath>
<TrainImagePath></TrainImagePath>
<OutputPath></OutputPath>
<TensorBoardLogPath />
<LoraModelPath />
<LearningRate>0.0001</LearningRate>
<Resolution>1024</Resolution>
<BatchSize>2</BatchSize>
<Epochs>8</Epochs>
<NetworkDim>8</NetworkDim>
<NetworkAlpha>3</NetworkAlpha>
<RegImagePath />
<ShuffleCaptions>true</ShuffleCaptions>
<KeepTokenCount>0</KeepTokenCount>
<SaveEveryNEpochs>0</SaveEveryNEpochs>
<OptimizerType>AdamW8bit</OptimizerType>
<WarmupSteps>250</WarmupSteps>
<OutputName></OutputName>
<Comment />
<CpuThreads>1</CpuThreads>
<NoBucketUpscaling>false</NoBucketUpscaling>
<UseWarmupInit>false</UseWarmupInit>
<ClipSkip>2</ClipSkip>
<Seed>42</Seed>
<SavePrecision>fp16</SavePrecision>
<SchedulerType>cosine_with_restarts</SchedulerType>
<MinBucketResolution>320</MinBucketResolution>
<MaxBucketResolution>1536</MaxBucketResolution>
<CaptionFileExtension>.txt</CaptionFileExtension>
<VAEPath />
<UnetLR>-1</UnetLR>
<TextEncoderLR>-1</TextEncoderLR>
<NoiseOffset>0</NoiseOffset>
<Momentum>0.9</Momentum>
<advancedTrainType>UNetOnly</advancedTrainType>
<CrossAttenType>xformers</CrossAttenType>
<UseGradient>true</UseGradient>
<UseWeightedCaptions>false</UseWeightedCaptions>
<AdaptiveNoiseScale>0</AdaptiveNoiseScale>
<MinSNRGamma>0</MinSNRGamma>
<MultiresNoiseIterations>0</MultiresNoiseIterations>
<MultiresNoiseDiscount>0</MultiresNoiseDiscount>
<NetworkDropout>0</NetworkDropout>
<RankDropout>0</RankDropout>
<ModuleDropout>0</ModuleDropout>
<MaxNormReg>0</MaxNormReg>
<CaptionDropout>0</CaptionDropout>
<IpNoiseGamma>0</IpNoiseGamma>
<ModuleType>LoRA</ModuleType>
<AlgoType>lora</AlgoType>
<ConvDim>4</ConvDim>
<ConvAlpha>1</ConvAlpha>
<UseConv2dExtend>true</UseConv2dExtend>
<DyLoRAUnit>4</DyLoRAUnit>
<DatasetConfigPath />
<TrainNorm>false</TrainNorm>
<RescaledOFT>false</RescaledOFT>
<ConstrainedOFT>false</ConstrainedOFT>
<UseScalar>false</UseScalar>
<UseTucker>false</UseTucker>
<WeightDocomposition>false</WeightDocomposition>
<UseBlockWeight>false</UseBlockWeight>
<BlockWeightIn>
<int>20</int>
<int>20</int>
<int>20</int>
<int>20</int>
<int>20</int>
<int>0</int>
<int>0</int>
<int>0</int>
<int>0</int>
<int>0</int>
<int>0</int>
<int>0</int>
</BlockWeightIn>
<BlockWeightMid>0</BlockWeightMid>
<BlockWeightMid01>20</BlockWeightMid01>
<BlockWeightMid02>20</BlockWeightMid02>
<BlockWeightOut>
<int>0</int>
<int>0</int>
<int>0</int>
<int>0</int>
<int>0</int>
<int>0</int>
<int>0</int>
<int>20</int>
<int>20</int>
<int>20</int>
<int>20</int>
<int>20</int>
</BlockWeightOut>
<BlockWeightOffsetIn>0</BlockWeightOffsetIn>
<BlockWeightOffsetOut>0</BlockWeightOffsetOut>
<BlockWeightPresetTypeIn>none</BlockWeightPresetTypeIn>
<BlockWeightPresetTypeOut>none</BlockWeightPresetTypeOut>
<BlockWeightZeroThreshold>0</BlockWeightZeroThreshold>
<UseBlockDim>false</UseBlockDim>
<BlockDimIn>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
</BlockDimIn>
<BlockDimMid>32</BlockDimMid>
<BlockDimMid01>4</BlockDimMid01>
<BlockDimMid02>4</BlockDimMid02>
<BlockDimBase>4</BlockDimBase>
<BlockDimOutSDXL>4</BlockDimOutSDXL>
<BlockDimOut>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
<int>64</int>
</BlockDimOut>
<BlockAlphaIn />
<BlockAlphaMid>-1</BlockAlphaMid>
<BlockAlphaOut />
<BlockAlphaInM>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
</BlockAlphaInM>
<BlockAlphaMidM>32</BlockAlphaMidM>
<BlockAlphaMid01>4</BlockAlphaMid01>
<BlockAlphaMid02>4</BlockAlphaMid02>
<BlockAlphaBase>4</BlockAlphaBase>
<BlockAlphaOutSDXL>4</BlockAlphaOutSDXL>
<BlockAlphaOutM>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
<decimal>64</decimal>
</BlockAlphaOutM>
<UseColorAug>false</UseColorAug>
<UseFastLoading>true</UseFastLoading>
<DontSaveMetadata>false</DontSaveMetadata>
<UseFlipAug>false</UseFlipAug>
<CropRandomly>false</CropRandomly>
<CacheLatents>true</CacheLatents>
<CacheLatentsToDisk>true</CacheLatentsToDisk>
<HighVRAM>false</HighVRAM>
<UseAdditionalOptArgs>false</UseAdditionalOptArgs>
<LRSchedulerCycle>4</LRSchedulerCycle>
<GradAccSteps>1</GradAccSteps>
<DataLoaderThreads>1</DataLoaderThreads>
<MaxTokens>75</MaxTokens>
<mixedPrecisionType>fp16</mixedPrecisionType>
<WeightDecay>0</WeightDecay>
<Eps>1E-06</Eps>
<D0>1E-06</D0>
<GrowthRate>0</GrowthRate>
<Betas0>0.9</Betas0>
<Betas1>0.999</Betas1>
<Betas2>0.999</Betas2>
<DAdaptMomentum>0.9</DAdaptMomentum>
<ProdigyBeta3>0</ProdigyBeta3>
<DCoef>1</DCoef>
<Decouple>false</Decouple>
<NoProx>false</NoProx>
<SafeguardWarmup>false</SafeguardWarmup>
<UseBiasCorrection>false</UseBiasCorrection>
<StableDiffusionType>XL</StableDiffusionType>
<NoHalfVAE>false</NoHalfVAE>
<CacheTextencoder>false</CacheTextencoder>
<CacheTextencoderToDisk>false</CacheTextencoderToDisk>
<IsEpoch>true</IsEpoch>
<UseFullFP16>false</UseFullFP16>
<UseFP8Base>false</UseFP8Base>
<RelativeStep>true</RelativeStep>
<ScaleParameter>true</ScaleParameter>
<SaveState>false</SaveState>
<MaskLoss>false</MaskLoss>
<RandomNoiseOffset>false</RandomNoiseOffset>
<RandomIpNoiseGamma>false</RandomIpNoiseGamma>
<TokensSeparator />
<LossType>LTwo</LossType>
<HuberScheduleType>SNR</HuberScheduleType>
<HuberC>0.1</HuberC>
<LoRAPlusLRRatio>0</LoRAPlusLRRatio>
<LoRAPlusUnetLRRatio>0</LoRAPlusUnetLRRatio>
<LoRAPlusTELRRatio>0</LoRAPlusTELRRatio>
</TrainParams>