お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
投稿日:
ソフトウェア::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>

SMBC VISAを事故カードとして止めて再発行したので再登録しようとしたら上手くいかなかったので、その解決録。

事象

Googleウォレットを開き、ウォレットに追加→クレジットカードまたはデビットカードを追加からiDへの登録を行うと「GoogleウォレットでiDをご利用いただけます」的なダイアログが表示され、そのまま進めていくと内容がよくわからないエラー(標準エラー+エラー理由が空欄)に遭遇し、登録に失敗する。

解決できた方法

iDアプリを経由してGoogleウォレットを開き、登録手続きを進めていくと無事登録できた。

iDアプリ経由だと規約同意画面が出てきたが、Googleウォレット直だとこれが出なかったので、何かしらの連携が必要だったのかもしれないがよくわかっていない。とりあえず登録できたので良し。

あとがき

Xを眺めている感じ同様の事象に遭遇してそうな人を多く見かけるので何かの解決になったらいいなぁ…。

メイクアガールを観てきた 三回目の続き。四回目の記事を書いていないため、今回の記事は三回目から飛んで五回目となっている。

去る3月1日、チネチッタでメイクアガールのスペシャルスタッフトークショー付き上映が行われたので、それに参加してきた記録とか、映画への想いとか。ちょうどノベライズを読み終わったところなので、そこへの想いもちょこっとだけ。

チネチッタへ

この日は朝から予定が入っており、10:30には終わる手はずだったが、30分オーバーした時のことを考慮して11:16発の新幹線で新神戸から新横浜に向かう予定だった。Yahoo乗換案内によるとこの予定では上映開始10分前にチネチッタにつく計算だった。

この予定は的中し、見事予定通り…となったものの、新神戸まであと少しのところで忘れ物に気が付いてしまい、どうにかなることを信じ、引き返したものの、余裕で間に合わず、一本後の新幹線に乗る羽目になった。開幕から中々の有様だったが、時刻表の読み合わせを行った結果、当初の予定時刻に到着できることが分かり、事なきを得た。

20250301_112306598.JPG

ギリギリで乗車車両を変えたため窓際が取れず、富士山は通路側の席から窓際の人の頭を避けて眺めることになってしまった。

20250301_131850080.JPG

なんとか11分前にチネチッタ前に到着でき、無事事なきを得た。駅前にチネチッタへの行き方が一切なく、土地の形から推定していったため無駄に遠回りしてしまったが、一種のテーマパークにも見える雰囲気のいい場所だった。

20250301_141902604.JPG

そしていつもの上映前の写真撮影。今回は人生初のぬい同伴だ。このぬいを取りに帰るためだけに時間に間に合わなくなるリスクを冒したので、その甲斐はあったと思う。たぶん。急いでカバンに入れたので0号の髪がやや乱れているのが申し訳ない。

20250301_142147748.JPG
20250301_142332846.JPG

そして上映終了後のトークで映し出されていたスクリーン。みんな撮っていたのでたぶん撮っていいものだと思う(適当)

20250301_164312216.JPG

しかし、がんばっていきまっしょいで松山に行った時も大概だったが、今回も川崎ということでずいぶん遠くまで来てしまった。しかも神奈川は今まで通過したことしかなかったので、これが初上陸であった。

鑑賞五回目の感想

そんなに書くことないかなと思っていたが、書こうと思えばつらつら出てくるもので、これがメイクアガールの恐ろしさだと感じた。

終盤のシーンに関して

0号が明と別居し、海中と話すシーンで「そんなのわからないですよ。できるかもしれないじゃないですか」というシーンがあり、この時の0号はまだ明とやり直せる可能性を考えていたと思うが、恐らくこの感情は海中と明が対峙し、海中のソルトが破壊されたことで砕け散ったと思う。あのシーンはあまりにも残酷だったし、あの状況でも0号が言葉を紡げ、さらに明への想いを募らせ続けられていたことは本当にすごいことだと思う。

この終盤のシーンでは0号は明の恋人になりたい、明のことが好きという変わらぬ想いがあったのに対し、明は0号と家族になりたいと考えており、最後まですれ違う思いは解消しなかった。何より、0号が私の気持ちを信じてほしいと言ったのに「わからずや」だとか「だから君はそういう風にできてない」と返す明は本当に救いがない。そしてここから0号は「私逆らえます」と言い、明への攻撃姿勢に完全に転換する。

このすぐ後に明は「話し合いがまだ足りない」などと詭弁を言うが、話し合いならもう十分にしただろうと思った。明は「混乱している」とも言っていたと思うが、それは明だけの話だ。0号は一切何も混乱していない。ただただひたすらに明のことが好きで、頭から離れなくて、この想いが作り物でないことを信じてほしかったんだ。

明が混乱しているのは、おそらく明は0号のことを勝手に家族扱いしようとしているが、0号は恋人としてみていること、そして海中の戦闘や、それまでの非日常的な光景などで頭の中がぐちゃぐちゃになっていたからだろう。しかし0号にとっては明がすべてで、明のこと以外はどうでもいいのだ。これが決定的な二人の間にある意識の乖離だと思う。本当にこればかりが悲しくて、メイクアガールは罪な作品だなと思った。余りにも純粋で、酷で、堪らなく愛おしい、この作品はそんなラブストーリーなのだ。

決して実ることない0号と明のラブストーリー、どこまでも救いがなく、だからこそ美しい。

私が好きな小説の一つにキノの旅という作品があり、この作品には「世界は美しくなんかない。そしてそれ故に、美しい。」という祝辞がある。メイクアガールは、まさにそのような作品だと思う。

ところで一番最後、0号が倒れる前のシーンで0号が「私の想いは偽物」といい、明が「そんなことない、君は僕なんかよりずっと――」と返すシーンがあったが、明はあの後何と言ったのだろうか。「本物」だろうか?「人間らしい」だろうか?恐らくこれは明の気持ちが最も0号に近くなった瞬間だと思う。後日、教室で「彼女じゃないよ」と返しているシーンがあるので、結局明は0号の恋人になりたい気持ちを否定しているようにも見え、あの時の態度は何だったのか?とも思うので、あの時の明がどういう意図で言っていたのかは定かではないのだが…。

そして0号が布団からいなくなり、ラボに移動したときに発する「おかえりなさい。『明さん』」というのが、水溜稲葉であるとしたら、「彼女じゃないよ」というのは母親を意識していたのか、それとも単に家族という認知だったのかも気になるところだが、母親と影が重なるシーンがあるあたり、母親ではなく、家族という認識で、恋人ではなく、家族が手に入ったことで明的には求めていた家族が手に入り、願望かなったりなのかなと思った。例えそこに明のことを好いていた0号がいなくてもだ。

明は海中に連れ去られた0号を追跡する前の回想で、0号の温もりを水溜稲葉由来のものとして解釈していたように見えるため、恐らくその面影があるのはうれしいことなのだろう。

個人的にこの作品を見ていて思うことは、どれほど言葉を交わしても、心は簡単には通じないし、想いを伝えることは難しいこと。人は簡単に変わらず、変えることもできず、どうしようもない無力さ。そして一度起きた勘違いは軌道修正することすらできず、明は自ら作ったはずの0号という恋人を忘れて、母親である水溜稲葉に傾倒してしまう悲しさだ。

0号が消えたのは痛ましく、それが水溜稲葉に乗っ取られているように見えたのは、非常に心外で、ありえないし、絶対に0号に戻ってきてほしかったが、そんなことはなく…本当に、本当にメイクアガールは救いがなく、それ故に美しい。まさに割れたガラスや水晶のようだ。だからこそ、私はメイクアガールが好きだ。これほどまでに心を突き動かされ、奪われる作品は過去に見たことがない。そう、メイクアガールは私の脳を鋭利な何かで刺してきて、そのままおもむろにぐちゃぐちゃにかき回してきたんだ…。

瞳が黄色くなることについて

そういえば、劇中の表現として創造者に反逆をするときに瞳の色が黄色くなる表現があるように思った。これは0号に限らずソルトもそのように見えた。そして明も瞳が黄色くなる瞬間があるということは、明にも生体防御が発動していたのだろうか?

このことについては後日ノベライズを読んだ感想について書こうと思っているので、その時に併せて書こうと思うが、ざっくりいうと書き換え不能な部分は水溜稲葉の意識だと考えていて、この意識はプログラムされたすべてのシステムに埋め込まれているのではないかという気がしている。

それ故にソルトに導かれた明がソルトから電撃を受けたときに水溜稲葉からの干渉を受けられたのではないかという気がしている。ノベライズでは相手の自我が強いと入り込めないが、脳が酸欠なら入り込めるとあったので、つまり明が気絶した状態であれば明の脳内に眠る水溜稲葉の意識が本人に干渉できるのではないか?ということを考えている。

恐らくメモリの中に格納されたシナプスのようなものは水溜稲葉の脳を転写したもので、明がこれを読めるのも、そういった部分が関係しているのではないかと思っている。

但しノベライズと映画には微妙に辻褄が合わない部分がある気がしているので、どこまで合っているのかはよくわからない。

スターシステム?

明が0号を追跡する過程で交通障害が起きるが、この時に二人のモブキャラが出てくる。「こっちだっけ?」という男性と「ええ、どうなってんの?」という女性だ。

シーンの割にはちゃんとしたセリフが設定しているのが気になっているのだが、もしかしてこれは次回作に出てくるキャラクターで、スターシステムなのかな?と思ったりした。

フレッツ光ネクストを契約している場合で、OCNをISPとして利用している場合に、請求先クレジットカードを変更しようとすると以下の画面が出るケースがある。このときに請求先クレジットカード番号を変える方法。

paste-image-2025-37-3_16-36-44-276.png

やり方

  1. Club NTT-Westにログイン
  2. 契約確認・お手続きを開く
  3. 「お支払い方法の変更」から「ご登録中のクレジットカード情報(クレジットカード会社やカード番号等)の変更お手続き」を開く
  4. 頑張って変更情報を入力する
  5. おわり

あとがき

OCNの請求カードを変えたいのにOCNのサイトからできないのは罠だと思う。

NTT西日本でフレッツ 光ネクストを契約しているが引っ越しの時に何故か登録住所が更新されなかったときに使える方法。

やり方

0120-116-116に電話をし、フレッツ 光ネクストの登録住所が現住所と異なるので変えて欲しいという。

備考

Club NTT-Westでは住所変更ができないので電話でやるのが早い。なんでないんだろうね?

paste-image-2025-27-3_16-26-35-248.png

チャットボットの選択肢にもない。

paste-image-2025-26-3_16-25-33-67.png

よくある質問の現在契約している回線の住所を変更したいによると有人チャットで対応してもらえるらしいので、こちらでもいいかもしれないが、画面が中々開かないので私は諦めてしまった。

なお登録住所を確認できる手段が恐らくないため、恐らく自分で気づくのは不可能。私はWebビリングに申し込んだときに面倒なエラーが発生し、電話対応が必要になり、その時に住所がおかしいと指摘されて知った。