zoukankan      html  css  js  c++  java
  • 【机器学习】单层感知器

    感知器介绍

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

  • 相关阅读:
    wait
    iOS UITableviewCell优化
    iOS本地版本和服务器对比
    iOS 二维码生成 改变颜色 添加中心图
    iOS坑点解析
    iOS View快照,View截屏
    双缓冲读感感悟
    查找附近点--Geohash方案讨论
    各种报告word模板
    跳转到设置里面各个页面iOS8
  • 原文地址:https://www.cnblogs.com/-wenli/p/12826272.html
Copyright © 2011-2022 走看看