【機器學習】單層感知器


 

感知器介紹

感知機(英語:Perceptron)是Frank Rosenblatt在1957年就職於Cornell航空實驗室(Cornell Aeronautical Laboratory)時所發明的一種人工神經網絡。它可以被視為一種最簡單形式的前饋式人工神經網絡,是一種二元線性分類器。

    Frank Rosenblatt給出了相應的感知機學習算法,常用的有感知機學習、最小二乘法和梯度下降法。譬如,感知機利用梯度下降法對損失函數進行極小化,求出可將訓練數據進行線性划分的分離超平面,從而求得感知機模型。 

     感知機是生物神經細胞的簡單抽象。神經細胞結構大致可分為:樹突、突觸、細胞體及軸突。單個神經細胞可被視為一種只有兩種狀態的機器——激動時為‘是’,而未激動時為‘否’。神經細胞的狀態取決於從其它的神經細胞收到的輸入信號量,及突觸的強度(抑制或加強)。當信號量總和超過了某個閾值時,細胞體就會激動,產生電脈沖。電脈沖沿着軸突並通過突觸傳遞到其它神經元。為了模擬神經細胞行為,與之對應的感知機基礎概念被提出,如權量(突觸)、偏置(閾值)及激活函數(細胞體)。

    在人工神經網絡領域中,感知機也被指為單層的人工神經網絡,以區別於較復雜的多層感知機(Multilayer Perceptron)。 作為一種線性分類器,(單層)感知機可說是最簡單的前向人工神經網絡形式。盡管結構簡單,感知機能夠學習並解決相當復雜的問題。感知機主要的本質缺陷是它不能處理線性不可分問題。 

   線性分類器的第一個迭代算法是1956年由Frank Rosenblatt提出的。這個算法被提出后,受到了很大的關注。感知器在神經網絡發展的歷史上占據着特殊的位置:它是第一個從算法上完整描述的神經網絡。在20世紀60年代和70年代,受感知器的啟發,工程師、物理學家以及數學家們紛紛投身於神經網絡不同方面的研究。這個算法在今天看來依然是有效的。

 

感知器結構與算法步驟

設有n維(特征數)輸入的單個感知機(如下圖所示),X1至X2為n維輸入向量的各個分量,W1至W2為各個輸入分量連接到感知機的權量(或稱權值),W0為偏置,激活函數(又曰激勵函數或傳遞函數),Z為標量輸出(也稱為凈輸入)。

 

 

 第一步

這里z稱為凈輸入(net input),它的值等於一個樣本的每個維度值x與維度對應的權重值w相乘后的和。

 

第二步

計算結果Z是一個連續的值,我們需要將結果轉換為離散的分類值,因此,這里,我們使用一個轉換函數,該函數稱為激勵函數(激活函數),這里θ就是閾值。

 

第三步

更新權重值

感知器是一個自學習算法,即可以根據輸入的數據(樣本),不斷調整權重的更新,最終完成分類。對於權重的更新公式如下:

  • η:學習速率(一個介於0.0到1.0之間的常數)
  • y(i):是第i個樣本的真實類標(即真實值)
  • y^(i):是第i個樣本的預測類標(預測值)。需要注意的是,權重向量中的所有權重值是同時更新的,這意味着在所有的權重 ΔwjΔwj 更新前,我們無法重新計算y^(i)。
  • 這里的i和j怎么理解?每次計算z是同一個樣本的維度值和權重值相乘之和,每次更新權重值會對每個權重值進行更新。
  • 類標是什么?類標就是分類的標簽,在這里類標就是1或者0。

更新原則:感知器的權重更新依據是:如果預測准確,則權重不進行更新,否則,增加權重,使其更趨向於正確的類別。

 

 

 

Python算法實現

1.對權重進行初始化。(初始化為0或者很小的數值。)
2.對訓練集中每一個樣本進行迭代,計算輸出值y。

  • 根據輸出值y與真實值,更新權重。
  • 循環步驟2。直到達到指定的次數(或者完全收斂)。

說明:

如果兩個類別線性可分,則感知器一定會收斂。
如果兩個類別線性不可分,則感知器一定不會收斂。
感知器收斂的前提是兩個類別必須是線性可分的,且學習速率足夠小。 
如果兩個類別無法通過一個線性決策邊界進行划分,可以為模型在訓練數據集上的學習迭代次數設置一個最大值, 或者設置一個允許錯誤分類樣本數量的閾值,否則,感知器訓練算法將永遠不停的更新權值。

import pandas as pd
import numpy as np
import  matplotlib.pyplot as plt

class Perceptron(object):
    """Perceptron classifier.
    參數:
    eta (學習率): float,取值范圍0.0-1.0
    n_iter(在訓練集進行迭代的次數) : int
    random_state (隨機數產生器的種子): int
    屬性:
    w_ (權重): ,np一維數組
    errors_ (存儲每輪訓練集判斷錯誤的次數): list

    """
    def __init__(self, eta=0.01, n_iter=50, random_state=1):
        self.eta = eta
        self.n_iter = n_iter
        self.random_state = random_state

    def fit(self, X, y):
        """Fit training data.
        Parameters
        ----------
        X : 二維np數組,形式:[[樣本1維度值1,樣本1維度值2...],[樣本2維度值1,樣本2維度值2...],...]
        y : 一維np數組,形式:[樣本1的類標],樣本2的類標,...]

        Returns
        -------
        self : object

        """
        #設置隨機數種子
        rgen = np.random.RandomState(self.random_state)
        #生成正態分布的隨機數,權重w
        self.w_ = rgen.normal(loc=0.0, scale=0.01, size=1 + X.shape[1])
        self.errors_ = []

        for _ in range(self.n_iter):
            # 迭代所有樣本,並根據感知器規則來更新權重
            errors = 0
            for xi, target in zip(X, y):
                # print(xi,target)
                update = self.eta * (target - self.predict(xi))
          #更新權重值 self.w_[0]
+= update self.w_[1:] += update * xi #預測錯誤:update如果不為0,則表示判斷錯誤 errors += int(update != 0.0) self.errors_.append(errors) return self #計算z的函數 def net_input(self, X): """Calculate net input""" # ϕ(z) = w0 * 1 + w1∗x1 + w2∗x2 + ... + wm∗xm z = self.w_[0] * 1 + np.dot(X, self.w_[1:]) return z #閾值函數 def predict(self, X): """Return class label after unit step""" return np.where(self.net_input(X) >= 0.0, 1, -1) df = pd.read_csv('https://archive.ics.uci.edu/ml/' 'machine-learning-databases/iris/iris.data', header=None) print(df.tail()) # select setosa and versicolor #選擇0-100行的第5列數據 y = df.iloc[0:100, 4].values #0-100行中,選擇第5列的列名為Iris-setosa的數據做處理,如果 y = np.where(y == 'Iris-setosa', -1, 1) # [1,1,1,1,1,...-1,-1,-1] # extract sepal length and petal length X = df.iloc[0:100, [0, 2]].values ppn = Perceptron(eta=0.1, n_iter=10) #訓練數據 ppn.fit(X, y) #迭代次數與每次迭代時預測錯誤的次數作圖 plt.plot(range(1, len(ppn.errors_) + 1), ppn.errors_, marker='o') plt.xlabel('Epochs') plt.ylabel('Number of updates') plt.savefig('images/02_07.png', dpi=300) # plt.show()

 

怎么判斷感知器是否收斂

import pandas as pd
import numpy as np
import  matplotlib.pyplot as plt



class Perceptron(object):
    """Perceptron classifier.
    參數:
    eta (學習率): float,取值范圍0.0-1.0
    n_iter(在訓練集進行迭代的次數) : int
    random_state (隨機數產生器的種子): int
    屬性:
    w_ (權重): ,np一維數組
    errors_ (存儲每輪訓練集判斷錯誤的次數): list

    """
    def __init__(self, eta=0.01, n_iter=50, random_state=1):
        self.eta = eta
        self.n_iter = n_iter
        self.random_state = random_state

    def fit(self, X, y):
        """Fit training data.
        Parameters
        ----------
        X : 二維np數組,形式:[[樣本1維度值1,樣本1維度值2...],[樣本2維度值1,樣本2維度值2...],...]
        y : 一維np數組,形式:[樣本1的類標],樣本2的類標,...]

        Returns
        -------
        self : object

        """
        #設置隨機數種子
        rgen = np.random.RandomState(self.random_state)
        #生成正態分布的隨機數,權重w
        self.w_ = rgen.normal(loc=0.0, scale=0.01, size=1 + X.shape[1])
        self.errors_ = []

        for _ in range(self.n_iter):
            # 迭代所有樣本,並根據感知器規則來更新權重
            errors = 0
            for xi, target in zip(X, y):
                # print(xi,target)
                update = self.eta * (target - self.predict(xi))
                self.w_[0] += update
                self.w_[1:] += update * xi
                #預測錯誤:update如果不為0,則表示判斷錯誤
                errors += int(update != 0.0)
            self.errors_.append(errors)
        return self

    #計算z的函數
    def net_input(self, X):
        """Calculate net input"""
        # ϕ(z) = w0 * 1 + w1∗x1 + w2∗x2 + ... + wm∗xm
        z = self.w_[0] * 1 + np.dot(X, self.w_[1:])
        return z

    #閾值函數
    def predict(self, X):
        """Return class label after unit step"""
        return np.where(self.net_input(X) >= 0.0, 1, -1)

df = pd.read_csv('https://archive.ics.uci.edu/ml/'
        'machine-learning-databases/iris/iris.data', header=None)
# print(df.tail())
# select setosa and versicolor
y = df.iloc[0:100, 4].values
y = np.where(y == 'Iris-setosa', -1, 1)
# extract sepal length and petal length
X = df.iloc[0:100, [0, 2]].values
# plot data
ppn = Perceptron(eta=0.1, n_iter=10)
ppn.fit(X, y)
plt.plot(range(1, len(ppn.errors_) + 1), ppn.errors_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Number of updates')

plt.savefig('images/02_07.png', dpi=300)
# plt.show()

 

 

 

 

怎么判斷兩個類別是否線性可分

使用散點圖顯示兩個類別的兩個維度

import pandas as pd
import  matplotlib.pyplot as plt

df = pd.read_csv('https://archive.ics.uci.edu/ml/'
        'machine-learning-databases/iris/iris.data', header=None)
print(df.tail())
# extract sepal length and petal length
X = df.iloc[0:100, [0, 2]].values
# plot data
plt.scatter(X[:50, 0], X[:50, 1],
            color='red', marker='o', label='setosa')
plt.scatter(X[50:100, 0], X[50:100, 1],
            color='blue', marker='x', label='versicolor')
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc='upper left')
# plt.savefig('images/02_06.png', dpi=300)
plt.show()

 

 關於plt.scatter使用詳解

 

 

 

參考:

https://blog.csdn.net/qq_42442369/article/details/87613450

https://blog.csdn.net/u012806787/article/details/80116098

https://blog.csdn.net/xylin1012/article/details/71931900

https://blog.csdn.net/yawdeep/article/details/78827088

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM