bp神经网络代码算法代码 : 不懂哪里错啊

BP神经网络模型与学习算法 - wentingtu - 博客园
一,什么是BP
"BP(Back Propagation)网络是1986年由Rumelhart和McCelland为首的科学家小组提出,是一种按误差逆传播算法训练的多层前馈网络,是目前应用最广泛的之一。BP网络能学习和存贮大量的输入-输出模式映射关系,而无需事前揭示描述这种映射关系的数学方程。它的学习规则是使用最速下降法,通过反向传播来不断调整网络的权值和阈值,使网络的误差平方和最小。BP神经网络模型拓扑结构包括输入层(input)、隐层(hide layer)和输出层(output layer)。"
我们现在来分析下这些话:
&是一种按误差逆传播算法训练的多层前馈网络&
BP是后向传播的英文缩写,那么传播对象是什么?传播的目的是什么?传播的方式是后向,可这又是什么意思呢。
传播的对象是误差,传播的目的是得到所有层的估计误差,后向是说由后层误差推导前层误差:
即BP的思想可以总结为
利用输出后的误差来估计输出层的直接前导层的误差,再用这个误差估计更前一层的误差,如此一层一层的反传下去,就获得了所有其他各层的误差估计。&
&BP神经网络模型拓扑结构包括输入层(input)、隐层(hide layer)和输出层(output layer)&
我们来看一个最简单的三层BP:
&BP网络能学习和存贮大量的输入-输出模式映射关系,而无需事前揭示描述这种映射关系的数学方程。&
BP利用一种称为激活函数来描述层与层输出之间的关系,从而模拟各层神经元之间的交互反应。
激活函数必须满足处处可导的条件。那么比较常用的是一种称为S型函数的激活函数:
那么上面的函数为什么称为是S型函数呢:
我们来看它的形态和它导数的形态:
p.s. S型函数的导数:
神经网络的学习目的:
希望能够学习到一个模型,能够对输入输出一个我们期望的输出。
学习的方式:
在外界输入样本的刺激下不断改变网络的连接权值
学习的本质:
对各连接权值的动态调整
学习的核心:
权值调整规则,即在学习过程中网络中各神经元的连接权变化所依据的一定的调整规则。
二,有监督的BP模型训练过程
有监督的BP模型训练表示我们有一个训练集,它包括了: input X 和它被期望拥有的输出 output Y
所以对于当前的一个BP模型,我们能够获得它针对于训练集的误差
所以BP的核心思想就是:将输出误差以某种形式通过隐层向输入层逐层反传,这里的某种形式其实就是:
也就是一种 "信号的正向传播 ----& 误差的反向传播"的过程:
这里解释下根据误差对权值的偏导数来修订权值:
随笔 - 186
Trackbacks - 0编程知识:通过&Python&代码实现神经网络算法
【前言】直接上代码是最有效的学习方式。
这篇教程通过由一段简短的 python 代码实现的非常简单的实例来讲解 BP 反向传播算法。
代码如下:
np.array([
[0,0,1],[0,1,1],[1,0,1],[1,1,1]
np.array([[0,1,1,0]]).T
2*np.random.random((3,4))
2*np.random.random((4,1))
xrange(60000):
1/(1+np.exp(-(np.dot(X,syn0))))
1/(1+np.exp(-(np.dot(l1,syn1))))
l2)*(l2*(1-l2))
l2_delta.dot(syn1.T)
l1.T.dot(l2_delta)
X.T.dot(l1_delta)
当然,上述程序可能过于简练了。下面我会将其简要分解成几个部分进行探讨。
第一部分:一个简洁的神经网络
一个用 BP 算法训练的神经网络尝试着用输入去预测输出。
考虑以上情形:给定三列输入,试着去预测对应的一列输出。我们可以通过简单测量输入与输出值的数据来解决这一问题。这样一来,我们可以发现最左边的一列输入值和输出值是完美匹配/完全相关的。直观意义上来讲,反向传播算法便是通过这种方式来衡量数据间统计关系进而得到模型的。下面直入正题,动手实践。
2 层神经网络:
# sigmoid function
nonlin(x,deriv=False):
if(deriv==True):
1/(1+np.exp(-x))
# input dataset
np.array([
# output dataset
np.array([[0,0,1,1]]).T
# seed random numbers to make calculation
# deterministic (just a good practice)
np.random.seed(1)
# initialize weights randomly with mean 0
2*np.random.random((3,1))
xrange(10000):
# forward propagation
nonlin(np.dot(l0,syn0))
# how much did we miss?
# multiply how much we missed by the
# slope of the sigmoid at the values in l1
nonlin(l1,True)
# update weights
np.dot(l0.T,l1_delta)
"Output After Training:"
Output After Training:
输入数据集,形式为矩阵,每 1 行代表 1 个训练样本。
输出数据集,形式为矩阵,每 1 行代表 1 个训练样本。
网络第 1 层,即网络输入层。
网络第 2 层,常称作隐藏层。
第一层权值,突触 0 ,连接 l0 层与 l1 层。
逐元素相乘,故两等长向量相乘等同于其对等元素分别相乘,结果为同等长度的向量。
元素相减,故两等长向量相减等同于其对等元素分别相减,结果为同等长度的向量。
若 x 和 y 为向量,则进行点积操作;若均为矩阵,则进行矩阵相乘操作;若其中之一为矩阵,则进行向量与矩阵相乘操作。
正如在“训练后结果输出”中看到的,程序正确执行!在描述具体过程之前,我建议读者事先去尝试理解并运行下代码,对算法程序的工作方式有一个直观的感受。最好能够在
ipython notebook 中原封不动地跑通以上程序(或者你想自己写个脚本也行,但我还是强烈推荐 notebook
)。下面是对理解程序有帮助的几个关键地方:
对比 l1 层在首次迭代和最后一次迭代时的状态。
仔细察看 “nonlin” 函数,正是它将一个概率值作为输出提供给我们。
仔细观察在迭代过程中,l1_error 是如何变化的。
将第 36 行中的表达式拆开来分析,大部分秘密武器就在这里面。
仔细理解第 39 行代码,网络中所有操作都是在为这步运算做准备。
下面,让我们一行一行地把代码过一遍。
建议:用两个屏幕来打开这篇博客,这样你就能对照着代码来阅读文章。在博客撰写时,我也正是这么做的。 :)
第 1 行:这里导入一个名叫 numpy 的线性代数工具库,它是本程序中唯一的外部依赖。
第 4 行:这里是我们的“非线性”部分。虽然它可以是许多种函数,但在这里,使用的非线性映射为一个称作 “sigmoid”
的函数。Sigmoid 函数可以将任何值都映射到一个位于 0 到 1
范围内的值。通过它,我们可以将实数转化为概率值。对于神经网络的训练, Sigmoid 函数也有其它几个非常不错的特性。
第 5 行: 注意,通过 “nonlin” 函数体还能得到 sigmod 函数的导数(当形参 deriv 为 True
时)。Sigmoid 函数优异特性之一,在于只用它的输出值便可以得到其导数值。若 Sigmoid 的输出值用变量 out
表示,则其导数值可简单通过式子 out *(1-out) 得到,这是非常高效的。
若你对求导还不太熟悉,那么你可以这样理解:导数就是 sigmod
函数曲线在给定点上的斜率(如上图所示,曲线上不同的点对应的斜率不同)。有关更多导数方面的知识,可以参考可汗学院的导数求解教程。
第 10 行:这行代码将我们的输入数据集初始化为 numpy
中的矩阵。每一行为一个“训练实例”,每一列的对应着一个输入节点。这样,我们的神经网络便有 3 个输入节点,4 个训练实例。
第 16 行:这行代码对输出数据集进行初始化。在本例中,为了节省空间,我以水平格式( 1 行 4 列)定义生成了数据集。“.T”
为转置函数。经转置后,该 y 矩阵便包含 4 行 1
列。同我们的输入一致,每一行是一个训练实例,而每一列(仅有一列)对应一个输出节点。因此,我们的网络含有 3 个输入, 1
行:为你的随机数设定产生种子是一个良好的习惯。这样一来,你得到的权重初始化集仍是随机分布的,但每次开始训练时,得到的权重初始集分布都是完全一致的。这便于观察你的策略变动是如何影响网络训练的。
第 23 行:这行代码实现了该神经网络权重矩阵的初始化操作。用 “syn0” 来代指
“零号突触”(即“输入层-第一层隐层”间权重矩阵)。由于我们的神经网络只有 2
层(输入层与输出层),因此只需要一个权重矩阵来连接它们。权重矩阵维度为(3,1),是因为神经网络有 3 个输入和 1
个输出。换种方式来讲,也就是 l0 层大小为 3 , l1 层大小为 1 。因此,要想将 l0 层的每个神经元节点与 l1
层的每个神经元节点相连,就需要一个维度大小为(3,1)的连接矩阵。:)
同时,要注意到随机初始化的权重矩阵均值为 0
。关于权重的初始化,里面可有不少学问。因为我们现在还只是练习,所以在权值初始化时设定均值为 0 就可以了。
另一个认识就是,所谓的“神经网络”实际上就是这个权值矩阵。虽然有“层” l0 和 l1
,但它们都是基于数据集的瞬时值,即层的输入输出状态随不同输入数据而不同,这些状态是不需要保存的。在学习训练过程中,只需存储 syn0
权值矩阵。
第 25 行:本行代码开始就是神经网络训练的代码了。本 for
循环迭代式地多次执行训练代码,使得我们的网络能更好地拟合训练集。
第 28 行:可知,网络第一层 l0 就是我们的输入数据,关于这点,下面作进一步阐述。还记得 X 包含 4
个训练实例(行)吧?在该部分实现中,我们将同时对所有的实例进行处理,这种训练方式称作“整批”训练。因此,虽然我们有 4 个不同的 l0
行,但你可以将其整体视为单个训练实例,这样做并没有什么差别。(我们可以在不改动一行代码的前提下,一次性装入 1000 个甚至
10000 个实例)。
行:这是神经网络的前向预测阶段。基本上,首先让网络基于给定输入“试着”去预测输出。接着,我们将研究预测效果如何,以至于作出一些调整,使得在每次迭代过程中网络能够表现地更好一点。
(4 x 3) dot (3 x 1) = (4 x 1)
本行代码包含两个步骤。首先,将 l0 与 syn0 进行矩阵相乘。然后,将计算结果传递给 sigmoid
函数。具体考虑到各个矩阵的维度:
(4 x 3) dot (3 x 1) = (4 x 1)
矩阵相乘是有约束的,比如等式靠中间的两个维度必须一致。而最终产生的矩阵,其行数为第一个矩阵的行数,列数则为第二个矩阵的列数。
由于装入了 4 个训练实例,因此最终得到了 4 个猜测结果,即一个(4 x
1)的矩阵。每一个输出都对应,给定输入下网络对正确结果的一个猜测。也许这也能直观地解释:为什么我们可以“载入”任意数目的训练实例。在这种情况下,矩阵乘法仍是奏效的。
第 32 行:这样,对于每一输入,可知 l1
都有对应的一个“猜测”结果。那么通过将真实的结果(y)与猜测结果(l1)作减,就可以对比得到网络预测的效果怎么样。l1_error
是一个有正数和负数组成的向量,它可以反映出网络的误差有多大。
第 36 行:现在,我们要碰到干货了!这里就是秘密武器所在!本行代码信息量比较大,所以将它拆成两部分来分析。
第一部分:求导
nonlin(l1,True)
如果 l1 可表示成 3 个点,如下图所示,以上代码就可产生图中的三条斜线。注意到,如在 x=2.0
处(绿色点)输出值很大时,及如在x=-1.0 处(紫色点)输出值很小时,斜线都非常十分平缓。如你所见,斜度最高的点位于 x=0
处(蓝色点)。这一特性非常重要。另外也可发现,所有的导数值都在 0 到 1 范围之内。
整体认识:误差项加权导数值
= l1_error *
nonlin(l1,True)
当然,“误差项加权导数值”这个名词在数学上还有更为严谨的描述,不过我觉得这个定义准确地捕捉到了算法的意图。 l1_error
是一个(4,1)大小的矩阵,nonlin(l1,True)返回的便是一个(4,1)的矩阵。而我们所做的就是将其“逐元素地”相乘,得到的是一个(4,1)大小的矩阵
l1_delta ,它的每一个元素就是元素相乘的结果。
当我们将“斜率”乘上误差时,实际上就在以高确信度减小预测误差。回过头来看下 sigmoid 函数曲线图!当斜率非常平缓时(接近于
0),那么网络输出要么是一个很大的值,要么是一个很小的值。这就意味着网络十分确定是否是这种情况,或是另一种情况。然而,如果网络的判定结果对应(x
= 0.5,y =
0.5)附近时,它便就不那么确定了。对于这种“似是而非”预测情形,我们对其做最大的调整,而对确定的情形则不多做处理,乘上一个接近于 0
的数,则对应的调整量便可忽略不计。
第 39 行:现在,更新网络已准备就绪!下面一起来看下一个简单的训练示例。
在这个训练示例中,我们已经为权值更新做好了一切准备。下面让我们来更新最左边的权值(9.5)。
权值更新量 = 输入值 * l1_delta
对于最左边的权值,在上式中便是 1.0 乘上 l1_delta 的值。可以想得到,这对权值 9.5
的增量是可以忽略不计的。为什么只有这么小的更新量呢?是因为我们对于预测结果十分确信,而且预测结果有很大把握是正确的。误差和斜率都偏小时,便意味着一个较小的更新量。考虑所有的连接权值,这三个权值的增量都是非常小的。
然而,由于采取的是“整批”训练的机制,因此上述更新步骤是在全部的 4 个训练实例上进行的,这看上去也有点类似于图像。那么,第
行做了什么事情呢?在这简单的一行代码中,它共完成了下面几个操作:首先计算每一个训练实例中每一个权值对应的权值更新量,再将每个权值的所有更新量累加起来,接着更新这些权值。亲自推导下这个矩阵相乘操作,你便能明白它是如何做到这一点的。
重点结论:
现在,我们已经知晓神经网络是如何进行更新的。回过头来看看训练数据,作一些深入思考。 当输入和输出均为 1
时,我们增加它们间的连接权重;当输入为 1 而输出为 0 时,我们减小其连接权重。
因此,在如下 4
个训练示例中,第一个输入结点与输出节点间的权值将持续增大或者保持不变,而其他两个权值在训练过程中表现为同时增大或者减小(忽略中间过程)。这种现象便使得网络能够基于输入与输出间的联系进行学习。
第二部分:一个稍显复杂的问题
考虑如下情形:给定前两列输入,尝试去预测输出列。一个关键点在于这两列与输出不存在任何关联,每一列都有 50% 的几率预测结果为
1 ,也有 50% 的几率预测为 0 。
那么现在的输出模式会是怎样呢?看起来似乎与第三列毫不相关,其值始终为 1 。而第 1 列和第 2 列可以有更为清晰的认识,当其中
1 列值为1(但不同时为 1 !)时,输出便为 1 。这边是我们要找的模式!
以上可以视为一种“非线性”模式,因为单个输入与输出间不存在一个一对一的关系。而输入的组合与输出间存在着一对一的关系,在这里也就是列 1
和列 2 的组合。
信不信由你,图像识别也是一种类似的问题。若有 100
张尺寸相同的烟斗图片和脚踏车图片,那么,不存在单个像素点位置能够直接说明某张图片是脚踏车还是烟斗。单纯从统计角度来看,这些像素可能也是随机分布的。然而,某些像素的组合却不是随机的,也就是说,正是这种组合才形成了一辆脚踏车或者是一个人。
我们的策略
由上可知,像素组合后的产物与输出存在着一对一的关系。为了先完成这种组合,我们需要额外增加一个网络层。第一层对输入进行组合,然后以第一层的输出作为输入,通过第二层的映射得到最终的输出结果。在给出具体实现之前,我们来看下这张表格。
权重随机初始化好后,我们便得到了层1的隐态值。注意到什么了吗?第二列(第二个隐层结点)已经同输出有一定的相关度了!虽不是十分完美,但也可圈可点。无论你是否相信,寻找这种相关性在神经网络训练中占了很大比重。(甚至可以认定,这也是训练神经网络的唯一途径),随后的训练要做的便是将这种关联进一步增大。syn1
权值矩阵将隐层的组合输出映射到最终结果,而在更新 syn1 的同时,还需要更新 syn0
权值矩阵,以从输入数据中更好地产生这些组合。
注释:通过增加更多的中间层,以对更多关系的组合进行建模。这一策略正是广为人们所熟知的“深度学习”,因为其正是通过不断增加更深的网络层来建模的。
3 层神经网络:
nonlin(x,deriv=False):
if(deriv==True):
1/(1+np.exp(-x))
np.array([[0,0,1],
np.array([[0],
np.random.seed(1)
# randomly initialize our weights with mean 0
2*np.random.random((3,4))
2*np.random.random((4,1))
xrange(60000):
# Feed forward through layers 0, 1, and 2
nonlin(np.dot(l0,syn0))
nonlin(np.dot(l1,syn1))
# how much did we miss the target value?
str(np.mean(np.abs(l2_error)))
# in what direction is the target value?
# were we really sure? if so, don't change too
l2_error*nonlin(l2,deriv=True)
# how much did each l1 value contribute to the l2 error (according
to the weights)?
l2_delta.dot(syn1.T)
# in what direction is the target l1?
# were we really sure? if so, don't change too
nonlin(l1,deriv=True)
l1.T.dot(l2_delta)
l0.T.dot(l1_delta)
输入数据集,形式为矩阵,每 1 行代表 1 个训练样本。
输出数据集,形式为矩阵,每 1 行代表 1 个训练样本。
网络第 1 层,即网络输入层。
网络第 2 层,常称作隐藏层。
假定为网络最后一层,随着训练进行,其输出应该逐渐接近正确结果
第一层权值,突触 0 ,连接 l0 层与 l1 层。
第二层权值,突触 1 ,连接 l1 层与 l2 层。
该值说明了神经网络预测时“丢失”的数目。
该值为经确信度加权后的神经网络的误差,除了确信误差很小时,它近似等于预测误差。
该值为 l2_delta 经 syn1 加权后的结果,从而能够计算得到中间层/隐层的误差。
该值为经确信度加权后的神经网络 l1 层的误差,除了确信误差很小时,它近似等于 l1_error 。
第 43 行:通过对 l2 层的误差进行“置信度加权”,构建 l1 层相应的误差。为了做到这点,只要简单的通过 l2 与 l1
间的连接权值来传递误差。这种做法也可称作“贡献度加权误差”,因为我们学习的是,l1 层每一个结点的输出值对 l2
层节点误差的贡献程度有多大。接着,用之前 2 层神经网络实现中的相同步骤,对 syn0 权值矩阵进行更新。
第三部分:总结与展望
个人建议:
如果你想认真弄懂神经网络,给你一点建议:凭借记忆尝试去重构这个网络。我知道这听起来有一些疯狂,但确实会有帮助的。如果你想能基于新的学术文章创造任意结构的神经网络,或者读懂不同网络结构的样例程序,我觉得这项训练会是一个杀手锏。即使当你在使用一些开源框架时,比如
Torch ,Caffe 或者 Theano
,这也会有所帮助的。在执行这种练习之前,我接触神经网络有好几年了。而这段时间也是我在这一领域所作的做好的投资(也没有花费很长时间)。
这个示例仍需附加一些其它功能,才能真正与业内最佳的网络结构相媲美。如果你想进一步改进你的网络,这里给出一些参考点。(后续可能还有更新)
网络层大小参数化
批量归一化
你自己的一些奇思妙想
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。神经网络BP算法源代码(C++)_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
神经网络BP算法源代码(C++)
上传于||文档简介
&&神​经​网​络​B​P​算​法​源​代​码​(​C​+​+​)​,​误​差​反​传​ ​算​法​,​十​年​前​写​的​了​,​运​行​过​,​无​误​。
阅读已结束,如果下载本文需要使用5下载券
想免费下载本文?
定制HR最喜欢的简历
你可能喜欢BP 神经网络算法 - 开源中国社区
当前访客身份:游客 [
当前位置:
发布于 日 15时,
Matlab软件下的BP神经网络算法,以及测试。
代码片段(1)
1.&[代码][C/C++]代码&&&&
function BP
%BP学习算法
%1初始化各参数
l=0.05;n=30;cells=6;times=30000;
x=linspace(0,2*pi,n);
t=sin(x);w1=rand(cells,1)*0.05;
w2=rand(1,cells)*0.05;
yw1=rand(cells,1)*0.05;
yw2=rand*0.05;
y=rand(1,n)*0.05;
e=zeros(1,times);
%2学习过程
for i=1:times
net1=w1*x(a)-yw1;
out=logsig(net1);
net2=w2*out-yw2;
y(a)=net2;
det2=t(a)-y(a);
det1=((det2*(w2)').*out).*(1-out);
w1=w1+det1*x(a)*l;
w2=w2+(det2*out)'*l;
yw1=-det1*l+yw1;
yw2=-det2*l+yw2;
ei=ei+det2^2/2;
if ei&0.008
counts=counts+1;
%示例sin(x)函数的逼近。
net1=w1*x(a)-yw1;
out=logsig(net1);
net2=w2*out-yw2;
y(a)=net2;
subplot(2,1,1);
plot(x,t,'r--',x,y,'k*-');
title('BP学习方法逼近 y=sin(x)');
if (counts&times)
subplot(2,1,2);
plot(count,e(1:sum));
disp('共运算次数为:');
title('BP 算法学习曲线误差');
xlabel('迭代次数');ylabel('均方误差');
开源中国-程序员在线工具:
相关的代码(333)
开源从代码分享开始
王维来的其它代码bp神经算法_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
bp神经算法
上传于||文档简介
&&这​已​经​讲​得​很​简​洁​了​,​过​程​一​清​二​楚
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
你可能喜欢

我要回帖

更多关于 bp神经网络代码 的文章

 

随机推荐