神经网络和BP算法推导

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

 

单层感知机

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

 

如果我们令 即感知机的输入。那幺当 时, ;当 时, 。因为 是 线性组合,所以最终得到的是一个超平面 ,超平面将输入样本分为了 和 -1两类。

 

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

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

多层感知机

 

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

 

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

单层前馈神经网络

 

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

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

 

权重
单层
前馈

 

神经元

 

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

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

 

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

 

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

 

输出怎幺得来?把输入值带入 激活函数 得到。

 

写成数学表达式就是:

 

 

 

是激活函数,常见的有sigmoid、tanh、ReLU。

 

Sigmoid函数

 

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

 

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

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

 

 

是 的复合函数, 又名 自然常数

 

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

 

曲线光滑,定义域内处处可导,且可以无限次求导

 

可以把任意输入压缩到 范围内

 

 

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

 

前向传播原理

 

现考虑一个样本 ,其中 是输入数据, 是实际值。我们现在来手动计算 预测值 。预测值 的计算过程是从输入层开始 从左往右计算 的,所以这个过程也叫作前向传播。

 

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

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

 

输入层

 

注意。输入层没有激活函数,所以:

 

 

隐藏层

 

 

 

 

 

输出层

 

如果我们把 作为类别为 的概率,将 作为类别为1的概率,则样本 的预测值可以写成 ,所以为了让 ,选用 作为输出层的激活函数。

 

 

 

令 ,

 

 

 

我们令 , ,那幺 ,同理设

 

神经网络可以明确的用数学语言表达,它的函数表达式,可以明确的写出来
复制代码

 

如果真的将这个数学表达式写出来,那幺这个数学函数 是一个包含 个参数的函数,函数输入 可得到预测值 ,这个表达式会非常长。

 

反向传播原理

 

我们现在来优化网络中这10个权重参数和4个偏置参数。

 

定义输出层的节点 的误差,可用的损失函数有:

 

 

    1. 均方误差:

 

    1. 交叉熵损失:

 

 

使用梯度下降算法来优化损失函数,则需要求出 损失函数对所有参数的导数 ,这个过程在计算上是从输出层开始 从右往左计算 的,因为与计算预测值 的过程恰巧相反,所以也叫作反向传播。

 

权重的导数

 

以计算权重 的偏导数为例,根据链式法则不难得到:

 

 

∵ ,又 ,

 

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

 

 

 

 

故原偏导数可写成:

 

 

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

 

 

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

 

则上式可写成:

 

 

如何理解?用 表示为隐藏层节点的位置, 表示为输出层节点的位置,那幺权重 的导数为 该权重前一层第i个节点的激活值与后一层第j个节点的误差值的乘积

 

下图是反向传播的示意图,损失函数产生的误差顺着红线一直往左边传,每经过一条红线就求一次导数,直到要求的权重也覆盖在红线为止。下图有三条红线,也就是损失函数 对 的导数需要用三个偏导数乘积形成的链式求导才能得到,且最后一个偏导数值为 。

如何计算 呢?继续使用链式法则 + 依葫芦画瓢可得:

 

 

令 为 的 误差值 ,那幺上式可以写成:

 

 

观察可以发现:

 

 

如何理解?如果用 表示输入层节点位置, 表示隐藏层节点位置,那幺权重 的导数为 该权重前一层第i个节点的激活值与后一层第j个节点的误差值的乘积每个节点的误差值 等于 连接权重 与 权重另一端所连节点的误差值 的乘积之和 与 本节点激活值的导数 的乘积

 

详细的推导过程读者可以自己琢磨一下,这里有个关键点需要注意:

因为 , ,所以

偏置的导数

 

如何求 的导数?根据之前的逻辑推导即可:

 

 

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

 

 

与权重导数不同的地方就是,在求导过程中的最后一项 。

 

如果加入偏置单元,也可以理解为偏置单元 的值为1,如下图所示:

正则化项

 

正则化(regularation)是防止机器学习过拟合的一种手段。一种常见的手段是通过将权重的平方之和加入到损失函数来实现。那幺损失函数变为:

 

 

所有权重、偏置之和称为 正则项 , 是 正则项系数 ,也叫 惩罚系数

 

加入正则化项后, 的导数要多算一个平方项的导数,以 为例

 

 

向量化

 

我们假设输入值 、 实际值 都是列向量。

 

观察 、 的表达式,进而发现可以用矩阵形式书写为:

 

 

不失一般性,设第 层的前向传播: ,其中 、 、 均为列向量, 为矩阵

 

激活值 ,所以激活值也是列向量。

 

损失函数向量化为:

 

 

 

表示把矩阵 的所有元素之和

 

* 表示求 哈达马积 ,即两个矩阵对应位置的元素的乘积所形成的一个新矩阵

 

输出层误差值向量化:

 

 

隐藏层误差向量化:

 

 

 

 

参数 导数向量化:

 

 

 

不失一般性,有:

 

小批量梯度下降

 

上述所有过程都是假设只有一个样本。

 

当参与计算的样本数量大于1时:

单个损失函数 => 所有样本损失值求平均
单个样本的输出层误差 => 所有样本输出层误差求平均

你不用写一个for循环来计算上述值,使用矩阵乘法会更为方便,这里留给读者思考。

 

实现

 

github: github.com/JerryCheese…

 

ann.py 是面向过程版本实现,且隐藏层数只能为1。

 

NN.py 是面向对象版本实现,支持多层隐藏层。

发表评论

电子邮件地址不会被公开。 必填项已用*标注