为什么神经元叫多层支持向量机和感知机机?

多层感知机是一种简单的多层神经网络模型。可以适用于回归问题。

  • batch参数用来指定mini-batch sgd优化器的样本批量大小,默认值为200(如样本数低于200,则为样本数)。

  • max_iter用来指定神经网络的最大迭代次数,默认值为200。

  • random_state用来指定随机种子,用来控制模型初始权重的随机性。如果给定特定值,重新跑模型的时候,可以得出同样的结果。

  • tol参数用于指定优化器的忍耐度。当损失函数的值的变化小于了忍耐度,便认为训练结束,从而停止训练。默认值为1e-4。

  • momentum参数用于指定随机梯度下降优化器的动量,其值介于0到1之间。该参数仅在优化器为sgd的情形下有效。

  • activation = relu,使用整流线性单元激活函数。(默认值)
  • solver用来指定优化器。

  • learning_rate = adaptive,使用自适应的学习率,当误差函数变化很小时,就会降低学习率。
  • hidden_layer_sizes用于指定网络架构,输入形式为元组,元组长度表示架构的层数,元组第i个数表示第i层的神经元个数。例如hidden_layer_sizes = “512-512-64”表示该多层感知机会用三个隐藏层,神经元数量分别为512,512,64。
    默认值为100,表示只用一个100个神经元的隐藏层。

多层感知机与softmax层——动手学习深度学习pytorch版

    • 1.5 交叉熵损失函数
    • 1.6 网络的最终输出
  • 2. 多层感知机——从零开始
    • 2.1 激活函数的代码实现
  • 2.3 交叉熵损失函数的计算
  • 2.4 线性层模块的定义
  • 2.5 多层感知机网络的代码实现
    • 3.1 多层感知机网络模块的搭建

??本系列是基于亚马逊李沐老师的教材《动手学习深度学习》,以及李沐老师对应的视频教程内容展开。但是李沐老师课程中使用的深度学习框架是MXNet,其实选择什么框架并不是重点,重点应该是其中的内容。课程既然叫动手学习深度学习,那当然要动手操作。用MXNet重复一遍教材内容并没有很好的学习效果,另外,我本身还是更喜欢使用pytorch框架,因此,希望将该教材的内容用pytorch实现一遍,并学习相关的知识内容。希望能给其他喜欢pytorch的读者一些帮助。代码开源供学习使用,如引用请注明出处,谢谢。

??在“线性回归”章节的内容中,我们介绍了如何实现一个属于自己的线性层,并用自己简单生成的数据集进行了验证,了解了一些有关深度学习训练和pytorch框架的基本知识。在本篇内容中,我们将使用更接近现实情况的数据集,并搭建一个更复杂的神经网络,来完成一个分类问题。

??使用的数据集是Fashion_MNIST,该数据集共有70000个样本,60000个样本作为训练集,10000个样本作为测试集。70000个样本中,总共包含10种类别的常见物品(见下图)。每张图片的尺寸是28*28的,所以我们可以将图片张开成为1×784的一维向量,作为我们网络的输入。网络的输出就是1×10的向量,向量中的每个元素都可以理解为属于每个种类的预测概率,比如向量的第一个元素代表输入图像属于pullover类别的概率。

??多层感知机其实就是多个线性层叠加起来的网络,这里我们以两个线性层叠加为例子。第一个线性层的输入就是图像像素个数,也就是784,每个像素都代表输入样本的一个特征,如下图的

x1??x784?。非输入和输出的层为我们称为隐藏层,如下图的

z1??zn?,其中这里的n取1000。然后,经过第一个线性层的计算后,输入数据应当从784个特征转化成了1000个特征,再将这1000个特征输入到第二个线性层中,第二个线性层输出维度为10,代表每个类别的概率。具体结构图如下:

??注意到上图中有几个特点:

  • 图中每个结点可以当作一个神经元。每层的输入神经元和所有的输出神经元都有一条线连着,每条线上都有一个权值

    Wij?,表示输入的第i个神经元与输出的第j个神经元的权值系数。另外,每个输出神经元都配有一个偏置系数

    bj?。所以,一个输出神经元对应所有输入神经元的结构,就是我们在“线性回归”里使用的简单线性层。这里只是把线性层的输出神经元个数变成了n个。那么,对应于每个输出神经元

    zi?,其计算公式为:

??其中,x是输入向量,

W:,j?是W矩阵第j列的列向量。

  • 在隐藏层的神经元中,除了

    zi?经过激活函数激活后的数值,假设激活函数是

    常用的激活函数在下文中会介绍。这里说明一下为什么要激活函数,因为如果不使用激活函数,那么其实上述网络的输出就是

    y=(x×W+b)×W′+b′?y=x×Wnew?+bnew?,也就是说,无论你叠多少层线性层,如果不加激活函数,那么其实和只有一层线性层是等价的。而加入了激活函数后,通常激活函数是非线性的,所以就有:

    这样,整个网络的映射就具备了非线性能力,不再等价于普通的线性层了。注意,最后一层线性层的输出通常就不需要激活函数激活了,对于分类问题,会使用下文提到的Softmax层进行归纳总结。

  • Wij?,Wi′j′?,bj?,bj′?都是网络的参数,都是需要进行训练更新的。

??激活函数其实种类特别特别多,有时间再专门介绍各种激活函数的特点及对比。这里就介绍最基本的三种:

??这是最早的激活函数。

0

??看起来就是简单的取最大值函数,但是因为它具有计算简单且性能较好的特性,是使用的最广泛的激活函数。

??先说明一下Softmax层的计算方法:

y=(y1?,y2?,...,y10?),分别代表输入样本x对应于每个类别的概率,那么softmax的计算方式为:

0

??简单来说就是先以所有输出为指数求e为底的指数数值,然后再进行标准化,使得

∑i=110?yi′?=1。这种标准化操作还是很好理解的,就是让输出变成对应每个类别的相对概率,比如

y1′?=0.5则说明该样本属于第一类的情况,在它相对于属于其他所有类的情况中,出现的概率为0.5。
??为什么Softmax要用e指数进行标准化,而不是其他方式(如min-max方式)?
??其实softmax的公式是基于最大熵模型理论的。最大熵模型简单来说就是:在已知部分知识的前提下(也就是已知网络输出的十个数值),关于未知分布(也就是样本属于十个类别的概率)最合理的推断就是符合已知知识最不确定或最随机的推断(也就是熵值最大)。其原则是承认已知事物(知识),且对未知事物不做任何假设,没有任何偏见。而已知网络的输出,求其真实概率分布的最大熵模型的解,就是softmax的表达式。
??也就是说,网络输出了十个数值,我们希望用这十个数值来求出样本属于每个类别最合理的概率模型,这个模型理论上来说就是最大熵模型,其求解公式就是softmax的数学表达式。

1.5 交叉熵损失函数

??假设随机变量X,其对应的真实概率密度是p(x),模型预测的概率密度是q(x)。
??KL散度(相对熵)是度量模型预测的结果信息量和真实事件的信息量之间的差值,即熵差。

??前一部分是真实事件的熵值,为定值,后一部分就是交叉熵:

??可以理解为用预测的概率分布

p(xi?),来求解事件的熵值。因为两个分布交叉使用,所以叫交叉熵。交叉熵大于真实事件的熵值。
??从上述表达式可以看出,

∵H(p,q)≥H(p),所以交叉熵越小,样本预测概率越接近真实概率。因此,将每个样本的交叉熵作为损失值,然后取均值,就是交叉熵损失函数:

??实际使用的时候,看起来好像是求和,但是其实

1.6 网络的最终输出

??经过上述折腾,最终网络经过softmax层会输出

∑i=110?yi?=1。此时,选择其中最大的

yi?,其对应的标签序号

i 就是网络最终预测的分类类别。

2. 多层感知机——从零开始

2.1 激活函数的代码实现

2.3 交叉熵损失函数的计算

2.4 线性层模块的定义

??和“线性回归”章节中的网络类很相似,稍微进行了一些修改。线性层中的权值和偏置都乘0.01是因为,最后一个线性层的网络输出要经过softmax层,而softmax的计算是包含指数e为底的幂次计算,如果网络输出数值过大,很容易导致softmax之后的结果全为nan(如下图)。因此,为了让网络初始的时候输出的数值减小一些,就需要将网络参数的初始化数值减小,所以乘了0.01。
??另外,设置系数w,b的requires_grad()属性的顺序需要非常注意,如果顺序不对,则会出现如下图所示的错误信息,警告你系数的梯度不存在。

2.5 多层感知机网络的代码实现

??为了简单起见,下面的代码只采用了两层线性层,感兴趣的读者可以自行增加更多的线性层,使用不同的激活函数,来看看网络的效果。

??由于pytorch对应的torchvision.datasets中有提供Fashion_MNIST的数据集载入,所以这里就不再麻烦自己创建数据集的Dataset类了,直接使用提供好的API下载并导入数据。当然,读者可以自己下载对应数据集,并自己完成数据的导入和Dataset类的创建,提高自己的熟练度。另外说明一下,pytorch导入的FashionMNIST数据集,已经帮你把图片标准化过了,也就是图片中的像素数值全都是[0,1]范围内的数值,而不是[0,255]。数据导入的代码如下:

3.1 多层感知机网络模块的搭建

??可以看到,使用pytorch框架为我们搭建网络省了很多事,你只要按网络结构把所需要的网络层都叠加在nn.Sequential()里面就可以了,注意,Sequential里不同的网络层之间有逗号分隔。还要注意网络的上下层之间,通道数要一一对应,也就是上层网络的输出通道数要等于下层网络的输入通道数。如果需要激活,就在需要激活的网络层后面加上对应的激活函数层。softmax也是一样。

??其实用pytorch提供的模块进行训练的代码和之前从零开始的训练代码非常类似。只是由于pytorch提供了损失函数和优化器的API,所以不需要再定义损失函数和优化器,只需要直接使用就可以了。具体代码如下:

??下图可以看到,我们自己手写的网络,其训练过程看起来更平稳,而且最终的准确率也比pytorch版本的高了大概10个百分点。不仅如此,pytorch版本的网络收敛速度还慢得多,本来打算都跑10个epoch,但是发现pytorch版跑完10个epoch居然还没收敛,因此就跑了25个epoch。其实结果还是蛮惊喜的,这是我这么多次手写代码第一次效果跑赢官方API的一次。原因目前还没找到,有知道的大神可以留言告知一下。从训练过程来看,pytorch搭建的网络它的loss下降的速度也比我们自己写的要慢,尤其是前几轮loss下降的很小。

??这里顺便说一下,可能很多人都很奇怪,为什么测试集的准确率会一直高于训练集的准确率?当然,巧合是一种解释;样本没有划分均衡也是有可能导致这种情况的(比如特征比较明显的都划分到测试集里了)。但是,此处最重要的原因是,这里的训练准确率是在训练过程中计算的,这时候,每个batch训练后更新网络参数,再训练下一个batch,网络是一边训练一边更新一边计算准确率的,所以其实这个训练准确率的获取并不是使用一个参数固定的网络,而是一个仍在不断更新进步的网络。而测试集的准确率是在一个epoch结束后才进行测试计算的,这时候对于一个epoch,训练以及结束,网络不再更新,此时的网络应该是当前epoch下的最优网络(最优是相对于当前epoch来说是最优的),那测试效果当然要比训练过程中使用未达到最优的网络要好一些。最简单的验证方式就是,在一个epoch训练完后,同时那训练集和测试集都进行准确率计算,这时候得到的结果就如下图,这时候就是理想的情况,训练集准确率高于测试集。当然,通常不会这么做,因为这样又要把训练的所有样本预测一遍,非常浪费时间。

感知机(perceptron)于1957年由Rosenblatt提出,是一种二分类线性模型。感知机以样本特征向量做为输入,输出为预测类别,取正、负两类。感知机最终学习到的是将输入空间(特征空间)划分为正、负两类的分离超平面,属于判别模型。为此,使用误分类做为损失函数,利用梯度降低优化该函数,可求得感知机模型。感知机是神经网络与支持向量机的基础。git

第 个样本的预测值 ,其中 称为激活函数, ,损失为 。单层感知机的目的就是习得合适的 与 ,使得全部样本的损失之和 最小。github

若是咱们令 即感知机的输入。那么当 时,;当 时, 。由于 是 线性组合,因此最终获得的是一个超平面 ,超平面将输入样本分为了 和 -1两类。算法

当输入 是二维向量时,用红点表示 的数据,黑点表示 的数据,最终习得的是一条直线,将两个数据分离开,以下图所示。bash

由于单层感知机最终习得是超平面,因此只能用于解决线性可分问题。对于下面这样的数据,单层感知机无能为力。网络

多层感知机也叫MLP,能够看作是一个有向图。MLP由多层节点组成,每一层全链接到下一层,除输入节点外,每一个节点都是一个带有非线性激活函数的神经元(unit)。多层感知机可用于解决线性不可分问题。机器学习

由于神经网络的和多层感知器是一个意思,因此下面直接对单层前馈神经网络进行详细说明。函数

下图是一个输入层节点数为3,隐藏层节点数为2,输出层节点数为2的前馈神经网络,该网络可用于解决二分类问题。学习

单层前馈神经网络本质上是一个多层感知机,有如下几个特色:优化

  1. 全链接。每一层的节点都与右边层的全部节点经过权重链接。
  2. 隐藏层只有一层。因此称之为单层
  3. 数据单向流动。每一层节点只做用于其以后的层,因此叫做前馈
  4. 本质是数学函数。神经网络能够明确的用数学语言表达。

咱们拿出隐藏层的一个神经元(unit)放大来看:

神经元的任务就是接受输入,产生输出

z 表示神经元的输入,a 是神经元的输出。

输入怎么得来?就是上一层的神经元输出与权重 的乘积之和再加上偏置

输出怎么得来?把输入值带入激活函数 获得。

Sigmoid的表达式为 ,定义域为 ,值域为

在 处,函数值为 ,其函数图像以下:

sigmoid函数有许多优美的性质,如:

  1. 是 的复合函数, 又名天然常数

  2. 1阶导函数为 。即函数在某一点的导数可由函数在这一点的函数值求得

  3. 曲线光滑,定义域内到处可导,且能够无限次求导

  4. 能够把任意输入压缩到 范围内

在反向传播算法(BP算法)中,性质二、3起到了极大的做用,性质4起到了防溢出的做用。

现考虑一个样本 ,其中 是输入数据,是实际值。咱们如今来手动计算 的计算过程是从输入层开始从左往右计算的,因此这个过程也叫做前向传播。

下图表示,为了获得 ,有哪些神经元被激活了。

为了方便表述,用 表示第 层的第 个神经元与第 层的第 个神经元相连的权重,用 表示第 层第 个神经元的偏置值。

注意。输入层没有激活函数,因此:

若是咱们把 做为类别为 的几率,将 做为类别为1的几率,则样本 的预测值能够写成 ,因此为了让 ,选用 做为输出层的激活函数。

咱们令 ,,那么 ,同理设

神经网络能够明确的用数学语言表达,它的函数表达式,能够明确的写出来
 
若是真的将这个数学表达式写出来,那么这个数学函数 是一个包含 个参数的函数,函数输入 可获得预测值 ,这个表达式会很是长。
咱们如今来优化网络中这10个权重参数和4个偏置参数。
定义输出层的节点 的偏差,可用的损失函数有:
 
使用梯度降低算法来优化损失函数,则须要求出损失函数对全部参数的导数,这个过程在计算上是从输出层开始从右往左计算的,由于与计算预测值 的过程恰巧相反,因此也叫做反向传播。
以计算权重 的偏导数为例,根据链式法则不可贵到:


∴ (注:这是二分类问题特有的交叉熵表示方式)





更通用化的表达,如何计算 ?依葫芦画瓢得:

令 表示输出层节点 的偏差值


如何理解?用 表示为隐藏层节点的位置, 表示为输出层节点的位置,那么权重 的导数为该权重前一层第i个节点的激活值与后一层第j个节点的偏差值的乘积
下图是反向传播的示意图,损失函数产生的偏差顺着红线一直往左边传,每通过一条红线就求一次导数,直到要求的权重也覆盖在红线为止。下图有三条红线,也就是损失函数 对 的导数须要用三个偏导数乘积造成的链式求导才能获得,且最后一个偏导数值为 。
 
如何计算 呢?继续使用链式法则 + 依葫芦画瓢可得:

令 为 的偏差值 ,那么上式能够写成:



如何理解?若是用 表示输入层节点位置, 表示隐藏层节点位置,那么权重 的导数为 该权重前一层第i个节点的激活值与后一层第j个节点的偏差值的乘积每一个节点的偏差值 等于 链接权重 与 权重另外一端所连节点的偏差值 的乘积之和 与 本节点激活值的导数 的乘积
详细的推导过程读者能够本身琢磨一下,这里有个关键点须要注意:
如何求 的导数?根据以前的逻辑推导便可:

如何求 的导数?链条太长,这里直接给出答案:

与权重导数不一样的地方就是,在求导过程当中的最后一项 。
若是加入偏置单元,也能够理解为偏置单元 的值为1,以下图所示:
 
 
正则化(regularation)是防止机器学习过拟合的一种手段。一种常见的手段是经过将权重的平方之和加入到损失函数来实现。那么损失函数变为:

全部权重、偏置之和称为 正则项 , 是 正则项系数,也叫 惩罚系数
加入正则化项后, 的导数要多算一个平方项的导数,以 为例

咱们假设输入值 、 实际值 都是列向量。
观察 、 的表达式,进而发现能够用矩阵形式书写为:

不失通常性,设第 层的前向传播:,其中 、 、 均为列向量,
激活值 ,因此激活值也是列向量。



表示把矩阵 的全部元素之和
* 表示求哈达马积,即两个矩阵对应位置的元素的乘积所造成的一个新矩阵










上述全部过程都是假设只有一个样本。
当参与计算的样本数量大于1时:
  • 单个损失函数 => 全部样本损失值求平均
  • 单个样本的输出层偏差 => 全部样本输出层偏差求平均
 
你不用写一个for循环来计算上述值,使用矩阵乘法会更为方便,这里留给读者思考。

ann.py 是面向过程版本实现,且隐藏层数只能为1。
NN.py 是面向对象版本实现,支持多层隐藏层。

我要回帖

更多关于 支持向量机和感知机 的文章

 

随机推荐