反向传播算法(Back Propagation)分二步进行,即正向传播和反向传播。这两个过程简述如下:

1.正向传播

输入的样本从输入层经过隐单元一层一层进行处理,传向输出层;在逐层处理的过程中。在输出层把当前输出和期望输出进行比较,如果现行输出不等于期望输出,则进入反向传播过程。

2.反向传播

反向传播时,把误差信号按原来正向传播的通路反向传回,逐层修改连接权值,以望代价函数趋向最小。

下面以单隐层的神经网络为例,进行权值调整的公式推导,其结构示意图如下:

输入层输入向量(n维):X=(x1,x2,…,xi,…,xn)T

隐层输出向量(隐层有m个结点):Y=(y1,y2,…,yj,…,ym)T

输出层输出向量(l维):O=(o1,o2,…,ok,…,ol)T

期望输出向量:d=(d1, d2,…,dk,…,dl)T

输入层到隐层之间的权值矩阵:V=(V1,V2,…,Vj,…,Vm)

隐层到输出层之间的权值矩阵用:W=(W1,W2,…,Wk,…,Wl)

对输出层第k个结点和隐含层的第j个结点有如下关系:

激活函数f(x)常用sigmoid函数(一个在生物学中常见的S型的函数,也称为S形生长曲线)或者tanh(双曲正切)函数。各种S型曲线函数如下图所示:

下面以sigmoid函数进行推导。sigmoid函数定义为:

其导函数为:

定义对单个样本输出层所有神经元的误差总能量总和为:

将以上误差定义式展开至隐层:

权值调整思路为:

上面式子中负号表示梯度下降,常数η∈(0,1)表示权值调整步长(学习速度)。推导过程中,对输出层有j=0,1,2,…,m;  k=1,2,…,l;对隐层有 i=0,1,2,…,n;  j=1,2,…,m

对输出层和隐层,上面式子可写为:

对输出层和隐层,定义δ:

将以上结果代入δ的表达式,并根据sigmoid函数与其导函数的关系:f'(x)=f(x)*[1-f(x)],可以计算出:

可以看出要计算隐层的δ,需要先从输出层开始计算,显然它是反向递推计算的公式。以此类推,对于多层神经网络,要先计算出最后一层(输出层)的δ,然后再递推计算前一层,直到输入层。根据上述结果,三层前馈网的BP学习算法权值调整计算公式为:

对所有输入样本(P为训练样本的个数),以总的平均误差能量作为经验损失函数(经验风险函数,代价函数)为:

最终目标是需要调整连接权使得经验损失函数最小。用BP算法训练网络时有两种训练方式:一种是顺序方式(Stochastic Learning),即每输入一个训练么样本修改一次权值;以上给出的权值修正步骤就是按顺序方式训练网络的;另一种是批处理方式(Batch Learning),即待组成一个训练周期的全部样本都一次输入网络后,以Ep为目标函数修正权值.

顺序方式所需的临时存储空间较批处理方式小,而且随机输入样本有利于权值空间的搜索具有随机性,在一定程度上可以避免学习陷入局部最小值。但是顺序方式的误差收敛条件难以建立,而批处理方式能精确地计算出梯度向量,误差收敛条件简单。

Stochastic learning is generally the preferred method for basic backpropagation for the following three reasons:

Despite the advantages of stochastic learning, there are still reasons why one might consider using batch learning:

下面采用激活函数为tanh(x)的三层网络来解决异或问题(当激活函数为奇函数时,BP 算法的学习速度要快一些,最常用的奇函数是双曲正切函数)

 # -*- coding: utf-8 -*-
import numpy as np # 双曲正切函数,该函数为奇函数
def tanh(x):
return np.tanh(x) # tanh导函数性质:f'(t) = 1 - f(x)^2
def tanh_prime(x):
return 1.0 - tanh(x)**2 class NeuralNetwork:
def __init__(self, layers, activation = 'tanh'):
"""
:参数layers: 神经网络的结构(输入层-隐含层-输出层包含的结点数列表)
:参数activation: 激活函数类型
"""
if activation == 'tanh': # 也可以用其它的激活函数
self.activation = tanh
self.activation_prime = tanh_prime
else:
pass # 存储权值矩阵
self.weights = [] # range of weight values (-1,1)
# 初始化输入层和隐含层之间的权值
for i in range(1, len(layers) - 1):
r = 2*np.random.random((layers[i-1] + 1, layers[i] + 1)) -1 # add 1 for bias node
self.weights.append(r) # 初始化输出层权值
r = 2*np.random.random( (layers[i] + 1, layers[i+1])) - 1
self.weights.append(r) def fit(self, X, Y, learning_rate=0.2, epochs=10000):
# Add column of ones to X
# This is to add the bias unit to the input layer
X = np.hstack([np.ones((X.shape[0],1)),X]) for k in range(epochs): # 训练固定次数
if k % 1000 == 0: print 'epochs:', k # Return random integers from the discrete uniform distribution in the interval [0, low).
i = np.random.randint(X.shape[0],high=None)
a = [X[i]] # 从m个输入样本中随机选一组 for l in range(len(self.weights)):
dot_value = np.dot(a[l], self.weights[l]) # 权值矩阵中每一列代表该层中的一个结点与上一层所有结点之间的权值
activation = self.activation(dot_value)
a.append(activation) # 反向递推计算delta:从输出层开始,先算出该层的delta,再向前计算
error = Y[i] - a[-1] # 计算输出层delta
deltas = [error * self.activation_prime(a[-1])] # 从倒数第2层开始反向计算delta
for l in range(len(a) - 2, 0, -1):
deltas.append(deltas[-1].dot(self.weights[l].T)*self.activation_prime(a[l])) # [level3(output)->level2(hidden)] => [level2(hidden)->level3(output)]
deltas.reverse() # 逆转列表中的元素 # backpropagation
# 1. Multiply its output delta and input activation to get the gradient of the weight.
# 2. Subtract a ratio (percentage) of the gradient from the weight.
for i in range(len(self.weights)): # 逐层调整权值
layer = np.atleast_2d(a[i]) # View inputs as arrays with at least two dimensions
delta = np.atleast_2d(deltas[i])
self.weights[i] += learning_rate * np.dot(layer.T, delta) # 每输入一次样本,就更新一次权值 def predict(self, x):
a = np.concatenate((np.ones(1), np.array(x))) # a为输入向量(行向量)
for l in range(0, len(self.weights)): # 逐层计算输出
a = self.activation(np.dot(a, self.weights[l]))
return a if __name__ == '__main__':
nn = NeuralNetwork([2,2,1]) # 网络结构: 2输入1输出,1个隐含层(包含2个结点) X = np.array([[0, 0], # 输入矩阵(每行代表一个样本,每列代表一个特征)
[0, 1],
[1, 0],
[1, 1]])
Y = np.array([0, 1, 1, 0]) # 期望输出 nn.fit(X, Y) # 训练网络 print 'w:', nn.weights # 调整后的权值列表 for s in X:
print(s, nn.predict(s)) # 测试

输出为:

参考:

http://www.bogotobogo.com/python/python_Neural_Networks_Backpropagation_for_XOR_using_one_hidden_layer.php

https://triangleinequality.wordpress.com/2014/03/31/neural-networks-part-2/

https://databoys.github.io/Feedforward/

http://www.cnblogs.com/wentingtu/archive/2012/06/05/2536425.html

《Neural Networks Tricks of the Trade》Second Edition

BP神经网络求解异或问题(Python实现)的更多相关文章

  1. BP神经网络及异或实现

    BP神经网络是最简单的神经网络模型了,三层能够模拟非线性函数效果. 难点: 如何确定初始化参数? 如何确定隐含层节点数量? 迭代多少次?如何更快收敛? 如何获得全局最优解? ''' neural ne ...

  2. ANN神经网络——实现异或XOR (Python实现)

    一.Introduction Perceptron can represent AND,OR,NOT 用初中的线性规划问题理解 异或的里程碑意义 想学的通透,先学历史! 据说在人工神经网络(artif ...

  3. BP神经网络原理及python实现

    [废话外传]:终于要讲神经网络了,这个让我踏进机器学习大门,让我读研,改变我人生命运的四个字!话说那么一天,我在乱点百度,看到了这样的内容: 看到这么高大上,这么牛逼的定义,怎么能不让我这个技术宅男心 ...

  4. BP神经网络与Python实现

    人工神经网络是一种经典的机器学习模型,随着深度学习的发展神经网络模型日益完善. 联想大家熟悉的回归问题, 神经网络模型实际上是根据训练样本创造出一个多维输入多维输出的函数, 并使用该函数进行预测, 网 ...

  5. 三层BP神经网络的python实现

    这是一个非常漂亮的三层反向传播神经网络的python实现,下一步我准备试着将其修改为多层BP神经网络. 下面是运行演示函数的截图,你会发现预测的结果很惊人! 提示:运行演示函数的时候,可以尝试改变隐藏 ...

  6. Python语言编写BP神经网络

    Python语言编写BP神经网络 2016年10月31日 16:42:44 ldy944758217 阅读数 3135   人工神经网络是一种经典的机器学习模型,随着深度学习的发展神经网络模型日益完善 ...

  7. Python实现bp神经网络识别MNIST数据集

    title: "Python实现bp神经网络识别MNIST数据集" date: 2018-06-18T14:01:49+08:00 tags: [""] cat ...

  8. python构建bp神经网络_曲线拟合(一个隐藏层)__2.代码实现

    IDE:jupyter 抽象程度可能不是那么高,以后再优化. 理论和代码实现的差距还是挺大的 数据集请查看 python构建bp神经网络(一个隐藏层)__1.数据可视化 部分代码预览 git上传.ip ...

  9. BP神经网络在python下的自主搭建梳理

    本实验使用mnist数据集完成手写数字识别的测试.识别正确率认为是95% 完整代码如下: #!/usr/bin/env python # coding: utf-8 # In[1]: import n ...

随机推荐

  1. 《zw版·delphi与halcon系列原创教程》zw版_THOperatorSetX控件函数列表 v11中文增强版

    <zw版·delphi与halcon系列原创教程>zw版_THOperatorSetX控件函数列表v11中文增强版 Halcon虽然庞大,光HALCONXLib_TLB.pas文件,源码就 ...

  2. kernel32.dll出错解决方案

    kernel32.dll 一.什么是kernel32内核文件 kernel32.dll是Windows 9x/Me中非常重要的32位动态链接库文件,属于内核级文件.它控制着系统的内存管理.数据的输入输 ...

  3. CSS Reset / Normalize 如何进行样式重置

    CSS Reset 过于激进,所有样式全部消除没有必要. 关键是保持各种浏览器的兼容,包括Bootstrap的CSS Reset也是走的这个路线. 线面这个就是后面一种思路的成果: http://ne ...

  4. Elasticsearch--Date math在索引中的使用

    在Elasticsearch,有时要通过索引日期来筛选某段时间的数据,这时就要用到ES提供的日期数学表达式 描述: 特别在日志数据中,只是查询一段时间内的日志数据,这时就可以使用日期数学表达式,这样可 ...

  5. linux设备驱动归纳总结(三):4.ioctl的实现【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-59419.html linux设备驱动归纳总结(三):4.ioctl的实现 一.ioctl的简介: 虽 ...

  6. TI CC254x BLE教程 2

    连接更新请求(connection update request) 如果slave不满意现有的连接参数, 比如间隔, 延迟等等, 可以向master提出自己希望的参数范围 连接终止(connectio ...

  7. 测试过程中LR的关联报错

    在测试过程中,录制的脚本会做一些关联.在测试的过程中,常常出现关联失败的情况. 如果最后的结果有检查点,检查点失败而事务失败. 每次出现这样的情况,我都不知道如何办.为了不出现错误,我都在关联函数里面 ...

  8. Symfony电子商务

    http://zhilihe.com/content/symfony%E7%94%B5%E5%AD%90%E5%95%86%E5%8A%A1%E9%A1%B9%E7%9B%AE%E6%80%BB%E7 ...

  9. java UUID

    UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符.UUID具有以下涵义: 经由一定的算法机器生成 为了保证 ...

  10. 在lua的string库和正则表达式

    一.前提要了解一下lua 的string几个方法 1. string库中所有的字符索引从前往后是1,2,...;从后往前是-1,-2,... 2. string库中所有的function都不会直接操作 ...