感知機(perceptron)是二類分類的線性分類模型,其輸入時實例的特徵向量,輸出爲實例的類別。取值爲+1和-1。
感知機模型
定義:假設輸入空間(特徵空間)是Χ∈Rn(n維歐式空間),輸出空間是Y={1,-1}。輸入x∈X表示實例的特徵向量,對應於輸入空間(特徵空間)的點;輸出y∈Y表示實例的類別。由輸入空間到輸出空間的映射如下:稱爲感知機。其中w∈Rn叫做權值,b∈R(實數)表示偏置。
感知機的學習策略
數據集
感知機訓練的前提是訓練集中的實例點都是線性可分的。
定義:給定一個數據集T={(x1,y1),(x2,y2),(x3,y3),……,(xn,yn)} 其中xi∈X=Rn (xi爲向量不能理解爲實數)yi∈Y={+1,-1}。
感知機訓練的目的是找到一個能將訓練集中的正實例點和負實例點完全分開的超平面。即確定感知機參數w,b的值。感知機所採用的學習策略是將經驗損失極小化。將誤分類點到超平面S的距離之和極小化。
Rn空間中x0點到超平面的距離: (類比點到直線距離)。因此對於誤分類點(xi,yi)來說所以xi點到超平面的距離s爲:。
假設誤分類點的集合爲M,那麼所有的誤分類點到超平面s的總的距離爲:
其中xi∈M。
感知機損失函數定義:
給定訓練數據集T={(x1,y1),(x2,y2),(x3,y3),……,(xn,yn)},xi∈X=Rn,yi∈Y={+1,-1},i=1,2,3……,N 感知機損失函數定義爲:(w,b)= 其中xi∈M。(說明1/||w||是常數,定義損失函數時不考慮)M是誤分類點的集合,這個損失函數就是感知機學習的經驗分險函數。顯然如果沒有誤分類點,損失函數的數值是0,誤分類點越少,誤分類函數的值就越小。損失函數(w,b)是連續可導函數。
感知機學習算法
感知機學習的目是求參數w,b使其爲以下損失函數極小化問題的解: 其中xi∈M,並且損失函數時關於w,b的函數。在極小化的過程中不是一次使用M中所有的誤分類點的梯度下降,而是一次隨機選取一個誤分類點使其梯度下降。損失函數的梯度:由▽w,▽b 給出:w ←w+η ,b←b+η 其中η是學習率。
原始感知機的代碼實現:(github鏈接:https://github.com/sparrowljq/StatisticalLearningMethod.git)
#原始感知機代碼 | |
import numpy as np | |
import matplotlib.pyplot as plt | |
# 輸入三個點x1(3,3)、x2(4,3)、x3(1,1)其中x1,x2爲正實例點,x3爲負實例點 | |
p_x = np.array([[3, 3], [4, 3], [1, 1]]) | |
y = np.array([1, 1, -1]) | |
# 繪製初始點 | |
for i in range(len(p_x)): | |
if y[i] == 1: | |
# r表示紅色 o表示圓點 | |
plt.plot(p_x[i][0], p_x[i][1], 'ro') | |
else: | |
# b表示藍色 o表示圓點 | |
plt.plot(p_x[i][0], p_x[i][1], 'bo') | |
# w超平面的法向量,b是超平面的截距,delta是指的是學習率 | |
w = np.array([0, 0]) | |
b = 0 | |
delta = 1 | |
for i in range(100): | |
choice = -1 | |
for j in range(len(p_x)): | |
# dot函數表示向量點積 | |
if y[j] != np.sign(np.dot(w, p_x[j]) + b): | |
choice = j | |
break | |
# 表示三個點都被正確分類 | |
if choice == -1: | |
break | |
w = w + delta * y[choice] * p_x[choice] | |
b = b + delta * y[choice] | |
line_x = [0, 10] | |
line_y = [0, 0] | |
print(w[1]) | |
# 超平面表達式爲wx+b=0 其中w爲向量 w1x1+w2x2+b=0 x2=(-w1x1-b)/w2 | |
for i in range(len(line_x)): | |
line_y[i] = (-w[0] * line_x[i] - b) / w[1] | |
print(line_y) | |
plt.plot(line_x, line_y) | |
plt.savefig("picture.png") | |
plt.show() |
對偶感知機:
對偶形式
對偶形式的基本想法是,將 w 和 b 表示爲是咧 xi 和標記 yi的線性組合的形式,通過求解其係數而得到 w 和 b。
w←w+ηyixi
b←b+ηyi
逐步修改 w,b,設修改 n 次,則 w,b 關於(xi,yi)(的增量分別是 αiyixi和 αiyi, 這裏 αi=niη。最後學習到的 w,b 可以分別表示爲:
w=∑αiyixi(其中i=1,2,……,N)
b=∑αiyi(其中i=1,2,……,N)
這裏, αi≥0,i=1,2,...,Nαi≥0,i=1,2,...,N,當 η=1時,表示第i個是實例點由於誤分類而進行更新的次數,實例點更新次數越多,說明它距離分離超平面越近,也就越難區分,該點對學習結果的影響最大。
感知機模型對偶形式:
f(x)=sign(∑αjyjxj⋅x+b)(其中j=1,2,……,N)
其中
α=(α1,α2,...,αN)
學習時初始化 α←0,b←0在訓練集中找分類錯誤的點,即:
yi(∑αjyjxj⋅xi+b)≤0(其中j=1,2,……,N)
然後更新:
αi←αi+η
b←b+ηyi
知道訓練集中所有點正確分類
對偶形式中訓練實例僅以內積的形式出現,爲了方便,可以預先將訓練集中實例間的內積計算出來以矩陣的形式存儲,即 Gram 矩陣。
對偶感知機的代碼實現:(github鏈接:https://github.com/sparrowljq/StatisticalLearningMethod.git)
# 對偶感知機的代碼 | |
import numpy as np | |
import matplotlib.pyplot as plt | |
p_x = np.array([[3, 3], [4, 3], [1, 1]]) | |
y = np.array([1, 1, -1]) | |
# 繪製初始點 | |
for i in range(len(p_x)): | |
if y[i] == 1: | |
plt.plot(p_x[i][0], p_x[i][1], 'ro') | |
else: | |
plt.plot(p_x[i][0], p_x[i][1], 'bo') | |
# 計算Gram矩陣 | |
Gram = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) | |
for i in range(len(p_x)): | |
for j in range(len(p_x)): | |
# dot函數表示矩陣的內積 | |
Gram[i][j] = np.dot(p_x[i], p_x[j]) | |
# 初始化α1,α2,α3的值 | |
afa = np.array([0, 0, 0]) | |
# 初始化法平面截距 | |
b = 0 | |
# 初始化學習率η的值 | |
delta = 1 | |
while 1: | |
# 用來表示所有的點是否被正分類 | |
choice = 1 | |
for i in range(len(p_x)): | |
if y[i] == np.sign(np.dot(afa * y, Gram[i]) + b): | |
continue | |
while 1: | |
# 只要進入該循環表示有點未正確分類 | |
choice = -1 | |
if y[i] == np.sign(np.dot(afa*y, Gram[i])+b): | |
break | |
else: | |
afa[i] = afa[i]+delta | |
b = b+delta*y[i] | |
if choice == 1: | |
break | |
print(afa) | |
w = np.dot(afa*y, p_x) | |
print(b) | |
line_x = [0, 10] | |
line_y = [0, 0] | |
for i in range(len(line_x)): | |
line_y[i] = (-w[0]*line_x[i]-b)/w[1] | |
plt.plot(line_x, line_y) | |
plt.savefig("a.png") | |
plt.show() |
程序執行結果: