http://www.cnblogs.com/bambipai/p/7922981.html------误差逆传播算法讲解

  人工神经网络包含多种不同的神经网络,此处的代码建立的是多层感知器网络,代码以《集体智慧编程》第四章 “nn.py" 为原型和框架,可以指定隐藏网络的层数和每层的节点数,利用反向传播法修正权值,并连接数据库,保存每层每个节点的权值等信息。代码在算法方面并没有做出改进,结构上可能不是特别严谨和简洁,在算法、结构方面并不一定可取,只是为建立多层隐藏网络提供一个思路,可以对神经网络有更好的理解。

  新建一个文件(hiddens.py),并在其中新建一个类,取名为searchnet:

 from math import tanh
import sqlite3 as sqlite
import random
class searchnet:
def __init__(self,dbname,n,num):
self.con=sqlite.connect(dbname)
self.h=n#隐藏层的数量
self.hiddennodes=num#每个隐藏层的节点数
def __del__(self):
self.con.close()
def maketables(self):
for i in range(self.h-1):
self.con.execute('create table hiddennode_%d(create_key,fromid,toid,strength)' % (i))
self.con.execute('create table wordhidden(fromid,toid,strength)')
self.con.execute('create table hiddenurl(fromid,toid,strength)')
self.con.commit()

其中,n和num分别是隐藏层的数量以及对应层数的节点数,然后我们建立了n-1张表存放隐藏层节点之间的权值,creat_key起到标示节点的作用,用以区别不同输入形成的隐藏层节点,input和out分别是输入内容和分类类别。

  接下来,我们来建立隐藏层以及节点之间的连接。

 def generatehiddennode(self,wordids,urls):
#用以标示不同输入产生的不同网络
sorted_words=[id for id in wordids]
sorted_words.sort()
self.createkey='_'.join(sorted_words) #生成所有隐藏层节点并建立连接,creatkey标示了输入的数据,每层每个节点的fromid和toid均不相同,代表了其层次和第几个
for i in range(self.h-1):
for j in range(self.hiddennodes[i]):
for k in range(self.hiddennodes[i+1]):
table='hiddennode_%d' % i
fromid=str(i)+'_'+str(j)
toid=str(i+1)+'_'+str(k)
strn=random.random()
self.con.execute("insert into %s (create_key,fromid,toid,strength) values ('%s','%s','%s',%.2f)" % (table,self.createkey,fromid,toid,strn)) #建立输入和隐藏层的连接
table='wordhidden'
strength=0.1
for j in range(self.hiddennodes[0]):
hiddenid='0_'+str(j)
for wordid in wordids:
self.con.execute("insert into %s (fromid,toid,strength) values ('%s','%s',%f)" % (table,wordid,hiddenid,strength)) #建立输出和隐藏层的连接
table='hiddenurl'
strength=0.2
for j in range(self.hiddennodes[self.h-1]):
hiddenid=str(self.h-1)+'_'+str(j)
for urlid in urls:
self.con.execute("insert into %s (fromid,toid,strength) values ('%s','%s',%f)" % (table,hiddenid,urlid,strength))
self.con.commit()

  首先连接输入的内容作为标示不同输入产生的不同隐藏层节点的标志,然后循环建立隐藏层节点之间的连接(因为是隐藏层之间的连接,所以只需要n-1个表),除了create_key还有一个id来区分节点,即代码中的fromid,x_y代表的是第x层隐藏层,第y个节点(x>=0,y>=0),隐藏层K层的toid就是K+1层的fromid,节点连接之间的权重在0-1之间随机产生。然后建立第0层隐藏层和输入层之间的连接,权值默认为0.1,第n-1层(最后一层)隐藏层和输出层之间的连接,权值默认为0.2,并将这些信息存入表。

  我们可以运行看一下效果。

  

                

  另外我想说明的一点是,我们所建立的节点以及下面要建立的网络都是抽象的,而数据库中的表是具象的,但这并不是说表就是网络的具象化,它仅是存储了网络中节点之间的连接,对于一个表中的fromid和toid来说,仅仅是一个名称,并不代表真正抽象的节点,所以我们在建立隐藏层K层与K+1层节点之间的连接时,即便还并没有生成及存储K+1层的formid,我们仍然可以完成K层数据的生成与存储,只要我们知道我们即将要生成的K+1层节点的名称(fromid)即可。

  产生了隐藏层所有节点之后,可以开始建立网络了,利用数据库中保存的信息,建立起包括所有当前权重值在内的相应网络。setupnetwork函数为searchnet类定义了多个实例变量,包括:输入内容列表、隐藏层节点及分类分别,每个节点的数值输出,节点之间的权重值(从数据库中获得)。

 def getallhiddenids(self,wordids,urlids):
ll={}
ll.setdefault(0,{})
cur=self.con.execute("select toid from wordhidden where fromid='%s'" % wordids[0])
for row in cur: ll[0].setdefault(row[0],1)
res=row[0]
for i in range(self.h-1):
ll.setdefault(i+1,{})
cur=self.con.execute("select toid from hiddennode_%d where create_key='%s' and fromid='%s' " % (i,res,self.createkey))
for row in cur: ll[i+1].setdefault(row[0],1)
res=row[0]
hn={}
for i in range(self.h):
node=sorted(ll[i].keys())
hn.setdefault(i,node)
return hn
 def getstrength(self,fromid,toid,layer):
if layer==-1: table='wordhidden'#-1层是输入层
elif 0<=layer<self.h-1: table='hiddennode_%d' % layer
else: table='hiddenurl'
res=self.con.execute("select strength from %s fromid='%s' and toid='%s'" % (table,fromid,toid)).fetchone()
if res==None:
if layer==-1: return -0.2
if 0<=layer<self.h: return 0
return res[0]

  在获得隐藏层权值和节点时,要注意create_key这一项,如果没有create_key这一项,储存在同一张表中不同输入所获得的隐藏层节点id是相同的,那么在获得权值时就会产生错误,这是create_key这一项存在的重要意义。

  接下来建立网络,并计算输出。对于网络中的每一层的节点,有来自上一层的输入值,Σw*x,即权值和来自上一层输入乘积的和,即为程序中的sum;输入通过“激活函数”后即为该层节点的输出,即为程序中self.ah,程序中使用反双曲正切函数tanh(x)作为激活函数。(程序没有对输入值进行保存,只保存了输出值)。

#初始化当前实例的ai,ah,ao
#获取数据中输入权重wi,输出权重wo
def setupnetwork(self,wordids,urlids):
# value lists
self.wordids=wordids
self.hns=self.getallhiddenids(wordids,urlids)#hns是个嵌套列表的字典
self.urlids=urlids self.ah={}#ah是隐藏层的节点值,key是哪一层,value是节点值的列表
self.w={}#w是权重值,key是该权重指向的哪一层,value是嵌套的列表,v[i][j]代表 i-j的weight
# node outputs
self.ai = [1.0]*len(self.wordids)
for i in range(self.h):
self.ah.setdefault(i,[1.0]*len(self.hns[i]))
self.ao = [1.0]*len(self.urlids) # create weights matrix
self.w.setdefault(-1,[[self.getstrength(wordid,hiddenid,-1)for hiddenid in self.hns[0]]
for wordid in self.wordids])
for i in range(self.h-1):
self.w.setdefault(i,[[self.getstrength(fromid,toid,i)for toid in self.hns[i+1]]
for fromid in self.hns[i]])
self.w.setdefault('o',[[self.getstrength(hiddenid,urlid,1) for urlid in self.urlids]
for hiddenid in self.hns[self.h-1]])
def feedforward(self):
# the only inputs are the query words
for i in range(len(self.wordids)):
self.ai[i] = 1.0 # 首先利用输入值得到第一层隐藏层的节点值
for j in range(len(self.hns[0])):
sum = 0.0
for i in range(len(self.wordids)):
sum = sum + self.ai[i] * self.w[-1][i][j]
self.ah[0][j] = tanh(sum) #然后循环得到其他隐藏层的节点值
for i in range(1,self.h):
for j in range(len(self.hns[i])):
sum=0.0
for k in range(len(self.hns[i-1])):
sum = sum + self.ah[i-1][k] * self.w[i-1][k][j]#i层的输入
self.ah[i][j] = tanh(sum)#i层的输出 # 最后得到输出层的
for k in range(len(self.urlids)):
sum = 0.0
for j in range(len(self.hns[self.h-1])):
sum = sum + self.ah[self.h-1][j] * self.w['o'][j][k]
self.ao[k] = tanh(sum) return self.ao[:]

  因为初始化输入值是相同的,因此两个节点的输出值也均为相同。

  下面利用反向传播法调整权值,反向传播,即让误差沿着网络反向传播,以ωij为例,以j层的输出对于输入的导数作为一个调节因子,然后沿着网络反向传播,在传播的过程中权值会对调节后的误差加权,并与i层节点的输出和学习率相乘,就是ωij的调节量。反向传播法是经典的权值修正算法,但此处对于算法不做具体说明,需要了解的童鞋可以参考http://www.cnblogs.com/bambipai/p/7922981.html。下面程序中,N是学习率,tanh(y)=1-y*y近似反正切函数的导数,作为误差的调节因子,y为0时,tanh最大,y为1时,tanh最小,因为,我们在训练时,会指定一个输出节点的输出目标为1(或接近1),这样,如果输出节点的输出接近于1,tanh(output)很小,权值的修正量就小,反之,权值的修正量就大,所以它可以作为调节因子。

def backPropagate(self, targets, N=0.5):
# calculate errors for output
output_deltas = {}#每一层每个结点的“调节后的误差”=error*dtanh(out),out是正向传播时相对于这一层的输出
change={}#权值的改变值 output_deltas.setdefault('o',[])
for k in range(len(self.urlids)):
error = targets[k]-self.ao[k]#期望输出与实际输出的差值
output_deltas['o'].append(dtanh(self.ao[k]) * error)#误差的调节因子:tanh(out) hid=self.h-1
output_deltas.setdefault(hid,[])
for j in range(len(self.hns[hid])):
error = 0.0
for k in range(len(self.urlids)):
error = error + output_deltas['o'][k]*self.w['o'][j][k]#沿网络反向传播的误差,与权值相乘
output_deltas[hid].append(dtanh(self.ah[hid][j]) * error)#该层的“调节后的误差” # calculate errors for hidden layer
for i in range(hid-1,-1,-1):
output_deltas.setdefault(i,[])
for j in range(len(self.hns[i])):
error = 0.0
for k in range(len(self.hns[i+1])):
error = error + output_deltas[i+1][k]*self.w[i][j][k]
output_deltas[i].append(dtanh(self.ah[i][j]) * error) # update output weights
for j in range(len(self.hns[hid])):
for k in range(len(self.urlids)):
change = output_deltas['o'][k]*self.ah[hid][j]#调节量=“误差”x该层的输入(正向传播的输入)
self.w['o'][j][k] = self.w['o'][j][k] + N*change # update input weights
for i in range(hid-1,-1,-1):
for k in range(len(self.hns[i])):
for j in range(len(self.hns[i+1])):
change = output_deltas[i+1][j]*self.ah[i][k]
self.w[i][k][j] = self.w[i][k][j] + N*change for j in range(len(self.wordids)):
for k in range(len(self.hns[0])):
change = output_deltas[0][k]*self.ai[j]
self.w[-1][j][k] = self.w[-1][j][k] + N*change

  我们看到,在经过5次的权值修正后,输出结果相对于最初的输出结果相对更接近于目标值。

  我们可以把修正后的权值更新到数据库,在这里同样注意“creat_key".

 def setstrength(self,fromid,toid,layer,strength):
if layer==-1:
table='wordhidden'
res=self.con.execute("select rowid from %s where fromid='%s' and toid='%s'" % (table,fromid,toid)).fetchone()
elif 0<=layer<self.h-1:
table='hiddennode_%d' % layer
res=self.con.execute("select rowid from %s where create_key='%s' and fromid='%s' and toid='%s'" % (table,self.createkey,fromid,toid)).fetchone()
else:
table='hiddenurl'
res=self.con.execute("select rowid from %s where fromid='%s' and toid='%s'" % (table,fromid,toid)).fetchone()
rowid=res[0]
self.con.execute('update %s set strength=%f where rowid=%d' % (table,strength,rowid))

setstrength

 def updatedatabase(self):
# set them to database values
for i in range(len(self.wordids)):
for j in range(len(self.hns[0])):
self.setstrength(self.wordids[i],self.hns[0][j],-1,self.w[-1][i][j])
for k in range(self.h-1):
for i in range(len(self.hns[k])):
for j in range(len(self.hns[k+1])):
self.setstrength(self.hns[k][i],self.hns[k+1][j],k,self.w[k][i][j])
for i in range(len(self.hns[self.h-1])):
for j in range(len(self.urlids)):
self.setstrength(self.hns[self.h-1][i],self.urlids[j],self.h,self.w['o'][i][j])
self.con.commit()

  到此,整个网络的建立、训练代码就完成了,但是这个网络只是对输入过的内容分类效果较好,并不能进行预测。

  以上代码适用于Python3.4,python2.x需要稍作改变

 1 def feedforward(self):
2 # the only inputs are the query words
3 for i in range(len(self.wordids)):
4 self.ai[i] = 1.0
6 # 首先利用输入值得到第一层隐藏层的节点值
7 for j in range(len(self.hns[0])):
8 sum = 0.0
9 for i in range(len(self.wordids)):
10 sum = sum + self.ai[i] * self.w[-1][i][j]
11 self.ah[0][j] = tanh(sum)
13 #然后循环得到其他隐藏层的节点值
14 for i in range(1,self.h):
15 for j in range(len(self.hns[i])):
16 sum=0.0
17 for k in range(len(self.hns[i-1])):
18 sum = sum + self.ah[i-1][k] * self.w[i-1][k][j]
19 self.ah[i][j] = tanh(sum)
21 # 最后得到输出层的
22 for k in range(len(self.urlids)):
23 sum = 0.0
24 for j in range(len(self.hns[self.h-1])):
25 sum = sum + self.ah[self.h-1][j] * self.w['o'][j][k]
26 self.ao[k] = tanh(sum)
28 retur

人工神经网络,支持任意数量隐藏层,多层隐藏层,python代码分享的更多相关文章

  1. SIGAI深度学习第三集 人工神经网络2

    讲授神经网络的理论解释.实现细节包括输入与输出值的设定.网络规模.激活函数.损失函数.初始化.正则化.学习率的设定.实际应用等 大纲: 实验环节: 理论层面的解释:两个方面,1.数学角度,映射函数h( ...

  2. 人工神经网络--ANN

    神经网络是一门重要的机器学习技术.它是目前最为火热的研究方向--深度学习的基础.学习神经网络不仅可以让你掌握一门强大的机器学习方法,同时也可以更好地帮助你理解深度学习技术. 本文以一种简单的,循序的方 ...

  3. 【机器学习】人工神经网络ANN

    神经网络是从生物领域自然的鬼斧神工中学习智慧的一种应用.人工神经网络(ANN)的发展经历的了几次高潮低谷,如今,随着数据爆发.硬件计算能力暴增.深度学习算法的优化,我们迎来了又一次的ANN雄起时代,以 ...

  4. 人工神经网络 Artificial Neural Network

    2017-12-18 23:42:33 一.什么是深度学习 深度学习(deep neural network)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高 ...

  5. python大战机器学习——人工神经网络

    人工神经网络是有一系列简单的单元相互紧密联系构成的,每个单元有一定数量的实数输入和唯一的实数输出.神经网络的一个重要的用途就是接受和处理传感器产生的复杂的输入并进行自适应性的学习,是一种模式匹配算法, ...

  6. [DL学习笔记]从人工神经网络到卷积神经网络_2_卷积神经网络

    先一层一层的说卷积神经网络是啥: 1:卷积层,特征提取 我们输入这样一幅图片(28*28): 如果用传统神经网络,下一层的每个神经元将连接到输入图片的每一个像素上去,但是在卷积神经网络中,我们只把输入 ...

  7. [DL学习笔记]从人工神经网络到卷积神经网络_1_神经网络和BP算法

    前言:这只是我的一个学习笔记,里边肯定有不少错误,还希望有大神能帮帮找找,由于是从小白的视角来看问题的,所以对于初学者或多或少会有点帮助吧. 1:人工全连接神经网络和BP算法 <1>:人工 ...

  8. 人工神经网络(ANN)

    参考资料:http://www.cnblogs.com/subconscious/p/5058741.html 从函数上来看,神经网络是回归方程的级联叠加,用来逼近目标函数的,本质是一种模拟特征与目标 ...

  9. 机器学习笔记之人工神经网络(ANN)

    人工神经网络(ANN)提供了一种普遍而且实际的方法从样例中学习值为实数.离散值或向量函数.人工神经网络由一系列简单的单元相互连接构成,其中每个单元有一定数量的实值输入,并产生单一的实值输出. 上面是一 ...

随机推荐

  1. 通过YUM升级centOS内核,以便安装docker

    安装Docker要满足一定的条件,对于cents系统,要求必须是64位,并且内核版本是3.10以上. 如果你的centos操作系统内核低于3.10,需要升级到这个版本以上,才能安装docker. 第一 ...

  2. HDU 4556 Stern-Brocot Tree

    题意:求SB树第N层分母分子小于均等于N的数有多少? 搞清楚了SB Tree的性质,这道题就很容易了.因为SB Tree中的数均为最简分数,所以筛一波欧拉函数即可. #include<bits/ ...

  3. java日期详解

    [TOC] 一.简介 java中的日期处理一直是个问题,没有很好的方式去处理,所以才有第三方框架的地位比如joda. 文章主要对java日期处理的详解,用1.8可以不用joda. 1. 相关概念 首先 ...

  4. day4、Linux基础题目

    第一题 我想在/data/da 目录下面创建 一个 da.txt 文件 [root@ll ~]# cd /data/oldboyedu -bash: cd: /data/oldboyedu: No s ...

  5. get和post提交数据的差别

    form表单提交,默认method = "get",所以你在提交数据的时候,最好将此參数指定为method = "post",否则你在提交大数据的时候,可能会出 ...

  6. 一段文字中的几个keyword显示高亮

    将一段文字中的几个keyword显示高亮 演示样例:将"我的愿望是当个绿巨人,所以我想让我的皮(derma)肤是绿色"中的"皮肤"显示绿色. <span ...

  7. HDU 1160 FatMouse&#39;s Speed (最长有序的上升子序列)

    题意:给你一系列个w,s.要你找到最长的n使得 W[m[1]] < W[m[2]] < ... < W[m[n]] and S[m[1]] > S[m[2]] > ... ...

  8. x86内存映射

    Contents 1 "Low" memory (< 1 MiB) 1.1 Overview 1.2 BIOS Data Area (BDA) 1.3 Extended BI ...

  9. RecyclerView高速通用适配Adapter

    RecyclerView Adapter 为RecyclerView提供更简单的适配器实现方式,不断更新完好中. Demo视频演示 GitHub地址 博客 使用 BaseViewHolder 的使用 ...

  10. 微信小程序的Web API接口设计及常见接口实现

    微信小程序给我们提供了一个很好的开发平台,可以用于展现各种数据和实现丰富的功能,通过小程序的请求Web API 平台获取JSON数据后,可以在小程序界面上进行数据的动态展示.在数据的关键 一环中,我们 ...