BP神经网络的Python实现
利用python实现了简易的 bp神经网络模型,利用误差逆传播算法以及梯度下降法对网络进行训练,具体公式推到等可参考《机器学习》等相关书籍。
源码以及数据集可在链接 https://download.csdn.net/download/wz2671/10790394下载。
BP_TEST.py
# -*- coding: UTF-8 -*-
from BPNet.bpNet import *
import matplotlib.pyplot as plt
# 数据集
bpnet = BPNet()
bpnet.loadDataSet("testSet2.txt")
bpnet.normalize()
# 绘制数据集散点图
bpnet.drawClassScatter(plt)
# BP神经网络进行数据分类
bpnet.bpTrain()
# 计算和绘制分类线
x, z = bpnet.BPClassfier()
bpnet.classfyLine(plt, x, z)
plt.show()
# 绘制误差曲线
bpnet.TrendLine(plt)
plt.show()
bpNet.py
# -*- coding: utf-8 -*-
from numpy import *
import matplotlib.pyplot as plt
"""
BP神经网络的Python实现
公式推导等可参考:周志华《机器学习》
"""
class BPNet(object):
def __init__(self):
# 网络参数
self.eb = 0.01 # 误差容限
self.eta = 0.1 # 学习率
self.mc = 0.3 # 动量因子
self.maxiter = 2000 # 最大迭代次数
self.errlist = [] # 误差列表
self.data = None # 数据集
self.label = None # 分类集
self.nSampNum = 0 # 样本集行数
self.nSampDim = 0 # 样本维度
self.nHidden = 4 # 隐含层神经元
self.nOut = 1 # 输出层
self.iterator = 0 # 最优时迭代次数
self.hide_wb = None # 隐含层模型参数
self.out_wb = None # 输出层模型参数
# 激活函数
def logistic(self, net):
return 1.0 / (1.0 + exp(-net))
# 传递函数的导函数
def dlogit(self, net):
return multiply(net, (1.0 - net))
# 矩阵各元素平方之和
def errorfunc(self, inX):
return sum(power(inX, 2)) * 0.5
# 数据归一化
def normalize(self):
[m, n] = shape(self.data)
for i in range(n - 1):
self.data[:, i] = (self.data[:, i] - mean(self.data[:, i])) / (std(self.data[:, i]) + 1.0e-10)
return self.data
# 加载数据集
def loadDataSet(self, filename):
self.data = []
self.label = []
fr = open(filename)
for line in fr.readlines():
lineArr = line.strip().split()
self.data.append([float(lineArr[0]), float(lineArr[1]), 1.0])
self.label.append(int(lineArr[2]))
self.data = array(self.data)
self.label = array(self.label)
m, n = shape(self.data)
self.nSampNum = m # 样本数量
self.nSampDim = n # 样本维度
# Train the bp net
def bpTrain(self):
# 数据集矩阵化
SampIn = mat(self.data.T)
expected = mat(self.label)
self.hide_wb = mat(2.0 * (random.rand(self.nHidden, self.nSampDim) - 0.5))
self.out_wb = mat(2.0 * (random.rand(self.nOut, self.nHidden + 1) - 0.5))
# 默认权值
dout_wbOld = 0.0
dhide_wbOld = 0.0
for i in range(self.maxiter):
# 工作信号正向传播
# 输入层到隐含层
hide_input = self.hide_wb * SampIn
hide_output = vstack((self.logistic(hide_input), ones((1, self.nSampNum))))
# 隐含层到输出层
out_input = self.out_wb * hide_output
out_output = self.logistic(out_input)
# 误差计算
err = expected - out_output
sse = self.errorfunc(err)
self.errlist.append(sse)
# 判断是否收敛至最优
if sse <= self.eb:
self.iterator = i + 1
break
# 误差信号反向传播
# 计算输出层梯度
delta_out = multiply(err, self.dlogit(out_output))
dout_wb = delta_out * hide_output.T
# 计算隐含层梯度
delta_hide = multiply(self.out_wb[:, :-1].T * delta_out, self.dlogit(hide_output[:-1, :]))
dhide_wb = delta_hide * SampIn.T
# 更新输出层和隐含层权值
if i == 0:
self.out_wb = self.out_wb + self.eta * dout_wb
self.hide_wb = self.hide_wb + self.eta * dhide_wb
else:
self.out_wb = self.out_wb + (1.0 - self.mc) * self.eta * dout_wb + self.mc * dout_wbOld
self.hide_wb = self.hide_wb + (1.0 - self.mc) * self.eta * dhide_wb + self.mc * dhide_wbOld
dout_wbOld = dout_wb
dhide_wbOld = dhide_wb
# bp神经网络分类器
def BPClassfier(self, steps=30):
x = linspace(self.data.min()-1, self.data.max()+1, steps)
xx = tile(x, (steps, 1))
yy = xx.T
# 三维矩阵的骚操作,一般人别想看懂
hide_output = array(self.hide_wb).dot(stack((xx, yy, ones((30, 30)))).transpose((1, 0, 2)))
out_output = array(self.out_wb).dot(vstack((self.logistic(hide_output), ones((1, steps, steps)))).transpose((1, 0, 2)))
zz = self.logistic(out_output)
return x, zz[0]
# 绘制分类线
def classfyLine(self, plt, x, z):
plt.contour(x, x, z, 1, colors='black')
# 绘制趋势线:
def TrendLine(self, plt, color='r'):
X = linspace(0, self.maxiter, self.maxiter)
Y = log2(self.errlist)
plt.xlabel("iteration")
plt.ylabel("loss")
plt.plot(X, Y, color)
# 绘制分类点
def drawClassScatter(self, plt):
negat_point = self.label == 0
plt.scatter(self.data[negat_point, 0], self.data[negat_point, 1], c='b', marker='o')
plt.scatter(self.data[~negat_point, 0], self.data[~negat_point, 1], c='r', marker='s')
实现结果图