BPNN

链接网址:http://blog.csdn.net/heyongluoyao8/article/details/48213345

BPNN

人工神经网络

  我们知道,人的脑袋具有很强的学习、记忆、联想等功能,虽然人类还没有完全搞明白人类的大脑,但是我们已经知道它的基本单位就是一个个神经元,即一个神经细胞,人的神级细胞个数大约为1011个,海兔大约为2000多个,数目越多就越复杂,处理信息的能力就越强。如下图所示,每个神经元由细胞体与突起构成,细胞体的结构与一般的细胞相似,包括细胞膜,细胞质与细胞核,突起是神经元胞体的延伸部分,按照功能的不同分为树突与轴突。树突的功能是接受冲动并将冲动传入细胞体,即接受其它神经元传来的信号,并将信号传给神经元它是传入神经末梢。而轴突将本神经元的冲动传递给其它的与之相连的神经元,因此它是输出神经末梢。 
Alt text 
这里写图片描述 
  大脑的神经元便是通过这样的连接进行信号传递来处理信息的,每个神经元通过其接受的信号来使得其兴奋或抑制。神经元内部信号的产生、传导采用电信号的方式进行,而神经元之间、神经元与肌肉之间则通常采用化学递质方式进行传导,即上级神经元的轴突在有电信号传递时释放出化学递质,作用于下一级神经元的树突,树突受到递质作用后产生出点信号,从而实现了神经元间的信息传递。而神经元的兴奋与抑制是由接受到的递质决定,有些递质起兴奋作用,有些起抑制作用。当传入神经元的冲动经整合,使细胞膜电位升高,超过动作电位的阈值时,为兴奋状态,产生神经冲动,由轴突神经末梢传出。当传入神经元的冲动经整合,使得细胞膜电位降低,低于阈值时,为抑制状态,不产生神经冲动。 
  大脑可通过自组织、自学习,不断适应外界环境的变化。大脑的自组织、自学习性,来源于神经网络结构的可塑性,主要反映在神经元之间连接强度的可变性上。由于神经元结构的可塑性,突触的传递作用可增强与减弱,因此神经元具有学习与遗忘功能。 
  人工神经网络起源于上世纪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 '''
  2 该网络中隐含层所有的偏置项使用在输入层增加一个节点(节点输入输出值恒为1.0来代替),而输出层没有偏置项
  3 @author hy
  4 '''
  5 import numpy as np
  6 '''
  7 激活函数类
  8 '''
  9 class Sigmoid:
 10     #sigmoid函数  
 11     def f(self,x):
 12         return 1/(1+np.exp(-x))
 13 
 14     #sigmoid函数的导数
 15     def df(self,x):
 16         y = self.f(x)
 17         return y-np.multiply(y,y)
 18 
 19 class Tanh:
 20     #双正切函数
 21     def f(self,x):
 22         return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x))
 23 
 24     #双正切函数的导数
 25     def df(self,x):
 26         y = self.f(x)
 27         return 1-np.multiply(y,y)
 28 '''
 29 工具类
 30 '''    
 31 class Utils:
 32     def uniform_distribution(self,x1,x2):
 33         return np.random.uniform(x1,x2)
 34     def create_random_matrix(self,row,col,periphery):
 35         m = np.zeros((row,col))
 36         for i in range(row):
 37             for j in range(col):
 38                 m[i][j] = self.uniform_distribution(-1*periphery, periphery)
 39         return m
 40     def create_matrix(self,row,col,init_value=None):
 41         m = np.zeros((row,col))
 42         if init_value is not None:
 43             for i in range(row):
 44                 for j in range(col):
 45                     m[i][j] = init_value
 46         return m
 47     def matrix_fill_zeros(self,m):
 48         return np.zeros(np.shape(m))
 49 '''
 50 BP神经网络类
 51 输入层、隐含层、输出层三层网络结构
 52 '''
 53 class BPNN:
 54     #网络初始化
 55     def __init__(self,input_node_num,hidden_node_num,output_node_num):
 56         #输入层节点个数,增加一个偏置项
 57         self.i_n = input_node_num+1
 58         #隐含层层节点个数
 59         self.h_n = hidden_node_num
 60         #输出层节点个数
 61         self.o_n = output_node_num
 62 
 63         self.utils = Utils()
 64 
 65         #输入层的输入(第i个样本),增加的偏置项节点的输入输出恒为1
 66         self.i_i = self.utils.create_matrix(self.i_n,1,1.0)
 67         #隐含层对第i个样本的输入
 68         self.h_i = self.utils.create_matrix(self.h_n,1,0.0)
 69         #输出层对第i个样本的输入
 70         self.o_i = self.utils.create_matrix(self.o_n,1,0.0)
 71 
 72         #输入层的第i个样本输出,增加的偏置项节点的输入输出恒为1
 73         self.i_o = self.utils.create_matrix(self.i_n,1,1.0)
 74         #隐含层对于第i个样本的输出
 75         self.h_o = self.utils.create_matrix(self.h_n,1,0.0)
 76         #o_o是预测值,第i个样本的预测值
 77         self.o_o = self.utils.create_matrix(self.o_n,1,0.0)
 78 
 79         #初始化连接权值矩阵
 80         self.w_i_h = self.utils.create_random_matrix(self.i_n,self.h_n,0.2)
 81         self.w_h_o = self.utils.create_random_matrix(self.h_n,self.o_n,2)
 82 
 83 
 84         #delta
 85         self.o_delta = self.utils.create_matrix(self.o_n, 1,0.0)
 86         self.h_delta = self.utils.create_matrix(self.h_n, 1,0.0)
 87 
 88         #delta w和,batch_size个样本的训练的和,也就是批量更新
 89         self.w_h_o_delta = self.utils.create_matrix(self.h_n,self.o_n,0.0)
 90         self.w_i_h_delta = self.utils.create_matrix(self.i_n,self.h_n,0.0)
 91 
 92     #训练
 93     def train(self,hidden_activation,output_activation,train_inputs,train_outputs,alpha,error_threshold,iteration_num,batch_percent):
 94         #隐含层的激活函数
 95         self.h_activation = hidden_activation
 96         #输出层的激活函数
 97         self.o_activation = output_activation
 98         #学习步长
 99         self.alpha = alpha
100         #训练样本的个数
101         self.train_sample_n = np.shape(train_inputs)[0]
102         #这次迭代的总误差
103         self.train_error = 0.0
104         #误差阈值
105         self.error_threshold = error_threshold
106         #最大迭代次数
107         self.iteration_num = iteration_num
108         #每一次批量更新需要使用的样本个数
109         if batch_percent>100:
110             batch_percent = 100
111         self.batch_size = (int)(self.train_sample_n*batch_percent/100)
112 
113         #训练样本输入,矩阵,每一行为一个样本特征
114         self.train_inputs = train_inputs
115         #训练样本真实值,矩阵,每一行为一个样本的值
116         self.train_outputs = train_outputs
117 
118         #开始训练
119         self.batch()
120 
121     #测试
122     def test(self,test_inputs,test_outputs=None):
123         #测试样本个数
124         self.test_sample_n = np.shape(test_inputs)[0]
125         #预测集合
126         predict_outputs = self.utils.create_matrix(self.test_sample_n, self.o_n,0.0)
127         for i in range(self.test_sample_n):
128             #预测第i个测试样本
129             self.predict(test_inputs[i:i+1:,::])
130             #预测结果在self.o_o中
131             predict_outputs[i:i+1:,::] = np.transpose(self.o_o)
132             print "actural: ",test_outputs[i] 
133         '''
134         print "predict values:"
135         print predict_outputs
136         #如果测试样本有结果,则输出真实结果以及预测总误差
137         if test_outputs is not None:
138             diff = test_outputs-predict_outputs
139             self.test_error = 0.5*np.sum(np.sum(np.multiply(diff,diff),axis=1),axis=0)[0,0]
140             print "actural values:"
141             print test_outputs
142             print "test error:"
143             print self.test_error
144         '''   
145 
146 
147     #预测一个样本
148     def predict(self,test_input):
149         #输入层的输出,即为其输入,i_nx1矩阵,因为有个偏置项,所有两个矩阵行数不一样,需要进行这样的赋值操作
150         self.i_o[0:self.i_n-1:,0:1:] = np.transpose(test_input[0:1:,::])
151         #计算隐含层每个节点的输出h_o
152         self.h_o = self.h_activation.f(np.transpose(self.w_i_h)*self.i_o)
153 
154         #计算输出层每个节点的输出o_o
155         self.o_o = self.o_activation.f(np.transpose(self.w_h_o)*self.h_o)
156 
157         print "predict: ",self.o_o
158 
159     #批量更新
160     def batch(self):
161         #一次batch使用的样本的编号集
162         inputs_indexs = [i for i in range(self.batch_size)]
163         #下次batch的需要使用的第一个样本的编号
164         last_index = (inputs_indexs[-1]+1)%self.train_sample_n
165         #批量更新,直到误差小于阈值或者达到最大迭代次数
166         while True:
167             #print "inputs_indexs:",inputs_indexs
168             self.one_batch(inputs_indexs)
169             #print "error: ",self.train_error
170             #剩余的迭代次数减1
171             self.iteration_num -= 1
172             #判断误差是否不再改变或者达到最大迭代次数
173             if self.terminate():
174                 break
175             else:#否则继续迭代
176                 #得到下次batch所需要使用的样本集所对应的编号集
177                 '''
178                 举例:训练样本集所对应的编号集是[0,1,2,3,4,5],样本个数为6,即train_sample_n=6
179                 如果batch_size=4,即每一次batch使用四个样本,
180                 那么第一次使用的batch样本集所对应的编号集inputs_indexs=[0,1,2,3]
181                 last_index = 4
182                 第二次使用的batch样本集所对应的编号集inputs_indexs=[4,5,0,1]
183                 即以后每次batch的inputs_indexs为:
184                 for i in range(self.batch_size):
185                     inputs_indexs.append((i+last_index)%self.train_sample_n)
186                 '''
187                 inputs_indexs = []
188                 for i in range(self.batch_size):
189                     inputs_indexs.append((i+last_index)%self.train_sample_n)
190                 last_index = (inputs_indexs[-1]+1)%self.train_sample_n
191 
192     #一次batch        
193     def one_batch(self,inputs_indexs):
194         #对每一个样本,首先使用前向传递,然后使用误差反向传播
195         for i in inputs_indexs:
196             #前向传递
197             self.fp(i)
198             #break
199             #反向传播
200             self.bp(i)
201         #更新权值
202         self.update()
203 
204 
205 
206     #第i个样本前向传递
207     def fp(self,i):
208         #输入层的输出,即为其输入,第i个样本, i_nx1矩阵
209         self.i_o[0:self.i_n-1:,0:1:] = np.transpose(self.train_inputs[i:i+1:,::])
210 
211         #计算隐含层每个节点的输入h_i,以及隐含层的输出h_o
212         self.h_i = np.transpose(self.w_i_h)*np.matrix(self.i_o)
213         self.h_o = self.h_activation.f(self.h_i)   
214 
215         #计算输出层每个节点的输入o_i,以及隐含层的输出o_o
216         self.o_i = np.transpose(self.w_h_o)*self.h_o  
217         self.o_o = self.o_activation.f(self.o_i)
218 
219 
220         #计算平方误差和
221         actural = np.transpose(self.train_outputs[i:i+1:,::])
222         tmp = self.o_o-actural
223         self.train_error = self.train_error + (np.transpose(tmp)*tmp)[0,0]
224 
225     #第i个样本误差反向传播
226     def bp(self,i):
227 
228         #对输出层每一个节点,计算Delta_{ij}^{T-1}=(y_{ij}-hat{y}_{ij}) cdot f'^{T}(v)|_{v=I_{ij}^{T}}
229         self.o_delta = np.multiply((self.o_o-np.transpose(self.train_outputs[i:i+1:,::])),
230                                    self.o_activation.df(self.o_i))
231         #print "self.o_delta:",self.o_delta
232         #使用公式frac{1}{p}sum_{i=1}^{p}Delta_{ij}^{T-1} cdot o^{T-1}_{ik}计算Delta {w_{kj}^{T-1}}
233         #前面的系数frac{1}{p}还没乘
234         self.w_h_o_delta = self.w_h_o_delta + self.h_o*np.transpose(self.o_delta)
235         #print "self.w_h_o_delta:",self.w_h_o_delta
236 
237 
238         #对隐含层每一个节点,计算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}}
239         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))
240         #print "self.h_delta:",self.h_delta
241         #使用公式frac{1}{p}sum_{i=1}^{p}Delta_{ij}^{T-2}cdot o^{T-2}_{ik}计算Delta {w_{kj}^{T-2}}
242         #前面的系数frac{1}{p}还没乘         
243         self.w_i_h_delta = self.w_i_h_delta + self.i_o*np.transpose(self.h_delta)
244         #print "self.w_i_h_delta:",self.w_i_h_delta
245 
246     #更新权值W
247     def update(self):
248         #按照公式更新输入层与隐含层之间的w: w^{T-2}_{kj}:=w^{T-2}_{kj}-alphafrac{1}{p}sum_{i=1}^{p}Delta_{ij}^{T-2}cdot o^{T-2}_{ik}
249         self.w_i_h = self.w_i_h - self.alpha/self.batch_size*self.w_i_h_delta
250         #按照公式更新隐含层与输出层之间的w: w^{T-1}_{kj}:=w^{T-1}_{kj}-alphafrac{1}{p}sum_{i=1}^{p}Delta_{ij}^{T-1} cdot o^{T-1}_{ik}
251         self.w_h_o = self.w_h_o - self.alpha/self.batch_size*self.w_h_o_delta
252         #delta清零
253         self.w_i_h_delta = Utils().matrix_fill_zeros(self.w_i_h_delta)
254         self.w_h_o_delta = Utils().matrix_fill_zeros(self.w_h_o_delta)
255 
256 
257     #判断迭代是否终止
258     def terminate(self):
259         if(0.5*self.train_error/self.batch_size<self.error_threshold
260             or self.iteration_num<=0):
261             return True
262         else:
263             print "error: ",self.train_error
264             self.train_error = 0.0
265             return False
266 
267 
268 if __name__=="__main__":
269     '''
270     inputs = np.matrix([[0,0],[0,1],[1,0],[1,1]])     
271     outputs = np.matrix([[0],[1],[1],[0]])
272     bpnn = BPNN(2, 5, 1)
273 
274     bpnn.train(Tanh(), Tanh(), inputs, 
275               outputs, 0.1, 0.001, 
276               10000, 100)
277     bpnn.test(inputs)
278     '''
279     #读取数据
280     r_fp = open("data","r")
281     #输入层节点数
282     input_level_node_num = 0
283     #隐藏层层节点数
284     hidden_level_node_num = 0    
285     #输出层节点数
286     output_level_node_num = 0
287     #输入数据
288     inputs = []
289     #数据的真实值
290     outputs = []
291     i = 0
292     for line in r_fp:
293         strs = line.strip().split(",")
294         #第一行是每层的节点数
295         if i==0:
296             input_level_node_num = int(strs[0])
297             hidden_level_node_num = int(strs[1])
298             output_level_node_num = int(strs[2])
299         else:
300             #数据,最后一列是真实值
301             #特征值向量
302             i_v = []
303             #真实值向量
304             o_v = []
305             for i in range(len(strs)-1):
306                 i_v.append(float(strs[i]))
307             o_v.append(float(strs[-1]))
308             inputs.append(i_v)
309             outputs.append(o_v)
310         i+=1
311     inputs = np.matrix(inputs)
312     outputs = np.matrix(outputs)
313     #每个特征以及结果的的最大值最小值归一化
314     max_inputs = np.max(inputs,axis=0)
315     min_inputs = np.min(inputs,axis=0)
316     normalize_inputs = (inputs-min_inputs)/(max_inputs-min_inputs)
317     max_outputs = np.max(outputs,axis=0)
318     min_outputs = np.min(outputs,axis=0)
319     normalize_outputs = (outputs-min_outputs)/(max_outputs-min_outputs)
320     #获取总共样本的个数
321     smaple_n = np.shape(normalize_inputs)[0]
322     #将数据按照2:1拆分成训练集与测试集
323     train_sample_n = smaple_n*2.0/3
324     train_inputs = normalize_inputs[0:train_sample_n:1,::]
325     train_outputs = normalize_outputs[0:train_sample_n:1,::]
326     test_inputs = normalize_inputs[train_sample_n:smaple_n:1,::]
327     test_outputs = normalize_outputs[train_sample_n:smaple_n:1,::]
328 
329     #构建网络
330     bpnn = BPNN(input_level_node_num, hidden_level_node_num, output_level_node_num)
331     #训练    
332     bpnn.train(Sigmoid(), Sigmoid(), train_inputs, 
333                   train_outputs, 0.2, 0.01, 
334                   1000, 100)    
335     #测试,其实最后预测值需要进行反归一化,这里没有做此步骤
336     bpnn.test(test_inputs,test_outputs)
原文地址:https://www.cnblogs.com/smuxiaolei/p/7570985.html