连载|神经网络(下)

误差逆传播算法(BP神经网络)

BP神经网络是一种按误差反向传播(简称误差反传)训练的多层前馈网络,其算法称为BP算法,它的基本思想是梯度下降法,利用梯度搜索技术,以期使网络的实际输出值和期望输出值的误差均方差为最小。

基本BP算法包括信号的前向传播和误差的反向传播两个过程。即计算误差输出时按从输入到输出的方向进行,而调整权值和阈值则从输出到输入的方向进行。

下面让我们从数学原理上来看一下BP算法是怎样工作的。

我们给定训练集 D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) } D=\{(x_1,y_1),(x_2,y_2),...,(x_m,y_m)\} D={(x1,y1),(x2,y2),...,(xm,ym)},输入示例有d个属性,输出是一个l维的实值向量,转换成如下图所示的前馈神经网络的输入输出的形式,该神经网络拥有d个输入神经元、l个输出神经元以及q个隐藏神经元。

在这里插入图片描述

对于输出层第j个神经元的阈值我们用 θ j \theta_j θj来表示,隐层中第h个神经元的阈值用 γ h \gamma_h γh来表示,输入层第i个神经元与隐层第h个神经元之间的连接权为 v h j v_{hj} vhj,隐层第h个神经元与输出层第j个神经元之间的连接权为 w h j w_{hj} whj。对于隐层和输出层的神经元假设我们都使用sigmoid函数。

对于训练样本 ( x k , y k ) (x_k,y_k) (xk,yk),假定神经网络的输出为

y ^ k = ( y ^ 1 k , y ^ 2 k , . . . , y ^ l k ) \hat{y}_k=(\hat{y}_1^k,\hat{y}_2^k,...,\hat{y}_l^k) y^k=(y^1k,y^2k,...,y^lk)

即对于第j个输出来说有(参考前馈神经网络):

y ^ j k = f ( β j − θ j ) \hat{y}_j^k=f(\beta_j-\theta_j) y^jk=f(βjθj) (1)

则我们可以得到相应的均方误差为:

E k = 1 2 ∑ j = 1 l ( y ^ j k − y j k ) 2 E_k=\frac{1}{2}\sum_{j=1}^l(\hat{y}_j^k-y_j^k)^2 Ek=21j=1l(y^jkyjk)2 (2)

对于上图中的神经网络我们需要确定输入层到隐层的d*q个权值、隐层到输出层的q*l个权值、q个隐层神经元的阈值、l个输出层神经元的阈值,一共则是(d+l+1)*q+l个参数需要确定。

和之前的参数更新方式一样,我们对于任意参数v的更新方式可以表示为如下的形式:

w ← w + Δ w w\leftarrow w+\Delta w ww+Δw

我们用隐层到输出层的连接权 w h j w_{hj} whj为例来进行推导,BP算法基于梯度下降的策略,以目标的负梯度方向对参数进行调整,对上文中的误差 E k E_k Ek,给定学习率 η \eta η,有:

Δ w h j = − η ∂ E k ∂ w h j \Delta w_{hj}=-\eta\frac{\partial E_k}{\partial w_{hj}} Δwhj=ηwhjEk (3)

我们根据上图中的网络关系可以知道 w h j w_{hj} whj先影响到第j个输出层神经元的输入值 β j \beta_j βj,再影响到其输出值 y ^ j k \hat{y}_j^k y^jk,然后影响到 E k E_k Ek,则有:

∂ E k ∂ w h j = ∂ E k ∂ y ^ j k ⋅ ∂ y ^ j k ∂ β j ⋅ ∂ β j ∂ w h j \frac{\partial E_k}{\partial w_{hj}}=\frac{\partial E_k}{\partial \hat{y}_j^k}\cdot\frac{\partial \hat{y}_j^k}{\partial \beta_{j}}\cdot\frac{\partial \beta_j}{\partial w_{hj}} whjEk=y^jkEkβjy^jkwhjβj (4)

根据图中 β j \beta_j βj的定义可以得到:

∂ β j ∂ w h j = b h \frac{\partial \beta_j}{\partial w_{hj}}=b_h whjβj=bh (5)

我们在前面假设神经元内都是sigmoid函数,并且sigmoid函数有一个很重要的导数性质如下:

f ′ ( x ) = f ( x ) ( 1 − f ( x ) ) f'(x)=f(x)(1-f(x)) f(x)=f(x)(1f(x))

因此我们可以根据式(1)(2)得到如下的式子(抛去 b h b_h bh的部分):

g i = ∂ E k ∂ y ^ j k ⋅ ∂ y ^ j k ∂ β j g_i=\frac{\partial E_k}{\partial \hat{y}_j^k}\cdot\frac{\partial \hat{y}_j^k}{\partial \beta_{j}} gi=y^jkEkβjy^jk

g i = − ( y ^ j k − y j k ) f ′ ( β j − θ j ) g_i=-(\hat{y}_j^k-y_j^k)f'(\beta_j-\theta_j) gi=(y^jkyjk)f(βjθj)

g i = ( y j k − y ^ j k ) y ^ j k ( 1 − y ^ j k ) g_i=(y_j^k-\hat{y}_j^k)\hat{y}_j^k(1-\hat{y}_j^k) gi=(yjky^jk)y^jk(1y^jk) (6)

我们把式子(5)(6)带入(4)式再带入(3)式可以得到如下的参数更新公式:

Δ w h j = η g i b h \Delta w_{hj}=\eta g_ib_h Δwhj=ηgibh

类似的我们也可以得到其他参数的更新公式:

Δ θ j = − η g i \Delta \theta_{j}=-\eta g_i Δθj=ηgi

Δ v i h = η e h x i \Delta v_{ih}=\eta e_hx_i Δvih=ηehxi

Δ γ h = η e h \Delta \gamma_{h}=\eta e_h Δγh=ηeh

e h = b h ( 1 − b h ) ∑ j = 1 l w h j g j e_h=b_h(1-b_h)\sum_{j=1}^lw_{hj}g_j eh=bh(1bh)j=1lwhjgj

以上便是我们BP算法的推导过程,在整个过程中我们先通过输出层得到误差,再从误差入手进行反向传播更新参数就OK了。

注:通常我们把学习率设置为0.1,学习率控制着算法的每一轮迭代时的更新步长,若太大则容易震荡,太小则收敛速度又会过慢,有时我们会在不同的网络层之间设定不同的学习率。

下面给出BP神经算法的简单代码实现(带有隐层的神经网络):

import numpy as np


def nonlin(x, deriv=False):
    if deriv == True:
        # 如果deriv=True我们就进行求导
        return x * (1 - x)
    else:
        # 返回sigmoid函数
        return 1 / (1 + np.exp(-x))


# 给定输入输出
x = np.array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
y = np.array([[0, 1, 1, 0]]).T
# 均值与标准差
mu, sigma = 0, 0.1
w0 = np.random.normal(mu, sigma, (3, 5))
w1 = np.random.normal(mu, sigma, (5, 1))
# 定义迭代次数
iter_size = 1000
# 定义学习率
lr = 1
for i in range(iter_size):
    # 输入层
    L0 = x
    # 隐藏层(输入层和隐藏层间权重为w0)
    L1 = nonlin(L0.dot(w0))
    # 输出层(隐藏层和输出层间权重为w1)
    L2 = nonlin(L1.dot(w1))
    # 损失函数
    L2_loss = L2 - y
    # 输出层的导数
    L2_delta = L2_loss * nonlin(L2, True)
    # 隐藏层到输出层的梯度
    grad1 = L1.T.dot(L2_delta)
    # 隐藏层到输出层参数更新
    w1 -= grad1 * lr
    # L1对L2_loss贡献了多少,反过来传梯度时就要乘以这个权重
    L1_loss = L2_delta.dot(w1.T)
    # 隐藏层的导数
    L1_delta = L1_loss * nonlin(L1, True)
    # 输入层到隐藏层的梯度
    grad0 = L0.T.dot(L1_delta)
    # 输入层到隐藏层的参数更新
    w0 -= grad0 * lr
print(L2)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二哥不像程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值