当wikiでは画像生成分野での学習における「loss」の意味で用いる
概要
- Wikipedia
https://ja.wikipedia.org/wiki/損失関数
- lossとは、簡単に言うと、学習中に発生する、教師画像と学習中の計算結果の差異のこと。
- 機械学習を行うということは、weightと呼ばれる変数を解く行為に相当する。
- ものすごく雑にまとめると線形多項式における最小二乗法みたいなものだが、最小二乗法のように連立方程式1発で解くことはできないので反復処理してweightを調整する。
説明上の都合、すごく簡単に表現した学習モデル f(入力画像) = g(weight, 入力画像) → (教師画像の予測値) g()は、例えば weight×入力画像 など
ここでf(), g()はモデル(事前学習モデルや既知のU-Net層などの関数)を含めた関数。
義務教育で習う二次関数でいうと、ax^2 + bx + cのa, b, cのところがweightやbiasといったパラメータ。
二次関数の式のxに相当するのは推論時の入力値で、画像生成モデルでは入力ノイズ画像、プロンプトやステップ数など。
lossが小さいほど、教師画像とモデル予測値とのズレが少ないということなので、学習用プログラムはloss削減するようにウェイト算出をします。
lossの種類
lossは設計次第で自由に作成できるが、実用面を考えると画像生成AIで使用されるものは限定される。
重み付けによる分類
- lossの値をどう重み付けするかという視点で分類ができる
lossの名称や評価対象というよりも、lossの算出方法に着目した分類である - 学習において基本的にはPyTorchに登録されている下記が使用されることが多い。
下記がよく使われるloss計算式。
- 数式と定義はリンク先に書いてありますので、このページでの定義の説明は省略します。
- sd-scripts, musubi-tunerでも上記のlossが使用されているが、loss計算式そのものをPyTorchを使用せずにスクリプトに内蔵することで、PyTorchのバージョンとの依存性を断つ工夫をしている。
L1, L2, SmoothL1, Huberの特徴
pred(予測値), target(目標値、教師データ)とするとき*1、便宜上、predとtargetの差を予実差と呼ぶものとします。何を比較するかはツールによって異なりますが、ピクセル毎の比較をする手法が多いです。
下記の特徴はケースバイケースなので、ここでは有名な問題の説明に留めます。
数式や定義は先述のリンクを参照して下さい。
L1 loss
予実差がそのままlossの値になる。
- メリット
- デメリット
- loss=0付近において、急激に勾配は正負反転する。
- 収束することが難しくなる。
- ベースモデルの学習済み情報が消されやすい
- どんな教師データに対しても、学習の進行ペースが比較的一定なので、メジャーな情報ばかり学習しがちで、数の少ない正則化画像が寄与しにくい
- データセットの画像枚数バランスの調整が煩わしくなる
- 学習の順序(画像のstepの順番)、timestep samplingの影響を受ける
- loss=0付近において、急激に勾配は正負反転する。
総じてデリケートな運用が要求される。
MSE(L2) loss
- 予実差の2乗がlossになる。
予実差が大きいと勾配が急速に大きくなり、
予実差が小さいと勾配はとても小さくなる。 - 画像生成AIの基礎論文(DDPM、Flow Matching)で使われている一番基本的なloss。
- メリット
- loss=0付近において、勾配が小さくなるため、限りなくloss=0周辺で収束しやすい。
- 収束しそうなウェイトと、そうでないウェイトに学習の速度差が発生し、特定のウェイトが遅れるということが少ない
- 主線部など面積が狭くても周囲とのコントラストの強い部分の学習が強化されエッジを復元しやすい
- デメリット
- 外れ値(画像のJPEGノイズや、余計な背景など)を拾いやすい
- ただし、正則化画像を準備することで打ち消すことは可能である
- 外れ値(画像のJPEGノイズや、余計な背景など)を拾いやすい
適当な設定でもそこそこ再現性の高い結果が得られるが、
好ましい情報(エッジやマイナータグ)、好ましくない情報(外れ値)の両方を取り入れやすくなるため、それをユーザーがどう判断するかで、評価が変わる。
SmoothL1 loss、Huber loss
- どちらのlossも、L1, L2の良い所をブレンドしたloss。
予実差が少ないときはL2を、予実差が大きいときはL1を使用する。- 特にMES(L2)の弱点を補うことができる。
- L1とL2を切り替えるしきい値を設定して使用する。
- sd-scriptsの場合は、huber_cというパラメータを指定する。
- 両者の違いは、huber_c値の設定によってL1領域(グラフの直線部分)の傾きが変わるか、同じかである。
ただ、sd-scriptsの場合はsmooth_L1しか使えないので、特に意識する必要はない。*図はとしあき自作(Gemini生成画像)
- メリット
- L1,L2のメリットすべて
- 外れ値を除外しやすいため、ベースモデルの特徴を維持しやすい
- デメリット
- 外れ値を除外し過ぎて教師画像が活かされにくくなる。
予実差小のときはL2効果によりブレーキがかかり、予実差大のときはL1効果によりブレーキがかかる、というダブルブレーキ構造が問題。- 結果として、ベースモデルからの脱出が難しくなる。
- c値の設定が面倒
c値を調整するとloss曲線の全体が変化するため、直感的な調整が困難である。- 具体的にはc=0.05, 0.1, 0.2, 1.0といった粗い設定をしない限り変化を実感しにくいにも関わらず、
c値の選択の有無で局所解から脱出可否が大きく左右されるために、c値の設定にもそれなりに厳密さが求められるという困難さがある。 - その難しさを理解するなら、ここで説明するよりも実際に挑戦する方が早い
- 具体的にはc=0.05, 0.1, 0.2, 1.0といった粗い設定をしない限り変化を実感しにくいにも関わらず、
- 外れ値を除外し過ぎて教師画像が活かされにくくなる。
- c値調整
ひとまずcを低めに設定して、もし収束せず不安定ならば、c値を上げてL2特性を強めるようにすると良いかも知れない。
- 補足
sd-scriptsのsmooth_L1は、PyTorchのsmooth_L1と数式の0.5倍になっていて、厳密には同じものではない
- huber_lossに関する情報
どのlossを使えばいいの?
- オプティマイザやLearning rate、loss_weighting*2, 正則化画像との強い相性があるので、ここでの説明は難しい。
それらのどの手段を用いて、収束と学習進行を両立させたいかのトレードオフ。 - とはいえ、L2特性があるのは便利なので、
L2, smooth L1のどちらかを選ぶのが一般的とされている。
評価対象による分類
ピクセル単位での比較ではなく、画像そのものの質を評価する方式
LPIPSなどがあるが、
当wikiでは使用することがないため、省略します。
lossは小さいほど良い? (よくある質問)
半分正解ですが、どちらかと言えば No.
あくまで「1つの指標」と捉えるのがベター、という意見が多いです。
「Yes」である理由
- 学習過程の進行度合い
- 最終的なモデル精度への寄与
- 教師画像の特徴をきちんと反映させたい場合、ある程度lossを小さく抑えることは有効。
- LoRAやHyperNetworkなど、非few‑shot系手法で学習した経験がある人には馴染みがある現象です。
「No」である理由
- lossはモデル性能の一部しか表せていない
- sd-scriptsなどの一般的なトレーニングツールでは、lossとして教師画像と予測値とのズレが数値的に大きいか小さいかしか計測していないことが多い。
- そのズレが人間の知覚特性にとって目立つか目立たないか、プロンプトの効きはどうかといった点は使ってみないとわからない。
- loss=0でも生成結果は完全一致しない
- loss=0は「たまたまそのバッチでドンピシャで予測できた」というだけで、すべての教師画像を網羅できているとは限らない。
- 「lossがほぼ0」は「誤差の絶対値の総和がゼロに近い」だけで、ピクセル単位で一致したわけではない。
またモデルの予測値は「教師画像そのもの」ではなく「教師画像を復元するために削るべきノイズ」であり、さらに生成時にはステップごとに予測誤差が蓄積するので、lossの見た目よりも復元画像は大きくズレることが多い。 - またモデルの予測誤差がわずか1点だけだったとしても、VAEがデコードした際に周囲に伝播する。
- 数ステップでloss≈0.01(1%)に到達しても、その時点の生成物は事前学習モデルの影響が大きく、教師画像の再現には至らないことが多い。
- 過学習の危険
- step数を増やしすぎると、特定層のウェイトが過大・過小になり、汎用性を失ったモデルになる。
- weightはテンソルなので、たとえloss=0でも解は一意に定まらない。
- ランダム要素への脆弱性
- 学習中に理想のweightを得られても、生成時にSeedやノイズが少し変わるだけで想定外の結果(奇形や別画風)になることがある。
- モデル種別が異なるとlossの相場も異なる
- SDXLやSD1.5とFlow Matchingモデルとだと予測ターゲットが異なるので、同じloss評価を使っていても数値の相場も異なる。
一般にFlow Matchingモデルのほうが予測が難しくlossが下がりにくい。
SDXLでもepredとvpredとで差が出る。
- SDXLやSD1.5とFlow Matchingモデルとだと予測ターゲットが異なるので、同じloss評価を使っていても数値の相場も異なる。
- 個々の教師画像x0との比較は勾配を出すための方便であって、モデルの真の学習ターゲットは想定しうるすべてのx0を考慮したうえでの期待値(加重平均)
- Flow Matchingモデルの場合は教師画像x0だけでなく起点画像(生成開始時のノイズに相当)x1についてもあらゆる可能性を考慮したうえでの期待値が学習ターゲットになるので、lossを0にするのは不可能に近い。
- 理想的なモデルであっても、推定される教師画像の候補が2つあってどちらの可能性も半々というときはそのステップでは中間ぐらいの予測値を返せばよく、lossは0にならなくても良い。
- この場合、理想的な学習が行われていればどちらかに寄りすぎるともう片方の教師画像でlossが大きくなるのでどちらにも偏らないように学習される。
- モデルに本当に学習させたいのは生成結果x0が誰にも不明な状況でどう編集すればいいか(ノイズe ∝ -Δxt log pt(xt) ただしpt(xt)は混合分布)だが計算不可能。
- 教師画像x0が(訓練ツールにとっては)既知の状態で、条件付き期待値(ノイズeの期待値 ∝ -E[Δxt log pt(xt|x0) | xt] ただしpt(xt|x0)は正規分布)の推定方法をモデルに学習させることができれば代用できることが数学的に分かっている。
結論
- lossは小さいほど良いが、小さいだけでは不十分。
- 常にloss=0を追い求めると、生成条件をわずかに変えただけで全く応用が効かないモデルになる可能性があります。
- 本来の目標は「lossを下げること」ではなく、その先にある「安定して高品質な汎用モデル」を作ることです。
loss=0にするには(参考)
極端な例として、loss=0にする方法は下記の通り。
これを読めば、いかにloss=0にすることが無意味なことがおわかりいただけると思います。
loss=0になる条件
- バッチ設定
batch_size=1、gradient_accumulation_steps=1 に固定。これ以外だと全画像のlossをゼロにする必要が出る。
- 過去ステップとの統一性度外視
過去のステップや学習済みウェイトの保持を考慮せず、各画像の瞬間的なlossゼロのみを追求。
- ランダム要素の無視
timestep・Seed値・ノイズなどの揺らぎを無視し、常にloss=0を目指す。
- 生成後の崩壊許容
学習後の生成プロセスで一瞬だけ完璧なら、その後の崩壊を無視。
- loss増幅機能使用不可
学習効率化のためのmin_SNR_gammaなどのloss増幅は使わず、lossを小さく抑える方向のみを重視(実質不可能)
