パーセプトロンで単純な識別の実験をし、そこでは訓練データが与えられたとき、
で表されるモデルを考えました。線形に識別できる問題しか扱えず、応用が効かなさそうですが、入力を非線形変換をした
を考えると柔軟な識別が可能になります。
実験してみました。
ここでは、入力をとしたとき、のような変換としています。曲線で分離されるような分布もきちんと識別できてますね。
よく線形分離不可として例にあげられるような以下の点も識別することができました。
パーセプトロンの記事で書きましたが、↓こちらの理解が合っているのかあまり自信がない。
しかし入力を非線形変換すれば、パーセプトロンのアルゴリズムで曲線の識別もできます。(参考:入力を非線形変換したパーセプトロン) 、、っと僕は理解しているのですが、あまりこのことに言及している説明を見たことがありません。僕が何か誤解しているのでしょうか?あるいは、線形分離可能な問題しか扱えないのは単純パーセプトロンであって、入力を非線形変換するということは、多層パーセプトロンに相当し、これであれば分離可能であるということでしょうか。
今回のコードです。
# 入力を非線形変換したパーセプトロン import matplotlib.pyplot as plt import numpy as np from matplotlib import cm # クラス分け def create_data(x0, x1): if (x0-0.5)**2 + 0.5*x1**2 - 1 > 0: return -1.0 else: return 1.0 # 識別結果を返す def f(x0, x1): if np.dot(w.T, phi(x0, x1)) > 0: return -1.0 else: return 1.0 # 非線形変換 def phi(x0, x1): return np.array([x0**2, x1**2, x0*x1, x0, x1, 1]) # 全データ数 N = 300 # 入力次元数 D = 2 # クラス数 K = 2 # 学習率 Eta = 0.1 # ランダムシードを固定 np.random.seed(0) # 2クラス分のデータを作成 x = np.random.uniform(-2, 2, [D, N]) t = np.empty([N]) t = np.vectorize(create_data)(x[0, :], x[1, :]) # 重みベクトルwを初期化 # Φ(x) = x0^2 + x1^2 + x0x1 + x0 + x0 + 1 とする(求める係数は6個) w = np.random.uniform(-1, 1, 6) # データを非線形変換する phi_x = np.array([phi(x[0, i], x[1, i]) for i in range(N)]) # 全データに対して更新処理を行い、誤りがなくなるまで繰り返す while True: # 更新処理の順をランダムで決める index = np.random.permutation(np.arange(0, N, 1)) break_flag = True # 更新処理 for i in range(N): if t[index[i]] * np.dot(w.T, phi_x[index[i], :]) < 0: w = w + Eta * t[index[i]] * phi_x[index[i], :] break_flag = False if break_flag: break plt.xlim(-2, 2) plt.ylim(-2, 2) # グラフの色分け a, b = np.meshgrid(np.linspace(-2, 2, 1000), np.linspace(-2, 2, 1000)) vec_f = np.vectorize(f) plt.contourf(a, b, vec_f(a, b), alpha=0.2, cmap=cm.coolwarm) plt.scatter(x[:,np.where(t==1)][0], x[:,np.where(t==1)][1], color="blue", alpha=0.5) plt.scatter(x[:,np.where(t==-1)][0], x[:,np.where(t==-1)][1], color="red", alpha=0.5) plt.show()