Python语言编写BP神经网络
Python语言编写BP神经网络
人工神经网络是一种经典的机器学习模型,随着深度学习的发展神经网络模型日益完善.
联想大家熟悉的回归问题, 神经网络模型实际上是根据训练样本创造出一个多维输入多维输出的函数, 并使用该函数进行预测, 网络的训练过程即为调节该函数参数提高预测精度的过程.神经网络要解决的问题与最小二乘法回归解决的问题并无根本性区别.
回归和分类是常用神经网络处理的两类问题, 如果你已经了解了神经网络的工作原理可以在http://playground.tensorflow.org/上体验一个浅层神经网络的工作过程.
感知机(Perceptron)是一个简单的线性二分类器, 它保存着输入权重, 根据输入和内置的函数计算输出.人工神经网络中的单个神经元即是感知机.
在前馈神经网络的预测过程中, 数据流从输入到输出单向流动, 不存在循环和返回的通道.
目前大多数神经网络模型都属于前馈神经网络, 在下文中我们将详细讨论前馈过程.
多层感知机(Multi Layer Perceptron, MLP)是由多个感知机层全连接组成的前馈神经网络, 这种模型在非线性问题中表现出色.
所谓全连接是指层A上任一神经元与临近层B上的任意神经元之间都存在连接.
反向传播(Back Propagation,BP)是误差反向传播的简称,这是一种用来训练人工神经网络的常见算法, 通常与最优化方法(如梯度下降法)结合使用.
本文介绍的神经网络模型在结构上属于MLP, 因为采用BP算法进行训练, 人们也称其为BP神经网络.
BP神经网络原理
经典的BP神经网络通常由三层组成: 输入层, 隐含层与输出层.通常输入层神经元的个数与特征数相关,输出层的个数与类别数相同, 隐含层的层数与神经元数均可以自定义.

每个神经元代表对数据的一次处理:

每个隐含层和输出层神经元输出与输入的函数关系为:
其中
表示神经元i与神经元j之间连接的权重,
代表神经元j的输出, sigmod是一个特殊的函数用于将任意实数映射到(0,1)区间.
上文中的sigmod函数称为神经元的激励函数(activation function), 除了sigmod函数
外, 常用还有tanh和ReLU函数.
我们用一个完成训练的神经网络处理回归问题, 每个样本拥有n个输入.相应地,神经网络拥有n个输入神经元和1个输出神经元.
实际应用中我们通常在输入层额外增加一个偏置神经元, 提供一个可控的输入修正;或者为每个隐含层神经元设置一个偏置参数.
我们将n个特征依次送入输入神经元, 隐含层神经元获得输入层的输出并计算自己输出值, 输出层的神经元根据隐含层输出计算出回归值.
上述过程一般称为前馈(Feed-Forward)过程, 该过程中神经网络的输入输出与多维函数无异.
现在我们的问题是如何训练这个神经网络.
作为监督学习算法,BP神经网络的训练过程即是根据前馈得到的预测值和参考值比较, 根据误差调整连接权重
的过程.
训练过程称为反向传播过程(BackPropagation), 数据流正好与前馈过程相反.
首先我们随机初始化连接权重
, 对某一训练样本进行一次前馈过程得到各神经元的输出.
首先计算输出层的误差:
其中
代表神经元j的误差,表示神经元j的输出, 表示当前训练样本的参考输出,
是上文sigmod函数的一阶导数.
计算隐含层误差:
隐含层输出不存在参考值, 使用下一层误差的加权和代替
.
计算完误差后就可以更新
和
:
其中
是一个称为学习率的参数,一般在(0,0.1)区间上取值.
实际上为了加快学习的效率我们引入称为矫正矩阵的机制, 矫正矩阵记录上一次反向传播过程中的
值, 这样
更新公式变为:
是一个称为矫正率的参数.随后更新矫正矩阵:
每一个训练样本都会更新一次整个网络的参数.我们需要额外设置训练终止的条件.
最简单的训练终止条件为设置最大迭代次数, 如将数据集迭代1000次后终止训练.
单纯的设置最大迭代次数不能保证训练结果的精确度, 更好的办法是使用损失函数(loss function)作为终止训练的依据.
损失函数可以选用输出层各节点的方差:
为了避免神经网络进行无意义的迭代, 我们通常在训练数据集中抽出一部分用作校验.当预测误差高于阈值时提前终止训练.
Python实现BP神经网络
首先实现几个工具函数:
- def rand(a, b):
- return (b - a) * random.random() + a
- def make_matrix(m, n, fill=0.0): # 创造一个指定大小的矩阵
- mat = []
- for i in range(m):
- mat.append([fill] * n)
- return mat
定义sigmod函数和它的导数:
- def sigmoid(x):
- return 1.0 / (1.0 + math.exp(-x))
- def sigmod_derivate(x):
- return x * (1 - x)
定义BPNeuralNetwork类, 使用三个列表维护输入层,隐含层和输出层神经元, 列表中的元素代表对应神经元当前的输出值.使用两个二维列表以邻接矩阵的形式维护输入层与隐含层, 隐含层与输出层之间的连接权值, 通过同样的形式保存矫正矩阵.
定义setup方法初始化神经网络:
- def setup(self, ni, nh, no):
- self.input_n = ni + 1
- self.hidden_n = nh
- self.output_n = no
- # init cells
- self.input_cells = [1.0] * self.input_n
- self.hidden_cells = [1.0] * self.hidden_n
- self.output_cells = [1.0] * self.output_n
- # init weights
- self.input_weights = make_matrix(self.input_n, self.hidden_n)
- self.output_weights = make_matrix(self.hidden_n, self.output_n)
- # random activate
- for i in range(self.input_n):
- for h in range(self.hidden_n):
- self.input_weights[i][h] = rand(-0.2, 0.2)
- for h in range(self.hidden_n):
- for o in range(self.output_n):
- self.output_weights[h][o] = rand(-2.0, 2.0)
- # init correction matrix
- self.input_correction = make_matrix(self.input_n, self.hidden_n)
- self.output_correction = make_matrix(self.hidden_n, self.output_n)
定义predict方法进行一次前馈, 并返回输出:
- def predict(self, inputs):
- # activate input layer
- for i in range(self.input_n - 1):
- self.input_cells[i] = inputs[i]
- # activate hidden layer
- for j in range(self.hidden_n):
- total = 0.0
- for i in range(self.input_n):
- total += self.input_cells[i] * self.input_weights[i][j]
- self.hidden_cells[j] = sigmoid(total)
- # activate output layer
- for k in range(self.output_n):
- total = 0.0
- for j in range(self.hidden_n):
- total += self.hidden_cells[j] * self.output_weights[j][k]
- self.output_cells[k] = sigmoid(total)
- return self.output_cells[:]
定义back_propagate方法定义一次反向传播和更新权值的过程, 并返回最终预测误差:
- def back_propagate(self, case, label, learn, correct):
- # feed forward
- self.predict(case)
- # get output layer error
- output_deltas = [0.0] * self.output_n
- for o in range(self.output_n):
- error = label[o] - self.output_cells[o]
- output_deltas[o] = sigmod_derivate(self.output_cells[o]) * error
- # get hidden layer error
- hidden_deltas = [0.0] * self.hidden_n
- for h in range(self.hidden_n):
- error = 0.0
- for o in range(self.output_n):
- error += output_deltas[o] * self.output_weights[h][o]
- hidden_deltas[h] = sigmod_derivate(self.hidden_cells[h]) * error
- # update output weights
- for h in range(self.hidden_n):
- for o in range(self.output_n):
- change = output_deltas[o] * self.hidden_cells[h]
- self.output_weights[h][o] += learn * change + correct * self.output_correction[h][o]
- self.output_correction[h][o] = change
- # update input weights
- for i in range(self.input_n):
- for h in range(self.hidden_n):
- change = hidden_deltas[h] * self.input_cells[i]
- self.input_weights[i][h] += learn * change + correct * self.input_correction[i][h]
- self.input_correction[i][h] = change
- # get global error
- error = 0.0
- for o in range(len(label)):
- error += 0.5 * (label[o] - self.output_cells[o]) ** 2
- return error
定义train方法控制迭代, 该方法可以修改最大迭代次数, 学习率
, 矫正率
三个参数.
- def train(self, cases, labels, limit=10000, learn=0.05, correct=0.1):
- for i in range(limit):
- error = 0.0
- for i in range(len(cases)):
- label = labels[i]
- case = cases[i]
- error += self.back_propagate(case, label, learn, correct)
编写test方法,演示如何使用神经网络学习异或逻辑:
- def test(self):
- cases = [
- [0, 0],
- [0, 1],
- [1, 0],
- [1, 1],
- ]
- labels = [[0], [1], [1], [0]]
- self.setup(2, 5, 1)
- self.train(cases, labels, 10000, 0.05, 0.1)
- for case in cases:
- print(self.predict(case))
完整源代码参见bpnn.py
Python语言编写BP神经网络的更多相关文章
- 运用Python语言编写获取Linux基本系统信息(三):Python与数据库编程,把获取的信息存入数据库
运用Python语言编写获取Linux基本系统信息(三):Python与数据库编程 有关前两篇的链接: 运用Python语言编写获取Linux基本系统信息(一):获得Linux版本.内核.当前时间 运 ...
- 运用Python语言编写获取Linux基本系统信息(二):文件系统使用情况获取
本文跟着上一篇文章继续写,上一篇文章的链接 运用Python语言编写获取Linux基本系统信息(一):获得Linux版本.内核.当前时间 一.随便说说 获取文件系统使用情况的思路和上一篇获取主要系统是 ...
- 利用c++编写bp神经网络实现手写数字识别详解
利用c++编写bp神经网络实现手写数字识别 写在前面 从大一入学开始,本菜菜就一直想学习一下神经网络算法,但由于时间和资源所限,一直未展开比较透彻的学习.大二下人工智能课的修习,给了我一个学习的契机. ...
- 运用Python语言编写获取Linux基本系统信息(一):获得Linux版本、内核、当前时间
申请博客有一段时间了,然而到现在还一篇没有写过..... 主要因为没有想到需要写些什么,最近在学习Python语言,照着书上看了看最基础的东西,发现根本看不进去,而且光看的话今天看了觉得都理解懂了,过 ...
- python手写bp神经网络实现人脸性别识别1.0
写在前面:本实验用到的图片均来自google图片,侵删! 实验介绍 用python手写一个简单bp神经网络,实现人脸的性别识别.由于本人的机器配置比较差,所以无法使用网上很红的人脸大数据数据集(如lf ...
- Python实现——二层BP神经网络
2019/4/23更新 下文中的正确率极高是建立在仅有50组训练数据的基础上的,十分不可靠.建议使用提供的另一个生成训练集的generate_all函数,能产生所有可能结果,更加可靠. 2019/4/ ...
- 用python语言编写网络爬虫
本文主要用到python3自带的urllib模块编写轻量级的简单爬虫.至于怎么定位一个网页中具体元素的url可自行百度火狐浏览器的firebug插件或者谷歌浏览器的自带方法. 1.访问一个网址 re= ...
- Python语言编写脚本时,对日期控件的处理方式
对日期控件,日期控件的输入控一般是不能手动输入的:把readonly属性去掉就好 其实很简单,我们不去搞时间日期空间,我们把它当成一个普通的input框处理就好了! 但是,很多此类型input框都是禁 ...
- 使用python语言编写脚本控制freeswitch总结
1. 在Linux环境下已经安装了freeswitch,(没安装freeswitch,请安装说明文档) 2. 进入源代码目录 cd libs/esl 目录下 首先安装 yum install p ...
随机推荐
- 软工个人项目———WC.exe(Java实现)
一.github地址 https://github.com/hhw-15521301615/hello-world 二.PSP表格 PSP2.1 Personal Software Process S ...
- appium 操作界面
操作界面函数: 1.swipe():模拟滑动 2.tap():点击坐标 1.swipe()函数:用来模拟滑动操作 参数说明: 坐标就是x/y坐标 duration是滑动从起点到终点坐标所耗费的时间. ...
- MySQL Case--Strict mode与NOT NULL
事故回溯 某业务流程操作为: 1.循环扫描某张待处理请求表,查看是否有请求等待处理. 2.找到待处理请求后,申请相关资源进行处理,并将处理结果插入到处理结果表中. 3.将该请求从待处理请求表中移除. ...
- Ftp站点搭建的详细过程(包括指定用户登录)
最近接到要部署一个Ftp站点的一个任务,然后过程中有点小插曲踩了一些坑(指定用户登录,用户名和密码都是对的,输入了超级多遍,还是不行,登录不上,后面详细说明解决方案),特此记录一下.避免大家踩坑. 参 ...
- 关于小程序授权地理位置(wx.getLocation + 用户体验)
wx.getLocation 如果用户曾点击过一次 “确认授权” , 那么再次调用该接口时将不会出现弹出框(可以直接拿到经纬度) 关于用户体验: 在 onLoad 中判断: 如果用户之前“没有触发过“ ...
- GDI显示图像时设定窗口大小为图像大小
先前已经能基于GDI显示png图像,但是窗口大小和图像尺寸并不一致.注意到opencv中的imshow的窗口和图像尺寸一致,这里进行设置. 原理 CreateWindow阶段并不能确定窗口大小,但是在 ...
- IPC机制和生产者消费者模型
IPC机制:(解决进程间的数据隔离问题) 进程间通信:IPC(inter-Process Comminication) 创建共享的进程列队,Queue 是多进程的安全列队,可以使用Queue 实现多进 ...
- FreeBSD关机后自动重启的解决办法
我用的是华硕的笔记本电脑,不知道别的电脑有没有这个情况,按handbook关机指令为shutdown -p now,但是我执行这个指令后电脑却自动重启,用Linux关机指令shutdown -h no ...
- Hikari java数据库连接池实战
环境InterlliJ2016.3 MySQL5.7.12 pom依赖: <dependency> <groupId>com.zaxxer</groupId> & ...
- CSP-S 2019提高组训练 服务器需求
时间限制:C/C++ 3秒 空间限制:C/C++ 262144K 题目描述 小多计划在接下来的n天里租用一些服务器,所有的服务器都是相同的.接下来n天中,第i天需要\(a_i\)台服务器工作,每台服务 ...