【統計學習方法】感覺機
- 前言
- 感覺機
-
- 概念簡述
- 學習算法
-
- ① 随機梯度下降法
- ② 對偶形式
-
- Gram矩陣
- 程式實作
-
- 自程式設計實作
- sklearn實作
前言
寫這個文章也是為了督促自己把短時間學到的知識搞清楚,也把記在筆記上的,書上的,程式上的知識整合一下,據說挂深度之眼的名,後續還能領點東西,就寫上了,目标還是寫一個自己能給自己講明白的學習筆記。
感覺機
概念簡述
(1)訓練一個感覺機模型,試着用我的話總結一下,就是用一條線(稱為超平面,二維是一條線,三維是一個面)來将平面中已知的正&負點(二分類)分隔開來的工作。
感覺機的數學模型(所有超平面的集合)如下:
(2)那麼一上來随便標明的初始超平面一定是不準的,怎麼衡量好壞呢,就涉及到了損失函數,表示為:誤分類點到超平面的總距離,數學表示如下:
(3)有了初始的不準确超平面,怎麼一步一步得到準确超平面呢,就涉及到了感覺機的學習算法:
學習算法
① 随機梯度下降法
其實就是感覺機的原始方法,給定初始學習率η,以及權值w,偏置b的初值,在輸入的訓練資料集中随機選出一個點,看在目前超平面劃分下,這個點是不是分對了,對了就不做改動,再選一個,錯了就更改超平面參數,數學表示如下:
當周遊了所有的點,一個感覺機模型就訓練好了,這也解釋了兩個問題:
1.想要用感覺機模型,輸入訓練集必須是線性可分的,要不然二維平面中輸入一大堆不可分的點,用來分割的這條線可能會在訓練集中來回跳動,直到最大疊代次數了,也不會把所有的點分開;
2.模型不是唯一的,因為一旦所有的點全分對了,這條線就不動了,那麼正序判斷到第n個點停止,與倒序判斷到第一個點停止,所得的模型顯然是不同的。
② 對偶形式
在我看來,對偶形式是原始形式在計算邏輯上進行優化的結果,對偶形式瞄準的是w和b在周遊所有點之後的增量,對偶形式的參數更新數學表示如下:
那麼就進行如下更新:
最終學習結束後展現到w,b上的數學表示如下:
其中:
對偶形式的邏輯,我的了解這樣的:
在原始形式下,計算的邏輯是先找錯誤分類點,找到了則對超平面更新,然後循環到結束。這裡在找誤分類點以及更新的時候都需要進行一些重複備援的計算(相比于對偶形式)
而對偶形式,相當于是一次把所有的誤分類點都找一遍,最後把所有誤分類點的更新進行加和,一次性更新,另外,從α(i)的更新規則可以看出,這是一個計數形式的更新,每多一個點,就增加一個步長(學習率η),在計算上,确實省下了很多功夫。
Gram矩陣
這個矩陣的來源是用w,b判斷誤分類點時,需要用wx(j),而在計算更新w值時,用到了w = w + ηy(i)*x(i),也就是說涉及到了x元素的一個内積,就是下圖紅框中的這部分:
那麼如果提前把整個内積算出來,就省下了很多的計算成本,也就是Gram矩陣了。
程式實作
這也是我第一次接觸python程式設計,是以程式是完全或者部分參考示例程式給出的,目的是弄懂整個程式設計的思想以及學會各個庫的使用
程式設計的題目如下:
使用工具:PyCharm & Anaconda
自程式設計實作
用到的庫:
import numpy as np
import matplotlib.pyplot as plt
預測函數(類):
class MyPerceptron:
def __init__(self):
self.w = None
self.b = 0
self.l_rate = 1
這裡w參數的次元是與輸入的x的次元相關的,是以需要先定義為None,b是常數設定為0,學習率設定為1。
def fit(self,X_train,y_train):
#用樣本點的特征數更新初始w,如x1=(3,3)T,
#有兩個特征,則self.w=[0,0]
self.w=np.zeros(X_train.shape[1])
i=0
while i<X_train.shape[0]:
X=X_train[i]
y=y_train[i]
# 如果y*(wx+b)≤0 說明是誤判點,更新w,b
if y*(np.dot(self.w, X) + self.b) <= 0:
self.w = self.w + self.l_rate * np.dot(y, X)
self.b = self.b + self.l_rate * y
i=0 #如果是誤判點,從頭進行檢測
else:
i+=1
這裡涉及到numpy的一些基礎知識,我也是邊看邊學的:
np.zeros()函數:定義一個全0數組,大小由輸入參數指定;
np.dot()函數:傳回兩向量的内積(對應元素乘積後求和)或者是傳回兩矩陣的乘積(正常的矩陣乘法)
繪圖函數:
對應語句分别加了注釋
def draw(X, w, b):
# 産生分離超平面上的兩點
X_new = np.array([[0], [6]])
y_predict = -b - (w[0] * X_new) / w[1]
plt.plot(X[:2, 0], X[:2, 1], "g*", label="1") # 畫正執行個體散點
plt.plot(X[2:, 0], X[2:, 1], "rx", label="-1") # 畫負執行個體散點
plt.plot(X_new, y_predict, "b-") # 畫出超平面
plt.axis([0, 6, 0, 6]) # 設定坐标軸範圍
plt.xlabel('x1') # X軸标簽
plt.ylabel('x2') # Y軸标簽
plt.title('Day2_test') # 圖檔标題
plt.legend() # 顯示圖例(圖例由上邊"label"給出)
plt.show() # 顯示圖像
最後是主函數:
def main():
# 構造訓練資料集
X_train=np.array([[3,3],[4,3],[1,1]])
y_train=np.array([1,1,-1])
# 建構感覺機對象,對資料集繼續訓練
perceptron=MyPerceptron()
perceptron.fit(X_train,y_train) # 預測函數中定義
print(perceptron.w)
print(perceptron.b)
# 結果圖像繪制
draw(X_train,perceptron.w,perceptron.b)
sklearn實作
用到的庫:
import numpy as np
from sklearn.linear_model import Perceptron
其中sklearn庫是從Anaconda中搜尋scikit-learn庫得到的。
代碼如下:
X_train = np.array([[3, 3], [4, 3], [1, 1]])
y = np.array([1, 1, -1])
perceptron = Perceptron(max_iter=1000, tol=1e-3)
perceptron.fit(X_train, y)
print("w:", perceptron.coef_, "\n", "b:", perceptron.intercept_, "\n", "n_iter:", perceptron.n_iter_)
# n_iter:總的疊代次數
res = perceptron.score(X_train, y)
print("correct rate:{:.0%}".format(res))
其中涉及到的perceptron類的一些參數及方法如下:
上述(屬性-變量)是perceptron類的輸出參數;
上圖中涉及到的參數就是在調用perceptron類時,可以傳入的參數;
另注:L1&L2正則化
運作結果如下: