Widrow-Hoffの学習規則

データの完全な分離ができない場合、
誤差を最小にするように、識別関数の重みベクトルを計算する。

(定式化)
教師信号 b_iと識別関数の値の差を誤差 \epsilon_{ip}と定義
 \epsilon_{ip} = g_i (x_p) - b_i
この誤差の2乗和を考える
 J_p = \frac{1}{2} \sum_{i=1}^c \epsilon_{ip}^2 = \frac{1}{2} \sum_{i=1}^c (g_i (x_p) - b_i)^2 = \frac{1}{2} \sum_{i=1}^c (\mathbf{w_i}^t \mathbf{x_p} - b_i)^2
これについて、すべての学習パターンについて総和をとる。
 J= \sum_{p=1}^n  J_p = \frac{1}{2} \sum_{p=1}^n \sum_{i=1}^c (\mathbf{w_i}^t \mathbf{x_p} - b_i)^2

やることは、このJを最小にする重みベクトルの計算。
最急降下法を用いると、更新式は

 \mathbf{w_i} ' = \mathbf{w_i} - \rho \frac{\partial J}{\partial \mathbf{w_i}} だから、
 \mathbf{w_i} ' = \mathbf{w_i} - \rho \sum_{p=1}^n (\mathbf{w_i}^t \mathbf{x_p} - b_i) \mathbf{x_p}

# coding: utf-8

import numpy as np
import matplotlib.pyplot as plt
from pylab import *

# サンプルデータの生成(2次元正規分布)
mean1 = [0,0]; cov1 = [[4,0],[0,100]]; N1 = 1000
X1 = np.random.multivariate_normal(mean1,cov1,N1)
mean2 = [30,-30]; cov2 = [[1,20],[20,50]]; N2 = 1000
X2 = np.random.multivariate_normal(mean2,cov2,N2)
X = np.concatenate((X1,X2))
# 描画
x,y = X.T
plt.plot(x,y,'k.'); plt.axis('equal'); #plt.show()

#識別関数 g(x,y)=w0 + w1*x + w2*y
#初期値
w0 = 60
w1 = 4
w2 = -1.0
rho = 0.00001

#Widrow-Hoffの学習規則を適用
i=0
for k in range(100):
    sum0 = 0
    sum1 = 0
    sum2 = 0
    for p in range(2000):
        dot = w0*1 + w1*X[p][0] + w2*X[p][1]
        #print X[p][0]
        if p < 1000:
            sum0 += (dot - 1) * 1.0
            sum1 += (dot - 1 ) * X[p][0]
            sum2 += (dot - 1) * X[p][1]
        else:
            sum0 += dot * 1.0
            sum1 += dot * X[p][0] 
            sum2 += dot *X [p][1]
        w0 = w0 - rho * sum0
        w1 = w1 - rho * sum1
        w2 = w2 - rho * sum2
    print w0,w1,w2


#得られた線形識別関数を描画
xsamp = linspace(-20,60,1000)
ysamp = -1.0*w1/w2 * xsamp -1.0 * w0/w2
plt.plot(xsamp,ysamp)
plt.show()

実行結果

どうやら最急降下法のコードが間違ってるらしい。

勘違いしてるところを書き直した。

# coding: utf-8

import numpy as np
import matplotlib.pyplot as plt
from pylab import *

# サンプルデータの生成(2次元正規分布)
mean1 = [0,0]; cov1 = [[4,0],[0,100]]; N1 = 1000
X1 = np.random.multivariate_normal(mean1,cov1,N1)
mean2 = [30,-30]; cov2 = [[1,20],[20,50]]; N2 = 1000
X2 = np.random.multivariate_normal(mean2,cov2,N2)
X = np.concatenate((X1,X2))
# 描画
x,y = X.T
plt.plot(x,y,'k.'); plt.axis('equal'); #plt.show()

#識別関数 g(x,y)=w0 + w1*x + w2*y
#初期値
w0 = 60
w1 = 4
w2 = -1.0
rho = 0.0008

#Widrow-Hoffの学習規則を適用

#ある点xiにおける識別関数 g(x,y)
#gi = w0 + w1*X[i][0] + w2*X[i][1]
#誤差の和


for p in range(2000):
    gi = w0 + w1*X[p][0] + w2*X[p][1]
    sum_gi_0 = 0
    sum_gi_1 = 0
    sum_gi_2 = 0
    #0<p<1000のとき gi-1
    if p < 1001:
        sum_gi_0 += (gi-1)
        sum_gi_1 += (gi-1)*X[p][0]
        sum_gi_2 += (gi-1)*X[p][1]
    #1000<p<2000のとき gi
    if p > 1000:
        sum_gi_0 += gi
        sum_gi_1 += gi *X[p][0]
        sum_gi_2 += gi *X[p][1]
    w0 = w0 - rho * sum_gi_0
    w1 = w1 - rho * sum_gi_1
    w2 = w2 - rho * sum_gi_2
print w0,w1,w2


#得られた線形識別関数を描画
xsamp = linspace(-20,60,1000)
ysamp = -1.0*w1/w2 * xsamp -1.0 * w0/w2
plt.plot(xsamp,ysamp)
plt.show()

実行結果

こんなもんなのかな。