反向传播算法(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. 由ccf第一题引出的问题

    当时的情况是这样的,代码中需要用到一个较大的二维数组,但只要定义这个大二维数组编译就出错,无奈后来用malloc自己实现了类似二维数组的操作. 其中的b数组设为全局的或者静态的也都可以解决overfl ...

  2. SQL Server session故障排查

    --根据作业名 查找session id select a.spid,a.blocked,b.name,substring(replace(a.PROGRAM_NAME,'SQLAgent - TSQ ...

  3. struct2 学习总结

    花了近半个月学习了struct2.现大致总结下学习点: 1. struct2 入门以及基本配置(未继承ActionSupport,配置struts.xml文件,execute方法直接返回SUCESS) ...

  4. Openstack的dashboard开发之【浏览器兼容性】

    完全不支持浏览器: ie9(含)以下ie低版本浏览器及使用ie低版本浏览器的内核的扩展浏览器,如360安全浏览器(内核ie6) 原因:不支持vnc(需要浏览器支持才有vnc功能),jquery也不在支 ...

  5. iOS,破冰!

    首发:个人博客,更新&纠错&回复 iOS,破冰! 今年学的技术,以iOS自学为成本最高昂:花几千块买了台mac mini电脑,又前后买了6本书籍,从头到尾是30天时间,当然,这30天里 ...

  6. [转]编译Android源代码常见错误解决办法

    1. 编译时出现/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../libz.so when ...

  7. Linux TTY框架【转】

    本文转载自:http://ju.outofmemory.cn/entry/281168 1. 前言 由于串口的缘故,TTY是Linux系统中最普遍的一类设备,稍微了解Linux系统的同学,对它都不陌生 ...

  8. php原子操作,文件锁flock,数据库事务

    php原子操作,文件锁flock,数据库事务 php没有继承posix标准支持的unix锁,只封装了一个linux系统调用flock(信号量也能做成锁),按理也是可以使用锁机制的,虽然效率低一点.ph ...

  9. C语言中%*s,%*c 是什么意思(还有%*.*s)

    在 scanf 和 printf 里效果是不一样的. 在printf,动态控制显示格式用的 printf("%*s",5,"123");执行一下,这条语句,输出 ...

  10. 将ASCII码位于32~126的95个字符输出到屏幕上,为了美观

    //将ASCII码位于32~126的95个字符输出到屏幕上,为了美观.要求小于100的码,前面加一个0,每八个转行class shijixing{ public static void main(St ...