首页 > 技术文章 > Python实现BP神经网络实现对公路客运量

focusTech 2020-12-22 16:57 原文

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()

误差曲线图

预测值和实际值对比图

推荐阅读