技術 約17分で読めます

WAI-Anima向けキャラLoRAの学習キャプションを自然言語+髪型タグで書き直す

いけさん目次

前回のWAI-Anima向けLoRA学習 で、Anima base + Qwen3 TEのアーキテクチャ的バイアスでサイドポニーの位置制御が効かないと結論づけた。学習素材53枚のキャプションは WAI-IL用にクリーンナップしたデータセット をそのまま流用していて、Anima推奨形式から外れていることに前回記事の最後で気付いていたので、まずキャプション側を整えるところから再着手した。

整える方針

前回記事の末尾 で挙げた次回方針:

  • キャプション順序を Anima 推奨に揃える
  • 自然言語で方向情報を含むサンプル説明を入れる
  • レーティング・品質タグを追加する

特に「自然言語で方向情報」がコア。前回のテストD(純自然言語)では推論側で効かなかったが、それは推論時の話で、学習時にQwen3 TEに方向情報を「概念として」教え込めていたかどうかは別問題として残る。Qwen3 TE が学習中に方向情報を抽出できる材料がそもそもキャプション側に存在しなかった という前回の仮説を、今回は素材側から潰しに行く。

Anima推奨フォーマットを一次情報で再確認

CivitaiのWAI-Anima v1ページAnima preview3-baseページから、現時点の公式推奨を整理した。

タグ順:

[品質/レーティング/safety] [1girl/1boy] [character] [series] [artist] [general tags]

各セクション内のタグ順は任意。

品質プレフィックスは:

masterpiece, best quality, score_7, safe,

safe を使う(SDXL時代の general ではない)。score_7 系の score タグだけアンダースコア許容、それ以外はスペース区切り・全部小文字。

自然言語は推奨だが必須ではない。AnimaはDanbooruタグ + 自然言語キャプション + 両者の組み合わせ で訓練されているので、学習データに自然言語版が含まれている以上、入れる方が解像度は上がる。

学習レートは公式推奨でrank 32 LoRAなら 2e-5 から開始。前回 AnimaLoraToolkit のデフォルトで 1.0e-4 を使ったのは5倍強だが、loss推移は問題なかったので結果的にOKだった。再学習では 2e-5〜5e-5 から試すのが本来推奨に近い。

year タグは入れないことにした

最初は前回記事の文体そのまま year 2024 を入れる予定だったが、公式ドキュメントを再確認すると:

  • year系タグは optional(必須・推奨ではない)
  • 用途: year 2024 year 2010 のような時代の絵柄ニュアンスへのバイアス
  • random tag dropout で訓練されており全タグ必須ではない

学習キャプションに year 2024 を入れると、kanachan2024年代の絵柄 が結びつき、推論時に同タグを入れないとキャラ再現が落ちる可能性がある。キャラ再現を年代と分離したいなら学習側には入れないのが正しい。

→ 学習キャプションには入れない。スタイル調整したくなったら推論プロンプト側で足せば済む。

髪型タグの方針: 「kanachan一体化」を諦めた

ここが今回の最大の方針転換。

これまでのIL/Anima両方で、学習キャプションに side ponytail 等の髪型タグを入れず、kanachan トリガー一語に「髪型・髪色・目色 すべて」を吸収させる戦略を取っていた。ILではうまく動いて、kanachan だけで髪型まで安定して再現できた(生成時に髪型を明示しなくてもサイドポニーで出る)。

前回のAnima学習 でも同じ戦略を使ったが、サイドポニー位置の左右が崩れた。flip_augment を切っても変わらず、追加検証で Anima base 自体に「side ponytail = viewer左」のバイアスがあることが判明(preview3-base + LoRAなしでも同じ位置)。

ここで詰みパターンが2つある:

  1. キャプションに髪型を入れない → kanachan 一体化を維持できるが、向き制御が壊れる
  2. キャプションに髪型を入れる → kanachan の定義が弱くなり髪がバラける可能性があるが、left side ponytail で向き制御を取り戻せるかもしれない

今回は2を選ぶ。理由:

  • IL での「kanachan一体化」は強力だったが、推論時に髪型を変えにくい副作用もあった。kanachan, twin tails のようにツインテにしようとしてもサイドポニーに引っ張られる
  • 髪型を独立タグ化すれば、kanachan, semi-long, hair down のような変化形が効く可能性が出る
  • Animaでは1の戦略で向きが取れない以上、2を試す価値がある
  • 仮に髪がバラけても、left side ponytail で都度指定すれば従来の見た目には戻せる

トレードオフを受け入れる前提で、髪型を独立学習させる方針に切り替える。

キャプションテンプレート

最終的に以下の構造で53枚を書き直した:

masterpiece, best quality, score_7, [safe/sensitive/explicit],
1girl, solo, kanachan,
[自然言語2文以上: シーン描写 + bound hair の画像内位置],
[キャラ属性タグ: brown eyes, left side ponytail, ahoge, brown hair, double parted bangs, medium hair, blue scrunchie, (medium breasts)],
[衣装・ポーズ・構図タグ],
white background, simple background,

自然言語の方針:

  • 全画像で2文以上
  • 画像内の bound hair の位置(right/left side of the image)を明記
  • danbooruタグ的な side ponytail という表現は自然言語側では避け、bound hair with a blue scrunchie のように描写

例(angry):

masterpiece, best quality, score_7, safe,
1girl, solo, kanachan,
A close-up portrait of a young girl with an angry expression and a slight frown looking directly at the viewer.
Her bound hair with a blue scrunchie is visible on the right side of the image,
and a small antenna of hair rises from the top of her head.
brown eyes, left side ponytail, ahoge, brown hair, double parted bangs, medium hair, blue scrunchie,
angry, frown, looking at viewer, portrait, bare shoulders,
white background, simple background

bound hair の位置記述は構図ごとに振り分け:

構図記述
正面立ち姿 / portraitvisible on the right side of the image
後ろ姿visible on the left side of the image
左プロファイル(viewer左を向く)extends from the back of her head
右プロファイル(viewer右を向く)visible behind her head

学習素材の53枚すべてキャラ視点で左サイドのサイドポニーなので、構図に応じて画像内の左右が決まる。

brown eyes は顔が見えない6枚(back / bikini / sportswear_back / fullbody_left_2 / left_back / right_back)で除外。medium breasts は胸部が直接見える nude.txt のみ追加。

53枚書き直しの作業フロー

人手で53枚やると見落としが必ず出るので、以下のフローで進めた。

  1. CSVに filename, image_path, old_caption, new_caption, notes の5列でまとめる
  2. PythonスクリプトでXLSXに変換し、先頭列にサムネイル画像を埋め込み
  3. Numbersで開いて画像と新キャプションを並列確認
  4. 修正点をスクリプトで一括反映
  5. 最終txtへ反映
# build_xlsx.py(一部)
from openpyxl.drawing.image import Image as XLImage
from PIL import Image as PILImage

for i, row in enumerate(rows, start=2):
    ws.cell(row=i, column=2, value=row["filename"])
    ws.cell(row=i, column=5, value=row["new_caption"])
    img_path = DIR / row["image_path"]
    thumb_path = THUMB_DIR / f"{img_path.stem}_thumb.png"
    with PILImage.open(img_path) as im:
        im.thumbnail((160, 320))
        im.save(thumb_path, "PNG")
    xl_img = XLImage(str(thumb_path))
    xl_img.anchor = f"A{i}"
    ws.add_image(xl_img)
    ws.row_dimensions[i].height = 130

CSVをUTF-8 BOMなしで出すとExcelが文字化け(SJIS誤認)するので、最終的にXLSX経由が無難。openpyxlとPillowは pip install openpyxl Pillow で入る。

旧キャプションのバグを2件発見

書き直し中に旧キャプションの内容が画像と合わない2件を発見した。

ファイル旧キャプション実画像
kanachan_bikini.txtnudeピンクbikini後ろ姿
kanachan_nude.txtbikini, pink bikini, from behind全裸正面

両ファイルのキャプションが完全に入れ替わっていた。直近2回の学習はこの誤キャプションを食わせた状態で回っていたことになる。bikini 概念に「裸のような表現」が、nude 概念に「ピンクbikini」が紐づいて学習された可能性がある。サイドポニー方向問題の影で見落としていた地雷。

新キャプションでは実画像通りに修正済み。ファイル名(bikini.png / nude.png)はそのまま残し、キャプションだけ実態に合わせる。

blazer色の認識ズレ

blazer_angry / pointing / run / stomach / left_side の5ファイルでblazerを最初 brown blazer と書いていたが、実画像はわりと赤みが強い。視覚的には reddish brown が最も近く、純粋な brown だと赤みが落ち、red だと茶みが落ちる。中間を取って reddish brown blazer に統一した。

NL側にも同じ表現を反映(brown school blazerreddish brown school blazer)。AI同士の対話だと色名のズレは詰めにくい論点で、人間の目でファイルを並べて見て指摘してもらえると一発で詰まる。

最終キャプションの差分

旧(angry):

kanachan, 1girl, solo, angry, portrait, front view, white background

新(angry):

masterpiece, best quality, score_7, safe, 1girl, solo, kanachan,
A close-up portrait of a young girl with an angry expression and a slight frown looking directly at the viewer.
Her bound hair with a blue scrunchie is visible on the right side of the image, and a small antenna of hair rises from the top of her head.
brown eyes, left side ponytail, ahoge, brown hair, double parted bangs, medium hair, blue scrunchie,
angry, frown, looking at viewer, portrait, bare shoulders,
white background, simple background

長さは10倍近いが、Anima側には自然言語ルート + Danbooruタグルートの両方から情報が流れる。Qwen3 TEが学習時に方向情報を取れる材料がキャプション側に存在する状態に持ってこれた。

副次効果として髪型変更が効く可能性

「kanachan一体化」を諦めて髪型を独立タグ化したことで、推論時の自由度が上がる可能性が出てくる。

ILで学習したLoRAだと、kanachan, twin tails のようにツインテール指定してもサイドポニーに引っ張られて崩れていた。髪型ごと kanachan 概念に取り込まれていたので、別の髪型を指定しても基底モデル + 元LoRAの優先順位でサイドポニーに戻ってしまう。

今回のキャプションでは left side ponytail を独立タグとして毎回明示しているので、推論時に:

  • kanachan, semi-long hair, hair down → 髪を解いた状態
  • kanachan, twin tails → ツインテール
  • kanachan, ponytail → 通常のポニーテール

のような変化形が効く可能性がある。逆に、kanachan 単独だとサイドポニーが安定しないリスクと表裏一体。left side ponytail を毎回足せば従来の見た目には戻せるはずなので、運用上のコストとしては許容範囲。

次の検証ポイント

学習側の準備は整った。残る調整項目:

  • keep_tokens: 1 → kanachan が先頭固定だったが、Anima推奨では [品質] が先頭になる構造。keep_tokens の値を再考する必要あり
  • learning_rate: 1.0e-42e-5〜5e-5 に下げる(公式推奨に寄せる)
  • flip_augment: false 継続(前回検証で意味なかったが念のため)
  • repeats / epochs は据え置き

ここまで揃えて再学習し、サイドポニー位置が left side ponytail で制御可能になるかが本命の検証。bikini/nude誤キャプションの修正が学習に効いてくるかも見どころ。

v1再学習の結果

YAML設定:

項目理由
shuffle_captionfalse自然言語ブロックの順序破壊を回避
keep_tokens1shuffle off なので実質無効
learning_rate5.0e-5Anima公式推奨(2e-5〜5e-5)の中間
flip_augmentfalse継続
sample_every1毎エポックで挙動を観察したい
epochs12据え置き

学習は約40分で通った。エポック毎のサンプルプロンプトは kanachan, 1girl, solo, left side ponytail, standing, looking at viewer, white background (danbooruタグ寄りのまま、自然言語の方向情報なし)。

baseline
v1 baseline
ep4
v1 ep4
ep6
v1 ep6
ep8
v1 ep8
ep12
v1 ep12

結果としては、12エポック中1エポック(ep6)だけサイドポニーが学習素材通りの方向(viewer右側=キャラ左側)に出た。残り11エポックは前回と同じくviewer左側(キャラ右側)。一見正解した ep6 もたまたまSeedガチャでハマっただけと考えるのが妥当で、方向制御は安定して取れていない。

加えて気になった点:

  • 髪色が学習素材の落ち着いた茶ではなく、オレンジ寄りに出る
  • ep7サンプルで頭頂の ahoge(アホ毛)がケモ耳のような形に化ける(黒い縁取り入りの謎の構造物が出る)

brown hair タグを独立化したことで、Anima base が解釈する「brown hair」(やや赤みの強い茶〜オレンジ)が呼び出されて、学習素材の実色と乖離した、というのが髪色問題の有力仮説。前回IL学習では kanachan 一語に髪色まで吸収させていたので、トリガー語が学習素材の実色に直接紐づいていた。タグ独立化のトレードオフが顕在化した形になる。

キャプション再修正: 色情報を kanachan に戻す

brown hairbrown eyes をキャプションから削除した。前回の戦略に部分的に巻き戻す形だが、髪型の構造タグ(side ponytail, ahoge, double parted bangs, medium hair)は独立タグとして残す。

perl -pi -e 's/\bbrown hair, //g; s/\bbrown eyes, //g' *.txt

方針:

種別扱い
キャラ核心髪色・目色kanachan に吸収(推論で変える必要なし)
可変アクセサリ衣装・表情・小物・ポーズ独立タグ(推論で変える前提)
構造タグ髪型の形独立タグ(ツインテ等への変更余地を残す)

blue scrunchie も独立で残した。シュシュは色違い・リボン化で変える可能性があるため。

left side ponytail というタグはDanbooruに存在しない

ここで重大な発見をした。Danbooruで left-side_ponytail を検索すると0件ヒット。実在するのは:

  • side_ponytail(親タグ)
  • high_side_ponytail / low_side_ponytail(高さのサブタグ)
  • short_side_ponytailside_drill(亜種)

left side ponytail存在しないタグ。Anima base はこの組み合わせを学習していないので、left + side + ponytail を分離して解釈するか、side ponytail 部分だけ拾って left を実質無視する。

つまりこれまでの「方向タグで制御」戦略は前提が崩壊していた。前回 IL学習も今回 v1 も、left side ponytail は base から見れば「side ponytail + ノイズ」でしかなく、方向情報は何も伝わっていなかった。

修正方針:

  • タグ側: left side ponytailside ponytail(実在タグだけ使う)
  • 方向情報: 自然言語側に完全移譲(“visible on the right side of the image”)

v2学習: 色タグ削除 + side ponytail + 自然言語方向

53枚のキャプションを再修正:

  • brown hair, brown eyes 削除
  • left side ponytailside ponytail
  • 自然言語の方向描写は維持

サンプルプロンプトもタグ寄りから自然言語+side ponytailへ変更:

masterpiece, best quality, safe, 1girl, solo, kanachan,
Her bound hair with a blue scrunchie is visible on the right side of the image.
side ponytail, ahoge, standing, looking at viewer, white background, simple background

YAMLは output_dir: /workspace/output/rework-v2output_name: kanachan-waianima-rework-v2 で前回と分離。それ以外は v1 と同設定。

観測

baseline
v2 baseline
ep4
v2 ep4
ep8
v2 ep8
ep10
v2 ep10
ep12
v2 ep12
  • baseline(LoRAなし、自然言語方向指定あり): サイドポニーが viewer右側(学習素材通り)に出た。Anima base + 自然言語の方向指定は機能していることが確認できた。ただし副作用として被写体が縄で縛られた状態で出た(後述)
  • epoch 1〜(LoRA入り): 方向は v1 ほど一方向に固定されず、エポックによって左右が入れ替わる。一貫性は無いが「viewer左固定」状態は脱した
  • 髪色は明確に改善: v1 のオレンジ寄りから学習素材の茶色に近い色に寄った。brown hair タグを抜いて kanachan に色を吸収させる戦略は正解だった

baseline ✓ → LoRA入りで方向がブレるという挙動は、LoRAが視覚特徴は吸収するが自然言語の方向トークンと強くバインドできていないことを示唆する。53枚という少ないサンプル数で rank 32 の LoRA が学ぶ容量の限界、あるいは Qwen3 0.6B TE の方向トークン解像度の問題かもしれない。

bound hair がbase modelに「縛られた人物」と解釈される

v2 baseline サンプルで、女の子が縄で縛られた状態で出力された。プロンプトの Her bound hair を Anima base が「bound = 拘束された」+「hair = 髪」ではなく、「拘束された(状態の)人物 + 髪」と解釈した可能性が高い。

LoRA入りエポックではこの縄は消える(学習素材に縄が一切ないので LoRA で中和される)が、baseline 状態や推論でLoRA strength を下げた時に再発する余地がある。

そもそも bound hair は冗長な表現でもある。ponytail の時点で「結ばれた髪」を意味するので、bound hairside ponytail に置き換えて表記を簡素化する。

perl -pi -e 's/\bHer bound hair\b/Her side ponytail/g; s/\bbound hair\b/side ponytail/g' *.txt

副次効果として、自然言語側にも side ponytail という Danbooru タグ語が含まれることになり、タグ列との対応関係が強化される。

v3学習: bound 表現を排除

v2 のキャプションから bound hair 関連を全削除。サンプルプロンプトも同様:

masterpiece, best quality, safe, 1girl, solo, kanachan,
Her side ponytail with a blue scrunchie is visible on the right side of the image.
side ponytail, ahoge, standing, looking at viewer, white background, simple background

output_dir: /workspace/output/rework-v3output_name: kanachan-waianima-rework-v3 で v2 と分離。save_every: 1 で全エポックの LoRA を残す(v1/v2 は4エポック単位だったので比較しづらかった)。

v3結果

baseline
v3 baseline
ep4
v3 ep4
ep7
v3 ep7
ep8
v3 ep8
ep9
v3 ep9
ep12
v3 ep12

縄拘束は baseline 含めて全エポックで完全に消えた。bound 表現を排除した効果が明確に出ている。髪色も v2 から継続して学習素材通りの茶色で安定、振れない。v1 の ep7 で出ていた頭頂のケモ耳化(黒縁取りの耳状アーティファクト)も v3 では発生していない。

ただしサイドポニーの方向は依然エポック間でバラつく。v2 と同じく、一方向固定ではないが安定もしない。

ローカルComfyUIでバストアップ検証

トレーナー内蔵samplerの最小プロンプトだけだと判定材料が薄いので、M1 Max のローカル ComfyUI で本気プロンプトを当てて ep7 / ep8 / ep9 を検証した。条件は832×1024、er_sde + simple、30steps、CFG 4.0、LoRA strength model=1.0 / clip=0.8、seed 42 固定。

ポジティブは前述のサンプルプロンプト + white collared shirt, red necktie, upper body, looking at viewer, front view。ネガティブは ツインテ系 / nsfw 系 / 解剖学崩れ系を弾く定型。

ep7 (seed 42)
v3 ep7 bust-up
ep8 (seed 42)
v3 ep8 bust-up
ep9 (seed 42)
v3 ep9 bust-up

ep8 だけサイドポニーが viewer右側(NL指定通り)に出た。ep7 と ep9 は逆方向(viewer左)に倒れた。ep8 単独で見ればキャラ造形・髪色・髪型・服装まで一貫して再現できており、本命の検証成功条件を満たしている。

ただしこの結果が ep8 LoRA の構造的優位なのか、seed 42 とのガチャでハマっただけかは判別がついていない。

ep8で全身 + 動き + LoRA強度の追加検証

ep8 を本命として、立ち姿・走り・LoRA強度スイープで方向の再現性を確認した。同じ ep8 LoRA、seed 42 固定で。

立ち姿(同プロンプト + 同seed、LoRA強度のみ可変):

strength 0.5
strength 0.5
strength 0.7
strength 0.7
strength 1.0
strength 1.0
LoRA strength方向
0.5viewer右(NL指定通り) ✅
0.7viewer左 ❌
1.0viewer左 ❌

走りポーズ(running, dynamic pose, motion blur, action shot を追加):

running (strength 1.0, seed 42)
running

走りポーズ + strength 1.0 でもなぜか方向は viewer右(正方向)に出た。同じstrength 1.0 でも立ち姿は viewer左に倒れたのに、走りポーズだと正方向。プロンプトが standing から running, dynamic pose に切り替わるとシード変わらずに方向が反転するということで、要因はLoRA強度・seed・プロンプトの三軸が絡んでいて単純に切り分けられない。

髪型は kanachan に焼き付いていない

LoRAの吸収範囲を切り分けるため、side ponytail を消して hair down, semi-long hair を要求した(ネガに side ponytail, ponytail, blue scrunchie, scrunchie を追加)。

hair down test (ep8, seed 42)
hair down

結果はあっさり髪を下ろした状態で出た。ポニーもシュシュも消えている。つまり:

  • ✅ 髪型は kanachan トリガーに焼き付いておらず、side ponytail タグ + 自然言語で発火している
  • ✅ キャラ核心(顔・髪色・目色・体型)は kanachan に吸収されている
  • ✅ 髪型独立化(rework方針のひとつ)は機能した

これで LoRA が学習している領域の境界がはっきりした。kanachan = キャラの顔・色・基本造形。side ponytail 等のタグ = 髪型構造。前者は強く焼き付き、後者はタグで切替可能。

Anima アーキテクチャ固有の制約

調べていく中で、これは AnimaLoraToolkit や rank 32 の問題ではなく、Anima アーキテクチャ全体に存在する既知の構造問題だと分かった。

Anima 公式リポジトリの議論 で「LoRA causes strong style dilution / override on Anima」として報告されている内容:

LoRA Weight結果
0.4–0.7アーティストタグ等の base 知識が大幅に希釈される
0.8–1.0base 知識がほぼ無効化される

原因は Anima の「CLIP-less」設計にある。SDXL 時代の CLIP の代わりに Qwen3 0.6B TE を使っていて、この強力な text encoding が LoRA 適応を圧倒する。LoRA を当てた時点で base が持っていた多様な視覚知識(方向性のある描き分けを含む)が「catastrophic forgetting」で薄れる。

公式推奨の対処:

  • LLM Adapter(TE と DiT を繋ぐ層)を訓練しない(AnimaLoraToolkitの既定値で除外済み)
  • 学習率を 1e-5 ~ 2e-5 に下げる(今回は 5e-5、推奨より高い)
  • ステップ数を 12,000+ に伸ばす(今回は 636 ステップ、推奨の 5% 程度)
  • Differential Output Preservation パッチの組み込み(開発中)

うちの今回の学習は、この推奨条件のうち学習率とステップ数で大きく外している。Catastrophic forgetting で方向情報が十分焼き付かなかった結果、LoRA の方向バイアスが NL 指定を上書きしたが、その上書きが不正確で viewer 左に倒れる、という挙動になっている可能性が高い。

結論

達成した点:

  • bound hairside ponytail: 自然言語の表現を変えるだけで「縛り」誤解釈を排除できた
  • brown hair / brown eyes 削除: 色情報を kanachan に吸収させて、タグ独立化で生まれていたAnima base interpretation との乖離を解消
  • left side ponytailside ponytail: 存在しないDanbooruタグの撤去
  • 髪型独立化: kanachan + side ponytail 等の組合せで髪型変更が効くことを確認(hair down で実証)

達成できなかった点:

  • サイドポニーの方向制御: 学習素材は53枚すべて同方向だが、LoRA 1.0 strength 推論ではエポック・seed・プロンプトのガチャ性が残る
  • 当面の運用では strength 0.5 で base + NL の方向制御に頼るのが現実解(ただしLoRA特徴は希釈される)
  • 根本対処は学習率を 2e-5 に下げ、12,000+ ステップ訓練し直すこと。約5時間 ・$4の追加コスト

「Anima向けの個別キャラLoRAは、SDXL系より遥かに学習コストがかかる」が今回の主な学び。kanachan トリガーでキャラ寄せ自体はできるが、方向のような細かい制御まで焼き付けるには、SDXL 時代の感覚(数百ステップ、rank 32)から大幅に予算を増やす必要がある。

ひとまず ep8 + strength 0.5 で運用しつつ、長時間訓練とDifferential Output Preservation のリリースを待つ。