BP算法
求解参数w的算法,神经网络的基础,权重的学习算法都是BP学习算法
信号“正向传播(FP)”求损失,“反向传播(BP)”回传误差;根据误差值修改每层的权重,继续迭代
输出层误差
O代表预测结果,d代表真实结果;系数是为了方便求导时计算
隐层的误差
netk是当前神经元的wx的结果;f(net)是激活函数,yj代表上一层隐层的输出值
输入层误差
推导过程
Python实现BP神经网络实现对公路客运量
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
'''
Python实现BP神经网络实现对公路客运量
'''
## 设置字符集,防止中文乱码
mpl.rcParams['font.sans-serif'] = [u'simHei']
mpl.rcParams['axes.unicode_minus'] = False
data = pd.read_csv('traffic_data.csv')
x = data[['人口数', '机动车数', '公路面积']]
y = data[['客运量', '货运量']]
# 由于人口数和其他特征属性差别较大,所以要进行归一化
x_scaler = MinMaxScaler(feature_range=(-1, 1))
y_scaler = MinMaxScaler(feature_range=(-1, 1))
x = x_scaler.fit_transform(x)
y = y_scaler.fit_transform(y)
# 为了后面和w进行矩阵的乘法操作
sample_in = x.T
sample_out = y.T
# 超参
max_epochs = 60000
learn_rate = 0.035
mse_final = 6.5e-4
sample_number = x.shape[0]
input_number = 3
output_number = 2
hidden_unit_number = 8
# 创建网格参数
# 8*3矩阵
w1 = np.random.rand(hidden_unit_number, input_number) - 0.1
# 8*1矩阵
b1 = np.random.rand(hidden_unit_number, 1) - 0.1
# 2*8矩阵
w2 = np.random.rand(output_number, hidden_unit_number) - 0.1
# 1*8矩阵
b2 = np.random.rand(output_number, 1) - 0.1
# sigmoid函数
def sigmoid(z):
return 1.0/(1.0 + np.exp(-z))
mse_history = []
for i in range(max_epochs):
# FP过程
# 隐藏层输出,transpose是让列相同才能矩阵相加,第二次transpose变回原形状
hidden_out = sigmoid(np.dot(w1, sample_in).transpose() + b1.transpose()).transpose()
# 输出层的输出(为了简化写法,输出层不进行sogmoid激活)
network_out = (np.dot(w2, hidden_out).transpose() + b2.transpose()).transpose()
# 误差判断
err = sample_out - network_out
mse = np.average(np.square(err))
mse_history.append(mse)
if mse < mse_final:
break
# BP过程
delta2 = -err
delta1 = np.dot(w2.transpose(), delta2) * hidden_out * (1 - hidden_out)
dw2 = np.dot(delta2, hidden_out.transpose())
db2 = np.dot(delta2, np.ones((sample_number, 1)))
dw1 = np.dot(delta1, sample_in.transpose())
db1 = np.dot(delta1, np.ones((sample_number, 1)))
w2 -= learn_rate * dw2
b2 -= learn_rate * db2
w1 -= learn_rate * dw1
b1 -= learn_rate * db1
## 设置字符集,防止中文乱码
mpl.rcParams['font.sans-serif'] = [u'simHei']
mpl.rcParams['axes.unicode_minus'] = False
# 误差曲线图
mse_history10 = np.log10(mse_history)
min_mse = min(mse_history10)
plt.plot(mse_history10)
plt.plot([0, len(mse_history10)], [min_mse, min_mse])
ax = plt.gca() # 移动坐标轴
ax.set_yticks([-2,-1,0,1,2,min_mse])
ax.set_xlabel('iteration')
ax.set_ylabel('MSE')
ax.set_title('Log10 MSE History')
plt.show()
# 仿真输出和实际输出对比图
# 隐藏层输出
hidden_out = sigmoid((np.dot(w1, sample_in).transpose() + b1.transpose())).transpose()
# 输出层输出
network_out = (np.dot(w2, hidden_out).transpose() + b2.transpose()).transpose()
# 反转获取实际值
network_out = y_scaler.inverse_transform(network_out.T)
sample_out = y_scaler.inverse_transform(y)
# fig是图像对象,axes坐标轴对象
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(12,10))
# k代表颜色,marker标记
line1 = axes[0].plot(network_out[:,0], 'k', marker='o')
line2 = axes[0].plot(sample_out[:,0], 'r', markeredgecolor='b', marker='*', markersize=9)
# 图例
axes[0].legend((line1, line2),('预测值', '真实值'), loc='upper left')
axes[0].set_title('客流模拟')
line3 = axes[1].plot(network_out[:,1],'k', marker='o')
line4 = axes[1].plot(sample_out[:,1], 'r', markeredgecolor='b', marker='*', markersize=9)
axes[1].legend((line3, line4), ('预测值','实际值'), loc='upper left')
axes[1].set_title('货流模拟')
plt.show()
误差曲线图
预测值和实际值对比图