お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。

SDXLを使ったキャラクターLoraの作り方メモ

投稿日:
ソフトウェア::Stable Diffusion

SDXLでキャラクターLoraをいい感じに作る方法。学習には教師画像のみを用いる。

必要なもの

やり方

1. 学習用の素材となる画像を集める

学習画像の枚数・パターン

多ければ多いほどいいが、多すぎると学習に時間がかかりすぎるので、ある程度選別する。

例えば3Dキャラクターを学習する場合は、1ポーズ当たり正面・斜め前・横・斜め後ろ・真後ろの流れで一周八面の画像をいくつかのポーズ分作っておくと再現性が高くなる。

奇麗な画像があまりとれない場合は、極力そのキャラクターの特徴が出ている画像を数枚集める。4枚とかでもいい。1枚は試したことないのでどうなるのか不明。

学習素材となる画像の選定

学習元画像には背景が入っていてもいいが、そのキャラクターだけが映り込んでいるものを選ぶ。ほかのキャラクターが入っていたらトリミングするなどで消したほうが良い。

2. 学習用の素材画像にタグを打つ

  1. AUTOMATIC1111を起動し、Tagger→Batch from directoryを開く
  2. 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>