精华内容
下载资源
问答
  • 多层感知器

    千次阅读 2019-08-08 22:57:26
    很简单的一个分布,但事实上就是无法用直线进行分类,后来就出现了多层感知器,主要改变的地方是把第一层的感知器的输出作为第二层感知器的输入,即使只是简单添加一层感知器,也足以解决xor问题,关键的原因是,多...

    在介绍单层感知器的时候,我们提到对于非线性可分问题,单层感知器是很难解决的,比如下面这个例子:

    很简单的一个分布,但事实上就是无法用直线进行分类,后来就出现了多层感知器,主要改变的地方是把第一层的感知器的输出作为第二层感知器的输入,即使只是简单添加一层感知器,也足以解决xor问题,关键的原因是,多了一层感知器,就像对原来的输入做了一个映射,第一层感知器的目的是对输入进行映射使得数据在新的空间能够线性可分,然后我们再利用第二层感知器对数据进行分类,我们通过训练模型,使得第一层感知器能更好地重新映射原输入,第二层感知器能更好地分类。

    接下来结合下图介绍一下多层感知器的一些术语和结构。

    多层感知器,又叫深度前馈网络、前馈神经网络。最左边的是输入层,就是我们的输入数据,最右边的是输出层,中间的就是隐藏层(因为训练数据并没有直接表明隐藏层的每一层的所需输出),实际上就是由感知器构成。从现在开始,感知器就开始称为神经元,而这整个包含了输入层、隐藏层和输出层的结构就是大名鼎鼎的神经网络。可以看到相邻层之间的神经元是全连接的。

    多层感知器的学习过程也是和感知器接近,主要都是计算训练数据的输出,根据预测输出和实际输出之间的差异去调整神经元的权值和阈值,不断迭代训练直到误差小于一定范围。同时也可能有一种情况,就是迭代次数已经很大可是模型依然无法得到很好的训练效果,这时我们就需要调整模型的超参数,比如神经元的数量、隐藏层的层数等等。基本上,这个过程和之前的线性回归等机器学习过程是一致的。

    想浏览更多关于数学、机器学习、深度学习的内容,可浏览本人博客

    展开全文
  • 多层感知器速成

    千次阅读 2020-07-07 09:38:29
    转载自《深度学习–基于Keras的Python实践》第四章 ...人工神经网络领域通常被称为神经网络或多层感知器(MLP,MultilayerPerceptron),多层感知器也许是最有用的神经网络类型。多层感知器是一种前馈.

    转载自《深度学习–基于Keras的Python实践》第四章
    魏贞原 著
    电子工业出版社
    微信文章地址:https://mp.weixin.qq.com/s/WWuKIE4ZGD3KFjLnBojjhQ
    很不错的书,推荐购买实体书。
    转载目的是为了方便大家学习,如有侵权,请联系 root@smileyan.cn 。立即删除

    人工神经网络是一个引人入胜的学习领域,尽管在开始学习的时候非常复杂。本章将会快速的介绍一下在人工神经网络领域使用的多层感知器。

    4.1 多层感知器

    人工神经网络领域通常被称为神经网络或多层感知器(MLP,MultilayerPerceptron),多层感知器也许是最有用的神经网络类型。多层感知器是一种前馈人工神经网络模型,其将输入的多个数据维度映射到单一的输出的数据维度上。感知器是单个神经元模型,它是较大神经网络的基石。多层感知器是一个研究如何模拟生物电脑模型来解决困难的计算任务的方法,是具有良好的鲁棒性算法和数据结构的模型。

    神经网络依靠系统的复杂程度,通过调整内部大量节点之间相互连接的关系,从而达到处理信息的目的。神经网络的一个重要特性是它能够从环境中学习,并把学习的结果分布存储于网络的突触连接中。在数学上,神经网络能够学习任何映射函数,并且已被证明是一种通用近似算法。神经网络的学习是一个过程,在其所处环境的激励下,相继给网络输入一些样本模式,并按照一定的规则(学习算法)调整网络各层的权值矩阵,待网络各层权值都收敛到一定值,学习过程结束。然后就可以用生成的神经网络来对真实数据做预测。神经网络的预测能力来自网络的分层或多层结构。数据结构可以选择(学习代表)不同尺度或分辨率的特征,并将它们组合成高阶特征。例如从线,到线的集合到形状。

    4.2 神经元

    神经元是构成神经网络的基本模块。神经元模型是一个包含加权输入,并且使用激活功能产生输出信号的基础计算单元。输入可以类比为神经元的树突,而输出可以类比为神经元的轴突,计算则可以类比为细胞核。图4-1是一个简单的神经元示例,有3个输入和一个输出构成。

    图 4.1

    4.2.1 神经元权重

    线性回归中输入的权重与回归方程中使用的系数非常相似。与线性回归一样,每个神经元也有一个偏差,可以被认为是总是具有值1.0的输入,它也必须加权。例如,神经元可能有两个输入,在这种情况下,它需要三个权重。每个输入一个,偏置一个。

    尽管可以使用更复杂的初始化方案,权重通常被初始化为小的随机值,例如0到0.3范围内的值。像线性回归一样,较大的权重表示模型的复杂性和脆弱性的增加。小随机数初始化权重初始值要非常接近0又不能等于0,就是将权重初始化为很小的数值,以此来打破对称性。

    采用小随机数初始化权重,为什么不将权重初始化为0?因为如果网络中的每个神经元都计算出同样的输出,然后它们就会在反向传播中计算出同样的梯度,从而进行同样的参数更新。换句话说,如果权重被初始化为同样的值,神经元之间就失去了不对称性的源头。如果神经元刚开始的时候是随机且不相等的,那么它们将计算出不同的更新,并将自身变成整个网络的不同部分。

    4.2.2 激活函数

    激活函数是将加权输入与神经元输出的简单映射。它被称为激活函数,是因为它控制神经元激活的阈值和输出信号的强度。历史上最简单的激活函数时临界值判定,如总和输入高于阈值,例如0.5,则神经元将输出1.0的值,否则将输出0.0。

    激活函数通常有如下一些性质:

    • 非线性:当激活函数是线性的时候,一个两层的神经网络就可以逼近基本上所有的函数了。但是,如果激活函数是恒等激活函数的时候(即f(x)=x),就不满足这个性质了,而且如果MLP使用的是恒等激活函数,那么其实整个网络跟单层神经网络是等价的。
    • 可微性:当优化方法是基于梯度的时候,这个性质是必须的
    • 单调性:当激活函数是单调的时候,单层网络能够保证是凸函数。
    • f(x)≈x:当激活函数满足这个性质的时候,如果参数的初始化是random的很小的值,那么神经网络的训练将会很高效;如果不满足这个性质,那么就需要很用心的去设置初始值。
    • 输出值的范围:当激活函数输出值是有限的时候,基于梯度的优化方法会更加稳定,因为特征的表示受有限权值的影响更显著;当激活函数的输出是无限的时候,模型的训练会更加高效,不过在这种情况小,一般需要更小的学习率。

    既然激活函数具有这些特征,那么如何选择计划函数呢?传统上使用非线性激活函数。这允许网络以更复杂的方式组合输入,从而可以构建的功能中更丰富的模型。使用类似逻辑函数的非线性函数也称为sigmoid函数,它们以s形分布输出0和1之间的值。双曲正切函数也称为Tanh,它在-1到+1范围内输出相同的分布。最近,线性整流函数( ReLU)已被证明可以提供更好的结果,相比于 sigmoid和Tanh,ReLU只需要一个阈值就可以得到激活值,而不用去算一大堆复杂的运算。当然ReLU 也有缺点,就是训练的时候很”脆弱”,很容易就“死掉”。举个例子,一个非常大的梯度流过一个ReLU 神经元,更新过参数之后,这个神经元再也不会对任何数据有激活现象了。如果这个情况发生了,那么这个神经元的梯度就永远都会是0。

    4.3 神经网络

    神经元被布置成神经元网络。一排或者一列神经元称为一层,一个网络可以有多个层。网络中神经元的架构通常被称为网络拓扑。如图所示:
    图4-2
    在开始介绍神经网络之前,有一些知识可以先记在心里:

    • 设计一个神经网络时,输入层与输出层的节点数往往是固定的,中间层则可以自由指定;
    • 神经网络结构图中的拓扑与箭头代表着预测过程时数据的流向,跟训练时的数据流有一定的区别;
    • 结构图里的关键不是圆圈(代表“神经元”),而是连接线(代表“神经元”之间的连接)。每个连接线对应一个不同的权重(其值称为权值),这是需要训练得到的。

    4.3.1 输入层(可视层)

    从数据集中获取输入的层也称为可视层,因为它是网络的暴露在外的部分。通常,在数据集中每个输入值或列具有一个神经元,具有一个神经元的神经网络。输入层的神经元与上述神经元不同,仅是简单地将输入值传递到下一层。

    4.3.2 隐藏层

    输入层之后的层被称为隐藏层,因为它们不直接暴露给输入。最简单的网络结构是在隐层中具有直接输出值的单个神经元。考虑到计算能力和高效算法的增加,可以构建非常深的神经网络。深度学习可以指神经网络中有很多隐藏层。多层的神经网络,过去在训练上表现不佳,使用现代技术和硬件可能仅需要几秒钟或几分钟就能完成训练。理论证明,两层神经网络可以无限逼近任意连续函数。也就是说,面对复杂的非线性分类任务,两层(带一个隐藏层)神经网络可以分类的很好,关键就是从输入层到隐藏层时,数据发生了空间变换。也就是说,两层神经网络中,隐藏层对原始的数据进行了一个空间变换,使其可以被线性分类,然后输出层的决策分界划出了一个线性分类分界线,对其进行分类。两层神经网络通过两层的线性模型模拟了数据内真实的非线性函数。因此,多层的神经网络的本质就是复杂函数拟合。

    4.3.3 输出层

    最后的隐藏层称为输出层,它负责输出与项目问题所需格式相对应的值的值或向量。输出层中激活功能的选择受建模的问题类型的强烈约束。例如:

    • 回归问题可能有单个输出神经元,神经元可能没有激活功能。
    • 二进制分类问题可能具有单个输出神经元,并使用sigmoid激活函数输出0和1之间的值,以表示预测主类的值的概率。这可以通过使用阈值为0.5,捕捉值小于阈值为0而变为清晰的类值,否则为1。
    • 多分类分类问题可能在输出层中有多个神经元,每个类别有一个神经元(例如著名的鸢尾花分类问题中的三个类别的三个神经元)。在这种情况下,可以使用softmax激活功能来输出网络预测每个类值的概率。选择具有最高概率的输出可用于产生清晰的类分类值。

    在设计一个神经网络时,输入层的节点数需要与特征的维度匹配,输出层的节点数要与目标的维度匹配。而中间层的节点数,却是由设计者指定的。因此,“自由”把握在设计者的手中。但是,节点数设置的多少,却会影响到整个模型的效果。如何决定这个自由层的节点数呢?目前业界没有完善的理论来指导这个决策。一般是根据经验来设置。较好的方法就是预先设定几个可选值,通过切换这几个值来看整个模型的预测效果,选择效果最好的值作为最终选择。这种方法又叫做GridSearch(网格搜索)。

    4.4 训练神经网络

    当完成对神经网络的配置后,需要通过数据集来训练神经网络模型。

    4.4.1 准备数据

    训练神经网络模型首先必须准备数据,数据必须是数值。如果数据中存在类别数据,例如男性和女性的性别属性,可以将其转换为称为一个热编码的数值来表示分类。如:将男性设置为1,女性设置为0。

    对于多分类问题,输出变量可以使用相同的热编码。这将从单个列创建一个二进制向量,为每个类别输出一个值,并且很容易直接与网络输出层中神经元的输出进行比较。神经网络需要以相同的尺度对输入进行缩放,因此可以将其数据缩放到0和1之间的范围,称为归一化(Normalization)。另一种流行的技术是使其标准化(Standardize),使每列的分布具有零的平均值和标准偏差1。标度也适用于图像像素数据,单词的数据可以被转换为整数,例如数据集中的单词的频率等级和其他编码技术。

    4.4.2 随机梯度下降算法

    经典并且最为有效的神经网络训练算法称为随机梯度下降。随机梯度下降是随机和优化相结合的产物,属于梯度下降的一种,适用于大规模的问题。要想理解随机梯度下降,需要先明确梯度下降。众所周知,每个优化问题会有一个目标函数,梯度下降就是采用迭代的策略,从初始点开始,每次沿着目标函数在当前点的负梯度方向前进一定的步长,只要步长设置合理,可以得到一个单调递减的序列,直至最终不再下降,即可得到最优解。对于一般优化问题,梯度下降可以找到局部最优解,对于凸优化问题,梯度下降可以得到全局最优解。但是,当数据量非常大时,梯度下降的计算开销非常大,现在的DeepLearning中的数据量时非常巨大的,为了降低梯度下降的巨大计算开销,就出现了随机梯度下降算法。随机梯度下降的基本想法很简单,就是不直接计算梯度的精确值,而是用梯度的无偏估计来代替梯度,以便降低计算开销。从而让数据快速收敛。

    输入通过神经元的激活函数,一直传递到输出,这个过程叫做向前传导。将网络的输出与预期输出进行比较,并计算出错误。然后,该错误通过网络一次传播回来,并且根据它们对错误的贡献量更新权重。这个过程称为反向传播算法。在神经网络的模型训练中,会使用训练数据重复此过程。整个训练数据集的一轮更新网络被称为epochs。完成整个神经网络模型的训练需要数十,数百或数千个epochs。

    4.4.3 权重更新

    使用每个训练数据中错误计算更新网络中的权重,被称为在线学习。这可能会导致网络快速而混乱的变化。作为改进方法,在所有训练过程中保存结果误差,并在最后更新网络,这被称为批量学习,通常更稳定。

    通常数据集非常大,为了提高计算效率,批处理的大小,网络在更新之前显示的示例的数量通常减少到一个很小的数目,例如数十或数百个示例。权重更新由被称为学习率的配置参数控制,它也被称为步长,并控制给定结果误差对网络权重的更新。通常使用较小的学习率,例如0.1或0.01或更小。此外,更新方程还可以设置其他配置参数:

    • 动量(Momentum):不恰当的初始权值可能使得网络的损失函数在训练过程中陷入局部最小值,达不到全局最优的状态。因此,如何消除这种不确定性,是训练深度网络是必须解决的一个问题。动量(Momentum)能够在一定程度上解决这个问题,即使在计算过程中很少存在结果误差,也能确保持续更新权重。
    • 学习率衰减(Learning Rate Decay):平衡模型的训练速度和损失(loss)后选择了相对合适的学习率(learningrate),但是训练集的损失下降到一定的程度后就不在下降,遇到这种情况通常可以通过适当降低学习率(learningrate)来实现。但是,降低学习率又会延长训练所需的时间。学习率衰减(learningrate decay)就是一种可以平衡这两者之间矛盾的解决方案。学习率衰减的基本思想是:学习率随着训练的进行逐渐衰减。

    4.4.4 预测新数据

    一旦神经网络被训练,就可以用来做出预测。可以通过对评估数据进行预测,来评估模型对未知数据的准确度。训练完成的模型,可以部署到生产环境,并对新数据做出预测。网络拓扑和最终的权重集都是需要保存到模型的数据。通过向网络提供输入并执行向前传导,计算新数据通过模型后的输出,来完成对新数据的预测。

    在单层神经网络时,使用的激活函数是sgn函数。到了两层神经网络时,使用的最多的是sigmoid函数。而到了多层神经网络时,通过一系列的研究发现,ReLU函数在训练多层神经网络时,更容易收敛,并且预测性能更好。因此,目前在深度学习中,最流行的非线性函数是ReLU函数。ReLU函数不是传统的非线性函数,而是分段线性函数。其表达式非常简单,就是y=max(x,0)。简而言之,在x大于0,输出就是输入,而在x小于0时,输出就保持为0。这种函数的设计启发来自于生物神经元对于激励的线性响应,以及当低于某个阈值后就不再响应的模拟。

    在多层神经网络中,训练的主题仍然是优化和泛化。当使用足够强的计算芯片(例如GPU图形加速卡)时,梯度下降算法以及反向传播算法在多层神经网络中的训练中仍然工作的很好。目前学术界主要的研究既在于开发新的算法,也在于对这两个算法进行不断的优化,例如,增加了一种带动量因子(momentum)的梯度下降算法。

    在深度学习中,泛化技术变的比以往更加的重要。这主要是因为神经网络的层数增加了,参数也增加了,表示能力大幅度增强,很容易出现过拟合现象。因此正则化技术就显得十分重要。目前,Dropout技术,以及数据扩容(Data-Augmentation)技术是目前使用的最多的正则化技术。

    转载自《深度学习–基于Keras的Python实践》第四章
    魏贞原 著
    电子工业出版社
    微信文章地址:https://mp.weixin.qq.com/s/WWuKIE4ZGD3KFjLnBojjhQ
    很不错的书,推荐购买实体书。
    转载目的是为了方便大家学习,如有侵权,请联系 root@smileyan.cn 。立即删除

    展开全文
  • 多层感知器的基本特征

    千次阅读 2018-04-22 18:06:33
    多层感知器的基本特征 Rosenblatt 感知器本质上是一个单层神经网络,这一网络局限于线性可分模式的分类问题。自适应滤波采用了 Widrow 和 Hoff 的 LMS 算法。这一算法也是基于权值可调的单个线性神经元,这也限制...

    多层感知器的基本特征

            Rosenblatt 感知器本质上是一个单层神经网络,这一网络局限于线性可分模式的分类问题。自适应滤波采用了 Widrow 和 Hoff 的 LMS 算法。这一算法也是基于权值可调的单个线性神经元,这也限制了这一算法的计算能力。为了克服感知器和 LMS 算法的实际局限,我们考虑所熟知的多层感知器这一神经网络结构。
            下面的三点揭示了多层感知器的基本特征:
    1. 网络中每个神经元模型包含一个可微的非线性激活函数。
    2. 网络中包括一个或多个隐藏在输人和输出神经节点之间的层。
    3. 网络展示出高度的连接性,其强度是由网络的突触权值决定的。

            同样这些特性也导致了现阶段关于网络行为知识的缺乏。首先,由于非线性分布式的存在和网络的高度连接性使得多层感知器的理论分析难于进行。第二,隐藏层的使用使得学习过程变得更难。这暗示着学习过程必须决定输入模式的哪些特征应该由隐藏层神经元表示出来。学习过程因此变得更困难了,因为不得不在大得多的可能函数空间中搜索,同时必须在输入模式的不同表示中进行选择。

    References
    (加) Simon Haykin (海金) 著, 申富饶, 徐烨, 郑俊, 晁静 译. 神经网络与机器学习[M]. 北京:机械工业出版社, 2011. 1-572

    展开全文
  • 多层感知器教学

    千次阅读 2016-02-04 19:23:26
    我们将要了解什么是多层感知器神经网络,为什么它这么强大以及我们如何实现它。 图一:多层感知器 我们将要介绍多层感知器神经网络以及反向传播算法,这是现今最流行的神经网络结构。 教学前提知识 读者要熟悉...
    

    原文,图片,代码来源:

    http://blog.refu.co/?p=931

    原文作者:

    Lefteris

    还推荐一个学习神经网络的免费书本:

    http://neuralnetworksanddeeplearning.com/index.html


    这个教程是之前感知器教学的后续。我们将要了解什么是多层感知器神经网络,为什么它这么强大以及我们如何实现它。

    Structure of a Multilayer perceptron

    图一:多层感知器


    我们将要介绍多层感知器神经网络以及反向传播算法,这是现今最流行的神经网络结构。


    教学前提知识

    读者要熟悉感知器神经网络(单个的)

    读者有c/c++的基础知识

    读者知道如何编译和运行程序


    教学目标

    读者将会了解到多层感知器神经网络

    读者将会了解到反向传播算法

    读者将会知道这个神经网络广泛应用在哪里

    读者将通过一个光学字符识别的例子学习到以上的知识


    这个神经网络在1986年与反向传播算法一起提出。直到那个时候,没有任何规则去训练多层的神经网络。多层感知器就如它的名字一样,由很多个神经元,分成很多层。如图一所示:

    1,输入层(input layer),这一层是神经网络的输入。在这一层,有多少个输入就有多少个神经元。

    2,一层或者多层隐藏层(hidden layers)。隐藏层在输入层和输出层之间,层数是可变的。隐藏层的功能就是把输入映射到输出。已经得到证明的是,一个只有一个隐藏层的多层感知器可以估算任何连接输入和输出的函数,如果这个函数存在的话。

    3,输出层,这层的神经元的多少取决于我们要解决的问题。


    多层感知器与简单的感知器有很多的不同。相同的是它们的权重都是随机的,所有的权重通常都是[-0.5,0.5]之间的随机数。除此之外,每个模式(pattern)输入到神经网络时,都会经过三个阶段。接下来让我们一个个详细地介绍。


    阶段一:输出的计算

    在这个阶段,我们计算神经网络的输出。在每一层,我们计算这一层每个神经元的触发值(firing value)。触发值通过计算连接这个神经元的前一层的所有神经元的值与相应的权重的乘积之和得到。有点拗口,看看代码吧

    for(int i = 0; i < previousLayerNeurons; i ++)
        value[neuron,layer] += weight(i,neuron) * value[i,layer-1];
     
        value[neuron,layer] = activationFunction(value[neuron,layer]);

    从上面的伪代码我们可以看到激励函数(activation function)。激励函数是用来归一化每个神经元的输出的。这个函数在感知器的分析中经常出现。这个输出的计算在神经网络中一层层往前直到输出层得到一些输出值。这些输出值一开始的时候都是随机的,跟我们的目标值没有什么关系。但这里是反向传递算法的开始之处。


    阶段二:反向传递

    反向传递算法使用了delta规则。这个算法就是在算delta,这是从输出神经元开始往回直到输入层的每个神经元的局部梯度下降。要计算输出神经元的delta,我们首先要得到每个输出神经元的误差。这是很简单的,因为多层感知器是有监督的训练网络,所以误差就是神经网络的输出与实际输出的差别。

    ej(n) = dj(n) – oj(n)

    e(n)是误差向量,d(n)是实际输出(期望输出),o(n)是神经网络的输出。现在可以计算delta了,

    deltaj(L)(n) = ej(L)(n) * f'(uj(L)(n)) ,这个式子是对于在输出层L的第j个神经元

    f'(uj(L)(n))是输出层L的第j个神经元的值的求导所得的值。

    deltaj(l)(n) = f'(uj(l)(n)) Σk(deltak(l+1)(n)*wkj(l+1)(n)),这个式子是对于隐藏层l的第j个神经元

    f'(uj(l)(n))是层l的第j个神经元的值的求导所得的值。在求和符号里面的是下一层所有神经元的delta值以及相应的权重的乘积。

    这一部分在delta规则中是很重要的,是反向传递算法的精髓。你可能会问为什么?因为中学数学老师教过我们,求导能得到一个函数随着它的输入的变化,这个函数变化了多少。通过反向传递求导的值,前面的神经元就会知道权重要变化多少以更好地让神经网络的输出符合实际的输出。这一切都要从神经网络的输出与实际输出的差别开始算起。是不是很神奇呢?

    阶段三:权重的调整

    在计算了所有神经元的delta之后,我们开始最后一个阶段的计算。这次,我们要根据以下式子调整权重:

    wji(l)(n+1) = wji(l)(n) + α * [wji(l)(n) – wji(l)(n-1)] + η * deltaj(l)(n)yi(l-1)(n)

    不要被这么多数学符号吓到,其实这很简单,这个式子说的是:

    对于层l来说,新的权重是在现在的权重上加上两样东西。第一个是现在权重与之前的权重的差别乘以一个系数α。这个系数叫做势系数(momentum coefficient)。势系数通过往多层神经网络里面加入已经发生的权重变化起到加速训练的作用。这是把双刃剑,因为如果势系数设得太大,神经网络不会收敛,很有可能陷入局部最小值。

    另一个加入的东西是层 l 的delta值乘以前一层 l-1 的神经元的输出,这个乘积还要乘以一个系数η,在前一个教学中我们已经学过这个系数叫学习步长。基本就是这样了!这就是多层感知器了。在统计分析中,神经网络是一个毋庸置疑的强有力的工具!

    实例

    多层感知器有很多应用。统计分析学,模式识别,光学符号识别只是其中的一些应用。我们将给出一个很简单的例子。最后,MLP(多层感知器)能够分辨出一些单色位图并且告诉我们每幅图对应哪个数字,这些图片是一些8×8 像素的图片。当然图片的像素可以由用户自己定义,因为程序会自动读取位图的大小。下图是一个例子:

    bitmaps

    这些数字很丑,是不是?对于计算机来说分辨它们会很难吗?这些丑的地方可以视作噪声。MLP(多层感知器)真的很擅长分辨噪声和实际的数据。让我们看看代码吧:

     class MLP
        {
        private:
        std::vector<float> inputNeurons;
        std::vector<float>> hiddenNeurons;
        std::vector<float> outputNeurons;
        std::vector<float> weights;
     
        FileReader* reader;
        int inputN,outputN,hiddenN,hiddenL;
        public:
        MLP(int hiddenL,int hiddenN);
        ~MLP();
     
        //assigns values to the input neurons
        bool populateInput(int fileNum);
        //calculates the whole network, from input to output
        void calculateNetwork();
        //trains the network according to our parameters
        bool trainNetwork(float teachingStep,float lmse,float momentum,int trainingFiles);
        //recalls the network for a given bitmap file
        void recallNetwork(int fileNum);
        };

    以上就是多层感知器的类。我们可以看到有神经元向量,权重向量。还有个FileReader的对象。这个FileReader是一个读取位图文件的类。MLP读取位图文件,计算神经网络的输出然后训练神将网络。此外,你还可以输入一个‘fileNum'来调用这个神经网络,看下神经网络对你给的图片上的数字的判断是什么。

     //Multi-layer perceptron constructor
        MLP::MLP(int hL,int hN)
        {
        //initialize the filereader
        reader = new FileReader();
        outputN = 10; //the 9 possible numbers and zero
        hiddenL = hL;
        hiddenN = hN;
     
        //initialize the filereader
        reader = new FileReader();
     
        //read the first image to see what kind of input will our net have
        inputN = reader->getBitmapDimensions();
        if(inputN == -1)
        {
        printf("There was an error detecting img0.bmp\n\r");
        return ;
        }
     
        //let's allocate the memory for the weights
        weights.reserve(inputN*hiddenN+(hiddenN*hiddenN*(hiddenL-1))+hiddenN*outputN);
     
        //also let's set the size for the neurons vector
        inputNeurons.resize(inputN);
        hiddenNeurons.resize(hiddenN*hiddenL);
        outputNeurons.resize(outputN);
     
        //randomize weights for inputs to 1st hidden layer
        for(int i = 0; i < inputN*hiddenN; i++)
        {
        weights.push_back( (( (float)rand() / ((float)(RAND_MAX)+(float)(1)) )) - 0.5 );//[-0.5,0.5]
        }
     
        //if there are more than 1 hidden layers, randomize their weights
        for(int i=1; i < hiddenL; i++)
        {
        for(int j = 0; j < hiddenN*hiddenN; j++)
        {
        weights.push_back( (( (float)rand() / ((float)(RAND_MAX)+(float)(1)) )) - 0.5 );//[-0.5,0.5]
        }
        }
        //and finally randomize the weights for the output layer
        for(int i = 0; i < hiddenN*outputN; i ++)
        {
        weights.push_back( (( (float)rand() / ((float)(RAND_MAX)+(float)(1)) )) - 0.5 );//[-0.5,0.5]
        }
        }
    神经网络把隐藏层的层数和隐藏层的神经元数作为参数来初始化神经元和权重向量。此外,通过一下这个语句,神经网络读取第一幅位图'imag0.bmp'以获取输入的维数(即输入层的神经元个数):
    <pre lang="" cpp="" style="box-sizing: inherit; font-size: 16px; font-family: Inconsolata, monospace; border: 1px solid rgb(209, 209, 209); line-height: 1.3125; margin-top: 0px; margin-bottom: 1.75em; max-width: 100%; overflow: auto; padding: 1.75em; white-space: pre-wrap; word-wrap: break-word; color: rgb(26, 26, 26); background-color: rgb(255, 255, 255);">inputN = reader->getBitmapDimensions();
    
    

    这个输入是这个教程的程序需要的。你可以随意输入任何大小的位图,但是之后输入的位图必须与第一输入的位图大小一致。大部分的神经网络的权重初始化范围是[-0.5,0.5]。

     void MLP::calculateNetwork()
        {
        //let's propagate towards the hidden layer
        for(int hidden = 0; hidden < hiddenN; hidden++)
        {
        hiddenAt(1,hidden) = 0;
        for(int input = 0 ; input < inputN; input ++)
        {
        hiddenAt(1,hidden) += inputNeurons.at(input)*inputToHidden(input,hidden);
        }
        //and finally pass it through the activation function
        hiddenAt(1,hidden) = sigmoid(hiddenAt(1,hidden));
        }
     
        //now if we got more than one hidden layers
        for(int i = 2; i <= hiddenL; i ++)
        {
        //for each one of these extra layers calculate their values
        for(int j = 0; j < hiddenN; j++)//to
        {
        hiddenAt(i,j) = 0;
        for(int k = 0; k < hiddenN; k++)//from
        {
        hiddenAt(i,j) += hiddenAt(i-1,k)*hiddenToHidden(i,k,j);
        }
        //and finally pass it through the activation function
        hiddenAt(i,j) = sigmoid(hiddenAt(i,j));
        }
        }
     
        int i;
        //and now hidden to output
        for(i =0; i < outputN; i ++)
        {
        outputNeurons.at(i) = 0;
        for(int j = 0; j < hiddenN; j++)
        {
        outputNeurons.at(i) += hiddenAt(hiddenL,j) * hiddenToOutput(j,i);
        }
        //and finally pass it through the activation function
        outputNeurons.at(i) = sigmoid( outputNeurons.at(i) );
        }
        }
    上面这个calculateNetwrok()计算当前输入的输出。它把输入的信号传递到输出层。上面的代码并没有什么特别,就是之前讲到的一些式子的实现。这个例子有10个不同的输出。每个输出表示的是 输入的模式是一个特定的数字的可能性。所以,输出1(接近1.0)表示输入的模式最有可能是1,以此类推。


    训练函数太大不能摆在这里,但是推荐你看.zip文件里面的源代码(原文中有源代码下载)。我们就集中看反向传递算法的实现。

    for(int i = 0; i < outputN; i ++)
        {
        //let's get the delta of the output layer
        //and the accumulated error
        if(i != target)
        {
        outputDeltaAt(i) = (0.0 - outputNeurons[i])*dersigmoid(outputNeurons[i]);
        error += (0.0 - outputNeurons[i])*(0.0-outputNeurons[i]);
        }
        else
        {
        outputDeltaAt(i) = (1.0 - outputNeurons[i])*dersigmoid(outputNeurons[i]);
        error += (1.0 - outputNeurons[i])*(1.0-outputNeurons[i]);
        }
        }
        //we start propagating backwards now, to get the error of each neuron
        //in every layer
        //let's get the delta of the last hidden layer first
        for(int i = 0; i < hiddenN; i++)
        {
        hiddenDeltaAt(hiddenL,i) = 0;//zero the values from the previous iteration
        //add to the delta for each connection with an output neuron
        for(int j = 0; j < outputN; j ++)
        {
        hiddenDeltaAt(hiddenL,i) += outputDeltaAt(j) * hiddenToOutput(i,j) ;
        }
        //The derivative here is only because of the
        //delta rule weight adjustment about to follow
        hiddenDeltaAt(hiddenL,i) *= dersigmoid(hiddenAt(hiddenL,i));
        }
     
        //now for each additional hidden layer, provided they exist
        for(int i = hiddenL-1; i >0; i--)
        {
        //add to each neuron's hidden delta
        for(int j = 0; j < hiddenN; j ++)//from
        {
        hiddenDeltaAt(i,j) = 0;//zero the values from the previous iteration
        for(int k = 0; k < hiddenN; k++)//to
        {
        //the previous hidden layers delta multiplied by the weights
        //for each neuron
        hiddenDeltaAt(i,j) += hiddenDeltaAt(i+1,k) * hiddenToHidden(i+1,j,k);
        }
        //The derivative here is only because of the
        //delta rule weight adjustment about to follow
        hiddenDeltaAt(i,j) *= dersigmoid(hiddenAt(i,j));
        }

    我们看到上面的代码是第二阶段反向传播算法。计算了输出并且知道期望输出(或者在上面的代码中叫做target),我们可以根据之前的等式计算delta。如果你不喜欢数学,我们给你有一些代码。你可以看到有很多宏(macros)去分辨不同层的权重以及delta。



    //Weights modification
        tempWeights = weights;//keep the previous weights somewhere, we will need them
     
        //hidden to Input weights
        for(int i = 0; i < inputN; i ++)
        {
        for(int j = 0; j < hiddenN; j ++)
        {
        inputToHidden(i,j) += momentum*(inputToHidden(i,j) - _prev_inputToHidden(i,j)) +
        teachingStep* hiddenDeltaAt(1,j) * inputNeurons[i];
        }
        }
     
        //hidden to hidden weights, provided more than 1 layer exists
        for(int i = 2; i <=hiddenL; i++)
        {
        for(int j = 0; j < hiddenN; j ++)//from
        {
        for(int k =0; k < hiddenN; k ++)//to
        {
        hiddenToHidden(i,j,k) += momentum*(hiddenToHidden(i,j,k) - _prev_hiddenToHidden(i,j,k)) +
        teachingStep * hiddenDeltaAt(i,k) * hiddenAt(i-1,j);
        }
        }
        }
     
        //last hidden layer to output weights
        for(int i = 0; i < outputN; i++)
        {
        for(int j = 0; j < hiddenN; j ++)
        {
        hiddenToOutput(j,i) += momentum*(hiddenToOutput(j,i) - _prev_hiddenToOutput(j,i)) +
        teachingStep * outputDeltaAt(i) * hiddenAt(hiddenL,j);
        }
        }
     
        prWeights = tempWeights;
    以上代码是我们最后的阶段,是一个从前向后由输入层到输出层的算法。我们用之前计算的delta来调整神经网络的权重。这个只是我们之前看到的权重调整的式子的代码实现。

    我们可以看到学习步长如何起作用。此外,细心的读者会发现我们把前一次的权重向量暂时地保存起来。这是因为势(momentum,向前冲之力)。之前那个权重调整的式子里面,势加快了训练速度,因为添加了权重的变化部分。


    这就是关于反向传播训练算法以及多层感知器的所有了。让我们看看那fileReader类吧。

     class FileReader
        {
        private:
        char* imgBuffer;
        //a DWORD
        char* check;
        bool firstImageRead;
        //the input filestream used to read
        ifstream fs;
     
        //image stuff
        int width;
        int height;
        public:
        FileReader();
        ~FileReader();
     
        bool readBitmap(int fileNum);
     
        //reads the first bitmap file, the one designated with a '0'
        //and gets the dimensions. All other .bmp are assumed with
        //equal and identical dimensions
        int getBitmapDimensions();
     
        //returns a pointer to integers with all the goals
        //that each bitmap should have. Reads it from a file
        int* getImgGoals();
     
        //returns a pointer to the currently read data
        char* getImgData();
     
        //helper function convering bytes to an int
        int bytesToInt(char* bytes,int number);
        };

    这个是fileReader类。这个类包含imgBuffer用来存储现在读取的位图数据,这个类用输入文件流来读取位图文件,这个类还会保存初始图片的宽和高。需要知道更多如何实现这些函数的可以看.zip文件。你需要知道的是这个类是用来读取指定的位图’img0.bmp',并且假定其它所有位图的大小是一样的,而且所有图片保存在相同的路径下。

    你可以用任何图片编辑程序去得到单色位图。你可以建立自己的位图,但要用升序的数字去保存他们,并且相应地更新golas.txt。此外,所有的图片要大小一致。

    How to use the executable

    假设你在相同的路径下有一些位图以及goals.txt文件,你可以如上图那样运行这个教程的例子。这就像在windows中使用cmd命令行一样,当然在Linux下也是可以运行的。你可以在上图看到如何调用。如果错误地调用了,你会马上看到一个改正的要求。

    Recalling the mlp


    在windows的训练期间和在Linux每1000代(epochs),你可以停止或者开始调用图片。你要输入图片的号码,就是图片文件名跟在‘img'后面那个数字。神经网络调用这个图片,然后它会告诉你它认为这个图片是什么数字。最后,你可以在上面这幅图看到,神经网络认为这个图片是0到9这些数字的概率。


    展开全文
  • 多层感知器MLP

    千次阅读 2019-11-08 09:12:28
    一、多层感知机(MLP)原理简介 多层感知机(MLP,Multilayer Perceptron)也叫人工神经网络(ANN,Artificial Neural Network),除了输入输出层,它中间可以有多个隐层,最简单的MLP只含一个隐层,即三层的结构,...
  • 多层感知器 在之前的博客中,我们了解到,感知器(指单层感知器)具有一定的局限——无法解决异或问题,即线性不可分的问题。 将多个单层感知器进行组合,就可以得到一个多层感知器(MLP——Multi-Layer Perceptron...
  • 多层感知器、隐藏神经元和信用分配 图 4.1 表示一个具有两个隐藏层和一个输出层的多层感知器的结构图。为了构筑多层感知器一般形式的描述平台,这里说的网络是全连接的 (fully connected)。这就是说在任意层上的一...
  • 多层感知器(MLP)

    千次阅读 2019-02-09 14:29:14
    多层感知器  多层感知器(Multilayer Perceptron,缩写MLP)是一种前向结构的人工神经网络,映射一组输入向量到一组输出向量。MLP可以被看作是一个有向图,由多个的节点层所组成,每一层都全连接到下一层。除了输入...
  • 多层感知器(MLP)

    2021-03-16 22:36:17
    多层感知器(神经网络) 如果逻辑回归模型是单个神经元:计算输入特征的加权和,然后使用一个激活函数(或传递函数)计算输出。 单个神经元(二分类) 多个神经元(多分类) 单层神经元的缺陷 无法拟合“异或”运算...
  • 用Python实现多层感知器神经网络

    千次阅读 2020-09-07 23:01:29
    我将介绍在Python中创建多层感知器(MLP)神经网络的基本知识。 感知器是神经网络的基本组成部分。感知器的输入函数是权重,偏差和输入数据的线性组合。具体来说:in_j = weight input + bias.(in_j =权重输入+偏差)...
  • % 用两层感知器实现异或XOR % 第一层是随机层,即权重何偏差随机确定,以第一层的输出作为第二层的输入
  • 多层感知器(MLP) Rosenblatt感知器和LMS算法,都是单层的并且是单个神经元构造的神经网络,他们的局限性是只能解决线性可分问题,例如Rosenblatt感知器一直没办法处理简单异或问题。然而日常生活中大多数问题...
  • 1.多层感知器与梯度下降算法 多层感知器也叫做神经网络 单层神经网络无法拟合异或问题,因此有了多层神经网络 多层神经网络也用梯度下降算法来训练 梯度下降法是一种致力于找到loss函数极值点的算法,使得...
  • 目录 ...3.建立多层感知器 重点: 1.散点图和plot的区别 2.对于二维数据,可视化的分类方式。-先计算区域的没一点的权重,绘制等高线图,然后撒点。-思路很好 代码: 1.加载数据 ...
  • 本讲从逻辑斯第回归入手,然后讲解softmax分类器,最后讲解多层感知器。文末提供注释详尽的Tensorflow代码实现。 逻辑斯第函数 逻辑斯第回归(Logistic Regression)起源于对生物学中种群数量的演变的建模。设...
  • 数据挖掘——多层感知器算法简介

    千次阅读 2016-08-03 17:35:17
    XOR(抑或)是一种非线性函数,不能被线性可分 人工神经网络简介人工神经网络由三部分组成: - 架构:描述神经元的层次与连接神经元的结构 - 激励函数 ...反馈环表示网络的一种内部状态多层感知器多层感知器(mu
  • 神经网络模型也是近些年大火的人工智能行业基础算法,SPSS软件中支持训练出多层感知器神经网络模型,今天我们一起来看看它是如何通过该专业统计分析软件训练出来的。 一、多层感知器总体介绍 我们准备好训练集数据...
  • SkLearn之MLP(多层感知器)

    千次阅读 2019-04-05 16:33:00
    Multi-layer Perceptron即多层感知器,也就是神经网络,要说它的Hello world,莫过于识别手写数字了。如果你已经了解它的原理并尝试过自己写一个后就可以试用下通用的类库,好将来用在生产环境。下面是使用SkLearn中...
  • CS311-神经计算 2018-2019年神经计算课程的作业。 MLP(多层感知器)的实现,它将学习如何解决XOR问题。
  • 多层感知器识别手写数字 1、介绍 1. 多层感知器模型介绍 2. 多层感知器模型的训练与预测 建立多层感知器模型后,必须先训练模型才能够进行预测(识别)这些手写数字。 训练 MNIST数据集的训练数据经过数据预处理...
  • 训练多层感知器 - 前向阶段 & 反向阶段 训练多层感知器的一个流行方法是反向传播算法,这包含 LMS 算法作为一个特例。训练分为如下的两个阶段: 1. 前向阶段,网络的突触权值是固定的,输人信号在网络中一层...
  • MLP (多层感知器

    千次阅读 2018-09-17 10:30:31
    MLP(Multi-Layer Perceptron),即多层感知器,是一种前向结构的人工神经网络,映射一组输入向量到一组输出向量。MLP可以被看做是一个有向图,由多个节点层组成,每一层全连接到下一层。除了输入节点,每个节点都是...
  • 多层感知器-原理

    2019-11-26 19:22:23
    深度学习之神经网络 神经网络的出现 神经网络的首次出现来美国神经生物学家沃伦·麦克洛克(Warren McCulloch)和数学家...感知器能够根据训练样本自动获取样本的组合 1.训练方式为有监督学习,即需要设定训练样...
  • RBF神经网络与多层感知器网络的比较 RBF 网络与多层感知器都是非线性多层前向网络 , 它们都是通用逼近器 。 对于任一 个多层感知器 , 总存在一个 RBF 网络可以代替它 , 反之亦然 。 但是 , 这两个网络也存在着 ...
  • 本代码使用newp建立两层感知器,用第一层的输出作为第二层的输入,每一步都有详细的说明,程序比较精简,只有20行代码,就实现了多层感知器解决异或的问题,经测试,正确率100%。 例:q=[1 1 0; 1 0 1]; >> a=sim...
  • MLPC(Multilayer Perceptron Classifier),多层感知器分类器,是一种基于前馈人工神经网络(ANN)的分类器。Spark中目前仅支持此种与神经网络有关的算法,在org.apache.spark.ml中(并非mllib)。本文通过代码来演示...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 20,613
精华内容 8,245
关键字:

多层感知器计算