BPNN
链接网址:http://blog.csdn.net/heyongluoyao8/article/details/48213345
BPNN
人工神经网络
我们知道,人的脑袋具有很强的学习、记忆、联想等功能,虽然人类还没有完全搞明白人类的大脑,但是我们已经知道它的基本单位就是一个个神经元,即一个神经细胞,人的神级细胞个数大约为1011个,海兔大约为2000多个,数目越多就越复杂,处理信息的能力就越强。如下图所示,每个神经元由细胞体与突起构成,细胞体的结构与一般的细胞相似,包括细胞膜,细胞质与细胞核,突起是神经元胞体的延伸部分,按照功能的不同分为树突与轴突。树突的功能是接受冲动并将冲动传入细胞体,即接受其它神经元传来的信号,并将信号传给神经元它是传入神经末梢。而轴突将本神经元的冲动传递给其它的与之相连的神经元,因此它是输出神经末梢。
大脑的神经元便是通过这样的连接进行信号传递来处理信息的,每个神经元通过其接受的信号来使得其兴奋或抑制。神经元内部信号的产生、传导采用电信号的方式进行,而神经元之间、神经元与肌肉之间则通常采用化学递质方式进行传导,即上级神经元的轴突在有电信号传递时释放出化学递质,作用于下一级神经元的树突,树突受到递质作用后产生出点信号,从而实现了神经元间的信息传递。而神经元的兴奋与抑制是由接受到的递质决定,有些递质起兴奋作用,有些起抑制作用。当传入神经元的冲动经整合,使细胞膜电位升高,超过动作电位的阈值时,为兴奋状态,产生神经冲动,由轴突神经末梢传出。当传入神经元的冲动经整合,使得细胞膜电位降低,低于阈值时,为抑制状态,不产生神经冲动。
大脑可通过自组织、自学习,不断适应外界环境的变化。大脑的自组织、自学习性,来源于神经网络结构的可塑性,主要反映在神经元之间连接强度的可变性上。由于神经元结构的可塑性,突触的传递作用可增强与减弱,因此神经元具有学习与遗忘功能。
人工神经网络起源于上世纪40~50年代,它是在基于人脑的基本单元-神经元的建模与联结,模拟人脑神经系统,形成一种具有学习、联想、记忆和模式识别等智能信息处理的人工系统,称为人工神经网络(Artificial Neural Networks,简称ANN),它是一种连接模型(Connection Model)。1943年神经生物学家MeCulloch与青年数学家Pitts合作,提出了第一个人工神经网络模型,并在此基础上抽象出神经元的数理模型(即神经元的阈值模型,超过阈值则兴奋,否则抑制),被称为MP模型(名字命名),这是ANN的启蒙阶段,ANN正式进入研究阶段。1958年Rosenblatt在原有的MP模型的基础上增加了学习机制,他提出的感知器模型,首次把神经网络理论付诸于工程实现,ANN研究迎来第一次高潮期。1969年出版的轰动一时的《Perceptrons》一书指出简单的线性感知器的功能是有限的,它无非解决线性不可分的而分类问题,如简单的线性感知器不能实现“异或”的逻辑关系,加上神经网络就和黑夹子一样,很多东西不透明,模型的解释性不强,参数过多,容易出错,容易过拟合,无法保证全局最优等问题,同时70年代集成电路和微电子技术的迅猛发展,使得传统的Von Neumenn计算机进入全盛时期,基于逻辑符号处理方法的人工智能得到了迅速发展并取得了显著的成果。ANN进入了长达10年的低潮期。1982年,美国科学院发表了著名的Hopfield网络模型的理论,不仅对ANN信息存储和提取功能进行了非线性数学概括,提出了动力方程和学习方程,使得ANN的构造与学习有了理论指导。这一研究激发了ANN的研究热情。1986年,由Rumelhat和McChekkand等16位作者参加撰写的《Parallel Distributed Processing: Exploration in Microstructures of Cognition》一书,建立了并行分布式处理理论,并提出了BP算法,解决了长期以来ANN中的权值调整问题没有有效解决方法的难题,可以求解感知器所不能解决的问题,回答了《Perceptrons》一书中关于神经网络局限性的问题,从实践中证实了ANN的有效性。BP算法产生了深远而广泛的影响,从至ANN的研究进入了蓬勃发展期。后来学者与研究者们又不断提出了RNN(Recurrent Neural Networks,递归神经网络)以及Deep Learning(深度学习)等模型。
'''
该网络中隐含层所有的偏置项使用在输入层增加一个节点(节点输入输出值恒为1.0来代替),而输出层没有偏置项
@author hy
'''
import numpy as np
'''
激活函数类
'''
class Sigmoid:
#sigmoid函数
def f(self,x):
return 1/(1+np.exp(-x)) #sigmoid函数的导数
def df(self,x):
y = self.f(x)
return y-np.multiply(y,y) class Tanh:
#双正切函数
def f(self,x):
return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x)) #双正切函数的导数
def df(self,x):
y = self.f(x)
return 1-np.multiply(y,y)
'''
工具类
'''
class Utils:
def uniform_distribution(self,x1,x2):
return np.random.uniform(x1,x2)
def create_random_matrix(self,row,col,periphery):
m = np.zeros((row,col))
for i in range(row):
for j in range(col):
m[i][j] = self.uniform_distribution(-1*periphery, periphery)
return m
def create_matrix(self,row,col,init_value=None):
m = np.zeros((row,col))
if init_value is not None:
for i in range(row):
for j in range(col):
m[i][j] = init_value
return m
def matrix_fill_zeros(self,m):
return np.zeros(np.shape(m))
'''
BP神经网络类
输入层、隐含层、输出层三层网络结构
'''
class BPNN:
#网络初始化
def __init__(self,input_node_num,hidden_node_num,output_node_num):
#输入层节点个数,增加一个偏置项
self.i_n = input_node_num+1
#隐含层层节点个数
self.h_n = hidden_node_num
#输出层节点个数
self.o_n = output_node_num self.utils = Utils() #输入层的输入(第i个样本),增加的偏置项节点的输入输出恒为1
self.i_i = self.utils.create_matrix(self.i_n,1,1.0)
#隐含层对第i个样本的输入
self.h_i = self.utils.create_matrix(self.h_n,1,0.0)
#输出层对第i个样本的输入
self.o_i = self.utils.create_matrix(self.o_n,1,0.0) #输入层的第i个样本输出,增加的偏置项节点的输入输出恒为1
self.i_o = self.utils.create_matrix(self.i_n,1,1.0)
#隐含层对于第i个样本的输出
self.h_o = self.utils.create_matrix(self.h_n,1,0.0)
#o_o是预测值,第i个样本的预测值
self.o_o = self.utils.create_matrix(self.o_n,1,0.0) #初始化连接权值矩阵
self.w_i_h = self.utils.create_random_matrix(self.i_n,self.h_n,0.2)
self.w_h_o = self.utils.create_random_matrix(self.h_n,self.o_n,2) #delta
self.o_delta = self.utils.create_matrix(self.o_n, 1,0.0)
self.h_delta = self.utils.create_matrix(self.h_n, 1,0.0) #delta w和,batch_size个样本的训练的和,也就是批量更新
self.w_h_o_delta = self.utils.create_matrix(self.h_n,self.o_n,0.0)
self.w_i_h_delta = self.utils.create_matrix(self.i_n,self.h_n,0.0) #训练
def train(self,hidden_activation,output_activation,train_inputs,train_outputs,alpha,error_threshold,iteration_num,batch_percent):
#隐含层的激活函数
self.h_activation = hidden_activation
#输出层的激活函数
self.o_activation = output_activation
#学习步长
self.alpha = alpha
#训练样本的个数
self.train_sample_n = np.shape(train_inputs)[0]
#这次迭代的总误差
self.train_error = 0.0
#误差阈值
self.error_threshold = error_threshold
#最大迭代次数
self.iteration_num = iteration_num
#每一次批量更新需要使用的样本个数
if batch_percent>100:
batch_percent = 100
self.batch_size = (int)(self.train_sample_n*batch_percent/100) #训练样本输入,矩阵,每一行为一个样本特征
self.train_inputs = train_inputs
#训练样本真实值,矩阵,每一行为一个样本的值
self.train_outputs = train_outputs #开始训练
self.batch() #测试
def test(self,test_inputs,test_outputs=None):
#测试样本个数
self.test_sample_n = np.shape(test_inputs)[0]
#预测集合
predict_outputs = self.utils.create_matrix(self.test_sample_n, self.o_n,0.0)
for i in range(self.test_sample_n):
#预测第i个测试样本
self.predict(test_inputs[i:i+1:,::])
#预测结果在self.o_o中
predict_outputs[i:i+1:,::] = np.transpose(self.o_o)
print "actural: ",test_outputs[i]
'''
print "predict values:"
print predict_outputs
#如果测试样本有结果,则输出真实结果以及预测总误差
if test_outputs is not None:
diff = test_outputs-predict_outputs
self.test_error = 0.5*np.sum(np.sum(np.multiply(diff,diff),axis=1),axis=0)[0,0]
print "actural values:"
print test_outputs
print "test error:"
print self.test_error
''' #预测一个样本
def predict(self,test_input):
#输入层的输出,即为其输入,i_nx1矩阵,因为有个偏置项,所有两个矩阵行数不一样,需要进行这样的赋值操作
self.i_o[0:self.i_n-1:,0:1:] = np.transpose(test_input[0:1:,::])
#计算隐含层每个节点的输出h_o
self.h_o = self.h_activation.f(np.transpose(self.w_i_h)*self.i_o) #计算输出层每个节点的输出o_o
self.o_o = self.o_activation.f(np.transpose(self.w_h_o)*self.h_o) print "predict: ",self.o_o #批量更新
def batch(self):
#一次batch使用的样本的编号集
inputs_indexs = [i for i in range(self.batch_size)]
#下次batch的需要使用的第一个样本的编号
last_index = (inputs_indexs[-1]+1)%self.train_sample_n
#批量更新,直到误差小于阈值或者达到最大迭代次数
while True:
#print "inputs_indexs:",inputs_indexs
self.one_batch(inputs_indexs)
#print "error: ",self.train_error
#剩余的迭代次数减1
self.iteration_num -= 1
#判断误差是否不再改变或者达到最大迭代次数
if self.terminate():
break
else:#否则继续迭代
#得到下次batch所需要使用的样本集所对应的编号集
'''
举例:训练样本集所对应的编号集是[0,1,2,3,4,5],样本个数为6,即train_sample_n=6
如果batch_size=4,即每一次batch使用四个样本,
那么第一次使用的batch样本集所对应的编号集inputs_indexs=[0,1,2,3]
last_index = 4
第二次使用的batch样本集所对应的编号集inputs_indexs=[4,5,0,1]
即以后每次batch的inputs_indexs为:
for i in range(self.batch_size):
inputs_indexs.append((i+last_index)%self.train_sample_n)
'''
inputs_indexs = []
for i in range(self.batch_size):
inputs_indexs.append((i+last_index)%self.train_sample_n)
last_index = (inputs_indexs[-1]+1)%self.train_sample_n #一次batch
def one_batch(self,inputs_indexs):
#对每一个样本,首先使用前向传递,然后使用误差反向传播
for i in inputs_indexs:
#前向传递
self.fp(i)
#break
#反向传播
self.bp(i)
#更新权值
self.update() #第i个样本前向传递
def fp(self,i):
#输入层的输出,即为其输入,第i个样本, i_nx1矩阵
self.i_o[0:self.i_n-1:,0:1:] = np.transpose(self.train_inputs[i:i+1:,::]) #计算隐含层每个节点的输入h_i,以及隐含层的输出h_o
self.h_i = np.transpose(self.w_i_h)*np.matrix(self.i_o)
self.h_o = self.h_activation.f(self.h_i) #计算输出层每个节点的输入o_i,以及隐含层的输出o_o
self.o_i = np.transpose(self.w_h_o)*self.h_o
self.o_o = self.o_activation.f(self.o_i) #计算平方误差和
actural = np.transpose(self.train_outputs[i:i+1:,::])
tmp = self.o_o-actural
self.train_error = self.train_error + (np.transpose(tmp)*tmp)[0,0] #第i个样本误差反向传播
def bp(self,i): #对输出层每一个节点,计算\Delta_{ij}^{T-1}=(y_{ij}-\hat{y}_{ij}) \cdot f'^{T}(v)|_{v=I_{ij}^{T}}
self.o_delta = np.multiply((self.o_o-np.transpose(self.train_outputs[i:i+1:,::])),
self.o_activation.df(self.o_i))
#print "self.o_delta:",self.o_delta
#使用公式\frac{1}{p}\sum_{i=1}^{p}\Delta_{ij}^{T-1} \cdot o^{T-1}_{ik}计算\Delta {w_{kj}^{T-1}}
#前面的系数frac{1}{p}还没乘
self.w_h_o_delta = self.w_h_o_delta + self.h_o*np.transpose(self.o_delta)
#print "self.w_h_o_delta:",self.w_h_o_delta #对隐含层每一个节点,计算\Delta_{ij}^{T-2}=\sum_{s=1}^{s_{T}}(y_{is}-\hat{y}_{is}) \cdot f'^{T}(v)|_{v=I_{is}^{T}}\cdot w_{js}^{T-1} \cdot f'^{T-1}(v)|_{v=I_{ij}^{T-1}}
self.h_delta = np.multiply(self.w_h_o*np.multiply((self.o_o-np.transpose(self.train_outputs[i:i+1:,::])),self.o_activation.df(self.o_i)),self.h_activation.df(self.h_i))
#print "self.h_delta:",self.h_delta
#使用公式\frac{1}{p}\sum_{i=1}^{p}\Delta_{ij}^{T-2}\cdot o^{T-2}_{ik}计算\Delta {w_{kj}^{T-2}}
#前面的系数frac{1}{p}还没乘
self.w_i_h_delta = self.w_i_h_delta + self.i_o*np.transpose(self.h_delta)
#print "self.w_i_h_delta:",self.w_i_h_delta #更新权值W
def update(self):
#按照公式更新输入层与隐含层之间的w: w^{T-2}_{kj}:=w^{T-2}_{kj}-\alpha\frac{1}{p}\sum_{i=1}^{p}\Delta_{ij}^{T-2}\cdot o^{T-2}_{ik}
self.w_i_h = self.w_i_h - self.alpha/self.batch_size*self.w_i_h_delta
#按照公式更新隐含层与输出层之间的w: w^{T-1}_{kj}:=w^{T-1}_{kj}-\alpha\frac{1}{p}\sum_{i=1}^{p}\Delta_{ij}^{T-1} \cdot o^{T-1}_{ik}
self.w_h_o = self.w_h_o - self.alpha/self.batch_size*self.w_h_o_delta
#delta清零
self.w_i_h_delta = Utils().matrix_fill_zeros(self.w_i_h_delta)
self.w_h_o_delta = Utils().matrix_fill_zeros(self.w_h_o_delta) #判断迭代是否终止
def terminate(self):
if(0.5*self.train_error/self.batch_size<self.error_threshold
or self.iteration_num<=0):
return True
else:
print "error: ",self.train_error
self.train_error = 0.0
return False if __name__=="__main__":
'''
inputs = np.matrix([[0,0],[0,1],[1,0],[1,1]])
outputs = np.matrix([[0],[1],[1],[0]])
bpnn = BPNN(2, 5, 1) bpnn.train(Tanh(), Tanh(), inputs,
outputs, 0.1, 0.001,
10000, 100)
bpnn.test(inputs)
'''
#读取数据
r_fp = open("data","r")
#输入层节点数
input_level_node_num = 0
#隐藏层层节点数
hidden_level_node_num = 0
#输出层节点数
output_level_node_num = 0
#输入数据
inputs = []
#数据的真实值
outputs = []
i = 0
for line in r_fp:
strs = line.strip().split(",")
#第一行是每层的节点数
if i==0:
input_level_node_num = int(strs[0])
hidden_level_node_num = int(strs[1])
output_level_node_num = int(strs[2])
else:
#数据,最后一列是真实值
#特征值向量
i_v = []
#真实值向量
o_v = []
for i in range(len(strs)-1):
i_v.append(float(strs[i]))
o_v.append(float(strs[-1]))
inputs.append(i_v)
outputs.append(o_v)
i+=1
inputs = np.matrix(inputs)
outputs = np.matrix(outputs)
#每个特征以及结果的的最大值最小值归一化
max_inputs = np.max(inputs,axis=0)
min_inputs = np.min(inputs,axis=0)
normalize_inputs = (inputs-min_inputs)/(max_inputs-min_inputs)
max_outputs = np.max(outputs,axis=0)
min_outputs = np.min(outputs,axis=0)
normalize_outputs = (outputs-min_outputs)/(max_outputs-min_outputs)
#获取总共样本的个数
smaple_n = np.shape(normalize_inputs)[0]
#将数据按照2:1拆分成训练集与测试集
train_sample_n = smaple_n*2.0/3
train_inputs = normalize_inputs[0:train_sample_n:1,::]
train_outputs = normalize_outputs[0:train_sample_n:1,::]
test_inputs = normalize_inputs[train_sample_n:smaple_n:1,::]
test_outputs = normalize_outputs[train_sample_n:smaple_n:1,::] #构建网络
bpnn = BPNN(input_level_node_num, hidden_level_node_num, output_level_node_num)
#训练
bpnn.train(Sigmoid(), Sigmoid(), train_inputs,
train_outputs, 0.2, 0.01,
1000, 100)
#测试,其实最后预测值需要进行反归一化,这里没有做此步骤
bpnn.test(test_inputs,test_outputs)
BPNN的更多相关文章
- Python笔记 #19# 实现bpnn
代码编辑&解释工具:Jupyter Notebook 快速入门 形象说明BP神经网络的用法(图片来自推特): Bpnn类最主要的三个方法: initialize方法,用于设定神经网络的层数.各 ...
- [BPNN]BP神经网络实现
BP神经网络实现 以3层网络为例,Python实现: 1.代码框架 主要函数: Init函数:设定InputLayer nodes.HiddenLayer nodes.OutputLayer node ...
- [BPNN]BP神经网络概念
BP神经网络概念 BP神经网络的计算过程: 由正向计算过程和反向计算过程组成: 正向计算过程,输入模式从输入层经隐单元层逐层处理,并转向输出层,每一层神经元的状态只影响下一层神经元的状态.如果在输出层 ...
- NLP&数据挖掘基础知识
Basis(基础): SSE(Sum of Squared Error, 平方误差和) SAE(Sum of Absolute Error, 绝对误差和) SRE(Sum of Relative Er ...
- 如何点击按钮后在加载外部的Js文件
或许有朋友遇到过,想等自己点击按钮之后才执行某一个js文件,那么,你运气好,看到了我的代码了哈哈, <html> <head> <title></title& ...
- 二、JavaScript语言--JS基础--JavaScript进阶篇--浏览器对象
1.window对象 window对象是BOM的核心,window对象指当前的浏览器窗口. window对象方法:
- 神经网络NN
神经网络基本模型: 1.前向神经网络:无圈的有向图N=(V,E,W),其中,V为神经元集合,E为连结权值集合,W为每一连结赋予一实值的权重. 神经元集V可以被分成无接受域的输入结点集V1,无投射域的输 ...
- ANN实现
ANN核心数据结构: typedef struct { int input_n; /* number of input units */ int h ...
- Python实现bp神经网络识别MNIST数据集
title: "Python实现bp神经网络识别MNIST数据集" date: 2018-06-18T14:01:49+08:00 tags: [""] cat ...
随机推荐
- bzoj2431逆序对数列
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2431 很容易想到n^3的做法.就是前 i 个数用第 i 个数最多能 i - 1 个逆序对,所 ...
- hive 处理小文件,减少map数
1.hive.merge.mapfiles,True时会合并map输出.2.hive.merge.mapredfiles,True时会合并reduce输出.3.hive.merge.size.per. ...
- FastDFS简介和安装
FastDFS是一个轻量级的开源分布式文件系统 FastDFS主要解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡 FastDFS实现了软件方式的RAID,可以使用廉价的IDE硬盘进 ...
- LLMNR欺骗工具Responder
LLMNR(Link-Local Multicast Name Resolution,链路本地多播名称解析)协议是一种基于DNS包格式的协议.它可以将主机名解析为IPv4和IPv6的IP地址.这样用户 ...
- 0122(本来是想ak的但是因为智障只拿了200。)
今天考了一场小测试,额,非常非常水,但是智障的我才A掉两道题. T1: 1.暑假作业 (mtime.pas/c/cpp) [问题描述] 暑假作业是必须要写的,越到假期结束前,写作业的效率就越高,小 ...
- secureCRT下linux rz命令上传文件失败或变小(破损)的问题解决方法
在使用secureCRT的linux服务器时候,很多时候需要安装软件,而服务器本身是没有连接外网的 ,这时候就需要用到rz命令了. 在使用rz命令时候,有时候上传文件会失败,是因为上传的文件流中包含某 ...
- ubuntu sudo apt-get update与sudo apt-get upgrade的作用及区别,以及python pip的安装
在UBUNTU下,我们维护一个源列表,源列表里面都是一些网址信息,这每一条网址就是一个源,这个地址指向的数据标识着这台源服务器上有哪些软件可以安装使用.编辑源命令: sudo gedit /etc/a ...
- python操作excel表格文件--使用xlrd模块
原文: http://www.cnblogs.com/lhj588/archive/2012/01/06/2314181.html 引言: 实际工作中,可能很多情况下都会用到excel表格,像如果不需 ...
- uva-110-没有for循环的排序
题意:看输出就懂了,暴力枚举题,字符串最大长度是8,所有长度等于8的长度是8!=1x2x3x4x5x6x7x8=40320,数据量比较小的.只是枚举的方向比较怪异,如下,长度等于3的串 a ab,ba ...
- Numpy的ndarry:一种多维数组对象
Numpy的ndarry:一种多维数组对象 Numpy最重要的一个特点就是其N维数组对象(即ndarry),该对象是一个快速而灵活的大数据集容器.你可以利用这种数组对整块数据执行一些数学运算,其语法跟 ...