Qwen3.8 Maxで教師データを増やし、Animaの成功conditioningを短文へ蒸留できるか試した
目次

前回のAnimaのQwen3-0.6BとLLMAdapterを調べた実験では、短いP0と成功するP3をQwen側・T5側で交差させた。 seed 42では、QwenだけをP3へ変えてT5をP0のままにしてもkanachanの見た目の特徴は戻らず、T5をP3へ変えるとkanachanとkeichanが正しく描き分けられた。
固定辞書で長いプロンプトを組み立てて、入力自体は短く済ませる方法もある。 今回は長文をAnimaへ入力せず、長文成功時のconditioningそのものを短いトリガーから再現できるかを試した。Qwen3-0.6Bを凍結したままDiT直前のconditioningを学習で作り出す小さなresamplerを組み、その学習に使う並び順とシーンの組み合わせをQwen3.8 Maxで増やした。
検証環境
| 項目 | 内容 |
|---|---|
| マシン | MacBook Pro M1 Max、統合メモリ64GB、MPS。抽出・学習・生成ともこの1台で、RunPodは使っていない |
| 生成 | ローカルComfyUI、1枚あたり約33秒(8 step) |
| ベースモデル | anima-base-v1.0.safetensors |
| LoRA | anima-turbo-lora-v0.1(speed、strength 1.0)、anima-4char-v1_epoch100(char、strength 1.0 / clip 0.8) |
| text encoder | qwen_3_06b_base.safetensors(CLIPTextEncode、type=qwen_image) |
| 教師ペア生成 | Qwen3.8 Max(アンバサダー枠、ModelScope経由のOpenAI互換API) |
| resampler学習 | 1500 stepで1分未満、tensor抽出は数十秒 |
Qwen3.8 Maxは内部tensorを返さないため、並び順とシーンの生成に使う
Qwen3.8 Max previewの早期アクセスでは、専用ワークスペースのOpenAI互換APIから文章とreasoning情報を取得できた。 一方、Alibaba Cloud Model StudioのChat Completions API仕様に記載された応答は、生成文、reasoning、logprobs、usageなどで構成され、各入力tokenの中間hidden stateを返す項目はない。仕様に載っている範囲では、Qwen3.8 Maxの内部tensorをAnimaへ直接入力する実験には使えない。
Model Studioにはembedding専用APIもある。仕様では入力ごとのembeddingベクトルを検索や類似度計算に使い、1024次元も選べる。ただtoken単位のhidden stateを返す仕様やAnimaのLLMAdapterとの互換性は書かれていないため、蒸留には使えない。Qwen3.8 Maxは学習データの生成にのみ使った。
MaxにはP3本文を書かせず、4人の並び順とシーンをJSONで12件返させた。 人物の過不足とJSONの欠落はローカルで検査し、固定rendererが同じ英語テンプレートからP3を組み立てた。Maxが決めるのは並び順とシーンだけで、Animaへ入る文面はrendererの固定テンプレートから出る。
処理ごとに担当を分ける
| 処理 | 実行場所 | 理由 |
|---|---|---|
| 4人の識別辞書から並び順+シーンのJSONを作る | Qwen3.8 Max API | 並び順とシーンの組み合わせを増やせる |
| JSONからP3を組み立てる | ローカルの固定renderer | 属性順と文型を固定し、教師プロンプトを再現可能にする |
| P3から成功conditioningを抽出する | 現在のAnima / Qwen3-0.6B / LLMAdapter | DiTがすでに生成成功に使っているtensorを教師にする |
| P0からhidden stateを抽出する | 現在のAnima / Qwen3-0.6B(凍結) | 同じ0.6Bを短い入力側にも使い、容量差ではなく変換の有無だけを比較する |
| resamplerを学習する | ローカルM1 Max(MPS) | 50M param程度の小さいネットワークなので、Qwen3-0.6B側さえ凍結すれば1台で足りる |
| 同一seedで画像を比較する | ローカルの生成環境 | 最終的にDiTが4人を描き分けられるかを確認する |
token数43と179の差をresamplerで埋める
前回の4人条件では、LLMAdapterのpadding前出力の長さがP0とP3で大きく違った。
| 入力 | T5実token数 | LLMAdapter出力 |
|---|---|---|
| P0、トリガー中心 | 43 | (1, 43, 1024) |
| P3、識別文・位置文・服装文あり | 179 | (1, 179, 1024) |
512tokenへpaddingした後ならshapeだけは同じになる。 しかしP0は43番目より後ろがほぼzeroで、P3は179番目まで意味のあるconditioningが入る。両者へそのままMSEを掛けると、同じ人物や属性を表す位置が対応せず、zero paddingの一致が損失の大部分を占める。
P0 : 43 token ──────────────── zero padding ────────────────
P3 : 179 token ───────────────────────────── zero padding ──
hidden sizeを1024へ射影するだけでは、このtoken数の差は埋まらない。 今回は射影に加えて、短いP0側のhidden stateから教師と同じ179tokenを作るresamplerを学習する。
flowchart TD
S[P0と人物辞書] --> M[Qwen3.8 Max API]
M --> J[並び順+シーンのJSON]
J --> R[固定renderer]
R --> L[P3教師プロンプト]
L --> A[現行Anima encoder]
A --> G[C_good<br/>179〜189×1024]
S --> O[Qwen3-0.6B凍結<br/>P0 hidden state]
O --> P[resampler<br/>学習済みquery200個]
P --> C[C_pred<br/>200×1024]
G --> D[distillation loss]
C --> D
初回は4人P3の定型プロンプトだけに限定し、学習済みqueryの数(NQ)を200に固定した。 ペアやトリオまで広げる場合は、教師maskも予測するか、組み合わせごとに有効長を与える設計を後から追加することにして実験開始。
Step 1、教師プロンプトを固定する
入力データはprompt_shortからprompt_teacherまでの4項目で保存する。
| フィールド | 内容 |
|---|---|
prompt_short | 実際に入力する短いプロンプト |
character_dict | トリガーごとの髪型、髪色、瞳、身長、服装 |
max_json | Qwen3.8 Maxが人物別に整理したJSON |
prompt_teacher | 固定rendererが作ったP3形式の英語プロンプト |
Maxに独自トリガーだけを与えて設定を推測させることはせず、辞書にない属性の追加・人物の欠落・順番の変更があったものは教師候補から除外する。API出力はtemperature、seed相当の指定、model ID、reasoning設定も一緒に保存する。
手書きした4ペア(order1〜4)
はじめはQwen3.8 Max APIを一切呼ばず、4人の識別文をanima-4char-qwen-conditioningで確立した固定テンプレート(トリガー+髪型/瞳/装飾の識別文+位置文+身長比較+服装文)のまま、4人の並び順だけを変えて手書きした。
| pair ID | short(P0) | renderer後のtoken数(T5実token) | 教師画像の判定 |
|---|---|---|---|
| order1 | kurara, keichan, kanachan, koharu | 179 | 成功。4人とも見た目の特徴・並び順・身長差が指示通り(既存記事で確認済み) |
| order2 | koharu, kanachan, keichan, kurara | 184 | 成功。4人とも見た目の特徴・並び順・身長差が指示通り(下記Step4画像) |
| order3 | keichan, kurara, koharu, kanachan | 189 | 見た目の特徴・並び順は指示通りで学習に使用。ただし身長差はkanachanがkoharuより低く、指示と合っていない(下記Step4画像の注記) |
| order4 | kanachan, koharu, kurara, keichan | 183 | 成功。4人とも見た目の特徴・並び順・身長差が指示通り(下記Step4画像) |
Max API実施記録(Run2)
次にQwen3.8 Maxを実際に呼んだ。usageはprompt_tokens=384・completion_tokens=2085・total_tokens=2469。
Maxへは4人の識別辞書(名前と髪型/瞳/装飾の短い説明)だけを与え、「4人の並び順(permutation)」と「短いシーンフレーズ」のペアをJSONで12件生成させた。文章そのもの(識別文・位置文・身長比較・服装文)はMaxに書かせず、renderer.py(固定renderer、後述)がローカルで組み立てる分担にした。
自己検査(ローカル側、Max呼び出しとは別処理)の対象は「4人の名前が過不足・重複なく含まれているか」「scene_short/scene_fullが空でないか」だけにした。12件中12件がこの検査を通過した(reject 0件)。
自己検査では4人の名前の過不足しか確認できないため、Step2で12件すべての教師P3画像を生成して目視確認した。1件(maxgen06)だけ、指定した並び順と実際に生成された4人の位置が一致しない失敗だった(教師プロンプトの文面は正しいが、生成結果側で見た目の特徴の位置が入れ替わった)。この1件は学習データから除外し、11/12を採用した。
| pair ID | 割り当て | 教師P3画像の判定 |
|---|---|---|
| maxgen00〜09の9件(maxgen06を除く) | 学習 | 成功。4人の見た目の特徴・並び順が指示通り |
| maxgen06 | 除外 | 失敗。見た目の特徴は揃うが並び順が指示と一致しない(下記画像) |
| maxgen10・maxgen11 | 検証用 | 成功。4人とも指示通り(下記Step4画像) |
固定renderer(renderer.py)は、4人の並び順を受け取って位置文(is on the far left / is second from the left / … / is on the far right)と身長比較文を組み立てる。身長比較文は既存の確立済み識別文の身長ロジックそのままで、同順位タイのkurara・keichanは2人目に出てきたときにthe same height as X、kanachanは同順位者が先に出ていればhalf a head shorter、まだ出ていなければhalf a head shorter than the tallest、koharuは常にthe shortestとする。
このrendererはorder1(既存の4char_P3)とorder2(既存の4char_P3_order_reversed)の実文と全く同じ文を出せることをself-testで確認済み。

Step 2、成功した教師tensorだけを保存する
prompt_teacherを現行Qwen3-0.6BとLLMAdapterへ入れ、encode経路の段階ごとに、Qwen3-0.6Bの最終hidden state、T5トークナイザーのIDsとweights、LLMAdapterのpadding前出力、512tokenへpaddingした後のconditioningと有効token mask、同じseedで生成した画像を保存する。
画像で4人の本人一致、属性、位置を確認し、失敗したプロンプトのconditioningをC_goodへ入れない。
教師tensorのdtype、各tokenのnorm、全体のmean・stdもmanifestへ残す。
実施記録
step_resampler_extract.py(step2_extract.pyを4ペア分バッチ化)で、order1〜4それぞれについてP0側とP3側のtensorを保存した。CPU固定で、DiT本体はロードしない。
- 入力側: P0(トリガーのみ)をQwen3-0.6Bへ通した
qwen_final。4orderとも同じ4トリガーの並べ替えなので、shapeは全order共通で(1, 38, 1024)float32 - 教師側: P3(識別文込み)を
qwen_final→LLMAdapterへ通したadapter_out_weighted(padding前、real length)。shapeはorderごとに(1, 179, 1024)〜(1, 189, 1024)(識別文の語数差でtoken数が変わる)
教師tensorの値域を先に確認すると、per-token L2 normの平均が4orderとも4.06〜4.17で揃っている一方、入力側のQwen最終hidden stateは110前後と教師の約27倍のスケールだった。この27倍の差が、Step3で最初のresampler実装の収束を止めた。
実施記録追記(Run2)
Step1のMax API生成12件のうち、教師P3画像で並び順の破綻が確認できたmaxgen06を除く11件分もP0側・P3側のtensorを同じ手順で抽出した(step_resampler_extract.pyのPAIRS辞書を拡張)。Max生成分はP0にscene_shortが加わる分だけP0側のtoken数がorder1〜4(常に38)より長く、43〜45で揃わない。Resampler側はcross-attentionのkey_padding_maskでpadding位置を無視する形に対応した。
これで学習データは合計16ペア(手書き4 + Max生成12)、うちmaxgen06を除いた15ペアが教師画像で確認済みになった。
Step 3、まず0.6Bのままresamplerだけを試す
P0を入れた現行Qwen3-0.6Bのhidden stateから、179tokenのC_goodを予測できるか試す。
この成否で、足りないのがQwen容量なのか、短文から長いconditioningへ展開する学習済み変換なのかを切り分ける。
Qwen3-0.6BとDiTは凍結する。Qwen hidden stateは先に保存し、学習中は射影層とresamplerだけをGPUへ載せる。
初期の損失はmasked MSE、cosine、distributionの3項で記録する。
L = λ_mse * masked_MSE(C_pred, C_good)
+ λ_cos * (1 - cosine(C_pred, C_good))
+ λ_stat * distribution_loss(C_pred, C_good)
distribution_lossではtoken norm、mean、stdを合わせる。
学習側の損失だけで判定せず、学習に混ぜず取り分けておいた検証用ペアのプロンプトから生成した画像で、4人の描き分けを確認する。
実施記録(Run 1)
学習をorder1・order3・order4、検証用をorder2(reversed)にした。P0(resamplerへの入力)は4orderとも4トリガーの並べ替えでtoken数が変わらないため、並び順という情報だけをQwen hidden stateから読み取って教師の並びを再現できるかを確かめる設定にした。
resamplerは学習済みquery 200個(NQ=200、教師最大長189に余裕を持たせた)がP0側のQwen最終hidden stateへcross-attentionする構成(resampler.py)。
| 項目 | 値 |
|---|---|
| アーキテクチャ | 学習済みquery(200×1024) + [self-attn→cross-attn→FFN]×3層、8 head |
| dim | 1024(Qwen最終hidden stateとLLMAdapter出力が両方1024なので射影無し) |
| trainable parameters | 50,598,912 |
| optimizer | AdamW、lr=2e-4、weight_decay=1e-4 |
| steps | 1500(学習3件をfull-batch) |
| 損失の重み | λ_mse=1.0、λ_cos=1.0、λ_stat=0.1 |
| 実行環境 | ローカルM1 Max、MPS |
最初の実装は1500stepでも収束しなかった。context(Qwen最終hidden state)をそのままcross-attentionのkey/valueへ入れていたため、resampler内部の値が入力側のスケール(per-token norm ~110)に引きずられ、教師(per-token norm ~4)との差を埋めるのに出力層のLayerNormだけでは足りず、train cos distanceが0.94前後で頭打ちになった(distribution_lossの内訳を確認すると、初期値の大部分がこの27倍のnormスケール差そのものだった)。contextに事前LayerNormを1枚挟み、出力LayerNormのweight初期値を1.0から0.2へ下げたところ、同じ1500stepで大きく改善した。
| train_mse | train_cos_dist | val_mse | val_cos_dist | |
|---|---|---|---|---|
| 修正前、step1500 | 0.213 | 0.943(≈ほぼ無相関) | 0.217 | 0.976 |
| 修正後、step1(初期値) | 0.059 | 0.999 | 0.049 | 0.794 |
| 修正後、step1500 | 0.00046 | 0.0047(≈コサイン類似度0.995) | 0.0234 | 0.595(≈コサイン類似度0.405) |
学習した3件(order1・order3・order4)はコサイン距離0.005までほぼ完全に再現した。一方検証用のorder2はコサイン距離0.59付近で頭打ちになり、MSEは学習側の約125倍だった。学習3件ではこんなものだと思う。
画像はもう少し込み入った結果になった(画像はStep4参照)。resamplerの検証用(order2)出力では、4人それぞれの見た目の特徴(kanachanのアホ毛+サイドポニー、koharuの黒髪・赤目、kuraraのrose-brown髪+ピアス、keichanの金髪+青リボン)が4人とも正しく描き分けられて出た。ここはP0そのまま(見た目の特徴が別の人物に混ざったり抜けたりする)より、はっきり良くなった。しかし並び順はorder2の指示(koharu, kanachan, keichan, kurara)でなく、学習に使ったorder4(kanachan, koharu, kurara, keichan)とほぼ一致していた。P0の入力token列は4orderとも4トリガーの並べ替えに過ぎず、resamplerは「どのorderで学習したパターンに一番近いか」で出力を選んでいるように見える。見た目の特徴の描き分けだけは初見の並びにも引き継がれたが、並び順がQwen hidden stateから読み取れているかどうかは、この3ペアの学習からでは判断できない。
実施記録(Run2、学習12件・検証用3件)
学習3件では並び順を読み取れているか判断できない、というRun1の結果を受けて、Step1のMax API生成分を使い、学習をorder1・order3・order4 + maxgen00〜09のうちmaxgen06を除いた9件の計12ペア、検証用をorder2 + maxgen10 + maxgen11の計3ペアに増やして、同じ設定(NQ=200、3層resampler、AdamW lr=2e-4、1500 step)で再学習した。
| train_mse | train_cos_dist | val_mse(集約) | val_cos_dist(集約) | |
|---|---|---|---|---|
| Run1(学習3/検証用1)、step1500 | 0.00046 | 0.0047 | 0.0234 | 0.595 |
| Run2(学習12/検証用3)、step1500 | 0.00045 | 0.0049 | 0.0203 | 0.605 |
学習側の再現度(コサイン距離0.005前後)はRun1とほぼ変わらず、検証用3件をまとめた値も0.595→0.605とほぼ横ばいだった。学習ペア数を4倍にしても、この数値の上では検証用は改善しなかった。
検証用3件の数値は個別でも大差なかった。
| 検証用 | mse | cos_dist |
|---|---|---|
| order2 | 0.0213 | 0.649 |
| maxgen10 | 0.0197 | 0.571 |
| maxgen11 | 0.0199 | 0.596 |
3件をまとめた数値は横ばいだったが、生成画像の崩れ方は3件で別々だった(画像はStep4参照)。学習に使った1パターンの丸暗記という単純な結果ではなくなった。
| 検証用 | 指示順 | 崩れ方 |
|---|---|---|
| order2 | koharu, kanachan, keichan, kurara | 1番目(koharu)と4番目(kurara)は指示通り。2番目と3番目でkanachanとkeichanが入れ替わる |
| maxgen10 | kanachan, keichan, koharu, kurara | 3番目(koharu)と4番目(kurara)は指示通り。1番目と2番目でkanachanとkeichanが入れ替わる |
| maxgen11 | koharu, kanachan, kurara, keichan | 1番目(koharu)だけ指示通り。2番目と3番目が両方keichan(金髪+リボン)の見た目になり、kuraraが出てこず、kanachanが4番目に押し出される |
3件に共通するのは、koharuの立ち位置(左から何番目に出るか)は3件とも指示通りで、kanachanとkeichanが隣接して入れ替わる・あるいは片方が重複する形で崩れるという点だった。並び順の情報の全てを丸暗記に頼っているとまでは言えない(3件とも別々の崩れ方をしており、単一の記憶パターンへ収束していない)。koharuのように見た目がほかと最も離れた特徴(黒髪・赤目、最も低身長)を持つ人物は指示した立ち位置に出やすい一方、kanachanとkeichanのように学習データ中で位置の入れ替わりパターンが多様だった2人の組み合わせは、まだ正しく描き分けられていないように見える。3件をまとめた損失だけでは「変化なし」に見えたが、検証用ごとの内訳と画像を並べて初めて崩れ方の違いが分かった。
Step 4、プロンプト展開とtensor蒸留を画像で比較する
同一プロンプト、同一seedで、P0の直接入力からresampler経由まで4条件を比較する。
- P0を現行Animaへそのまま入力
- 固定辞書からP3を作って現行Animaへ入力
- Qwen3.8 MaxのJSONからP3を作って現行Animaへ入力
- P0からQwen3-0.6B+resamplerで
C_predを作る
| 条件 | 4人の本人一致 | 属性の混ざり | 位置 | 備考 |
|---|---|---|---|---|
| P0 | 崩れる(下記画像) | あり | 指示順と一致しない | 人数が3人に減ることもあった |
| 固定renderer P3(手書き4件、蒸留なし) | 4/4成功 | なし | 指示順どおり | order1〜4。Step1参照 |
| 固定renderer P3(Max生成12件、蒸留なし) | 11/12成功 | maxgen06のみ並び順が入れ替わる | maxgen06以外は指示順どおり | Max→P3の結果。Step1参照 |
| 0.6B resampler(蒸留あり) | 部分的(下記) | 見た目の特徴の描き分けはP0より崩れが少ない | Run1: 学習に使った別orderをほぼ再現。Run2: koharu/kuraraは合うがkanachan/keichanが入れ替わる | コサイン距離 Run1: 0.595 / Run2: 0.605(検証用3件まとめ) |
蒸留なしの固定renderer P3は16件中15件が指示通りに描き分けられ、蒸留ありの0.6B resamplerは検証用の並び順が崩れた。短い入力プロンプトの手前でMaxに並び順とシーンを決めさせ、rendererでP3化してAnimaへ入力する方法を、蒸留の対照条件として残す。
複数seedでの確認セクションを除き、大半の比較はseed 42のみの1回で行った。1seedの成功を安定性へ一般化しない。 人物数、本人一致、属性、並び順を別々に判定する。
実施記録(seed 42のみ)
教師として使ったorder3・order4のP3も、resamplerの学習データに入れる前に単独で生成して確認した。まずorder3の教師P3はこうなった。

後で気づいたが、このorder3は身長差が指示どおりに出ていない。教師プロンプトの文面はrendererの身長ロジックどおり(koharuが常に最も低い)なのに、生成画像ではkanachanがkoharuより低い。教師画像の判定を見た目の特徴と並び順中心でやっていたため、この時点では見落としたまま学習データに使っている。ただ学習結果へのダメージはそんなになさそうで、この後の生成では身長差はちゃんと出ている。身長文が正しいプロンプト側の情報もあるからかもしれない。
こちらはorder4の教師P3。身長差もこちらは指示どおりに出ている。

order1は学習に使ったペアで、P0そのまま・教師P3・resamplerのC_predを比較する。C_predは学習で見た組み合わせなので、教師とほぼ同じ画像になるかを確認する。1枚目はP0をそのまま入れた結果。

2枚目は教師P3を入れた結果。

3枚目はresamplerのC_predを入れた結果。教師P3とほぼ同じ絵が出た。

order2は検証用で、resamplerの学習に一度も使っていない並び順。P0そのまま・教師P3・resamplerのC_predに、比較用のorder4教師P3を加えた4枚を並べる。1枚目はP0をそのまま入れた結果。

2枚目は教師P3を入れた結果。指示した並び順はこの画像のとおりになる。

3枚目はresamplerのC_predを入れた結果。

4枚目は比較用の再掲で、学習に使ったorder4の教師P3。

この4枚を比べると、見た目の特徴の破綻はP0そのまま(1枚目)よりはっきり減っている一方、並び順は指示(教師P3、2枚目)ではなく学習に使ったorder4(4枚目)と一致している。「並び順の情報がQwen hidden stateから読み取られて教師へ再現された」というより、「学習中に見た並び順のうち一番近いものが選ばれた」という暗記に近い結果だった。
実施記録(Run2、seed 42のみ)
Run1のresamplerを学習12件・検証用3件で再学習した後、同じ3条件(P0そのまま・教師P3・C_pred)を検証用3件(order2・maxgen10・maxgen11)で生成し直した。order2のP0そのまま・教師P3画像はRun1と同じ(プロンプト自体を変えていないため)なので上の2枚を再利用し、C_predだけ再学習後のものへ差し替える。

maxgen10は検証用で、指示順はkanachan, keichan, koharu, kurara。シーンは駅のホームで待つ。1枚目がP0(トリガー+シーンフレーズ)そのまま、2枚目が教師P3、3枚目がRun2で再学習したresamplerのC_pred。



maxgen11は検証用で、指示順はkoharu, kanachan, kurara, keichan。シーンは雨の中庭で遊ぶ。並びはmaxgen10と同じく、P0そのまま・教師P3・Run2のC_pred。



検証用の3件を並べると、3件をまとめた損失はRun1とほぼ変わらなかった一方、崩れ方はRun1(学習に使った1パターンをほぼ再現する)とは違う形になった。koharuの立ち位置は3件とも合っていたが、kanachanとkeichanは入れ替わる(order2・maxgen10)か、片方が重複してもう片方が消える(maxgen11)かのどちらかで、まだ指示順を正しく再現できていない。P0そのまま(1枚目)は依然として4人目が欠落したり制服になったりと、指示順以前に人数や属性から崩れている点は変わらない。
複数seedでの確認(seed 1234・9999を追加)
ここまでの検証用3件の結果はseed 42の1回だけだったので、C_predを固定したまま(resamplerの重みも入力P0も変えない)、生成のseedだけ1234・9999に変えて同じ検証用3件を再生成した。C_pred自体はseedに関わらず同じtensorなので、ここではDiTのサンプリングが変わったときに4人の描き分けの傾向が変わるかどうかを確かめた。以下、order2・maxgen10・maxgen11の順に、seed1234と9999の結果を2枚ずつ並べる。






3seedを並べると、order2とmaxgen10は3seedとも完全に同じ(誤った)並びを再現した。この2条件の入れ替わりはsampling seedだけでは説明しにくく、C_pred側の影響が強いと思われる。一方maxgen11だけはseedごとに違う崩れ方をした(seed42・1234はkeichanの重複+kurara欠落、seed9999は4人とも出るが並びが違う)。この3件の中では、maxgen11のconditioningがDiTのサンプリングによって異なる解釈を受けやすい可能性がある。
蒸留は並び順が崩れ、固定rendererは16件中15件成功した
学習側はRun1(3ペア)・Run2(12ペア)ともコサイン距離0.005前後まで教師conditioningを再現した一方、検証用3件をまとめたコサイン距離は0.595→0.605で、学習ペア数を4倍にしても数値は変わらなかった。生成画像の崩れ方だけが、Run1では学習に使った1パターンをほぼ再現する丸暗記だったのに対し、Run2ではkoharuの立ち位置は合うがkanachanとkeichanが入れ替わる・重複する形へ変わった。この変化は3件をまとめた損失には出ていない。order2とmaxgen10は3seedとも同一の誤った並びを再現した。
一方、蒸留なしでMaxのJSONを固定rendererでP3化してAnimaへ入力する方式は、16件中15件で指示通りに描き分けられた。MSEとコサイン距離が十分下がっても検証用の並び順が直らなかったことから、今回の特徴量レベルの損失(masked MSE + cosine + distribution loss)では、DiTがconditioningのどの差を使って人物を描き分けているかまでは捉えられていないと思われる。C_predをC_goodへ近づける代わりに、同一latent・同一timestepでDiTのnoise prediction自体を一致させる損失(L_dit = MSE(DiT(x_t, t, C_pred), DiT(x_t, t, C_good)))へ進める余地は残っているが、DiTを通したbackpropが必要になり計算量が増えるため、この記事の範囲では試していない。