机器学习中,神经网络算法可以说是当下使用的最广泛的算法。神经网络的结构模仿自生物神经网络,生物神经网络中的每个神经元与其他神经元相连,当它“兴奋”时,想下一级相连的神经元发送化学物质,改变这些神经元的电位;如果某神经元的电位超过一个阈值,则被激活,否则不被激活。误差逆传播算法(error back propagation)是神经网络中最有代表性的算法,也是使用最多的算法之一。

误差逆传播算法理论推导

  误差逆传播算法(error back propagation)简称BP网络算法。而一般在说BP网络算法时,默认指用BP算法训练的多层前馈神经网络。

  下面是一个简单的BP神经网络示意图。其拥有一个输入层,一个隐含层,一个输出层。推导中采用这种简单的三层的神经网络。

  定义相关的一些变量如下:

  1. 假设有 d 个输入神经元,有 l 个输出神经元,q 个隐含层神经元;
  2. 设输出层第 j 个神经元的阈值为 θj
  3. 设隐含层第 h 个神经元的阈值为 γh
  4. 输入层第 i 个神经元与隐含层第 h 个神经元之间的连接权为 Vih 
  5. 隐含层第 h 个神经元与输出层第 j 个神经元之间的连接权为 Whj 
  6. 记隐含层第 h 个神经元接收到来自于输入层的输入为 αh:

     

  7. 记输出层第 j 个神经元接收到来自于隐含层的输入为 βj

             ,其中 bh 为隐含层第 h 个神经元的输出

  理论推导:

  在神经网络中,神经元接收到来自来自其他神经元的输入信号,这些信号乘以权重累加到神经元接收的总输入值上,随后与当前神经元的阈值进行比较,然后通过激活函数处理,产生神经元的输出。

  激活函数:

  理想的激活函数是阶跃函数,“0”对应神经元抑制,“1”对应神经元兴奋。然而阶跃函数的缺点是不连续,不可导,且不光滑,所以常用sigmoid函数作为激活函数代替阶跃函数。如下图分别是阶跃函数和sigmoid函数。

  阶跃函数

  sigmoid函数:

  对于一个训练例(xk, yk),假设神经网络的输出为 Yk ,则输出可表示为:

    

f(***)表示激活函数,默认全部的激活函数都为sigmoid函数。

  则可以计算网络上,(xk, yk)的均方差误差为:

    

  乘以1/2是为了求导时能正好抵消掉常数系数。

  现在,从隐含层的第h个神经元看,输入层总共有 d 个权重传递参数传给他,它又总共有 l 个权重传递参数传给输出层, 自身还有 1 个阈值。所以在我们这个神经网络中,一个隐含层神经元有(d+l+1)个参数待确定。输出层每个神经元还有一个阈值,所以总共有 l 个阈值。最后,总共有(d+l+1)*q+l 个待定参数。

首先,随机给出这些待定的参数,后面通过BP算法的迭代,这些参数的值会逐渐收敛于合适的值,那时,神经网络也就训练完成了。

  任意权重参数的更新公式为:

    

  下面以隐含层到输出层的权重参数 whj 为例说明:

  我们可以按照前面给出的公式求出均方差误差 Ek ,期望其为0,或者为最小值。而BP算法基于梯度下降法(gradient descent)来求解最优解,以目标的负梯度方向对参数进行调整,通过多次迭代,新的权重参数会逐渐趋近于最优解。对于误差 Ek ,给定学习率(learning rate)即步长 η ,有:

    

  再看一下参数的传递方向,首先 whj 影响到了输出层神经元的输入值 β,然后影响到输出值 Yj,然后再影响到误差 Ek ,所以可以列出如下关系式:

    

  根据输出层神经元的输入值 β的定义:

    

  得到:

    

  对于激活函数(sigmoid函数):

    

  很容易通过求导证得下面的性质:

    

  使用这个性质进行如下推导:

  令:

    

  又由于:

    

  所以:

     

  由前面的定义有:

    

  所以:

    

  把这个结果结合前面的几个式子代入:

    ,  ,  

  得到:

    

  所以:

    

  OK,上面这个式子就是梯度了。通过不停地更新即梯度下降法就可实现权重更新了。

    

  推导到这里就结束了,再来解释一下式子中各个元素的意义。

    

  η 为学习率,即梯度下降的补偿;为神经网络输出层第 j 个神经元的输出值;为给出的训练例(xk, yk)的标志(label),即训练集给出的正确输出;为隐含层第 h 个神经元的输出。

  

  类似可得:

    

  其中,

    

  这部分的解法与前面的推导方法类似,不做赘述。

  接下来是代码部分:

  这段代码网上也有不少地方可以看到,后面会简单介绍一下程序。

  完整程序:文件名“NN_Test.py”

# _*_ coding: utf-8 _*_import numpy as npdef tanh(x):return np.tanh(x)def tanh_derivative(x):return 1 -  np.tanh(x) * np.tanh(x)# sigmod函数
def logistic(x):return 1 / (1 + np.exp(-x))# sigmod函数的导数
def logistic_derivative(x):return logistic(x) * (1 - logistic(x))class NeuralNetwork:def __init__ (self, layers, activation = 'tanh'):if activation == 'logistic':self.activation = logisticself.activation_deriv = logistic_derivativeelif activation == 'tanh':self.activation = tanhself.activation_deriv = tanh_derivative# 随机产生权重值self.weights = []for i in range(1, len(layers) - 1):     # 不算输入层,循环self.weights.append((2 * np.random.random( (layers[i-1] + 1, layers[i] + 1)) - 1) * 0.25 )  self.weights.append((2 * np.random.random( (layers[i] + 1, layers[i+1])) - 1) * 0.25 )#print self.weightsdef fit(self, x, y, learning_rate=0.2, epochs=10000):x = np.atleast_2d(x) temp = np.ones([x.shape[0], x.shape[1]+1])temp[:, 0:-1] = xx = tempy = np.array(y)for k in range(epochs): # 循环epochs次i = np.random.randint(x.shape[0])   # 随机产生一个数,对应行号,即数据集编号  a = [x[i]]  # 抽出这行的数据集# 迭代将输出数据更新在a的最后一行for l in range(len(self.weights)):a.append(self.activation(np.dot(a[l], self.weights[l])))# 减去最后更新的数据,得到误差error = y[i] - a[-1]deltas = [error * self.activation_deriv(a[-1])]# 求梯度for l in range(len(a) - 2, 0, -1):deltas.append(deltas[-1].dot(self.weights[l].T) * self.activation_deriv(a[l]) )#反向排序
            deltas.reverse()   # 梯度下降法更新权值for i in range(len(self.weights)):layer = np.atleast_2d(a[i])delta = np.atleast_2d(deltas[i])self.weights[i] += learning_rate * layer.T.dot(delta)def predict(self, x):x = np.array(x)temp = np.ones(x.shape[0] + 1)temp[0:-1] = x   a = tempfor l in range(0, len(self.weights)):a = self.activation(np.dot(a, self.weights[l]))return a     

简要说明:

def tanh(x):return np.tanh(x)def tanh_derivative(x):return 1 -  np.tanh(x) * np.tanh(x)# sigmod函数
def logistic(x):return 1 / (1 + np.exp(-x))# sigmod函数的导数
def logistic_derivative(x):return logistic(x) * (1 - logistic(x))

分别表示两种激活函数,tanh函数和sigmoid函数以及其的导数,有关激活函数前文有提及。

        if activation == 'logistic':self.activation = logisticself.activation_deriv = logistic_derivativeelif activation == 'tanh':self.activation = tanhself.activation_deriv = tanh_derivative

“activation”参数决定了激活函数的种类,是tanh函数还是sigmoid函数。

     self.weights = []for i in range(1, len(layers) - 1):     # 不算输入层,循环self.weights.append((2 * np.random.random( (layers[i-1] + 1, layers[i] + 1)) - 1) * 0.25 )  self.weights.append((2 * np.random.random( (layers[i] + 1, layers[i+1])) - 1) * 0.25 )#print self.weights    

以隐含层前后层计算产生权重参数,参数初始时随机,取值范围是[-0.25, 0.25]

        x = np.atleast_2d(x) temp = np.ones([x.shape[0], x.shape[1]+1])temp[:, 0:-1] = xx = tempy = np.array(y)

创建并初始化要使用的变量。

for k in range(epochs): # 循环epochs次i = np.random.randint(x.shape[0])   # 随机产生一个数,对应行号,即数据集编号  a = [x[i]]  # 抽出这行的数据集# 迭代将输出数据更新在a的最后一行for l in range(len(self.weights)):a.append(self.activation(np.dot(a[l], self.weights[l])))# 减去最后更新的数据,得到误差error = y[i] - a[-1]deltas = [error * self.activation_deriv(a[-1])]# 求梯度for l in range(len(a) - 2, 0, -1):deltas.append(deltas[-1].dot(self.weights[l].T) * self.activation_deriv(a[l]) )#反向排序
            deltas.reverse()   # 梯度下降法更新权值for i in range(len(self.weights)):layer = np.atleast_2d(a[i])delta = np.atleast_2d(deltas[i])self.weights[i] += learning_rate * layer.T.dot(delta)

进行BP神经网络的训练的核心部分,在代码中有相应注释。

    def predict(self, x):x = np.array(x)temp = np.ones(x.shape[0] + 1)temp[0:-1] = x   a = tempfor l in range(0, len(self.weights)):a = self.activation(np.dot(a, self.weights[l]))return a     

这段是预测函数,其实就是将测试集的数据输入,然后正向走一遍训练好的网络最后再返回预测结果。

测试验证函数:

# _*_ coding: utf-8 _*_from NN_Test import NeuralNetwork
import numpy as npnn = NeuralNetwork([2, 2, 1], 'tanh')
x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([0, 1, 1, 0])
nn.fit(x, y)
for i in [[0, 0], [0, 1], [1, 0], [1, 1]]:print(i, nn.predict(i))

程序中测试的是异或关系,下面是运行结果:

([0, 0], array([-0.01628435]))
([0, 1], array([ 0.99808061]))
([1, 0], array([ 0.99808725]))
([1, 1], array([-0.03867579]))

显然与标准异或关系近似。

  

机器学习入门学习笔记:(1)BP神经网络原理推导及程序实现相关推荐

  1. 机器学习入门学习笔记:(2.2)线性回归python程序实现

      上一篇博客中,推导了线性回归的公式,这次试着编程来实现它.(机器学习入门学习笔记:(2.1)线性回归理论推导 )   我们求解线性回归的思路有两个:一个是直接套用上一篇博客最后推导出来的公式:另一 ...

  2. 机器学习入门学习笔记:(2.3)对数几率回归推导

    理论推导   在以前的博客(机器学习入门学习笔记:(2.1)线性回归理论推导 )中推导了单元线性回归和多元线性回归的模型.   将线性回归模型简写为:y=ωTx+by = \omega^Tx+b:   ...

  3. 机器学习入门学习笔记:(3.2)ID3决策树程序实现

    前言 之前的博客中介绍了决策树算法的原理并进行了数学推导(机器学习入门学习笔记:(3.1)决策树算法).决策树的原理相对简单,决策树算法有:ID3,C4.5,CART等算法.接下来将对ID3决策树算法 ...

  4. 机器学习入门学习笔记:(4.2)SVM的核函数和软间隔

    前言 之前讲了有关基本的SVM的数学模型(机器学习入门学习笔记:(4.1)SVM算法).这次主要介绍介绍svm的核函数.软间隔等概念,并进行详细的数学推导.这里仅将自己的笔记记录下来,以便以后复习查看 ...

  5. 深度学习(神经网络) —— BP神经网络原理推导及python实现

    深度学习(神经网络) -- BP神经网络原理推导及python实现 摘要 (一)BP神经网络简介 1.神经网络权值调整的一般形式为: 2.BP神经网络中关于学习信号的求取方法: (二)BP神经网络原理 ...

  6. Kaggle教程 机器学习入门学习笔记

    机器学习入门学习笔记 [跳转]<Kaggle教程 机器学习入门>系列课程目录 >> 决策树 简介:是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零 ...

  7. AI从入门到放弃:BP神经网络算法推导及代码实现笔记

    作者 | @Aloys (腾讯员工,后台工程师) 本文授权转自腾讯的知乎专栏 ▌一. 前言: 作为AI入门小白,参考了一些文章,想记点笔记加深印象,发出来是给有需求的童鞋学习共勉,大神轻拍! [毒鸡汤 ...

  8. 机器视觉学习笔记:BP神经网络详解

    https://www.toutiao.com/a6717160299482317324/ BP神经网络的代表者是D.Rumelhart和J.McCelland,"反向传播(backprop ...

  9. 机器学习入门学习笔记:(4.1)SVM算法

    前言 支持向量机(Support Vector Machine,简称SVM)可以说是最经典的机器学习算法之一了.这几天再看SVM,参考了一些书籍和博客,这里把自己的笔记记录下来,以便以后复习查看. 间 ...

最新文章

  1. 想让论文能发表,应该星期几投稿?丨SCI研究
  2. (转)彻底学通string.Format以及IFormattable,IFormatProvider,ICustomFormatter
  3. Hadoop HDFS (3) JAVA訪问HDFS之二 文件分布式读写策略
  4. 大数据-HDFS文件系统是什么
  5. dp - 求连续区间异或的最大值
  6. nullnullicon 小图标
  7. MyBatis基础:MyBatis数据基本操作(2)
  8. 教师节,老师最大的愿望是...
  9. 创建分布式爬虫的步骤
  10. Unity3D 《坦克大战》案例源码过程
  11. 柳夜熙又更新了,虚拟人的底层技术是什么?
  12. 新人小白的第一次天池比赛感受
  13. tp无线路由器设置打印服务器,TP-Link TL-WDR4320 无线路由器打印服务器设置指南
  14. IDEA安装流程(dear dad级教程)
  15. Python正则表达式中的r
  16. C语言socket重连和心跳,c# socket 心跳 重连
  17. CSS学习笔记(内边距~文字在盒子里的垂直居中)
  18. psapi.lib,psapi.h,psapi.dll下载
  19. OpenGLES---设置获取Shader程序属性
  20. mysql找不到my.ini的解决方法

热门文章

  1. php excel cpu高,phpexcel读文件的时候cpu99%
  2. Echarts组件 tooltip提示formatter函数
  3. 彩色图批量转换成灰度图、批量格式转换、批量重命名
  4. 【C++】18.char[] 与 string 的区别 与 互相转化、c_str() 函数用法
  5. Python-OpenCV 处理视频(四): 运动检测
  6. Ubuntu命令行下安装、卸载、管理软件包的方法
  7. MATLAB R2014a 中文版下载安装图文教程
  8. 常用Apache Commons工具类备忘
  9. 【java开发系列】—— spring简单入门示例
  10. 深度学习目标检测系列:RCNN系列算法图解