神经网络结构由输入层,隐藏层和输出层构成,神经网络中的每个结点都与上一层全部的结点都有链接,咱们称之为全链接,以下图html
在图中的神经网络中,原始的输入数据,经过第一层隐含层的计算得出的输出数据,会传到第二层隐含层。而第二层的输出,又会做为输出层的输入数据。python
由下图可知咱们能够计算出隐藏层的第一个神经元的值:算法
其中为激活函数markdown
由下图可知咱们能够计算出隐藏层的第二个神经元的值:网络
由下图可知咱们能够计算出隐藏层的第三个神经元的值:app
到此咱们己经算出全部从输入层到隐藏层的全部值。dom
由下图可知咱们能够计算出隐藏层到第一个输出神经元的值:函数
同理能够得出,
的值:oop
为了简化咱们之后的数据处理流程,如今咱们设第层的输入数据为向量
,权重为
,偏置变量为
。则咱们从上面的求解流程能够得出
层的数据为:学习
至此神经网络的前向传播过程己经讲完。
反向转播的思想就是,咱们经过前向传播后计算出网络的输出值,知道输出值后咱们就能够求出输出层的残差,再从输出层反向把残差传回各层的神经元中。
假设咱们有一个固定样本集 ,它包含
个样例。咱们能够用批量梯度降低法来求解神经网络。具体来说,对于单个样例
,其代价函数以下图(摘自网络):
咱们能够定义总体代价函数以下图(摘自网络):
以上关于定义中的第一项是一个均方差项。第二项是一个规则化项(也叫权重衰减项),其目的是减少权重的幅度,防止过分拟合。
有了整体代价函数后,咱们的目标能够转化成求代价函数的最小值。咱们使用梯度降低算法求代价函数的最小值,因此咱们得出如下公式:
咱们对整体代价函数求偏导:
经过上面两个式子能够看出,咱们把问题转化成求与
的值
因此对于第 层(输出层)的每一个输出单元
,咱们根据如下公式计算残差(下图摘自网络):
对 的各个层,第
层的第
个节点的残差计算方法以下(下图摘自网络):
计算咱们须要的偏导数,计算方法以下:
# -*- coding: utf-8 -*- ''' Created on @author: Belle ''' from numpy.random.mtrand import randint import numpy as np '''双曲函数''' def tanh(value): return (1 / (1 + np.math.e ** (-value))) '''双曲函数的导数''' def tanhDer(value): tanhValue = tanh(value) return tanhValue * (1 - tanhValue) ''' Bp神经网络model ''' class BpNeuralNetWorkModel: def __init__(self, trainningSet, label, layerOfNumber, studyRate): '''学习率''' self.studyRate = studyRate '''计算隐藏层神经元的数量''' self.hiddenNeuronNum = int(np.sqrt(trainningSet.shape[1] + label.shape[1]) + randint(1, 10)) '''层数据''' self.layers = [] '''建立输出层''' currentLayer = Layer() currentLayer.initW(trainningSet.shape[1], self.hiddenNeuronNum) self.layers.append(currentLayer) '''建立隐藏层''' for index in range(layerOfNumber - 1): currentLayer = Layer() self.layers.append(currentLayer) '''输出层后面不须要求权重值''' if index == layerOfNumber - 2: break nextLayNum = 0 '''初始化各个层的权重置''' if index == layerOfNumber - 3: '''隐藏层到输出层''' nextLayNum = label.shape[1] else: '''隐藏层到隐藏层''' nextLayNum = self.hiddenNeuronNum currentLayer.initW(self.hiddenNeuronNum, nextLayNum) '''输出层的分类值''' currentLayer = self.layers[len(self.layers) - 1] currentLayer.label = label '''神经网络前向传播''' def forward(self, trainningSet): '''计算输入层的输出值''' currentLayer = self.layers[0] currentLayer.alphas = trainningSet currentLayer.caculateOutPutValues() preLayer = currentLayer for index in range(1, len(self.layers)): currentLayer = self.layers[index] '''上一层的out put values就是这一层的zValues''' currentLayer.zValues = preLayer.outPutValues '''计算alphas''' currentLayer.caculateAlphas() '''最后一层不须要求输出值,只要求出alpha''' if index == len(self.layers) - 1: break '''输入层计算out puts''' currentLayer.caculateOutPutValues() '''指向上一层的layer''' preLayer = currentLayer '''神经网络后向传播''' def backPropogation(self): layerCount = len(self.layers) '''输出层的残差值''' currentLayer = self.layers[layerCount - 1] currentLayer.caculateOutPutLayerError() '''输出层到隐藏层''' preLayer = currentLayer layerCount = layerCount - 1 while layerCount >= 1: '''当前层''' currentLayer = self.layers[layerCount - 1] '''更新权重''' currentLayer.updateWeight(preLayer.errors, self.studyRate) if layerCount != 1: currentLayer.culateLayerError(preLayer.errors) layerCount = layerCount - 1 preLayer = currentLayer ''' 建立层 ''' class Layer: def __init__(self): self.b = 0 '''使用正态分布的随机值初始化w的值''' def initW(self, numOfAlpha, nextLayNumOfAlpha): self.w = np.mat(np.random.randn(nextLayNumOfAlpha, numOfAlpha)) '''计算当前层的alphas''' def caculateAlphas(self): '''alpha = f(z)''' self.alphas = np.mat([tanh(self.zValues[row1,0]) for row1 in range(len(self.zValues))]) '''求f'(z)的值(即f的导数值)''' self.zDerValues = np.mat([tanhDer(self.zValues[row1,0]) for row1 in range(len(self.zValues))]) '''计算out puts''' def caculateOutPutValues(self): '''计算当前层z = w * alpha的的下一层的输入值''' self.outPutValues = self.w * self.alphas.T + self.b '''计算输出层的残差''' def caculateOutPutLayerError(self): self.errors = np.multiply(-(self.label - self.alphas), self.zDerValues) print("out put layer alphas ..." + str(self.alphas)) '''计算其它层的残差''' def culateLayerError(self, preErrors): self.errors = np.mat([(self.w[:,column].T * preErrors.T * self.zDerValues[:,column])[0,0] for column in range(self.w.shape[1])]) '''更新权重''' def updateWeight(self, preErrors, studyRate): data = np.zeros((preErrors.shape[1], self.alphas.shape[1])) for index in range(preErrors.shape[1]): data[index,:] = self.alphas * (preErrors[:,index][0,0]) self.w = self.w - studyRate * data ''' 训练神经网络模型 @param train_set: 训练样本 @param labelOfNumbers: 训练总类别 @param layerOfNumber: 神经网络层数,包括输出层,隐藏层和输出层(默认只有一个输入层,隐藏层和输出层) ''' def train(train_set, label, layerOfNumber = 3, sampleTrainningTime = 5000, studyRate = 0.6): neuralNetWork = BpNeuralNetWorkModel(train_set, label, layerOfNumber, studyRate) '''训练数据''' for row in range(train_set.shape[0]): '''当个样本使用梯度降低的方法训练sampleTrainningTime次''' for time in range(sampleTrainningTime): '''前向传播 ''' neuralNetWork.forward(train_set[row,:]) '''反向传播''' neuralNetWork.backPropogation() 复制代码
测试代码
# -*- coding: utf-8 -*- ''' Created on 2018��5��27�� @author: Belle ''' import BpNeuralNetWork import numpy as np train_set = np.mat([[0.05, 0.1], [0.3, 0.2]]) labelOfNumbers = np.mat([0.1, 0.99, 0.3]) layerOfNumber = 4 bpNeuralNetWork = BpNeuralNetWork.train(train_set, labelOfNumbers, layerOfNumber) 复制代码
如下是测试代码的输出值