python对BP神经网络实现
一、概念理解
开始之前首先了解一下BP神经网络,BP的英文是back propagationd的意思,它是一种按误差反向传播(简称误差反传)训练的多层前馈网络,其算法称为BP算法。
它的基本思想是 梯度下降法,利用梯度搜索技术,期望使网络的 实际输出值和 期望输出值的误差和均方差为最小。
基本BP算法包括信号的前向传播和误差的反向传播两个过程。
正向传播过程:输入信号——通过隐含层——>作用于输出节点(经过非线性变换,产生输出信号)——>验证实际输出结果是否与期望输出符合【若不符合,转入到误差的反向传播】
反向传播过程:输出误差——通过隐含层——>输入层(逐层反传,并将误差分摊给各层单元)——>获得误差信号(作为调整各单元权值的依据)——>调整输入节点与隐层节点的联接强度和隐层节点与输出
节点的联接强度以及阈值——>误差沿梯度方向下降——>经过反复学习训练——>确定与最小误差相对应的网络参数(权值和阈值)——>结束
二、python实现过程
1、前言
实现任务例子:
路运量主要包括公路客运量和公路货运量两方面。某个地区的公路运量主要与该地区的人数、机动车数量和公路面积有关,已知该地区20年(1990-2009)的公路运量相关数据如下:
(1) 人数/万人
20.55 22.44 25.37 27.13 29.45 30.10 30.96 34.06 36.42 38.09 39.13 39.99 41.93 44.59 47.30 52.89 55.73 56.76 59.17 60.63
(2) 机动车数量/万辆
0.6 0.75 0.85 0.9 1.05 1.35 1.45 1.6 1.7 1.85 2.15 2.2 2.25 2.35 2.5 2.6 2.7 2.85 2.95 3.1
(3) 公路面积/单位:万平方公里
0.09 0.11 0.11 0.14 0.20 0.23 0.23 0.32 0.32 0.34 0.36 0.36 0.38 0.49 0.56 0.59 0.59 0.67 0.69 0.79
(4) 公路客运量/万人
5126 6217 7730 9145 10460 11387 12353 15750 18304 19836 21024 19490 20433 22598 25107 33442 36836 40548 42927 43462
(5) 公路货运量(单位:万吨)
1237 1379 1385 1399 1663 1714 1834 4322 8132 8936 11099 11203 10524 11115 13320 16762 18673 20724 20803 21804
结果检测:预测2010和2011年的公路客运量和公路客运量?、
准备:
(1)、激活函数
此函数为

,注意的是在机器学习中,np.exp()的参数可以是向量,当传入是向量的时候,其返回值是该向量内所有的元素值分别进行公式求值后构成的一个列表。
1 def sigmod(x):
2 return 1 / (1 + np.exp(-x))
(2)、数据的读取
需要了解xlrd函数的的使用
2、实现过程
(1)、数据读取
训练数据的读取
1 def read_xls_file(filename): #读取训练数据
2 data = xlrd.open_workbook(filename)
3 sheet1 = data.sheet_by_index(0)
4 m = sheet1.nrows
5 n = sheet1.ncols
6 # 人口数量 机动车数量 公路面积 公路客运量 公路货运量
7 pop,veh,roa,pas,fre=[],[],[],[],[]
8 for i in range(m):
9 row_data = sheet1.row_values(i)
10 if i > 0:
11 pop.append(row_data[1])
12 veh.append(row_data[2])
13 roa.append(row_data[3])
14 pas.append(row_data[4])
15 fre.append(row_data[5])
16 dataMat = np.mat([pop,veh,roa])
17 labels = np.mat([pas,fre])
18 dataMat_old = dataMat
19 labels_old = labels
20 # 数据集合,标签集合,保留数据集合,保留标签集合
21 return dataMat,labels,dataMat_old,labels_old
测试数据的读取
def read_xls_testfile(filename): #读取测试数据
data = xlrd.open_workbook(filename)
sheet1 = data.sheet_by_index(0)
m = sheet1.nrows
n = sheet1.ncols
pop = []
veh = []
roa = []
for i in range(m):
row_data = sheet1.row_values(i)
if i > 0:
pop.append(row_data[1])
veh.append(row_data[2])
roa.append(row_data[3])
dataMat = np.mat([pop,veh,roa])
return dataMat
(2)、最大最小法归一
将原始数据线性化的方法转换到[0 1]的范围,归一化公式如下:

1 def Norm(dataMat,labels):
2 dataMat_minmax = np.array([dataMat.min(axis=1).T.tolist()[0],dataMat.max(axis=1).T.tolist()[0]]).transpose()
3 dataMat_Norm = ((np.array(dataMat.T)-dataMat_minmax.transpose()[0])/(dataMat_minmax.transpose()[1]-dataMat_minmax.transpose()[0])).transpose()
4 labels_minmax = np.array([labels.min(axis=1).T.tolist()[0],labels.max(axis=1).T.tolist()[0]]).transpose()
5 labels_Norm = ((np.array(labels.T).astype(float)-labels_minmax.transpose()[0])/(labels_minmax.transpose()[1]-labels_minmax.transpose()[0])).transpose()
6 return dataMat_Norm,labels_Norm,dataMat_minmax,labels_minmax
(3)、训练模型
返回值为4个权值以及最大可迭代次数
1 def BP(sampleinnorm, sampleoutnorm,hiddenunitnum=3):
2 # 超参数
3 maxepochs = 60000 # 最大迭代次数
4 learnrate = 0.030 # 学习率
5 errorfinal = 0.65*10**(-3) # 最终迭代误差
6 indim = 3 # 输入特征维度3
7 outdim = 2 # 输出特征唯独2
8 # 隐藏层默认为3个节点,1层
9 n,m = shape(sampleinnorm)
10 w1 = 0.5*np.random.rand(hiddenunitnum,indim)-0.1 #8*3维
11 b1 = 0.5*np.random.rand(hiddenunitnum,1)-0.1 #8*1维
12 w2 = 0.5*np.random.rand(outdim,hiddenunitnum)-0.1 #2*8维
13 b2 = 0.5*np.random.rand(outdim,1)-0.1 #2*1维
14
15 errhistory = []
16
17 for i in range(maxepochs):
18 # 激活隐藏输出层
19 hiddenout = sigmod((np.dot(w1,sampleinnorm).transpose()+b1.transpose())).transpose()
20 # 计算输出层输出
21 networkout = (np.dot(w2,hiddenout).transpose()+b2.transpose()).transpose()
22 # 计算误差
23 err = sampleoutnorm - networkout
24 # 计算代价函数(cost function)sum对数组里面的所有数据求和,变为一个实数
25 sse = sum(sum(err**2))/m
26 errhistory.append(sse)
27 if sse < errorfinal: #迭代误差
28 break
29 # 计算delta
30 delta2 = err
31 delta1 = np.dot(w2.transpose(),delta2)*hiddenout*(1-hiddenout)
32 # 计算偏置
33 dw2 = np.dot(delta2,hiddenout.transpose())
34 db2 = 1 / 20 * np.sum(delta2, axis=1, keepdims=True)
35
36 dw1 = np.dot(delta1,sampleinnorm.transpose())
37 db1 = 1/20*np.sum(delta1,axis=1,keepdims=True)
38
39 # 更新权值
40 w2 += learnrate*dw2
41 b2 += learnrate*db2
42 w1 += learnrate*dw1
43 b1 += learnrate*db1
44
45 return errhistory,b1,b2,w1,w2,maxepochs
(7)、曲线显示
显示内容为两个内容:1、神经网络曲线图(包括客运量预测输出、客运量真实输出、货运量预测输出、货运量真实输出)2、误差曲线图
1 def show(sampleinnorm,sampleoutminmax,sampleout,errhistory,maxepochs): # 图形显示
2 matplotlib.rcParams['font.sans-serif']=['SimHei'] # 防止中文乱码
3 hiddenout = sigmod((np.dot(w1,sampleinnorm).transpose()+b1.transpose())).transpose()
4 networkout = (np.dot(w2,hiddenout).transpose()+b2.transpose()).transpose()
5 diff = sampleoutminmax[:,1]-sampleoutminmax[:,0]
6 networkout2 = networkout
7 networkout2[0] = networkout2[0]*diff[0]+sampleoutminmax[0][0]
8 networkout2[1] = networkout2[1]*diff[1]+sampleoutminmax[1][0]
9 sampleout = np.array(sampleout)
10
11 fig,axes = plt.subplots(nrows=2,ncols=1,figsize=(12,10))
12 line1, = axes[0].plot(networkout2[0],'k',markeredgecolor='b',marker = 'o',markersize=7)
13 line2, = axes[0].plot(sampleout[0],'r',markeredgecolor='g',marker = u'$\star$',markersize=7)
14 line3, = axes[0].plot(networkout2[1],'g',markeredgecolor='g',marker = 'o',markersize=7)
15 line4, = axes[0].plot(sampleout[1],'y',markeredgecolor='b',marker = u'$\star$',markersize=7)
16 axes[0].legend((line1,line2,line3,line4),(u'客运量预测输出',u'客运量真实输出',u'货运量预测输出',u'货运量真实输出'),loc = 'upper left')
17 axes[0].set_ylabel(u'公路客运量及货运量')
18 xticks = range(0,22,1)
19 xtickslabel = range(1990,2012,1)
20 axes[0].set_xticks(xticks)
21 axes[0].set_xticklabels(xtickslabel)
22 axes[0].set_xlabel(u'年份')
23 axes[0].set_title(u'BP神经网络')
24
25 errhistory10 = np.log10(errhistory)
26 minerr = min(errhistory10)
27 plt.plot(errhistory10)
28 axes[1]=plt.gca()
29 axes[1].set_yticks([-2,-1,0,1,2,minerr])
30 axes[1].set_yticklabels([u'$10^{-2}$',u'$10^{-1}$',u'$1$',u'$10^{1}$',u'$10^{2}$',str(('%.4f'%np.power(10,minerr)))])
31 axes[1].set_xlabel(u'训练次数')
32 axes[1].set_ylabel(u'误差')
33 axes[1].set_title(u'误差曲线')34 plt.show()
35 plt.close()
36 return diff, sampleoutminmax
(8)、主函数
1 if __name__ == "__main__":
2 dataMat,labels,dataMat_old,labels_old = read_xls_file('训练.xls')
3 dataMat_Norm,labels_Norm, dataMat_minmax, labels_minmax = Norm(dataMat,labels)
4 err, b1, b2, w1, w2,maxepochs = BP(dataMat_Norm,labels_Norm,6)
5 dataMat_test = read_xls_testfile('测试.xls')
6 diff, sampleoutminmax = show(dataMat_Norm,labels_minmax,labels,err,maxepochs)
7 pre(dataMat_test,dataMat_minmax,diff, sampleoutminmax ,w1,b1,w2,b2)
(9)、拓展
以上采用的是数据读取,也可以直接定义,返回的值是里面的数据以及label就可以了,可以自己实验一下。
1 # 人数(单位:万人)
2 population = [20.55, 22.44, 25.37, 27.13, 29.45, 30.10, 30.96, 34.06, 36.42, 38.09, 39.13, 39.99, 41.93, 44.59, 47.30,
3 52.89, 55.73, 56.76, 59.17, 60.63]
4 # 机动车数(单位:万辆)
5 vehicle = [0.6, 0.75, 0.85, 0.9, 1.05, 1.35, 1.45, 1.6, 1.7, 1.85, 2.15, 2.2, 2.25, 2.35, 2.5, 2.6, 2.7, 2.85, 2.95,
6 3.1]
7 # 公路面积(单位:万平方公里)
8 roadarea = [0.09, 0.11, 0.11, 0.14, 0.20, 0.23, 0.23, 0.32, 0.32, 0.34, 0.36, 0.36, 0.38, 0.49, 0.56, 0.59, 0.59, 0.67,
9 0.69, 0.79]
10 # 公路客运量(单位:万人)
11 passengertraffic = [5126, 6217, 7730, 9145, 10460, 11387, 12353, 15750, 18304, 19836, 21024, 19490, 20433, 22598, 25107,
12 33442, 36836, 40548, 42927, 43462]
13 # 公路货运量(单位:万吨)
14 freighttraffic = [1237, 1379, 1385, 1399, 1663, 1714, 1834, 4322, 8132, 8936, 11099, 11203, 10524, 11115, 13320, 16762,
15 18673, 20724, 20803, 21804]
16
17 # 数据转为矩阵
18 samplein = np.mat([population, vehicle, roadarea])
19 sampleinminmax = np.array([samplein.min(axis=1).T.tolist()[0], samplein.max(axis=1).T.tolist()[0]]).transpose() # 3*2
20 sampleout = np.mat([passengertraffic, freighttraffic])
21 sampleoutminmax = np.array(
22 [sampleout.min(axis=1).T.tolist()[0], sampleout.max(axis=1).T.tolist()[0]]).transpose() # 2*2
三、总结
1、整体代码
注意:记得替换掉数据集,该程序只适用于数据集保存在表格里,如果其他格式,请参考python的其他文件形式的读取
import numpy as np
import xlrd
import matplotlib.pyplot as plt
def read_xls_file(filename):
data = xlrd.open_workbook(filename)
sheet1 = data.sheet_by_index(0)
m = sheet1.nrows
n = sheet1.ncols
pop,veh,roa,pas,fre=[],[],[],[],[]
for i in range(m):
row_data = sheet1.row_values(i)
if i > 0:
pop.append(row_data[1])
veh.append(row_data[2])
roa.append(row_data[3])
pas.append(row_data[4])
fre.append(row_data[5])
dataMat = np.mat([pop,veh,roa])
labels = np.mat([pas,fre])
dataMat_old = dataMat
labels_old = labels
return dataMat,labels,dataMat_old,labels_old
读取测试集
def read_xls_testfile(filename): # 读取测试数据
data = xlrd.open_workbook(filename)
sheet1 = data.sheet_by_index(0)
m = sheet1.nrows
n = sheet1.ncols
pop = []
veh = []
roa = []
for i in range(m):
row_data = sheet1.row_values(i)
if i > 0:
pop.append(row_data[1])
veh.append(row_data[2])
roa.append(row_data[3])
dataMat = np.mat([pop, veh, roa])
return dataMat
# 由于数据数量级相差太大,我们要先对数据进行归一化处理Min-Max归一化
def Norm(dataMat, labels):
dataMat_minmax = np.array([dataMat.min(axis=1).T.tolist()[0], dataMat.max(axis=1).T.tolist()[0]]).transpose()
dataMat_Norm = ((np.array(dataMat.T) - dataMat_minmax.transpose()[0]) / (
dataMat_minmax.transpose()[1] - dataMat_minmax.transpose()[0])).transpose()
labels_minmax = np.array([labels.min(axis=1).T.tolist()[0], labels.max(axis=1).T.tolist()[0]]).transpose()
labels_Norm = ((np.array(labels.T).astype(float) - labels_minmax.transpose()[0]) / (
labels_minmax.transpose()[1] - labels_minmax.transpose()[0])).transpose()
return dataMat_Norm, labels_Norm, dataMat_minmax, labels_minmax
# 激活函数
def sigmod(x):
return 1 / (1 + np.exp(-x))
# Back Propagation
def BP(sampleinnorm, sampleoutnorm, hiddenunitnum=3):
# 超参数
maxepochs = 60000 # 最大迭代次数
learnrate = 0.030 # 学习率
errorfinal = 0.65 * 10 ** (-3) # 最终迭代误差
indim = 3 # 输入特征维度3
outdim = 2 # 输出特征唯独2
# 隐藏层默认为3个节点,1层
n, m = shape(sampleinnorm)
w1 = 0.5 * np.random.rand(hiddenunitnum, indim) - 0.1 # 8*3维
b1 = 0.5 * np.random.rand(hiddenunitnum, 1) - 0.1 # 8*1维
w2 = 0.5 * np.random.rand(outdim, hiddenunitnum) - 0.1 # 2*8维
b2 = 0.5 * np.random.rand(outdim, 1) - 0.1 # 2*1维
errhistory = []
for i in range(maxepochs):
# 激活隐藏输出层
hiddenout = sigmod((np.dot(w1, sampleinnorm).transpose() + b1.transpose())).transpose()
# 计算输出层输出
networkout = (np.dot(w2, hiddenout).transpose() + b2.transpose()).transpose()
# 计算误差
err = sampleoutnorm - networkout
# 计算代价函数(cost function)sum对数组里面的所有数据求和,变为一个实数
sse = sum(sum(err ** 2)) / m
errhistory.append(sse)
if sse < errorfinal: # 迭代误差
break
# 计算delta
delta2 = err
delta1 = np.dot(w2.transpose(), delta2) * hiddenout * (1 - hiddenout)
# 计算偏置
dw2 = np.dot(delta2, hiddenout.transpose())
db2 = 1 / 20 * np.sum(delta2, axis=1, keepdims=True)
dw1 = np.dot(delta1, sampleinnorm.transpose())
db1 = 1 / 20 * np.sum(delta1, axis=1, keepdims=True)
# 更新权值
w2 += learnrate * dw2
b2 += learnrate * db2
w1 += learnrate * dw1
b1 += learnrate * db1
return errhistory, b1, b2, w1, w2, maxepochs
def show(sampleinnorm, sampleoutminmax, sampleout, errhistory, maxepochs): # 图形显示
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 防止中文乱码
hiddenout = sigmod((np.dot(w1, sampleinnorm).transpose() + b1.transpose())).transpose()
networkout = (np.dot(w2, hiddenout).transpose() + b2.transpose()).transpose()
diff = sampleoutminmax[:, 1] - sampleoutminmax[:, 0]
networkout2 = networkout
networkout2[0] = networkout2[0] * diff[0] + sampleoutminmax[0][0]
networkout2[1] = networkout2[1] * diff[1] + sampleoutminmax[1][0]
sampleout = np.array(sampleout)
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(12, 10))
line1, = axes[0].plot(networkout2[0], 'k', markeredgecolor='b', marker='o', markersize=7)
line2, = axes[0].plot(sampleout[0], 'r', markeredgecolor='g', marker=u'$\star$', markersize=7)
line3, = axes[0].plot(networkout2[1], 'g', markeredgecolor='g', marker='o', markersize=7)
line4, = axes[0].plot(sampleout[1], 'y', markeredgecolor='b', marker=u'$\star$', markersize=7)
axes[0].legend((line1, line2, line3, line4), (u'客运量预测输出', u'客运量真实输出', u'货运量预测输出', u'货运量真实输出'), loc='upper left')
axes[0].set_ylabel(u'公路客运量及货运量')
xticks = range(0, 22, 1)
xtickslabel = range(1990, 2012, 1)
axes[0].set_xticks(xticks)
axes[0].set_xticklabels(xtickslabel)
axes[0].set_xlabel(u'年份')
axes[0].set_title(u'BP神经网络')
errhistory10 = np.log10(errhistory)
minerr = min(errhistory10)
plt.plot(errhistory10)
axes[1] = plt.gca()
axes[1].set_yticks([-2, -1, 0, 1, 2, minerr])
axes[1].set_yticklabels(
[u'$10^{-2}$', u'$10^{-1}$', u'$1$', u'$10^{1}$', u'$10^{2}$', str(('%.4f' % np.power(10, minerr)))])
axes[1].set_xlabel(u'训练次数')
axes[1].set_ylabel(u'误差')
axes[1].set_title(u'误差曲线')
plt.show()
plt.close()
return diff, sampleoutminmax
def pre(dataMat, dataMat_minmax, diff, sampleoutminmax, w1, b1, w2, b2): # 数值预测
# 归一化数据
dataMat_test = ((np.array(dataMat.T) - dataMat_minmax.transpose()[0]) / (
dataMat_minmax.transpose()[1] - dataMat_minmax.transpose()[0])).transpose()
# 然后计算两层的输出结果
# 隐藏层
hiddenout = sigmod((np.dot(w1, dataMat_test).transpose() + b1.transpose())).transpose()
# 输出层
networkout1 = (np.dot(w2, hiddenout).transpose() + b2.transpose()).transpose()
networkout = networkout1
# 计算结果
networkout[0] = networkout[0] * diff[0] + sampleoutminmax[0][0]
networkout[1] = networkout[1] * diff[1] + sampleoutminmax[1][0]
print("2010年预测的公路客运量为:", int(networkout[0][0]), "(万人)")
print("2010年预测的公路货运量为:", int(networkout[1][0]), "(万吨)")
print("2011年预测的公路客运量为:", int(networkout[0][1]), "(万人)")
print("2011年预测的公路货运量为:", int(networkout[1][1]), "(万吨)")
if __name__ == "__main__":
dataMat, labels, dataMat_old, labels_old = read_xls_file('训练.xls')
dataMat_Norm, labels_Norm, dataMat_minmax, labels_minmax = Norm(dataMat, labels)
err, b1, b2, w1, w2, maxepochs = BP(dataMat_Norm, labels_Norm, 6)
dataMat_test = read_xls_testfile('测试.xls')
diff, sampleoutminmax = show(dataMat_Norm, labels_minmax, labels, err, maxepochs)
pre(dataMat_test, dataMat_minmax, diff, sampleoutminmax, w1, b1, w2, b2)
2、结果展示

2010年预测的公路客运量为: 53980 (万人)
2010年预测的公路货运量为: 28513 (万吨)
2011年预测的公路客运量为: 55716 (万人)
2011年预测的公路货运量为: 29521 (万吨)
注:以上均为自己学习使用,希望可以帮助到你,感谢支持!!!
Original: https://blog.csdn.net/yxk666/article/details/119418458
Author: 相识已是上上签
Title: python对BP神经网络实现
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/618364/
转载文章受原作者版权保护。转载请注明原作者出处!