sn42
R&D Job in Japan.
Topics
My Twitter
Jupyter Notebookはこちら
点推定の代わりに**周辺化**によってモデルのハイパーパラメータを評価しましょう。
L個の に対し、あるモデルの不確かさはモデルの事後分布で評価できます。
このとき、を**モデルエビデンス**といい、モデル空間におけるデータの周辺尤度となっています。
はベイズ因子と呼ばれ、仮説検定におけるエビデンスの強さを評価するのに使われています。
事後分布が求まれば、予測分布は以下のように求められます。
①モデルエビデンスの解釈1
パラメータを事前分布からランダムにサンプリングしたときに、観測データが生成する確率。
②モデルエビデンスの解釈2
は、あるパラメーターの最頻値で尖っているとき、
となるので、モデルエビデンスは以下のようになります。
第1項はデータへの適合度を表し、第2項はモデルの複雑さによるペナルティを表しています。
**フルベイズ的**に扱うために、ハイパーパラメータにも事前分布を導入します。
→ すべてのパラメータに対して解析的に周辺化することは難しい。
→ パラメータに関する周辺尤度を最大にするようにハイパーパラメータを決めましょう。
ベイズの定理から なので、を最大にするを求めます。
は**エビデンス関数**と呼ばれます。
と変形できるので、これを最大にするを求めます。
ここで、以前の結果から以下のようにしています。
① について最大化
という固有方程式を考えます。
だから、これは固有値を持つことになるので、
となるので、エビデンス関数のに関する最大値(停留点)は、
右辺はに依存するから、これはの陰関数。→から更新を繰り返して収束させます。
② について最大化
よって、エビデンス関数のに関する最大値(停留点)は、
右辺はに依存するから、これはの陰関数。→から更新を繰り返して収束させます。
以上の手法を Python で実装します。初期値から始めて収束するまで更新を繰り返します。
alpha=1.0
beta=1.0
N = 20
M = 10
tol=1e-4
maxiter=100
ary_mu = np.linspace(0,1,M)
x_real = np.arange(0, 1, 0.01)
y_real = np.sin(2*np.pi*x_real)
x_train = np.linspace(0,1,N)
y_train = np.sin(2*np.pi*x_train) + np.random.normal(0,0.3,N)
def opt(Phi,t,tol,maxiter,alpha,beta):
tmp_lambdas = eigh((Phi.T).dot(Phi))[0]
cnt = 0
while cnt < maxiter:
lambdas = beta * tmp_lambdas
S_ = inv(alpha * np.identity(M) + beta * (Phi.T).dot(Phi))
m_ = beta * (S_.dot(Phi.T).dot(t.T))
alpha_old = alpha
beta_old = beta
gamma = np.sum(lambdas/(alpha+lambdas))
alpha = gamma/np.dot(m_,m_)
beta = (len(t) - gamma) / norm(t - Phi.dot(m_)**2)
if (abs(alpha - alpha_old)<tol)and(abs(beta-beta_old)<tol):
break
cnt += 1
return alpha,beta
def phi(mus, x):
ret = np.array([np.exp(-(x-mu)**2/(2*0.1**2)) for mu in mus])
ret[0] = 1
return ret
def pred(x_train, y_train,alpha,beta,ax):
N = x_train.shape[0]
PHI = np.array([phi(ary_mu,x) for x in x_train]).reshape(N,M)
alpha,beta=opt(PHI,y_train,tol,maxiter,alpha,beta)
S = inv(alpha * np.identity(M) + beta * (PHI.T).dot(PHI))
m = beta * (S.dot(PHI.T).dot(y_train.T))
PHI_real = np.array([phi(ary_mu,x) for x in x_real]).reshape(100,M)
pred_mean = PHI_real.dot(m)
pred_std = np.sqrt(1.0/beta + np.diag(PHI_real.dot(S).dot(PHI_real.T)))
ax.plot(x_train, y_train, 'bo')
ax.plot(x_real, y_real, 'g-')
ax.plot(x_real, pred_mean, 'r-')
ax.fill_between(x_real, pred_mean+pred_std, pred_mean-pred_std, color='pink')
ax.set_xlim(0.0, 1.0)
ax.set_ylim(-2, 2)
ax.set_title('Evidence approximation(alpha={},beta={})'.format(round(alpha,3),round(beta,3)))
f,ax = plt.subplots(1,1,figsize=(6,4))
pred(x_train, y_train,alpha,beta,ax)
データ点の個数によるハイパーパラメータの違いを確認しましょう。データ点が少ない場合は最適化できていません。
alpha=1.0
beta=1.0
N = 20
M = 10
tol=1e-4
maxiter=100
ary_mu = np.linspace(0,1,M)
x_real = np.arange(0, 1, 0.01)
y_real = np.sin(2*np.pi*x_real)
x_train = np.linspace(0,1,N)
y_train = np.sin(2*np.pi*x_train) + np.random.normal(0,0.3,N)
def opt(Phi,t,tol,maxiter,alpha,beta):
tmp_lambdas = eigh((Phi.T).dot(Phi))[0]
cnt = 0
while cnt < maxiter:
lambdas = beta * tmp_lambdas
S_ = inv(alpha * np.identity(M) + beta * (Phi.T).dot(Phi))
m_ = beta * (S_.dot(Phi.T).dot(t.T))
alpha_old = alpha
beta_old = beta
gamma = np.sum(lambdas/(alpha+lambdas))
alpha = gamma/np.dot(m_,m_)
beta = (len(t) - gamma) / norm(t - Phi.dot(m_)**2)
if (abs(alpha - alpha_old)<tol)and(abs(beta-beta_old)<tol):
break
cnt += 1
return alpha,beta
def phi(mus, x):
ret = np.array([np.exp(-(x-mu)**2/(2*0.1**2)) for mu in mus])
ret[0] = 1
return ret
def pred(x_train, y_train,alpha,beta,ax):
N = x_train.shape[0]
PHI = np.array([phi(ary_mu,x) for x in x_train]).reshape(N,M)
alpha,beta=opt(PHI,y_train,tol,maxiter,alpha,beta)
S = inv(alpha * np.identity(M) + beta * (PHI.T).dot(PHI))
m = beta * (S.dot(PHI.T).dot(y_train.T))
PHI_real = np.array([phi(ary_mu,x) for x in x_real]).reshape(100,M)
pred_mean = PHI_real.dot(m)
pred_std = np.sqrt(1.0/beta + np.diag(PHI_real.dot(S).dot(PHI_real.T)))
ax.plot(x_train, y_train, 'bo')
ax.plot(x_real, y_real, 'g-')
ax.plot(x_real, pred_mean, 'r-')
ax.fill_between(x_real, pred_mean+pred_std, pred_mean-pred_std, color='pink')
ax.set_xlim(0.0, 1.0)
ax.set_ylim(-2, 2)
ax.set_title('N={}(alpha={},beta={})'.format(N,round(alpha,3),round(beta,3)))
f,axes = plt.subplots(4,1,figsize=(5,15))
r = np.arange(N)
np.random.shuffle(r)
for i,k in enumerate((1, 2, 5, N)):
indices = np.sort(r[0:k])
pred(x_train[indices], y_train[indices],alpha,beta,axes[i])
は、有効(well-determined)なパラメータの数 を表しています。
をに変化させると、はに変化します。
→ は、の大きさを制御し、はデータに制約されるパラメータの数を表しています。
→ のとき(データ数がとても多い時)、すべてのがwell-determinedとなります。
基底関数を固定する欠点:次元の呪い
一般的には、データ集合に助けられています。