上篇博客我们说了感知器,这篇博客主要记录自适应线性神经元的实现算法及一些其他的训练细节,自适应线性神经元(简称为Adaline)由Bernard Widrow和他的博士生Tedd Hoff提出,对感知器算法进行了改进。

当然Adaline对输入向量x的处理和感知器是一样的,都是使用一个权重向量w与x线性组合后得到z,再使用激活函数将z压缩到二元输入(1/-1),区别在于Adaline使用梯度下降法来更新w。

因为我们的目的是准确分类,那么我们需要来衡量分类效果的好坏,在这里我们介绍目标函数:
\[
J(w) = \frac12 \sum_i^n(y^i - \phi(z^i))^2
\]
它也可以叫做损失函数,通过上式我们可以大致理解为什么叫做损失函数,此函数可以计算出所有训练样本的真实值和预测值之间的误差平方和(Sum of Squared Errors,简称SSE),式子前面的那个1/2是为了之后求导方便添加的,没有其他意义。

有了损失函数,于是我们的目的更具体一点,就是为了选择合适的w,使损失函数取得最小值,损失函数越小,就意味着错误分类的情况越少,算法的分类效果也就越好。而因为Adaline的损失函数是一个凸函数,所以我们可以使用梯度下降来找到使损失函数取值最小的权重向量w,我们可以想象为一个小球滚下山:

刚开始的w也许会得到一个很大的损失函数,但是由于损失函数J是w的函数,并且也是一个凸函数,它存在一个最小值,学过微积分的朋友应该知道,要找到一个函数的最值,一般的方法通过求导并使导数为零,解出的那个x就是最值,在这里的梯度下降也就是求导,但由于w是一个权重向量,是多维的,所以需要损失函数对w求偏导,得到w中每个分量的偏导数,然后再更新整个w,具体的推导过程如下:
\[
注意:w为向量,w_j为向量w中的某一分量\\w = w + \Delta w\\\Delta w = -\eta\Delta J(w)\\\frac{\partial J}{\partial w_j} = \frac{\partial }{\partial w_j} \frac 12 \sum_i(y^i-\phi(z^i))^2 \\= \frac 12 \frac{\partial }{\partial w_j} \sum_i(y^i-\phi(z^i))^2 \\= \frac 12 \sum_i2(y^i-\phi(z^i)) \frac{\partial }{\partial w_j}(y^i-\phi(z^i))\\= \sum_i(y^i-\phi(z^i))\frac{\partial }{\partial w_j}(y^i-\sum_i(w_j^ix_j^i))\\=\sum_i(y^i-\phi(z^i))(-x_j^i)\\=-\sum_i(y^i-\phi(z^i))x_j^i\\所以\Delta w_j = -\eta\frac{\partial J}{\partial w_j}=\eta\sum_i(y^i-\phi(z^i))x_j^i
\]
一点要注意所以的权重向量w中的分量是同时更新的,而且每次更新都用到了所有的训练样本,所以梯度下降法也被称为批量梯度下降(batch gradient descent)

接下来我们具体来实现自适应线性神经元,由于和感知机的学习规则很相似,所以直接在感知器的基础上进行修改得到,其中需要修改fit方法,因为在这里我们要使用梯度下降算法。

class AdalineGD(object):
    """ADAptive LInear NEuron classifier.

    Parameters
    ----------
    eta:float
        Learning rate(between 0.0 and 1.0
    n_iter:int
        Passes over the training dataset.

    Attributes
    ----------
    w_:1d-array
        weights after fitting.
    errors_:list
        Number of miscalssifications in every epoch.

    """

    def __init__(self, eta=0.01, n_iter=10):
        self.eta = eta
        self.n_iter = n_iter

    def fit(self, X, y):
        """Fit training data.

        :param X:{array-like}, shape=[n_samples, n_features]
        Training vectors,
        :param y: array-like, shape=[n_samples]
        Target values.
        :return:
        self:object

        """

        self.w_ = np.zeros(1 + X.shape[1]) # Add w_0
        self.cost_ = []

        for i in range(self.n_iter):
            output = self.net_input(X)
            errors = (y - output)
            self.w_[1:] += self.eta * X.T.dot(errors)
            self.w_[0] += self.eta * errors.sum()
            cost = (errors ** 2).sum() / 2.0
            self.cost_.append(cost)
        return self

    def net_input(self, X):
        """Calculate net input"""
        return np.dot(X, self.w_[1:]) + self.w_[0]

    def activation(self, X):
        """Computer linear activation"""
        return self.net_input(X)

    def predict(self, X):
        """Return class label after unit step"""
        return np.where(self.activation(X) >= 0.0, 1, -1)

分别使用不同的学习率(0.01和0.0001)训练,观察神经元学习过程。其中学习率、迭代次数我们称他们为超参数(hyperparameters),我们可以手动设置,超参数设置的是否合适对于整个训练过程都很重要。

fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(8,4))
ada1 = AdalineGD(n_iter=10, eta=0.01).fit(X, y)
ax[0].plot(range(1, len(ada1.cost_) + 1), np.log10(ada1.cost_), marker='o')
ax[0].set_xlabel('Epochs')
ax[0].set_ylabel('log(Sum-squared-error)')
ax[0].set_title('Adaline - Learning rate 0.01')
ada2 = AdalineGD(n_iter=10, eta=0.0001).fit(X, y)
ax[1].plot(range(1, len(ada2.cost_) + 1), ada2.cost_, marker='o')
ax[1].set_xlabel('Epochs')
ax[1].set_ylabel('Sum-squared-error')
ax[1].set_title('Adaline - Learning rate 0.0001')
plt.show()

可以看出,左图中学习率为0.01,随着迭代次数的增加,误差在增加,说明学习率设置的不合适,产生了很大的危害,而右图学习率为0.0001,随着迭代次数的增加,误差在减少,但是减少的过于缓慢,算法收敛的很慢,训练的效率太低,所以我们可以看出过大或过小的学习率都是不合适的。

由右图可以看出,如果学习率过大,就会导致每次梯度下降时都跳过了对应最小值的权重向量w,使得算法无法收敛。

接下来我们介绍一种数据预处理方法,在训练前将特征进行某种缩放操作,这里我们称为特征标准化,可以使所有特征数据缩放成平均值为0,方差为1,加快模型的训练速度,而且可以避免模型学习的很扭曲。

具体公式如下:
\[
x_j^, = \frac {x_j-\mu_j}{\sigma_j}
\]
具体实现如下:

X_std = np.copy(X)
X_std[:, 0] = (X[:,0] - X[:,0].mean()) / X[:,0].std()
X_std[:, 1] = (X[:,1] - X[:,1].mean()) / X[:,1].std()

数据已经预处理结束,接下来我们开始训练模型

ada = AdalineGD(n_iter=15, eta=0.01)
ada.fit(X_std, y)
plot_decision_region(X_std, y, classifier=ada)
plt.title('Adaline - Gradient Descent')
plt.xlabel('sepal length [standardized]')
plt.ylabel('petal length [standardized]')
plt.legend(loc='upper left')
plt.show()

plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epoches')
plt.ylabel('Sum-squared_error')
plt.show()

从上图看出,随着迭代次数的增加,误差逐渐降低,虽然学习率为0.01,在进行标准化之前,算法并不能收敛,但经过标准化后,算法最终收敛。

python机器学习——自适应线性神经元的更多相关文章

  1. 吴裕雄 python 机器学习——支持向量机线性分类LinearSVC模型

    import numpy as np import matplotlib.pyplot as plt from sklearn import datasets, linear_model,svm fr ...

  2. 吴裕雄 python 机器学习——局部线性嵌入LLE降维模型

    # -*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as plt from sklearn import datas ...

  3. Python机器学习中文版

    Python机器学习简介 第一章 让计算机从数据中学习 将数据转化为知识 三类机器学习算法 第二章 训练机器学习分类算法 透过人工神经元一窥早期机器学习历史 使用Python实现感知机算法 基于Iri ...

  4. Python机器学习中文版目录

    建议Ctrl+D保存到收藏夹,方便随时查看 人工智能(AI)学习资料库 Python机器学习简介 第一章 让计算机从数据中学习 将数据转化为知识 三类机器学习算法 第二章 训练机器学习分类算法 透过人 ...

  5. 《Python 机器学习》笔记(二)

    机器学习分类算法 本章将介绍最早以算法方式描述的分类机器学习算法:感知器(perceptron)和自适应线性神经元. 人造神经元--早期机器学习概览 MP神经元 生物神经元和MP神经元模型的对应关系如 ...

  6. python机器学习——随机梯度下降

    上一篇我们实现了使用梯度下降法的自适应线性神经元,这个方法会使用所有的训练样本来对权重向量进行更新,也可以称之为批量梯度下降(batch gradient descent).假设现在我们数据集中拥有大 ...

  7. Python机器学习笔记:不得不了解的机器学习知识点(2)

    之前一篇笔记: Python机器学习笔记:不得不了解的机器学习知识点(1) 1,什么样的资料集不适合用深度学习? 数据集太小,数据样本不足时,深度学习相对其它机器学习算法,没有明显优势. 数据集没有局 ...

  8. python机器学习实战(四)

    python机器学习实战(三) 版权声明:本文为博主原创文章,转载请指明转载地址 www.cnblogs.com/fydeblog/p/7364317.html 前言 这篇notebook是关于机器学 ...

  9. Python机器学习:5.6 使用核PCA进行非线性映射

    许多机器学习算法都有一个假设:输入数据要是线性可分的.感知机算法必须针对完全线性可分数据才能收敛.考虑到噪音,Adalien.逻辑斯蒂回归和SVM并不会要求数据完全线性可分. 但是现实生活中有大量的非 ...

随机推荐

  1. 我的Spring Boot学习记录(二):Tomcat Server以及Spring MVC的上下文问题

    Spring Boot版本: 2.0.0.RELEASE 这里需要引入依赖 spring-boot-starter-web 这里有可能有个人的误解,请抱着怀疑态度看. 建议: 感觉自己也会被绕晕,所以 ...

  2. bugku猫片

    这个猫片思路清奇,真的让我长知识了. 开局一只猫,挺可爱的.   拿到图片,老套路来一波,首先 winhex打开是正常png图片,binwalk ,stegslove都没有任何收获. 折腾了好久没有任 ...

  3. Java技能树-图片版

    最近在总结技能树,打算先拓宽下视野和技术的广度,后面会详细研究每个常用的技术点,补充技术的深度!下面是我在ProcessOn上总结的,里面有些有注释,点击这里注册ProcessOn,点击这里,可查看或 ...

  4. 第10项:重写equals时请遵守通用约定

      重写equals方法看起来似乎很简单,但是有许多重写方式会导致错误,而且后果非常严重.最容易避免这类问题的办法就是不覆盖equals方法,在这种情况下,类的每个实例都只能与它自身相等.如果满足了以 ...

  5. eclipse基础设置

    主要参考blog https://jingyan.baidu.com/article/d5a880eb6c4f7813f147ccef.html https://blog.csdn.net/Ricar ...

  6. i春秋DMZ大型靶场实验(二)提权漏洞

    拿到靶场 直接进行扫描 爆破路径 发现 phpinfo, phpmyadmin  更具phpinfo 获取跟路径  也可以通过 输入错路径爆出绝对路径 phpmyamin  弱口令登录  root,r ...

  7. 提权案例(一)渗透某asp.net网站通过sql server数据库public 提权 思路分享

    先罗列出sql server 角色用户的权限 按照从最低级别角色(bulkadmin)到最高级别角色(sysadmin)的顺序进行描述:1.bulkadmin:这个角色可以运行BULK INSERT语 ...

  8. 在Spring Boot项目中使用Spock测试框架

    本文首发于个人网站:在Spring Boot项目中使用Spock测试框架 Spock框架是基于Groovy语言的测试框架,Groovy与Java具备良好的互操作性,因此可以在Spring Boot项目 ...

  9. javascript函数前面加~波浪线的作用

    如下,在函数前加上波浪号,其作用是把函数声明转换为表达式,这样就可以直接运行. ~function sayHello(){ console.log('hello'); }() 测试: 在console ...

  10. C++ 11标准

    C++11,也称为C++0x.为目前C++编程语言的最新正式标准(ISO/IEC 14882:2011).它将取代第二版标准ISO/IEC 14882:2003(第一版ISO/IEC 14882:19 ...