BP神经网络原理及Python实现代码


Posted in Python onDecember 18, 2018

本文主要讲如何不依赖TenserFlow等高级API实现一个简单的神经网络来做分类,所有的代码都在下面;在构造的数据(通过程序构造)上做了验证,经过1个小时的训练分类的准确率可以达到97%。

完整的结构化代码见于:链接地址

先来说说原理

网络构造

BP神经网络原理及Python实现代码

上面是一个简单的三层网络;输入层包含节点X1 , X2;隐层包含H1,H2;输出层包含O1。
输入节点的数量要等于输入数据的变量数目。
隐层节点的数量通过经验来确定。
如果只是做分类,输出层一般一个节点就够了。

从输入到输出的过程

1.输入节点的输出等于输入,X1节点输入x1时,输出还是x1.
2. 隐层和输出层的输入I为上层输出的加权求和再加偏置,输出为f(I) , f为激活函数,可以取sigmoid。H1的输出为 sigmoid(w1x1 + w2x2 + b)

误差反向传播的过程

Python实现

构造测试数据

# -*- coding: utf-8 -*-
import numpy as np
from random import random as rdn

'''
说明:我们构造1000条数据,每条数据有三个属性(用a1 , a2 , a3表示)
a1 离散型 取值 1 到 10 , 均匀分布
a2 离散型 取值 1 到 10 , 均匀分布
a3 连续型 取值 1 到 100 , 且符合正态分布 
各属性之间独立。

共2个分类(0 , 1),属性值与类别之间的关系如下,
0 : a1 in [1 , 3] and a2 in [4 , 10] and a3 <= 50
1 : a1 in [1 , 3] and a2 in [4 , 10] and a3 > 50
0 : a1 in [1 , 3] and a2 in [1 , 3] and a3 > 30
1 : a1 in [1 , 3] and a2 in [1 , 3] and a3 <= 30
0 : a1 in [4 , 10] and a2 in [4 , 10] and a3 <= 50
1 : a1 in [4 , 10] and a2 in [4 , 10] and a3 > 50
0 : a1 in [4 , 10] and a2 in [1 , 3] and a3 > 30
1 : a1 in [4 , 10] and a2 in [1 , 3] and a3 <= 30
'''


def genData() :
 #为a3生成符合正态分布的数据
 a3_data = np.random.randn(1000) * 30 + 50
 data = []
 for i in range(1000) :
 #生成a1
 a1 = int(rdn()*10) + 1
 if a1 > 10 :
  a1 = 10
 #生成a2
 a2 = int(rdn()*10) + 1
 if a2 > 10 :
  a2 = 10
 #取a3
 a3 = a3_data[i] 
 #计算这条数据对应的类别
 c_id = 0
 if a1 <= 3 and a2 >= 4 and a3 <= 50 :
  c_id = 0 
 elif a1 <= 3 and a2 >= 4 and a3 > 50 :
  c_id = 1 
 elif a1 <= 3 and a2 < 4 and a3 > 30 :
  c_id = 0
 elif a1 <= 3 and a2 < 4 and a3 <= 30 :
  c_id = 1
 elif a1 > 3 and a2 >= 4 and a3 <= 50 :
  c_id = 0 
 elif a1 > 3 and a2 >= 4 and a3 > 50 :
  c_id = 1 
 elif a1 > 3 and a2 < 4 and a3 > 30 :
  c_id = 0
 elif a1 > 3 and a2 < 4 and a3 <= 30 :
  c_id = 1
 else :
  print('error')
 #拼合成字串
 str_line = str(i) + ',' + str(a1) + ',' + str(a2) + ',' + str(a3) + ',' + str(c_id)
 data.append(str_line)
 return '\n'.join(data)

激活函数

# -*- coding: utf-8 -*-
"""
Created on Sun Dec 2 14:49:31 2018

@author: congpeiqing
"""
import numpy as np

#sigmoid函数的导数为 f(x)*(1-f(x))
def sigmoid(x) :
 return 1/(1 + np.exp(-x))

网络实现

# -*- coding: utf-8 -*-
"""
Created on Sun Dec 2 14:49:31 2018

@author: congpeiqing
"""

from activation_funcs import sigmoid
from random import random

class InputNode(object) :
 def __init__(self , idx) :
 self.idx = idx
 self.output = None
  
 def setInput(self , value) :
 self.output = value
 
 def getOutput(self) :
 return self.output
 
 def refreshParas(self , p1 , p2) :
 pass
 
 
class Neurode(object) :
 def __init__(self , layer_name , idx , input_nodes , activation_func = None , powers = None , bias = None) :
 self.idx = idx 
 self.layer_name = layer_name
 self.input_nodes = input_nodes 
 if activation_func is not None :
  self.activation_func = activation_func
 else :
  #默认取 sigmoid
  self.activation_func = sigmoid
 if powers is not None :
  self.powers = powers
 else :
  self.powers = [random() for i in range(len(self.input_nodes))]
 if bias is not None :
  self.bias = bias
 else :
  self.bias = random()
 self.output = None
  
 def getOutput(self) :
 self.output = self.activation_func(sum(map(lambda x : x[0].getOutput()*x[1] , zip(self.input_nodes, self.powers))) + self.bias)
 return self.output
  
 def refreshParas(self , err , learn_rate) :
 err_add = self.output * (1 - self.output) * err 
 for i in range(len(self.input_nodes)) :
  #调用子节点
  self.input_nodes[i].refreshParas(self.powers[i] * err_add , learn_rate)
  #调节参数
  power_delta = learn_rate * err_add * self.input_nodes[i].output 
  self.powers[i] += power_delta
  bias_delta = learn_rate * err_add
  self.bias += bias_delta
 
 
class SimpleBP(object) :
 def __init__(self , input_node_num , hidden_layer_node_num , trainning_data , test_data) :
 self.input_node_num = input_node_num
 self.input_nodes = [InputNode(i) for i in range(input_node_num)]
 self.hidden_layer_nodes = [Neurode('H' , i , self.input_nodes) for i in range(hidden_layer_node_num)]
 self.output_node = Neurode('O' , 0 , self.hidden_layer_nodes)
 self.trainning_data = trainning_data
 self.test_data = test_data
 
 
 #逐条训练
 def trainByItem(self) :
 cnt = 0
 while True :
  cnt += 1
  learn_rate = 1.0/cnt
  sum_diff = 0.0
  #对于每一条训练数据进行一次训练过程
  for item in self.trainning_data :
  for i in range(self.input_node_num) :
   self.input_nodes[i].setInput(item[i])
  item_output = item[-1]
  nn_output = self.output_node.getOutput()
  #print('nn_output:' , nn_output)
  diff = (item_output-nn_output)
  sum_diff += abs(diff)
  self.output_node.refreshParas(diff , learn_rate)
  #print('refreshedParas')
  #结束条件 
  print(round(sum_diff / len(self.trainning_data) , 4))
  if sum_diff / len(self.trainning_data) < 0.1 :
  break
 
 def getAccuracy(self) :
 cnt = 0
 for item in self.test_data :
  for i in range(self.input_node_num) :
  self.input_nodes[i].setInput(item[i])
  item_output = item[-1]
  nn_output = self.output_node.getOutput()
  if (nn_output > 0.5 and item_output > 0.5) or (nn_output < 0.5 and item_output < 0.5) :
  cnt += 1
 return cnt/(len(self.test_data) + 0.0)

主调流程

# -*- coding: utf-8 -*-
"""
Created on Sun Dec 2 14:49:31 2018

@author: congpeiqing
"""
import os
from SimpleBP import SimpleBP
from GenData import genData

if not os.path.exists('data'):
 os.makedirs('data') 

#构造训练和测试数据
data_file = open('data/trainning_data.dat' , 'w')
data_file.write(genData())
data_file.close()

data_file = open('data/test_data.dat' , 'w')
data_file.write(genData())
data_file.close()


#文件格式:rec_id,attr1_value,attr2_value,attr3_value,class_id
#读取和解析训练数据
trainning_data_file = open('data/trainning_data.dat')
trainning_data = []
for line in trainning_data_file :
 line = line.strip()
 fld_list = line.split(',')
 trainning_data.append(tuple([float(field) for field in fld_list[1:]]))
trainning_data_file.close()

#读取和解析测试数据
test_data_file = open('data/test_data.dat')
test_data = []
for line in test_data_file :
 line = line.strip()
 fld_list = line.split(',')
 test_data.append(tuple([float(field) for field in fld_list[1:]]))
test_data_file.close()


#构造一个二分类网络 输入节点3个,隐层节点10个,输出节点一个
simple_bp = SimpleBP(3 , 10 , trainning_data , test_data)
#训练网络
simple_bp.trainByItem()
#测试分类准确率
print('Accuracy : ' , simple_bp.getAccuracy())
#训练时长比较长,准确率可以达到97%

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python+MongoDB自增键值的简单实现
Nov 04 Python
django上传图片并生成缩略图方法示例
Dec 11 Python
Python实现自动上京东抢手机
Feb 06 Python
python组合无重复三位数的实例
Nov 13 Python
Python常用爬虫代码总结方便查询
Feb 25 Python
python抓取搜狗微信公众号文章
Apr 01 Python
在Django的View中使用asyncio的方法
Jul 12 Python
Python partial函数原理及用法解析
Dec 11 Python
Django使用Celery加redis执行异步任务的实例内容
Feb 20 Python
详解Python3中的 input() 函数
Mar 18 Python
Python列表嵌套常见坑点及解决方案
Sep 30 Python
python利用pytesseract 实现本地识别图片文字
Dec 14 Python
python 执行文件时额外参数获取的实例
Dec 18 #Python
python实现基于信息增益的决策树归纳
Dec 18 #Python
Django实现一对多表模型的跨表查询方法
Dec 18 #Python
Python实现字典排序、按照list中字典的某个key排序的方法示例
Dec 18 #Python
python实现求特征选择的信息增益
Dec 18 #Python
python实现连续图文识别
Dec 18 #Python
Django ManyToManyField 跨越中间表查询的方法
Dec 18 #Python
You might like
PHP字符串长度计算 - strlen()函数使用介绍
2013/10/15 PHP
php缩小png图片不损失透明色的解决方法
2013/12/25 PHP
CI框架在CLI下执行占用内存过大问题的解决方法
2014/06/17 PHP
PHP二维数组排序简单实现方法
2016/02/14 PHP
PHPStudy下如何为Apache安装SSL证书的方法步骤
2019/01/23 PHP
使用jquery实现div的tab切换实例代码
2013/05/27 Javascript
Javascript字符串对象的常用方法简明版
2014/06/26 Javascript
javascript简单实现图片预加载
2014/12/03 Javascript
Node.js操作Firebird数据库教程
2016/03/04 Javascript
JavaScript的React框架中的JSX语法学习入门教程
2016/03/05 Javascript
Backbone中View之间传值的学习心得
2016/08/09 Javascript
ES6 迭代器(Iterator)和 for.of循环使用方法学习(总结)
2018/02/08 Javascript
Javascript实现秒表倒计时功能
2018/11/17 Javascript
通过实例解析js简易模块加载器
2019/06/17 Javascript
layui动态绑定事件的方法
2019/09/20 Javascript
LayUi数据表格自定义赋值方式
2019/10/26 Javascript
Vue快速实现通用表单验证功能
2019/12/05 Javascript
Vue看了就会的8个小技巧
2021/01/21 Vue.js
python实现支持目录FTP上传下载文件的方法
2015/06/03 Python
Python中列表和元组的相关语句和方法讲解
2015/08/20 Python
在类Unix系统上开始Python3编程入门
2015/08/20 Python
Python遍历目录中的所有文件的方法
2016/07/08 Python
python中import学习备忘笔记
2017/01/24 Python
Python实现判断并移除列表指定位置元素的方法
2018/04/13 Python
python实现基于朴素贝叶斯的垃圾分类算法
2019/07/09 Python
Django自带日志 settings.py文件配置方法
2019/08/30 Python
python matplotlib:plt.scatter() 大小和颜色参数详解
2020/04/14 Python
基于python爬取链家二手房信息代码示例
2020/10/21 Python
python中的yield from语法快速学习
2020/11/06 Python
英国领先的高街书籍专家:Waterstones
2018/02/01 全球购物
计算机考试作弊检讨书1000字
2015/01/01 职场文书
外科护士长工作总结
2015/08/12 职场文书
深入理解Vue的数据响应式
2021/05/15 Vue.js
Python绘制地图神器folium的新人入门指南
2021/05/23 Python
PostgreSQL出现死锁该如何解决
2022/05/30 PostgreSQL
SpringBoot详解执行过程
2022/07/15 Java/Android