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. MongoDB-Use --auth parameter with connecting error

    When you use mongoDB started as "mongod --dbpath ../../data/db --auth", and you use the ex ...

  2. SAML2.0 协议初识(一)

    一.什么是 SAML 协议? SAML 即安全断言标记语言,英文全称是 Security Assertion Markup Language.它是一个基于 XML 的标准,用于在不同的安全域(secu ...

  3. hdu 4869 Turn the pokers (思维)

    Turn the pokers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  4. Java并发与同步

    Java中并发的形式无非是多线程和多进程两种形式.这两种形式都是能够利用多核来发挥计算能力的. 先说并发: 多进程意味着同一时候执行多个JVM.这个代价通常比多线程高,每一个JVM都有自己的堆栈.都要 ...

  5. Vue深度学习(6)- 组件

    使用组件 在Vue中,可以用 Vue.extend() 创建一个组件构造器: var MyComponent = Vue.extend({ template:'..........' //选项 }) ...

  6. ASP.NET Core 返回 Json DateTime 格式

    ASP.NET Core 返回 Json 格式的时候,如果返回数据中有DateTime类型,如何自定义其格式呢?配置如下: services.AddMvc().AddJsonOptions(opt = ...

  7. 开发wordpress主题

    查看我的wordpress站点 第一步:下载wordpress安装包 官网下载==> 第二步:本地安装开发环境 官网给出的环境要求: 可以选择安装wamp/xampp集成PHP开发环境,安装很简 ...

  8. Python:list 和 array的对比以及转换时的注意事项

    Python:list 和 array的对比以及转换时的注意事项 zoerywzhou@163.com http://www.cnblogs.com/swje/ 作者:Zhouwan 2017-6-4 ...

  9. 浅析JavaScript的字符串查找函数:indexOf和search

    语法 ①indexOf:方法可返回某个指定的字符串值在长字符串中首次出现的位置.如果被查找字符串没有找到,返回-1. indexOf 说明:该方法将从头到尾地检索字符串 stringObject,看它 ...

  10. 项目(1)----用户信息管理系统(5)---(剩余jsp界面)

    完成剩余jsp界面 首页界面前面我写了,接下来还有就是一个显示所有用户界面 1:注册界面 2:显示所有用户信息界面 1:注册界面 <%@ page language="java&quo ...