【机器学习】单层感知器

 

感知器介绍

感知机(英语: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

 

posted @ 2020-05-04 13:28  -零  阅读(2748)  评论(0编辑  收藏  举报