BP神经网络
一、BP神经网络模型及其前向传播
学了感知机以及逻辑斯蒂回归模型再来看BP神经网络,可以感觉到一脉相承。感知机加上sigmoid非线性激活就是逻辑斯蒂回归,逻辑斯蒂回归在累加几个“隐层”(输入输出之间再加隐藏层)就是BP神经网络的模型。
隐层的加入增强了模型的表达能力,隐层的层数添加也可以更多,模型复杂度增强的同时也增强了模型的非线性拟合能力(表达能力);输出层神经元可以变为多个(不只逻辑斯蒂回归的两个),这样便可以应用于多分类和回归任务;模型非线性激活函数也可以不仅仅是sigmoid,也可以是tanh、relu和softmax等等。BP神经网络有的书也叫做有些叫做多隐层感知机(Multi-Layer Perceptron,MLP)或者DNN(Deep Neural Networks ),其实都是一个东西。
模型结构可以在很多书籍中找到,示意图如下图:
从图中可以看出神经元是全连接的方式计算,这个形式就是后面深度学CNN的全连接层。下面以三层神经网络来描述其前向计算过程,假设激活函数为sigmoid:
输入层神经元的值就是样本特征向量的值;中间隐藏层每一个神经元的计算是输入层所有神经元的线性组合+非线性激活;同理用上面计算得到的隐藏层神经元得知,计算输出层,输出层每一个神经元的值由隐层所有神经元线性组合得到(根据实际应用的不同,输出层是可以没有激活函数的)。复杂的神经网络就是通过这些简单运算链式地计算到最后一层,还是easy…
设训练样本集为
样本特征的维数为m(输入神经元个数应与其维数一致),y为样本标签(输出神经元个数与其维数一致。
1、输入层神经元向量为
2、for l=2 to k
一直计算到最后一层(第k层)。
二、BP神经网络反向传播算法
反向传播算法其实就是让模型学习到合适的参数的算法,如同其他机器学习算法一样也需要一个合适的策略(模型、策略和算法三要素之一)。神经网络的损失函数定义就是其学习策略,此处定义损失函数为模型输出与样本标签的L2损失函数。优化的目标为最小化损失函数如下.
上式其实是batch的表示方式(基于样本集的最小二乘表示),为了后续符号统一现在将损失函数表示为
其中aL 为输出层神经元向量,y为样本标签向量,两个向量维度一致。和以前推导逻辑斯蒂回归模型和线性回归模型一样,我们采用机器学习常用的梯度下降算法计算梯度及更新网络参数。方向求导其实采用的就是链式求导法则,从输出层依次递推计算到前面。
输出层第L层递推式如下
则带入到损失函数得到输出层损失
现在求w和b的偏导数(是不是和线性回归差不多?步骤都是一样的,只是函数变得复杂了,需要链式求导)
'
其中' 的值根据具体选择的激活函数来求得。此处针对输出层某一个神经元而言的哦,所以
是一个值。如果是针对所有输出层的表达式则需要写成
此处⊙为Hadamard积,维度相同的两个向量的Hadamard积仅仅是其对应元素相乘,而不是内积。
从上面梯度计算式中不难发现w和b的偏导有相同的部分
因此需要计算的未知部分主要是这个,后面具体都是 都是已知的,令
求解他才是关键,称之为输出层误差(caffe中表示为diff)求出来了,前面层的梯度则可以根据输出层误差递推地求出(链式法则),
求出所有层误差,求解w和b的偏导数就ok了,又
则w和b的偏导数
具体怎么求 呢?前面的递推式已经很明显,如果计算出后一层的梯度
,则
问题转化为 了,易知
则
带入则
链式求导大法好用!总结就是只要求得某一层的δl ,求得w和b的偏导就简单。注意:这种不是针对某一个神经元,而是针对某一层所有神经元表达式,w是矩阵,矩阵每一行表示一个其中一个连接的所有权重具体含义可以参见更为详细的博客:
https://blog.csdn.net/u014303046/article/details/78200010
BP神经网络共L层。由于梯度下降法有批量(Batch),小批量(mini-Batch),随机三个变种,为了简化描述,这里我们以最基本的批量梯度下降法为例来描述反向传播算法。实际上在业界使用最多的是mini-Batch的梯度下降法。不过区别仅仅在于迭代时训练样本的选择而已。
BP神经网络反向传播算法:
1、输入:1)输入训练样本集
2)模型:L层神经网络(输入层、若干隐藏层和输出层)
3)学习率 、最大迭代次数MAX
2、输出:训练好的神经网络,即训练好的参数及模型
3、算法流程:
1)随机初始化各隐藏层与输出层的线性关系系数矩阵W和偏倚向量b的值。
2)For i to MAX
for j to n
a) 输入层神经元向量为a1=xi
b) for l=2 to L
c) 由输出层及损失函数定义计算δL
'
d) for l= L-1 to 2, 进行反向传播算法计算
e) 根据计算得到的各层误差更新参数w和b
for l = 2 to L
3) 输出训练好的BP神经网络模型,预测的话按照同样的预处理输入样本特征向量(特征向量与输入神经网络一致)。
三、Python实现
# -*- coding: utf-8 -*-
import numpy as np
import os
def sigmoid(x):
return 1.0/(1.0+np.exp(-x))
def sigmoid_d(x):
return x*(1-x)
def loadData(path):
dataMat=[] #特征
labelMat=[] #标签
fr = open(path) #打开txt文件
for line in fr.readlines():
lineArr = line.strip().split()
dataMat.append([float(lineArr[0]), float(lineArr[1])]) # 前面的1,表示方程的常量。比如两个特征X1,X2,共需要三个参数,W1+W2*X1+W3*X2
labelMat.append(int(lineArr[2]))
return np.array(dataMat), np.array(labelMat)
#3层BP神经网络demo
class BP(object):
def __init__(self,layers):
self.w1=np.random.random((layers[1],layers[0]))*2-1 #随机初始化为-1到1之间的数
self.b1=np.random.random((layers[1],1))*2-1 #随机初始化为-1到1之间的数
self.w2=np.random.random((layers[2],layers[1]))*2-1
self.b2=np.random.random((layers[2],1))*2-1
def train(self, X, Y, lr=0.1, epochs=10000):
for n in range(epochs + 1):
i=np.random.randint(X.shape[0])
x=X[i]
x=np.array(x)
x=np.reshape(x,(2,1))
#1、前向计算
L1=sigmoid(np.dot(self.w1,x)+self.b1)
L2=sigmoid(np.dot(self.w2,L1)+self.b2)
#2、反向误差反传 delta
yi=Y[i]
yi=np.reshape(yi,(1,1))
delta_L2=(L2-yi)*sigmoid_d(L2)
delta_L1=np.dot(self.w2.T,delta_L2,)*sigmoid_d(L1)
#3、反向传播
self.w1=self.w1-lr*delta_L1.dot(x.T)
self.b1=self.b1-lr*delta_L1
self.w2=self.w2-lr*delta_L2.dot(L1.T)
self.b2=self.b2-lr*delta_L2
if n%5==0:
print "loss %.2f \n"%(L2-Y[i])
prediction=[]
for j in range(X.shape[0]):
prediction.append(self.predict(X[j]))
accuracy = np.mean(np.equal(prediction, Y)) # 求平均值
print('epoch:',n, 'accuracy:', accuracy)
def predict(self,x):
x = np.array(x)
x = np.reshape(x,(2, 1))
L1 = sigmoid(np.dot(self.w1, x) + self.b1)
L2 = sigmoid(np.dot(self.w2, L1) + self.b2)
if L2>0.5:
return 1
else:
return 0
X,Y=loadData("E:/Machine learning/python_Learn/testSet.txt")
BPNet=BP([2,5,1])
BPNet.train(X,Y,0.01,60000)