入力を,出力をとする.分類問題と違って,の定義の仕方に工夫が必要.例えば以下のようにを定義する.
ただし,.そうすると,
で不正解となる.分類問題と同じ代理損失が使える.
これは,-insensitive lossと呼ばれる.
Written with StackEdit.
入力をx∈X,出力をy∈{−1,1}とする.f(x)≥0のときは正例と,f(x)<0のときは負例と予測する分類器を考える.m=yf(x)とすると,m≥0のとき正解で,m<0のとき,不正解となる.不正解のときは1を,正解の時は0になるような損失関数を以下のように定義する.
I[m<0]
ただし,Iは指示関数である.有名な損失関数として,hinge lossや,exponential lossがある.
ℓhingeℓexp=max{0,1−m}=exp(−m)
流れ的には,目的関数を指示関数を使って上のように定義して,代理損失で置き換えるって感じかな.
Written with StackEdit.
ヒンジ損失の劣勾配を求めようと思う.と言っても,[1]のPointwise maximumのテクニックを使えば一発なのだが.まずはこれを示そう.以下の関数を考える.
f(x)=i=1,…,mmaxfi(x)
あるxに対して,f(x)=fk(x)だったとする.g∈∂fk(x)とする.
f(y)≥fk(y)≥fk(x)+gT(y−x)=f(x)+gT(y−x)
より,g∈∂f(x)である.
以下で定義されるヒンジ損失を考える.
ℓhinge(w)=max{0,1−ywTx}
上記の事実を踏まえると,
g={0d−yx(1−ywTx≥0)(1−ywTx<0)
となる.
Written with StackEdit.
前にL1-Normの劣微分
について書いたが,間違っていたので修正.
[1]のPointwise maximumの項に書いてあるテクニックを使う.x∈Rdとして,∥x∥1を以下のように表す(結構感動的).
f(x)=∥x∥1=max{sTx∣s∈{−1,1}d}
xに対して,∥x∥1=sTxとなったとする.この時,sは以下のようになる.
sj=⎩⎨⎧1−1−1 or 1(xj>0)(xj<0)(xj=0)
sTxのsubgradientをgとすると,g∈∂f(x)である.最後に,g=sである.
参考:
Written with StackEdit.
今回は劣勾配法を使って,L1正則化最小二乗学習(Lasso)を実装してみたいと思う.最適化問題を,以下のように定義する.
wmin 21i=1∑n(yi−wTxi)2+λ∥w∥1
第一項はwjで微分可能なので,その勾配を使い,第二項は列勾配を使う.これで更新式を出すと,
wj←wj−η(−i=1∑n(yi−wTxi)xij+λsgn(wj))
となる.まとめると,
w←w−η(−XT(y−Xw)+λsgn(w))
となる.これを実装したクラスが以下.
class Lasso(object):
def __init__(self, eta=1e-4, reg=1, max_iter=1000):
self.eta = eta
self.reg = reg
self.max_iter = max_iter
def fit(self, X, y):
w = np.zeros(X.shape[1])
for _ in range(self.max_iter):
g = - X.T.dot(y - X.dot(w)) + self.reg * np.sign(w)
w = w - self.eta * g
self.w = w
return self
def predict(self, X):
return X.dot(self.w)
1次元で実験してみる.
import numpy as np
import matplotlib.pyplot as plt
random_state = 0
rnd = np.random.RandomState(random_state)
n, d = 100, 2
sigma = 0.5
x = np.linspace(-2, 2, n)
y = x + rnd.normal(0, sigma, size=n)
model = Lasso()
model.fit(np.c_[x], y)
y_pred = model.predict(np.c_[x])
plt.scatter(x, y)
plt.plot(x, y_pred, "r-", linewidth=3)
結果は以下.きちんと学習されているっぽい.
次にL1正則化を施したことにより,解がスパースになることを確認するために,100次元のデータで実験する.コードは例えば以下.
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
X, y = make_regression(n_samples=500, n_features=100, n_informative=10, random_state=random_state)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=random_state)
model = Lasso()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(np.sqrt(mean_squared_error(y_test, y_pred))) # 0.008980784567524594
きちんと解がスパースになっていることを確認してみる.例えば,
np.around(model.w, 3)
とすると,
array([ 0. , -0. , -0. , 0. , -0. , 0. , 0. , -0. ,
-0. , 0. , 0. , -0. , 0. , 0. , -0. , -0. ,
0. , 0. , -0. , 0. , 0. , -0. , 99.673, 0. ,
0. , -0. , 0. , 0. , -0. , 0. , 41.788, 0. ,
-0. , -0. , 0. , -0. , 0. , -0. , 0. , -0. ,
-0. , 74.23 , -0. , 0. , 0. , 0. , 0. , 0. ,
-0. , -0. , 0. , -0. , 0. , 0. , 0. , 0. ,
-0. , -0. , 0. , -0. , 0. , 37.469, -0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , -0. , -0. ,
30.374, 44.89 , 0. , 50.938, 0. , 0. , -0. , -0. ,
-0. , 0. , 0. , 98.669, -0. , 0. , 27.71 , 0. ,
0. , -0. , -0. , -0. , -0. , 86.562, -0. , 0. ,
-0. , -0. , 0. , 0. ])
となって,n_informativeの数だけ非ゼロになっている.
Written with StackEdit.
機械学習の問題設定 機械学習の問題設定を見直したのでメモ. ( Ω , F , P ) (\Omega, \mathcal{F}, P) ( Ω , F , P ) : ベースとなる確率空間 ( X , F X ) (\mathcal...