本內容將介紹機器學習中的 感知機模型,並說明感知機學習算法的原始形式和對偶形式。
感知機(perceptron)是二分類的線性分類模型,屬於判別模型,是一種監督學習算法。
其輸入爲實例的特徵向量,輸出爲實例的類別,取 +1 和 -1 二值。感知機對應於輸入空間(特徵空間)中將實例劃分爲正負兩類的分離超平面,屬於判別模型。感知機學習旨在求出將訓練數據進行線性劃分的分離超平面,爲此,導入基於誤分類的損失函數,利用梯度下降法對損失函數進行極小化,求得感知機模型。感知機學習算法具有簡單而易於實現的優點,分爲原始形式和對偶形式。感知機預測是用學習得到的感知機模型對新的輸入實例進行分類。感知機 1957 年由 Rosenblatt 提出,是神經網絡與支持向量機的基礎。
一、感知機模型
假設輸入空間(特徵空間)是 ,輸出空間是 。輸入 表示實例的特徵向量,對應於輸入空間(特徵空間)的點;輸出 表示實例的類別。由輸入空間到輸出空間的如下函數:
稱爲感知機。其中, 和 爲感知機模型參數, 叫作權值(weight)或權值向量(weight vector), 叫作偏置(bias), 表示 和 的點積。sign 是符號函數,即
感知機模型的假設空間是定義在特徵空間中的所有線性分類模型(linear classification model)或線性分類器(linear classifier),即函數 。
二、感知機學習策略
假設訓練數據集是線性可分的,感知機學習的目標是求得一個能夠將訓練集中正實例點和負實例點完全正確分開的分離超平面。爲了找出這樣的超平面,即確定感知機模型參數 ,,需要確定一個學習策略,即定義(經驗)損失函數並將損失函數極小化。
感知機將誤分類點到超平面 的總距離作爲損失函數。輸入空間 中任一點 到超平面 的距離:
其中, 是 的 範數。
另外,誤分類的數據 滿足
因此,誤分類點 到超平面 的距離是
假設超平面 的誤分類點集合爲 ,那麼所有誤分類點到超平面 的總距離爲
如果假設 ,就得到感知機學習的損失函數
其中 爲誤分類點的集合。這個損失函數就是感知機學習的經驗風險函數。
對一個特定的樣本點的損失函數:在誤分類時是參數 , 的線性函數,並且大於0,在正確分類時是 0。因此,給定訓練數據集 ,損失函數 是 , 的連續可導函數,並且是非負的。
感知機學習的策略是在假設空間中選取使損失函數式(1.3)最小的模型參數 , ,即感知機模型。
三、感知機學習算法
感知機學習問題轉化爲求解損失函數式(1.3)的最優化問題,最優化的方式是隨機梯度下降法。感知機學習算法分爲原始形式和對偶形式。
3.1 感知機學習算法的原始形式
感知機學習算法是對以下最優化問題的算法。給定一個訓練集
其中 ,,,求參數 ,,使其爲以下損失函數極小化問題的解
其中 爲誤分類點的集合。
感知機學習算法是誤分類驅動的,具體採用隨機梯度下降法(stochastic gradient descent)。首先,任意選取一個超平面 ,,然後用梯度下降法不斷地極小化目標函數(1.4)。極小化過程中不是一次使 中所有誤分類點的梯度下降,而是一次隨機選取一個誤分類點使其梯度下降。
假設誤分類點集合 是固定的,那麼損失函數 的梯度由
給出。
隨機選取一個誤分類點 ,對 , 進行更新:
式中 是步長,在統計學習中又稱爲學習率(learning rate)。這樣,通過迭代可以期待損失函數 不斷減小,直到爲 0。綜上所述,得到如下算法:
算法 1.1 (感知機學習算法的原始形式)
輸入:訓練數據集 ,其中 ,,;學習率 ;
輸出:;感知機模型 。
訓練步驟:
(1)選取初值 ,
(2)在訓練集中選取數據
(3)如果 ,則更新,
(4)跳轉到(2),直至訓練集中沒有誤分類點。
這種學習算法直觀上有如下解釋:當一個實例點被誤分類,即位於分離超平面的錯誤一側時,則調整 , 的值,使分類超平面向該誤分類點的一側移動,以減少該誤分類點與超平面的距離,直至超平面越過該誤分類點使其被正確分類。
Python 代碼實現:
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self):
pass
def processData(self, datas):
xArr = np.array([x[0] for x in datas])
yArr = np.array([x[1] for x in datas])
return xArr, yArr
def train(self, train_datas, learning_rate = 1):
xArr, yArr = self.processData(train_datas)
self.w = np.zeros(xArr.shape[1])
self.b = 0
self.learning_rate = learning_rate
num = 0
while(True) :
num = 0
for i in range(len(train_datas)):
# num += 1
loss = yArr[i] * (np.dot(self.w, xArr[i]) + self.b)
print('loss = ', loss)
if loss <= 0:
self.w += learning_rate*yArr[i]*xArr[i]
self.b += learning_rate*yArr[i]
break
num += 1
print('num = ', num)
if num >= len(train_datas):
break;
def predict(self, x):
return np.where(np.dot(self.w, x) + self.b >= 0.0, 1, -1)
if __name__ == "__main__":
datas = [[(1,2),-1],[(2,1),-1],[(2,2),-1],[(1,4),1],[(3,3),1],[(5,4),1],[(3, 3), 1], [(4, 3), 1], [(1, 1), -1],[(2, 3), -1], [(4, 2.5), 1]]
perceptron = Perceptron()
perceptron.train(datas, 0.1)
print("w = ", perceptron.w, ", b = ", perceptron.b)
fig = plt.figure('Input Figure')
xArr = np.array([x[0] for x in datas])
yArr = np.array([x[1] for x in datas])
pPlotx, pPloty, nPlotx, nPloty = [], [], [], []
for i in range(len(datas)):
if yArr[i] > 0:
pPlotx.append(xArr[i][0])
pPloty.append(xArr[i][1])
else :
nPlotx.append(xArr[i][0])
nPloty.append(xArr[i][1])
pPlot, nPlot = plt.plot(pPlotx, pPloty, 'b+', nPlotx, nPloty, 'rx')
plt.legend(handles=[pPlot, nPlot], labels=['Positive Sample', 'Negtive Sample'], loc='upper center')
x0_max, x0_min = max(xArr[:, 0])+1, min(xArr[:, 0])-1
x1_max, x1_min = max(xArr[:, 1])+1, min(xArr[:, 1])-1
x = np.arange(x0_min, x0_max, 0.1)
plt.plot(x, (-perceptron.b-perceptron.w[0]*x)/perceptron.w[1], 'b')
plt.show()
運行以上代碼,將得出以下的擬合圖:
當訓練數據集線性可分時,感知機學習算法原始形式迭代是收斂的。對於不同的選擇初值,以及迭代過程中誤分類點的不同選擇順序,感知機算法會存在多個不同的解。當訓練集線性不可分時,感知機學習算法不收斂,迭代結果會發生震盪。
3.2 感知機學習算法的對偶形式
對偶形式的基本思想是:將 和 表示爲實例 和標記 的線性組合的形式,通過求解其係數而求得 和 。不失一般性,在原始形式的算法中可假設初始值 ,均爲0。對誤分類點 通過
逐步修改 和 ,設修改 次,則 和 關於 的增量分別是 和 ,這裏 。這樣,從學習過程中不難看出,最後學習到的 和 可以分別表示爲
這裏,,。
算法 1.2 (感知機學習算法的對偶形式)
輸入:訓練數據集 ,其中 ,,;學習率 ;
輸出:;感知機模型 。其中 。
訓練步驟:
(1),
(2)在訓練集中選取數據
(3)如果 ,則更新 ,
(4)跳轉到(2),直至訓練集中沒有誤分類點。
對偶形式中訓練實例僅以點積的形式出現。爲了方便,可以預先將訓練集中實例間的點積計算出來並以矩陣的形式存儲,這個矩陣就是所謂的 Gram 矩陣(Gram matrix)。
參考:
[1] 李航《統計學習方法》