使用python创建一个使用归一化、Xavier初始化、正则化方法和MSGD的BP网络,该网络有8个输入1个输出1层隐藏层,要求分为两个模块(py文件),且一个是BP网络,另一个是主函数,在每句代码后添加注释;训练集数据存于xlsx表格前3000行中,测试集为之后的40行,且均为float类型,即训练模型时以3000行数据作为训练集,而之后也可以将40行的测试集数据输入模型中并正常运行出结果。并且能够输出各输入的权重。尝试在main模块中实现将训练后的BP网络模型输出为一个文件,绘制R2图来说明模型的拟合度,并且输出MAE、MSE、预测值和真实值之间的相对误差平均百分比,绘制测试集的各输入对应的实际输出和预测输出的拟合折线图,且R2图和折线图中使用的数据均为未变换数据。
时间: 2023-11-27 09:49:29 浏览: 79
以下是实现要求的代码,包括BP网络模块和主函数模块:
### bp_network.py
```python
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
class BPNN:
def __init__(self, input_size, hidden_size, output_size):
"""
初始化BP神经网络
:param input_size: 输入层大小
:param hidden_size: 隐藏层大小
:param output_size: 输出层大小
"""
self.input_size = input_size
self.hidden_size = hidden_size
self.output_size = output_size
self.W1 = np.random.randn(self.input_size, self.hidden_size) * np.sqrt(1.0 / self.input_size) # Xavier初始化输入层权重
self.b1 = np.zeros(self.hidden_size)
self.W2 = np.random.randn(self.hidden_size, self.output_size) * np.sqrt(1.0 / self.hidden_size) # Xavier初始化隐藏层权重
self.b2 = np.zeros(self.output_size)
def sigmoid(self, x):
"""
Sigmoid激活函数
"""
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(self, x):
"""
Sigmoid激活函数的导数
"""
return x * (1 - x)
def forward(self, X):
"""
前向传播
:param X: 输入数据
"""
self.z1 = np.dot(X, self.W1) + self.b1
self.a1 = self.sigmoid(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = self.sigmoid(self.z2)
def backward(self, X, y, learning_rate, reg_lambda):
"""
反向传播
:param X: 输入数据
:param y: 输出数据
:param learning_rate: 学习率
:param reg_lambda: L2正则化系数
"""
delta2 = (self.a2 - y) * self.sigmoid_derivative(self.a2)
dW2 = np.dot(self.a1.T, delta2) + reg_lambda * self.W2 # 加入L2正则化
db2 = np.sum(delta2, axis=0)
delta1 = np.dot(delta2, self.W2.T) * self.sigmoid_derivative(self.a1)
dW1 = np.dot(X.T, delta1) + reg_lambda * self.W1 # 加入L2正则化
db1 = np.sum(delta1, axis=0)
# 更新权重和偏置
self.W1 -= learning_rate * dW1
self.b1 -= learning_rate * db1
self.W2 -= learning_rate * dW2
self.b2 -= learning_rate * db2
def train(self, X, y, learning_rate, reg_lambda, n_iterations):
"""
训练模型
:param X: 输入数据
:param y: 输出数据
:param learning_rate: 学习率
:param reg_lambda: L2正则化系数
:param n_iterations: 迭代次数
"""
for i in range(n_iterations):
self.forward(X)
self.backward(X, y, learning_rate, reg_lambda)
def predict(self, X):
"""
预测结果
:param X: 输入数据
"""
self.forward(X)
return self.a2
def get_weights(self):
"""
获取各输入的权重
"""
return self.W1.T
def normalize_data(data):
"""
归一化数据
:param data: 待归一化数据
"""
scaler = MinMaxScaler()
data = scaler.fit_transform(data)
return data, scaler
def load_data(file_path):
"""
加载数据
:param file_path: 文件路径
"""
data = pd.read_excel(file_path).values.astype(float)
X_train, scaler = normalize_data(data[:3000, :-1])
y_train = data[:3000, -1].reshape(-1, 1)
X_test = scaler.transform(data[3000:, :-1])
y_test = data[3000:, -1].reshape(-1, 1)
return X_train, y_train, X_test, y_test, scaler
```
### main.py
```python
import numpy as np
import matplotlib.pyplot as plt
from bp_network import BPNN, load_data, normalize_data
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
def save_model(model, scaler):
"""
保存模型
:param model: 训练后的BP网络模型
:param scaler: 归一化器
"""
np.savez('model.npz', W1=model.W1, b1=model.b1, W2=model.W2, b2=model.b2)
scaler_min = scaler.data_min_
scaler_scale = scaler.scale_
np.savez('scaler.npz', scaler_min=scaler_min, scaler_scale=scaler_scale)
def load_model():
"""
加载模型
"""
model_data = np.load('model.npz')
W1 = model_data['W1']
b1 = model_data['b1']
W2 = model_data['W2']
b2 = model_data['b2']
model = BPNN(W1.shape[0], W1.shape[1], W2.shape[1])
model.W1 = W1
model.b1 = b1
model.W2 = W2
model.b2 = b2
scaler_data = np.load('scaler.npz')
scaler_min = scaler_data['scaler_min']
scaler_scale = scaler_data['scaler_scale']
scaler = normalize_data(np.zeros((1, scaler_min.shape[0])))[1]
scaler.data_min_ = scaler_min
scaler.scale_ = scaler_scale
return model, scaler
def plot_fit(X_test, y_test, y_pred):
"""
绘制拟合折线图
:param X_test: 测试数据集
:param y_test: 测试数据集的真实输出
:param y_pred: 测试数据集的预测输出
"""
for i in range(X_test.shape[1]):
plt.plot(X_test[:, i], y_test, label='true')
plt.plot(X_test[:, i], y_pred, label='predict')
plt.legend()
plt.show()
if __name__ == '__main__':
# 加载数据
X_train, y_train, X_test, y_test, scaler = load_data('data.xlsx')
# 训练模型
model = BPNN(X_train.shape[1], 8, 1) # 输入层8个节点,隐藏层8个节点,输出层1个节点
model.train(X_train, y_train, 0.01, 0.01, 10000)
# 保存模型
save_model(model, scaler)
# 加载模型
model, scaler = load_model()
# 预测结果
y_pred = model.predict(X_test)
# 反归一化
y_test = scaler.inverse_transform(y_test)
y_pred = scaler.inverse_transform(y_pred)
# 计算各种指标
r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
relative_error = np.mean(np.abs((y_pred - y_test) / y_test)) * 100
# 输出各种指标
print('R2 score:', r2)
print('MAE:', mae)
print('MSE:', mse)
print('Relative error:', relative_error)
# 绘制拟合折线图
plot_fit(X_test, y_test, y_pred)
# 绘制R2图
plt.scatter(y_test, y_pred)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2)
plt.xlabel('True values')
plt.ylabel('Predicted values')
plt.title('R2 score: %.4f' % r2)
plt.show()
```
需要注意的是,由于归一化器需要保存,因此在保存模型时也需要将归一化器保存起来,以便在加载模型时可以反归一化数据。在加载模型时,需要使用与训练时相同的归一化器对测试集数据进行归一化,以便进行预测。
阅读全文