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 ...
随机推荐
- 深入了解Cookie和Session
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...
- IDEA 阿里巴巴代码规范检查插件
1.问题概要 大家都想写出规范的代码,可规范的标准是什么勒,估计每个人心中的标准都不是完全一致的 在分工合作越来越精细化的时代,我们需要一个最大程度接近公认的规范,这里我们以阿里巴巴的代码规范作为参考 ...
- Pandas 数据筛选,去重结合group by
Pandas 数据筛选,去重结合group by 需求 今小伙伴有一个Excel表, 是部门里的小伙9月份打卡记录, 关键字段如下: 姓名, 工号, 日期, 打卡方式, 时间, 详细位置, IP地址. ...
- Load Balancing in gRPC
背景 基于每次调用的负载均衡 需要注意的是,gRPC的负载均衡发生在每次调用时,而不是每次连接时.换句话说,就算所有的请求来自于同一个客户,我们也希望可以将它们负载均衡到所有的服务器. 负载均衡的方法 ...
- Linux IO 概念(1)
基础概念 文件描述fd 文件描述符(file description),用于表述指向文件引用的抽象话题概念 文件描述符在形式上是一个非负整数,实际上它是一个索引值,指向内核为每一个进程所维护的该进程打 ...
- PAT甲级1005水题飘过
题目分析:用一个字符串输入之后遍历每一位求和后,不断%10获取最后一位存储下来,逆序用对应的英文单词输出(注意输入为0的情况) #include<iostream> #include< ...
- Linux跑脚本用sh和./有什么区别?
一个很有意思的例子: sh是一个shell.运行sh a.sh,表示我使用sh来解释这个脚本:如果我直接运行./a.sh,首先你会查找脚本第一行是否指定了解释器,如果没指定,那么就用当前系统默认的sh ...
- adb命令过滤w级别日志命令
adb logcat *:W 过滤某关键字日志 adb logcat *:W | find "woyihome" 过滤某关键字日志,生成txt文档 adb logcat *:W | ...
- lettcode 上的几道哈希表与链表组合的数据结构题
目录 LRU缓存 LFU缓存 全O(1)的数据结构 lettcode 上的几道哈希表与链表组合的数据结构题 下面这几道题都要求在O(1)时间内完成每种操作. LRU缓存 LRU是Least Recen ...
- 洛谷 P2312 解方程 题解
P2312 解方程 题目描述 已知多项式方程: \[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\] 求这个方程在 [1,m][1,m] 内的整数解(\(n\) 和 \(m\) 均为 ...