感知器及其在Python中的實(shí)現(xiàn)
什么是感知器?

生物神經(jīng)元示意圖
感知器的概念類似于大腦基本處理單元神經(jīng)元的工作原理。神經(jīng)元由許多由樹突攜帶的輸入信號、胞體和軸突攜帶的一個(gè)輸出信號組成。當(dāng)細(xì)胞達(dá)到特定閾值時(shí),神經(jīng)元會(huì)發(fā)出一個(gè)動(dòng)作信號。這個(gè)動(dòng)作要么發(fā)生,要么不發(fā)生。
類似地,感知器具有許多輸入(通常稱為特征),這些輸入被饋送到產(chǎn)生一個(gè)二元輸出的線性單元中。因此,感知器可用于解決二元分類問題,其中樣本將被識別為屬于預(yù)定義的兩個(gè)類之一。
算法

感知器原理圖
由于感知器是二元類器(0/1),我們可以將它們的計(jì)算定義如下:

讓我們回想一下,兩個(gè)長度為n的向量的點(diǎn)積由下式給出:

函數(shù)f(x)= b + w.x是權(quán)重和特征向量的線性組合。 因此,感知器是線性分類器-一種使用線性預(yù)測器函數(shù)進(jìn)行預(yù)測的算法。
權(quán)重表示x中每個(gè)特征xᵢ 對機(jī)器學(xué)習(xí)模型行為的有效性。特征xᵢ的權(quán)重wᵢ越高,對輸出的影響就越大。偏差“ b”類似于線性方程式中的截距,它是一個(gè)常數(shù),可以幫助機(jī)器學(xué)習(xí)模型以最適合數(shù)據(jù)的方式進(jìn)行調(diào)整。偏差項(xiàng)假設(shè)虛擬輸入特征系數(shù)x₀= 1。
可以使用以下算法訓(xùn)練模型:

Python實(shí)現(xiàn)
我們考慮用于實(shí)現(xiàn)感知器的機(jī)器學(xué)習(xí)數(shù)據(jù)集是鳶尾花數(shù)據(jù)集。這個(gè)數(shù)據(jù)集包含描述花的4個(gè)特征,并將它們歸類為屬于3個(gè)類中的一個(gè)。我們剝離了屬于類' Iris-virginica '的數(shù)據(jù)集的最后50行,只使用了兩個(gè)類' Iris-setosa '和' Iris-versicolor ',因?yàn)檫@些類是線性可分的,算法通過最終找到最優(yōu)權(quán)重來收斂到局部最小值。
- import numpy as np
- import pandas as pd
- import matplotlib.pyplot as plt
- def load_data():
- URL_='https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
- data = pd.read_csv(URL_, header = None)
- print(data)
- # make the dataset linearly separable
- data = data[:100]
- data[4] = np.where(data.iloc[:, -1]=='Iris-setosa', 0, 1)
- data = np.asmatrix(data, dtype = 'float64')
- return data
- data = load_data()

將具有兩個(gè)特征的數(shù)據(jù)集可視化,我們可以看到,通過在它們之間畫一條直線,可以清楚地分隔數(shù)據(jù)集。
我們的目標(biāo)是編寫一個(gè)算法來找到這條線并正確地對所有這些數(shù)據(jù)點(diǎn)進(jìn)行分類。
- plt.scatter(np.array(data[:50,0]), np.array(data[:50,2]), marker='o', label='setosa')
- plt.scatter(np.array(data[50:,0]), np.array(data[50:,2]), marker='x', label='versicolor')
- plt.xlabel('petal length')
- plt.ylabel('sepal length')
- plt.legend()
- plt.show()


現(xiàn)在我們實(shí)現(xiàn)上面提到的算法,看看它是如何工作的。我們有4個(gè)特征,因此每個(gè)特征有4個(gè)權(quán)重。請記住,我們定義了一個(gè)偏置項(xiàng)w₀,假設(shè)x₀= 1,使其總共具有5個(gè)權(quán)重。
我們將迭代次數(shù)定義為10。這是超參數(shù)之一。在每次迭代時(shí),算法都會(huì)為所有數(shù)據(jù)點(diǎn)計(jì)算類別(0或1),并隨著每次錯(cuò)誤分類更新權(quán)重。
如果樣本分類錯(cuò)誤,則權(quán)值將由向相反方向移動(dòng)的增量更新。因此,如果再次對樣本進(jìn)行分類,結(jié)果就會(huì)“錯(cuò)誤較少”。我們將任何label≤0歸類為“0”(Iris-setosa),其它歸類為“1”(Iris-versicolor)。
- def perceptron(data, num_iter):
- features = data[:, :-1]
- labels = data[:, -1]
- # set weights to zero
- w = np.zeros(shape=(1, features.shape[1]+1))
- misclassified_ = []
- for epoch in range(num_iter):
- misclassified = 0
- for x, label in zip(features, labels):
- x = np.insert(x,0,1)
- y = np.dot(w, x.transpose())
- target = 1.0 if (y > 0) else 0.0
- delta = (label.item(0,0) - target)
- if(delta): # misclassified
- misclassified += 1
- w += (delta * x)
- misclassified_.append(misclassified)
- return (w, misclassified_)
- num_iter = 10
- w, misclassified_ = perceptron(data, num_iter)

現(xiàn)在,讓我們繪制每次迭代中分類錯(cuò)誤的樣本數(shù)。我們可以看到該算法在第4次迭代中收斂。也就是說,所有樣本在第4次通過數(shù)據(jù)時(shí)都已正確分類。
感知器的一個(gè)特性是,如果數(shù)據(jù)集是線性可分離的,那么該算法一定會(huì)收斂!
- epochs = np.arange(1, num_iter+1)
- plt.plot(epochs, misclassified_)
- plt.xlabel('iterations')
- plt.ylabel('misclassified')
- plt.show()

局限性
- 僅當(dāng)數(shù)據(jù)集可線性分離時(shí),單層感知器才有效。
- 該算法僅用于二元分類問題。但是,我們可以通過在每個(gè)類中引入一個(gè)感知器來擴(kuò)展算法以解決多類分類問題。