深層学習

L1とL2ペナルティ

L1とL2の勾配・更新則の違いを、ゼロに止まる挙動と weight decay の実装まで結び付けて整理します。

  • B|標準
  • 深層学習

数式の記号で止まったら 記号の読み方 (∂・⊙・転置・上付き添字を、読み方から)

ひとことで言うと

L1ペナルティは重みの絶対値を、L2ペナルティは重みの二乗を損失に加えます。同じ「重みを小さくする」処理でも、L1は小さい重みをゼロへ押し込み、L2は全体を滑らかに縮める点が実装上の分岐です。

L1は細い枝を根元から切る剪定、L2はすべての枝を同じ比率で短くする剪定です。どちらも木を小さくしますが、残る枝の本数は同じになりません。

なぜ必要か

損失を J(θ)J(\theta)、パラメータを θ\theta、係数を λ>0\lambda>0 とすると、目的関数はデータ損失にペナルティを足した形になります。L1とL2では勾配の形が違うため、同じ学習率・同じ λ\lambda でも更新の軌跡が変わります。

実装では、L2ペナルティを optimizer の weight_decay として指定することが多く、「損失に足す場合」と「optimizerが勾配に項を足す場合」を同じ更新則で読めることが必要です。

見る対象L1L2
更新を決める量符号(ゼロでは劣勾配)重みそのもの
典型的な結果ゼロが生じる非ゼロのまま縮む

仕組み

L1とL2を次のように定義します。θi\theta_i はパラメータの第 ii 成分、JJ はデータ損失、λ\lambda は罰則の強さです。

JL1(θ)=J(θ)+λ∑i∣θi∣,JL2(θ)=J(θ)+λ2∑iθi2J_{L1}(\theta)=J(\theta)+\lambda\sum_i|\theta_i|,\qquad J_{L2}(\theta)=J(\theta)+\frac{\lambda}{2}\sum_i\theta_i^2

L2では微分がそのまま λθi\lambda\theta_i になるため、通常のSGD(学習率を η\eta、データ損失の勾配を gig_i とします)は次になります。

θi←θi−η(gi+λθi)=(1−ηλ)θi−ηgi\theta_i\leftarrow\theta_i-\eta(g_i+\lambda\theta_i) =(1-\eta\lambda)\theta_i-\eta g_i

データ勾配がゼロなら、毎回 1−ηλ1-\eta\lambda 倍です。これが weight decay と呼ばれる理由です。ただし momentum や AdamW では更新の解釈が変わるため、試験ではまず「勾配に λθ\lambda\theta を加えるSGD」の条件を確認します。

L1の微分はゼロで連続ではありません。θi≠0\theta_i\ne0 では符号関数 sign⁡(θi)\operatorname{sign}(\theta_i)、ゼロでは劣勾配 si∈[−1,1]s_i\in[-1,1] を使います。

∂∣θi∣={{+1}θi>0{−1,1}θi=0{−1}θi<0\partial|\theta_i|=\begin{cases}\{+1\}&\theta_i>0\\ \{-1,1\}&\theta_i=0\\ \{-1\}&\theta_i<0\end{cases}

そのためゼロ付近では、データ損失の勾配がこの範囲に収まると更新をゼロで止められます。L2は非ゼロの重みをゼロにしにくく、L1は疎なパラメータを作りやすい差があります。バイアス項は入力に依存しないオフセットで重みとは役割が違うため、通常は罰則から外します。

試験でどう問われるか

問われ方正解に寄る条件引っかけ
L1とL2の勾配を比較L1は符号、L2は重みに比例L1の勾配を常に重みそのものとする
L2の更新則を読むg+λθg+\lambda\theta を学習率で更新し、勾配ゼロなら一定割合で縮む毎回一定量を引くとする
ゼロの扱いL1はゼロで劣勾配を選び、ゼロに止まり得るゼロでも通常の微分値が一意にあるとする
罰則の対象を選ぶ通例は重みだけで、バイアスを除外全パラメータへ必ず同じ罰則をかける

実装で確かめる

データ損失の勾配をゼロに固定し、L2の割合縮小とL1の更新をNumPyで確認します。ゼロで選ぶ劣勾配も明示します。

import numpy as np

theta = np.array([2.0, -1.0, 0.0])
eta, lam = 0.1, 0.2
l2 = theta - eta * (lam * theta)
assert np.allclose(l2, (1 - eta * lam) * theta)

subgrad = np.sign(theta)
subgrad[2] = 0.0  # ゼロで選ぶ劣勾配
l1 = theta - eta * lam * subgrad
assert np.allclose(l1, [1.98, -0.98, 0.0])
print(l2, l1)

取り違えやすいもの

用語切り分け
L1ペナルティ符号を使う。ゼロ解・疎性が生じやすい
L2ペナルティ重みに比例する勾配。SGDでは weight decay と同じ形で読める
weight decay実装上の呼び名。単純SGDではL2型の勾配項として現れる
バイアスの更新入力に依存しないオフセット。通常はL1/L2の対象外

想起チェック

L2のデータ勾配がゼロのとき、1回の更新で重みはどうなるか

θ\theta は 1−ηλ1-\eta\lambda 倍になります。一定量を引くのではなく、現在値に比例して縮みます。

L1で重みがゼロに止まり得る理由は何か

ゼロでの劣勾配が [−1,1][-1,1] の範囲を持つためです。データ損失側の勾配を相殺する値を選べます。

バイアスを通常は正則化しない理由は何か

バイアスは入力に依存しない全体のオフセットで、重みとは役割が違うためです。

出典