BP 神经网络(反向传播的神经网络)的解读,python 代码


人工神经网络这几年太火了,普遍用于预测、语音或图像识别。四五年前曾经想学习,但没有找到好的学习资料,一直一知半解的。最近一段时间因为要用 BP 神经网络做需求预测,就重新捡起来了。中文资料大部分的讲解不清晰(符号普遍比较混乱),于是结合维基百科以及查阅的几个英文资料,写下自己对这一算法的理解。

一、 神经网络算法的内涵

神经网络的目标是:找到一个能把一组输入最好地映射到其正确输出的函数。例如一个简单的分类任务,其中输入是动物的图像,正确的输出将是动物的名称。或者根据历史需求数据,预测未来一期的需求。

神经网络的思想(内涵)类似回归分析中经常用到的拟合,都用到了最小二乘的思想:数学意义上的决策目标是:选取一些参数(神经网络中每个输入的权重),使得拟合的输出与期望输出的误差平方和最小。

下面是一个神经网络示意图(输入层有 3个神经元,隐含层有 3个神经元,输出层有 3个神经元),输入信息经过正向传播到输出,计算实际输出与期望输出的误差后,在反向传播误差;重复这个过程,在传播过程中,不断减少误差,直到误差减少到一定程度终止。

误差反向传播,是该神经网络叫做 BP 神经网络的原因。

在这里插入图片描述

二、神经元之间信息的传递

每个神经元接受上一层所有神经元传递过来的信息,然后传递到下一层。接受信号时,按一定权重 w i j w_{ij} wij 接受信号。 下图是一个接受信号与传递信号的示意图:
在这里插入图片描述

w i j w_{ij} wij 表示从神经元 i i i 传递到神经元 j j j 时的权重(每个神经元的阈值 θ j \theta_j θj 也能放在权重里表示,为了便于推算和理解,下面就不提阈值了),神经元 i i i 处传来的信息值大小为 o i o_i oi(若神经元 i i i 在输入层,则 o i = x i o_i=x_i oi=xi),则每个神经元 j j j 的激活值 (activation value) a j a_j aj 等于:
a j = ∑ i w i j o i (1) a_j=\sum_i w_{ij}o_i\tag{1} aj=iwijoi(1)

神经元 j j j 有了激活值后,根据它的激活函数(或叫传递函数) φ \varphi φ ,计算得到它的信息量大小 o j o_j oj
o j = φ ( a j ) = φ ( ∑ i w i j o i ) (2) o_j=\varphi(a_j)=\varphi(\sum_i w_{ij}o_i)\tag{2} oj=φ(aj)=φ(iwijoi)(2)

常用的激活函数 φ \varphi φ 为 Sigmoid 函数,即:
φ ( z ) = 1 1 + e − z \varphi(z)=\frac{1}{1+e^{-z}} φ(z)=1+ez1
使用这个函数的一个重要原因是它的一阶导数方便求解,
∂ φ ∂ z = φ ( z ) ( 1 − φ ( z ) ) (3) \frac{\partial\varphi}{\partial z}=\varphi(z)(1-\varphi(z))\tag{3} zφ=φ(z)(1φ(z))(3)

三、采用梯度下降法使误差减小

一般来说,神经元 j j j 产生的误差 E E E 这样定义:
E j = 1 2 ∑ j = 1 m ( t j − y j ) 2 (4) E_j=\frac{1}{2}\sum_{j=1}^m(t_j-y_j)^2\tag{4} Ej=21j=1m(tjyj)2(4)

其中 t j t_j tj 表示输出层的期望输出, y j y_j yj 表示输出层的实际输出,假设输出层有 m m m 个神经元。我们的目标是选取合适的权重 w i j w_{ij} wij,使得 E E E 最小,BP 神经网络一般采用梯度下降法逐渐更新权重(类似最优化中的最速下降法,参见本人另外一篇博客关于最速下降法的迭代公式:https://blog.csdn.net/robert_chen1988/article/details/53167156)。

因此,计算 E E E w i j w_{ij} wij 的一阶导数:
∂ E j ∂ w i j = ∂ E j ∂ y j ∂ y j ∂ w i j \frac{\partial E_j}{\partial w_{ij}}=\frac{\partial E_j}{\partial y_j}\frac{\partial y_j}{\partial w_{ij}} wijEj=yjEjwijyj

我们统一用 o j o_j oj 表示 y j y_j yj o j o_j oj 表示输出的信息值,在最后的输出层,输出的信息值为 y j y_j yj),则:
∂ E j ∂ w i j = ∂ E j ∂ o j ∂ o j ∂ w i j \frac{\partial E_j}{\partial w_{ij}}=\frac{\partial E_j}{\partial o_j}\frac{\partial o_j}{\partial w_{ij}} wijEj=ojEjwijoj

根据公式 (2) 与公式 (3), 输出信息值 o j o_j oj 又是激活值 a j a_j aj 的函数,而激活值 a j a_j aj 才与 w i j w_{ij} wij 有直接联系,因此:
∂ E j ∂ w i j = ∂ E j ∂ o j ∂ o j ∂ w i j = ∂ E j ∂ o j ∂ o j ∂ a j ∂ a j ∂ w i j (5) \frac{\partial E_j}{\partial w_{ij}}=\frac{\partial E_j}{\partial o_j}\frac{\partial o_j}{\partial w_{ij}}=\frac{\partial E_j}{\partial o_j}\frac{\partial o_j}{\partial a_j}\frac{\partial{a_j}}{\partial w_{ij}}\tag{5} wijEj=ojEjwijoj=ojEjajojwijaj(5)

下面分开计算每一项,由公式(1):
∂ a j ∂ w i j = ∂ ( ∑ i w i j o i ) ∂ w i j = o i (6) \frac{\partial{a_j}}{\partial w_{ij}}=\frac{\partial({\sum_i w_{ij}o_i})}{\partial w_{ij}}=o_i\tag{6} wijaj=wij(iwijoi)=oi(6)

即这项导数是传递它信息的神经元的信息值。由公式 (3):

∂ o j ∂ a j = φ ( a j ) ( 1 − φ ( a j ) ) = o j ( 1 − o j ) (7) \frac{\partial{o_j}}{\partial a_j}=\varphi(a_j)(1-\varphi(a_j))=o_j(1-o_j)\tag{7} ajoj=φ(aj)(1φ(aj))=oj(1oj)(7)

而计算 ∂ E ∂ o j \frac{\partial E}{\partial o_j} ojE 则要分两种情况讨论:

  1. o j o_j oj 位于最后的输出层,则 o j = y j o_j=y_j oj=yj,根据公式(4)
    ∂ E ∂ o j = ∂ E ∂ y j = y j − t j (8) \frac{\partial E}{\partial o_j}=\frac{\partial E}{\partial y_j}=y_j-t_j\tag{8} ojE=yjE=yjtj(8)

根据公式 (5),(6)(7)(8),得到:
∂ E j ∂ w i j = ∂ E j ∂ o j ∂ o j ∂ a j ∂ a j ∂ w i j = ∂ E j ∂ o j ∂ o j ∂ a j o i = ( y j − t j ) y j ( 1 − y j ) o i (9) \frac{\partial E_j}{\partial w_{ij}}=\frac{\partial E_j}{\partial o_j}\frac{\partial o_j}{\partial a_j}\frac{\partial{a_j}}{\partial w_{ij}}=\frac{\partial E_j}{\partial o_j}\frac{\partial o_j}{\partial a_j}o_i=(y_j-t_j)y_j(1-y_j)o_i\tag{9} wijEj=ojEjajojwijaj=ojEjajojoi=(yjtj)yj(1yj)oi(9)

  1. o j o_j oj 位于输入层或隐含层, 神经元 j j j 输出值 o j o_j oj 造成的误差等于它输出的所有神经元造成的误差之和 (本人的理解),设神经元 j j j 输出的神经元的集合为 L L L,因此得到:
    ∂ E j ∂ o j = ∑ l ∈ L ( ∂ E l ∂ o j ) = ∑ l ∈ L ∂ E l ∂ o l ∂ o l ∂ a l ∂ a l ∂ o j = ∑ l ∈ L ∂ E l ∂ o l ∂ o l ∂ a l w j l (10) \frac{\partial E_j}{\partial o_j}=\sum_{l\in L}(\frac{\partial E_l}{\partial o_j})=\sum_{l\in L}\frac{\partial E_l}{\partial o_l}\frac{\partial o_l}{\partial a_l}\frac{\partial{a_l}}{\partial o_{j}}=\sum_{l\in L}\frac{\partial E_l}{\partial o_l}\frac{\partial o_l}{\partial a_l}w_{jl}\tag{10} ojEj=lL(ojEl)=lLolElalolojal=lLolElalolwjl(10)

这两种情况都满足下面式子:(只不过两种情况的 ∂ E ∂ o j \frac{\partial E}{\partial o_j} ojE 不同)
∂ E j ∂ w i j = ∂ E j ∂ o j ∂ o j ∂ a j ∂ a j ∂ w i j = ∂ E j ∂ o j ∂ o j ∂ a j o i (11) \frac{\partial E_j}{\partial w_{ij}}=\frac{\partial E_j}{\partial o_j}\frac{\partial o_j}{\partial a_j}\frac{\partial{a_j}}{\partial w_{ij}}=\frac{\partial E_j}{\partial o_j}\frac{\partial o_j}{\partial a_j}o_i\tag{11} wijEj=ojEjajojwijaj=ojEjajojoi(11)

为了方便,令
δ j = ∂ E j ∂ o j ∂ o j ∂ a j \delta_j=\frac{\partial E_j}{\partial o_j}\frac{\partial o_j}{\partial a_j} δj=ojEjajoj,则权重的一阶导数可以简化成:
∂ E j ∂ w i j = δ j o i (12) \frac{\partial E_j}{\partial w_{ij}}=\delta_j o_i\tag{12} wijEj=δjoi(12)

其中, δ j \delta_j δj 的取值与上面两种情况有关(根据表达式(9),(10)):
δ j = { ( y j − t j ) y j ( 1 − y j ) 若  j  位于输出层 ( ∑ l ∈ L ∂ E l ∂ o l ∂ o l ∂ a l w j l ) o j ( 1 − o j ) = ( ∑ l ∈ L δ l w j l ) o j ( 1 − o j ) 若  j  不位于输出层 (13) \delta_j= \begin{cases} (y_j-t_j)y_j(1-y_j) \quad &若~j~位于输出层\\ \\ \left(\sum_{l\in L}\frac{\partial E_l}{\partial o_l}\frac{\partial o_l}{\partial a_l}w_{jl}\right)o_j(1-o_j)=\left(\sum_{l\in L}\delta_l w_{jl}\right)o_j(1-o_j)\quad &若~j~不位于输出层 \end{cases}\tag{13} δj= (yjtj)yj(1yj)(lLolElalolwjl)oj(1oj)=(lLδlwjl)oj(1oj) j 位于输出层 j 不位于输出层(13)

于是,表达式(12),(13)就是权重相对于误差的一阶导数取值。BP 神经网络采用梯度下降法使得误差降低。

类似最速下降法的思想,BP 神经网络在迭代时,采用下面的方法更新权重,不断使得误差减小:
w i j = w i j − η ∂ E j ∂ w i j w_{ij}=w_{ij}-\eta\frac{\partial E_j}{\partial w_{ij}} wij=wijηwijEj

其中 η \eta η 就是梯度下降法的步长,在神经网络算法中称为学习速率,而权重沿负梯度方向更新。

四、BP 神经网络的局限性

  1. 不能保证得到全局最优解
  2. 输入的数据不要求标准化,但若标准化,可以提高神经网络的表现。

五、一个 python 例子

用 BP 神经网络预测 sklearn 包中自带的乳腺癌数据例子:

## 测试一下癌症数据
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import classification_report
from sklearn.preprocessing import StandardScaler

cancer = datasets.load_breast_cancer()
cancer_data =  cancer['data']
cancer_target = cancer['target']

cancer_data_train, cancer_data_test, cancer_target_train, \
    cancer_target_test = train_test_split(cancer_data, cancer_target, test_size = 0.2)
    
# 数据标准化
stdScaler = StandardScaler().fit(cancer_data_train)
cancer_trainStd = stdScaler.transform(cancer_data_train)
cancer_testStd = stdScaler.transform(cancer_data_test)

# 建立 BP 模型
bpnn = MLPClassifier(hidden_layer_sizes = (20,10),
    max_iter = 200, solver = 'adam',random_state=45)
bpnn.fit(cancer_trainStd, cancer_target_train)

# 预测
y_pred = bpnn.predict(cancer_testStd) # 返回预测结果
print('神经网络预测结果评价报告:\n', classification_report(cancer_target_test,y_pred))

生成的结果为:

在这里插入图片描述
预测的准确率达到 98%,跟支持向量机的预测结果差不多。

转载于个人公众号:Python 统计分析与数据科学

在这里插入图片描述

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

心态与习惯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值