PRML3章(1)線形回帰モデルと最尤推定

最終更新日: 2020年5月28日

Jupyter Notebookはこちら


回帰の目的 …… データ集合{xi}\{x_i\}から目標{ti}\{t_i\}を予測します。

線形基底関数モデル

単純にxix_iについて線形結合するのは「線形回帰」と呼ばれます。

y(x,w)=w0+w1x1+...+wDxDy(\vec{x},\vec{w}) = w_0 + w_1x_1 + ... + w_Dx_D

ここでは、xix_i について**非線形な関数の線形結合**を考えましょう。

y(x,w)=w0+j=1M1wjϕj(x)y(\vec{x},\vec{w}) = w_0 + \sum_{j=1}^{M-1}w_j \phi_j (\vec{x})

これは、パラメータwwについての線形結合なので「線形モデル」となります!

w0w_0は鬱陶しいので、ϕ0(x)=1\phi_0(\vec{x}) = 1 とすれば、

y(x,w)=wTϕ(x) y(\vec{x},\vec{w}) = \vec{w}^T \vec{\phi} (\vec{x})

ただし、

x=(x0xD)w=(w0wM1)ϕ=(ϕ0ϕM1) \vec{x} = \left(\begin{array}{c} x_0 \\ \vdots \\ x_D \\ \end{array}\right) \quad \vec{w} = \left(\begin{array}{c} w_0 \\ \vdots \\ w_{M-1} \\ \end{array}\right) \quad \vec{\phi} = \left(\begin{array}{c} \phi_0 \\ \vdots \\ \phi_{M-1} \\ \end{array}\right) \quad

とします。w0w_0は「バイアスパラメータ」、ϕj(x)\phi_j(\vec{x})は「基底関数」と呼びます。


基底関数の例

  1. ガウス基底関数

ϕj(x)=exp{(xμ)22s2}\phi_j (\vec{x}) = \exp \{-\frac{(x-\mu)^2}{2s^2}\}

  1. シグモイド基底関数

ϕj(x)=11+exp(xμjs)=σ(xμjs)\phi_j (\vec{x}) = \frac {1}{1+\exp(\frac{x-\mu_j}{s})} = \sigma(\frac{x-\mu_j}{s})

  1. フーリエ基底関数

ϕj(x)=exp(jnkx)\phi_j (\vec{x}) = \exp(jnkx)

Gaussian Basis function

import numpy as np

def GBF(x,m,s):
    return np.exp(-(x - m)**2/(2*(s)**2))

gaussian.png

Sigmoid Basis fuction

import numpy as np

def SBF(x,m,s):
    return 1 / (1 + np.exp(-(x-m)/s))

sigmoid.png

最尤推定:最小二乗法で尤もらしい回帰モデルを推定しよう

t=y(x,w)+ε=(決定論的関数)+(ガウスノイズ) t = y(\vec{x},\vec{w}) + \varepsilon = (決定論的関数) + (ガウスノイズ)

目標変数 tt は決定論的関数とガウスノイズの和で表されるとしましょう

εN(ε0,β1)\varepsilon \sim \mathcal{N}(\varepsilon |0,\beta^{-1})、つまりガウスノイズは平均 00 分散 β1\beta^{-1} の正規分布に従うので、

p(tx,w,β)=N(ty(x,w),β1)p(t|\vec{x},\vec{w},\beta) = \mathcal{N}(t|y(\vec{x},\vec{w}),\beta^{-1})

と表されます。また、新たなxnew\vec{x_{new}}に対する予測値は、ttの条件付き期待値で与えられて、

E[txnew]=tp(txnew)dt=y(xneww)\mathbb{E}[t|\vec{x_{new}}] = \int t p(t|\vec{x_{new}})dt = y(\vec{x_{new}}|\vec{w})

つまり、予測値はxnew\vec{x_{new}}を**決定論的関数に代入する**ことで得られます

次に、データ集合を考えます。

Data={x1,,xN},t=(t1,...,tN)Data = \{\vec{x_1}, \ldots ,\vec{x_N}\}, \vec{t} = (t_1,...,t_N) とするとき、

p(tData,w,β)=n=1NN(tnwTϕ(xn),β1) p(\vec{t}|Data,\vec{w},\beta) = \prod_{ n = 1 }^N \mathcal{N}(t_n|\vec{w}^T\vec{\phi}(\vec{x_n}),\beta^{-1})
 lnp(tw,β)=n=1NlnN(tnwTϕ(xn),β1)        =N2lnβN2ln(2π)βED(w)\therefore \ \ln p(\vec{t}|\vec{w},\beta) = \sum_{ n = 1 }^N \ln \mathcal{N}(t_n|\vec{w}^T\vec{\phi}(\vec{x_n}),\beta^{-1}) \\          = \frac{N}{2}\ln\beta - \frac{N}{2}\ln(2\pi)-\beta E_D(\vec{w})

ただし、最小二乗誤差は、ED(w)=12n=1N{tnwTϕ(xn)}2E_D(\vec{w})=\frac{1}{2} \sum_{n=1}^N\{t_n - \vec{w}^T\vec{\phi}(\vec{x_n})\}^2です。

最尤推定をするために、対数尤度 lnp(tw,β)\ln p(\vec{t}|\vec{w},\beta)w\vec{w} について最大化します

w\vec{w} に依存するのは ED(w)E_D(\vec{w}) だけなので、これを最小化すればよいでしょう。

lnp(tw,β)=0 βn=1N{tnwTϕ(xn)}ϕ(xn)T=0 n=1NtnϕTwT(n=1NϕϕT)=0 wML=(n=1NϕϕT)1n=1Nϕ tn\nabla \ln p(\vec{t}|\vec{w},\beta) = 0 \\ \therefore \ \beta \sum_{n=1}^N \{ t_n - \vec{w}^T\vec{\phi}(\vec{x_n}) \}\vec{\phi}(\vec{x_n})^T = 0 \\ \therefore \ \sum_{n=1}^N t_n \vec{\phi}^T - \vec{w}^T(\sum_{n=1}^N\vec{\phi} \cdot \vec{\phi}^T) = 0 \\ \therefore \ \vec{w_{ML}} = (\sum_{n=1}^N\vec{\phi} \cdot \vec{\phi}^T)^{-1}\sum_{n=1}^N\vec{\phi} \ t_n \\

これは、**正規方程式**と呼ばれ、計画行列 Φ\Phi ・ペンローズの疑似逆行列 Φ\Phi^\dagger を用いて表すことができます。

wML=(ΦTΦ)1ΦTt=Φt \vec{w_{ML}} = (\Phi^T\Phi)^{-1}\Phi^T\vec{t} = \Phi^\dagger \vec{t}

ただし、計画行列 Φ\Phi は以下のように定義します。

Φ=(ϕ1(x1)ϕM1(x1)ϕ1(xN)ϕM1(xN))\Phi = \left( \begin{array}{ccc} \phi_1(\vec{x_1}) & \ldots & \phi_{M-1}(\vec{x_1})\\ \vdots & \ddots & \vdots \\ \phi_1(\vec{x_N}) & \ldots & \phi_{M-1}(\vec{x_N}) \end{array} \right)

サイン関数+ノイズによって生成されたサンプルに対し最尤推定をしましょう。Pythonによる実装は以下です

import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import inv
from ipywidgets import interact

# 基底関数の実装
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 solve(mus,x_train,y_train,N,m):
    # 計画行列(3.16式)の計算
    PHI = np.array([phi(mus,x) for x in x_train]).reshape(N,m)
    # 最尤推定解(3.15式)の計算
    w_ml = inv(PHI.transpose().dot(PHI)).dot(PHI.transpose()).dot(y_train)
    return w_ml

# 真の関数はsin()
x_real = np.arange(0, 1, 0.01)
y_real = np.sin(2*np.pi*x_real)

@interact(M=(2,10))
def plot(M):
    ary_mu = np.linspace(0,1,M)

    f,ax = plt.subplots(1,3,figsize=(10,3))

    for i,N in enumerate([10,20,30]):
        ax[i].plot(x_real,y_real,'g-')

        x_train = np.linspace(0,1,N)
        y_train = np.sin(2*np.pi*x_train) + np.random.normal(0,0.3,N)
        ax[i].scatter(x_train,y_train,)

        w_ml = solve(ary_mu,x_train,y_train,N,M)

        x_range = np.linspace(0,1,100)
        ax[i].plot(x_range,[phi(ary_mu,x).dot(w_ml) for x in x_range],'r-')
        ax[i].set_title('N={}'.format(N))

linear_regress.png


バイアスパラメータ w0w_0 の役割

ED(w)E_D(\vec{w})w0w_0について最大化してみます。w0w_0を明示すると、

ED(w)=12n=1N{tnw0j=1M1wjϕj(xn)}2E_D(\vec{w})= \frac{1}{2} \sum_{n=1}^N\{t_n - w_0 - \sum_{j=1}^{M-1}w_j \phi_j (\vec{x_n})\}^2

となるので、EDw0=0\frac{\partial E_D}{\partial w_0} = 0 としたとき、

w0=1Nn=1Ntnj=1M1(wj1Nn=1Nϕj(xn))=tˉj=1M1wjϕjˉw_0 = \frac{1}{N} \sum_{n=1}^N t_n - \sum_{j=1}^{M-1} (w_j \frac{1}{N} \sum_{n=1}^N \phi_j (\vec{x_n})) \\ = \bar{t} - \sum_{j=1}^{M-1} w_j \bar{\phi_j}

と表されます。したがって、

w0=(目標値の平均)(基底の平均の重み付き線形和)w_0 = (目標値の平均) - (基底の平均の重み付き線形和)

となるため、w0w_0 はこの2つの差を埋める働きをしていることがわかります


ノイズの精度 β\beta の役割

同様に、EDβ=0\frac{\partial E_D}{\partial \beta} = 0 としたとき、

1βML=1Nn=1N{tnwMLTϕ(xn)}2\frac{1}{\beta_{ML}} = \frac{1}{N}\sum_{n=1}^N\{t_n-\vec{w_{ML}}^T\vec{\phi}(\vec{x_n})\}^2

と表されます。したがって、

1βML=(残差の分散)\frac{1}{\beta_{ML}} = (残差の分散)

となるため、β\beta は残差の精度を表していることがわかります


最小二乗法の意味

回帰関数は、M個の基底関数によって作られるM次元空間上の点となります。

よって、最小二乗誤差は、

ED=12(t1tN)(y(x1,w)y(xN,w))2E_D = \frac{1}{2} \left\|{ \left(\begin{array}{c} t_1 \\ \vdots \\ t_N \\ \end{array}\right) - \left(\begin{array}{c} y(\vec{x_1},\vec{w}) \\ \vdots \\ y(\vec{x_N},\vec{w}) \\ \end{array}\right)} \right\|^2

と表され、目標値と回帰関数の**M次元空間上のユークリッド距離**となります


逐次学習(オンライン学習)

大規模データの時は、一つずつデータを使ってパラメータを更新していくことが多いです。

このときの更新式は、

w(t+1)=w(t)+ηEn\vec{w}^{(t+1)} = \vec{w}^{(t)} + \eta\nabla E_n

とすればよいでしょう。この手法は、確率的勾配化法とも呼ばれています。

正則化最小二乗法

ΦTΦ\Phi^T\Phi が非正則に近いとき、逆行列が計算しにくくなり正規方程式が不安定となってしまいます。

これを防ぐために、誤差関数に正則化項を追加して正規性を保つようにすることがあります

二乗誤差では、

E=12n=1N{tnwTϕ(xn)}2+λ2wwTE = \frac{1}{2} \sum_{n=1}^N\{t_n - \vec{w}^T\vec{\phi}(\vec{x_n})\}^2 + \frac{\lambda}{2} \vec{w} \cdot \vec{w}^T

という誤差を代わりに用います。このときの最尤推定値は、

wML=(λI+ΦTΦ)1ΦTt \vec{w_{ML}} = (\lambda I + \Phi^T\Phi)^{-1}\Phi^T\vec{t}

となります。この手法は「荷重減衰」や「パラメータ縮小推定」と呼ばれています。

前回の手法に正則化項を加えましょう。Pythonによる実装は以下です

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 solve(mus,x_train,y_train,N,m,l_):
    PHI = np.array([phi(mus,x) for x in x_train]).reshape(N,m)
    # 正則化項を加える
    w_ml = inv(l_*np.identity(m)+PHI.transpose().dot(PHI)).dot(PHI.transpose()).dot(y_train)
    return w_ml

x_real = np.arange(0, 1, 0.01)
y_real = np.sin(2*np.pi*x_real)

@interact(M=(2,10),l=(10,100))
def plot(M,l):
    ary_mu = np.linspace(0,1,M)
    l *= 0.01

    f,ax = plt.subplots(1,3,figsize=(10,3))

    for i,N in enumerate([10,20,30]):
        ax[i].plot(x_real,y_real, 'g-')

        x_train = np.linspace(0,1,N)
        y_train = np.sin(2*np.pi*x_train) + np.random.normal(0,0.3,N)
        ax[i].scatter(x_train,y_train,)

        w_ml = solve(ary_mu,x_train,y_train,N,M,l)

        x_range = np.linspace(0,1,100)
        ax[i].plot(x_range,[phi(ary_mu,x).dot(w_ml) for x in x_range],'r-')
        ax[i].set_title('N={}'.format(N))

regu_regress.png


Reference

  • Bishop, Christopher M. Pattern recognition and machine learning. springer, 2006.