Perceptron(感知機)
感知機是二分類的線性分類器,屬於判別模型。由Rosenblatt在1957年提出,是神經網絡和支持向量機(SVM)的基礎。感知機本身相當於神經網絡中的一個神經元,只能進行簡單的線性分類。感知機的學習目標是通過訓練數據得到線性劃分的超平面。爲此,引入基於分類誤差的損失函數,利用梯度下降法對損失函數進行極小化,來求解感知機模型。
1.感知機模型
定義:假設輸入空間(特徵空間)是
其中
2.感知機學習策略
線性可分定義:給定一個數據集
其中
假設數據集是線性可分的,感知機的目標就是求得一個能夠將所有樣本正確分類的超平面,即學習出前面感知機模型的參數
對於誤分類數據
即預測類別
如果有M個誤分類點,那麼所有誤分類點到超平面的總距離爲:
不考慮前面係數,則對於任意給定的訓練數據集
感知機模型
可以看出,損失函數是非負的,如果沒有誤分類點了,則損失函數的值爲0.因此,給定訓練樣本
3.感知機學習算法
通過上述學習策略,我們知道感知機最終的學習目的可以轉化爲最優化問題,即對於給定的數據集
在具體求解過程中,採用的是梯度下降法:
所謂梯度,是一個向量,方向是標量場變化最快的方向 ,大小是改點到周圍點的最大變化率。隨機選取一個誤分類點
其中,
- Algorithm 2.1
- Input: traning_data
T={(x1,y1),(x2,y2),…,(xN,yN)} , traning_rateη(0<η≤1) - Output: parameter:
w,b ,f(x)=sign(w⋅x+b) - Initialize:
w0,b0 - for randomly selected item
(xi,yi)∈T - if
yi(w⋅xi+b)≤0 -
w←w+ηyixi -
b←b+ηyi - end if
end for
在示例中,我們選取正樣本爲
x1=(3,3)T,x2=(4,3)T ,負樣本爲x3=(1,1)T ,通過Python來實現感知機的原始形式:
感知機原始形式代碼
# Project: Machine Learning-Perceptron
# Author: Lyndon
# Date: 2015/10/15
import copy
from matplotlib import pyplot as plt
from matplotlib import animation
#initialize
training_data=[[(3,3),1],[(4,3),1],[(1,1),-1]]
w=[0,0] #weight
b=[0] #bias
step=1 #learning rate
history=[]
# update parameters using stochastic gradient descent
# parameter item: an item which is classified into wrong class
# return: NULL
def update(item):
global w,b,history
w[0]+=step*item[1]*item[0][0]
w[1]+=step*item[1]*item[0][1]
b[0]+=step*item[1]
print w,b
history.append([copy.copy(w),copy.copy(b)])
# calculate the item classified result. y_i*(w*x_i+b)<=0 wrong
# parameter item: training_data
# return: classified result
def calculate(item):
res=0;
for i in range(len(item[0])):
res+=w[i]*item[0][i]
res+=b[0]
res*=item[1]
return res
# check if the classifier can correctly classify all data
# parameter item: Null
# return: correct or not
def check():
flag=False
for item in training_data:
if calculate(item)<=0:
update(item)
flag=True
if not flag:
print "Result: w:" +str(w)+"b"+str(b)
return flag
# main function
if __name__=="__main__":
for i in range(1000):
if not check():
break
# set up the figure
fig = plt.figure()
ax = plt.axes(xlim=(0,6),ylim=(0,6))
line, = ax.plot([],[],lw=2)
label = ax.text([],[],'')
# initialization function for base frame
def init():
line.set_data([],[])
x1, y1, x2, y2=[], [], [], [] #initialize the training data,(x1,y1) is positive
for item in training_data:
if item[1]>0:
x1.append(item[0][0])
y1.append(item[0][1])
else:
x2.append(item[0][0])
y2.append(item[0][1])
plt.plot(x1,y1,'bo',x2,y2,'rx')
plt.axis([-6, 6, -6, 6])
plt.grid(True)
plt.xlabel('x')
plt.ylabel('y')
plt.title('Machine Learning - perceptron')
return line, label
# animation function
def animate(i):
global ax, line, label
w = history [i][0]
b = history [i][1]
# hyperplane: w[0]*x_i+w[1]*y_i+b=0; y_i=-(w[0]*x_i+b)/w[1]
if w[1]==0:
return line, label
x1 = -6
y1 = -(w[0]*x1+b[0])/w[1]
x2 = 6
y2 = -(w[0]*x2+b[0])/w[1]
line.set_data([x1,x2],[y1,y2])
x0=0
y0 = -(w[0]*x0+b[0])/w[1]
label.set_text(history[i])
label.set_position([x0,y0])
return line,label
# call the animator
print history
anim=animation.FuncAnimation(fig,animate,init_func=init,frames=len(history),interval=1000)
plt.show()
算法的收斂性
對於線性可分的訓練數據集
(1),存在滿足條件
(2)令
詳細推導可見李航《統計學習方法》P31
感知機學習算法的對偶形式
感知機學習算法的原始形式和對偶形式主要是與支持向量機學習算法的原始形式和對偶形式相對應。其基本思想是將學習參數
其中
- Algorithm 2.2
- Input: traning_data
T={(x1,y1),(x2,y2),…,(xN,yN)} , traning_rateη(0<η≤1) - Output: parameter:
a,b ,f(x)=sign(∑Nj=1ajyjxj⋅x+b) - Initialize:
a0,b0 - for randomly selected item
(xi,yi)∈T - if
yi(∑Nj=1ajyjxj⋅xi+b)≤0 -
ai←ai+η -
b←b+ηyi - end if
end for
對偶形式中的訓練樣本僅以內積的形式出現。爲了方便,可以預先將訓練樣本間的內積求出來,並以矩陣形式存儲,這樣在計算過程中將簡化很多運算。矩陣形式爲:
G=[xi⋅yj]N×N
感知機對偶形式代碼
# Project: Machine Learning-Perceptron_dual
# Author: Lyndon
# Date: 2015/10/15
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
#initialize model f(x)=sign(sum(a_j*y_j*x_j*x_i+b))
training_data=np.array([[(3,3),1],[(4,3),1],[(1,1),-1]])
a = np.zeros(len(training_data),np.float)
b = 0.0
Gram = None
x = np.empty((len(training_data),2), np.float)
y = np.array(training_data[:,1])
for i in range(len(training_data)):
x[i]=training_data[i][0]
history=[]
# calculate the Gram matrix for dual form
# parameter item: Null
# return: Gram matrix
def cal_Gram():
g = np.empty((len(training_data),len(training_data)),np.float)
for i in range(len(training_data)):
for j in range(len(training_data)):
g[i][j]=np.dot(training_data[i][0],training_data[j][0])
return g
# update parameters using stochastic gradient descent
# parameter item: an item which is classified into wrong class
# return: NULL
def update(i):
global a,b,history
a[i]+=1
b+=y[i]
print a,b
history.append([np.dot(a*y,x),b])
# calculate the item classified result. y_i*(w*x_i+b)<=0 wrong
# parameter item: training_data
# return: classified result
def calculate(i):
global a,b
res = np.dot(a*y,Gram[i])
res = (res+b)*y[i]
return res
# check if the classifier can correctly classify all data
# parameter item: Null
# return: correct or not
def check():
flag=False
for i in range(len(training_data)):
if calculate(i)<=0:
update(i)
flag=True
if not flag:
w=np.dot(a*y,x)
print "Result: w:" +str(w)+"b:" +str(b)
return flag
# main function
if __name__=="__main__":
Gram = cal_Gram()
for i in range(1000):
if not check():
break
# set up the figure
fig = plt.figure()
ax = plt.axes(xlim=(0,6),ylim=(0,6))
line, = ax.plot([],[],lw=2)
label = ax.text([],[],'')
# initialization function for base frame
def init():
line.set_data([],[])
x1, y1, x2, y2=[], [], [], [] #initialize the training data,(x1,y1) is positive
for item in training_data:
if item[1]>0:
x1.append(item[0][0])
y1.append(item[0][1])
else:
x2.append(item[0][0])
y2.append(item[0][1])
plt.plot(x1,y1,'bo',x2,y2,'rx')
plt.axis([-6, 6, -6, 6])
plt.grid(True)
plt.xlabel('x')
plt.ylabel('y')
plt.title('Machine Learning - perceptron_dual')
return line, label
# animation function
def animate(i):
global ax, line, label
w = history [i][0]
b = history [i][1]
# hyperplane: w[0]*x_i+w[1]*y_i+b=0; y_i=-(w[0]*x_i+b)/w[1]
if w[1]==0:
return line,label
x1 = -6
y1 = -(w[0]*x1+b)/w[1]
x2 = 6
y2 = -(w[0]*x2+b)/w[1]
line.set_data([x1,x2],[y1,y2])
x0=0
y0 = -(w[0]*x0+b)/w[1]
label.set_text(history[i])
label.set_position([x0,y0])
return line,label
# call the animator
print history
anim=animation.FuncAnimation(fig,animate,init_func=init,frames=len(history),interval=1000)
plt.show()
下圖是感知機對偶形式的訓練過程的可視化過程,通過該圖形可以直觀的看到該程序對給定樣本集的訓練過程
PS:
本文爲機器學習(2)總結筆記,主要通過Python編程實現,更深入理解概念和原理。理論主要參考李航《統計學習方法》,程序參照了碼農網的博客。本文Python實現連接。