引言:BP 神经网络的 “痛点” 与优化思路

BP(Back Propagation)神经网络是应用最广泛的人工神经网络之一,凭借其强大的非线性拟合能力,在回归预测、模式识别等领域大放异彩。但传统 BP 神经网络存在两个核心问题:

  1. 初始权重敏感:随机初始化的权重易导致网络陷入局部最优,而非全局最优;
  2. 收敛效率低:反向传播的梯度下降过程对初始值依赖大,训练耗时且效果不稳定。

为解决这些问题,本文提出 “Tent 混沌映射初始化 + 麻雀搜索算法(SSA)优化” 的组合方案:

  • Tent 混沌映射替代随机初始化,生成遍历性更强的初始种群,为优化打下基础;
  • 麻雀搜索算法(SSA) 全局搜索 BP 网络的最优权重 / 偏置,突破局部最优的限制。

本文将从理论到代码,完整拆解这一优化方案,即使是零基础的小白也能理解核心逻辑,并复现完整实验。

一、核心理论基础

1.1 BP 神经网络:从 “结构” 到 “计算”

BP 神经网络的核心是 “前向传播计算输出,反向传播更新权重”,我们从最基础的结构和公式讲起。

(1)网络结构

一个典型的三层 BP 网络包含:

  • 输入层:节点数为特征维度 nin​(对应代码中inputnum);
  • 隐藏层:节点数 nhid​(代码中通过遍历找最优值hiddennum_best);
  • 输出层:节点数 nout​(回归任务通常为 1,对应代码中outputnum=1)。
(2)前向传播公式

前向传播是 “输入→隐藏→输出” 的计算过程,核心公式如下:

步骤 1:输入层→隐藏层隐藏层的净输入(加权和):

其中:

  • wih​:输入层第i个节点到隐藏层第h个节点的权重;
  • xi​:输入层第i个节点的输入值;
  • bh​:隐藏层第h个节点的偏置。

隐藏层输出(激活函数用 tanh,对应代码中activation='tanh'):

步骤 2:隐藏层→输出层

输出层的净输入:

其中:

  • who​:隐藏层第h个节点到输出层第o个节点的权重;
  • bo​:输出层第o个节点的偏置。

输出层输出(回归任务无激活函数):

(3)损失函数与优化目标

BP 的核心是最小化预测值与真实值的误差,代码中使用均方误差(MSE) 作为损失函数:

其中N为样本数,yk​为真实值,y^​k​为预测值。

代码中进一步将训练集和测试集的 MSE 取平均作为适应度函数:

(4)隐藏层节点数选择

隐藏层节点数是 BP 的关键超参数,代码中通过遍历搜索最优值:

选择训练 MSE 最小的节点数作为最优值(hiddennum_best)。

1.2 Tent 混沌映射:更 “均匀” 的初始化方式

随机初始化权重易导致种群分布不均,而Tent 混沌映射能生成具有 “遍历性、随机性、规律性” 的序列,让初始种群覆盖更广泛的搜索空间。

(1)Tent 映射的数学公式

Tent 映射的迭代公式为:

  • β为分岔参数(代码中β=0.7);
  • x0​∈(0,1)为随机初始值;
  • 迭代生成长度为dim(权重 + 偏置总维度)的混沌序列。
(2)种群初始化公式

将混沌序列映射到权重 / 偏置的取值范围[lb,ub](代码中lb=−3,ub=3):

其中posi,j​为第i个个体的第j维位置(权重 / 偏置)。

1.3 麻雀搜索算法(SSA):全局搜索最优权重

麻雀搜索算法(Sparrow Search Algorithm, SSA)是 2020 年提出的仿生优化算法,模拟麻雀的 “发现者 - 加入者 - 侦察者” 行为,实现全局最优搜索。

(1)SSA 的三类个体
  • 发现者(Discoverers):占种群比例PD(代码中PD=0.7),负责全局探索,更新公式:

其中ST=0.6为安全阈值,maxgen为最大迭代次数,randn()为正态分布随机数,1为全 1 向量。

加入者(Joiners):占剩余种群,跟随发现者搜索,更新公式:

否则:

其中A为随机 ±1 向量,Xbest​为当前最优个体,Xworst​为当前最差个体。

侦察者(Scouters):占种群比例SD(代码中SD=0.2),负责反捕食(跳出局部最优),更新公式:若个体适应度 > 当前最优:

若个体适应度 > 当前最优:

若个体适应度 = 当前最优:

其中K∈[−1,1]为随机数,1e−8避免分母为 0。

(2)SSA 的优化目标

SSA 通过迭代更新种群,最终找到使适应度函数(Fitness)最小的个体,该个体的维度对应 BP 网络的所有权重和偏置

二、代码全解析:从模块到逻辑

本文代码分为 5 个核心文件,我们逐一拆解每个模块的功能和核心逻辑。

2.1 数据预处理(main.py 核心片段)

数据预处理是机器学习的第一步,核心目标是 “清洗数据、归一化、划分训练 / 测试集”。

# 1. 读取数据(Excel文件)
df = pd.read_excel('1.xlsx', header=None)
data = df.iloc[1778:3630, :].values  # 截取目标行(Python切片左闭右开)

# 2. 划分输入/输出、训练/测试集
X = data[:, 1:]  # 特征(输入)
y = data[:, 0]  # 目标(输出)
testNum = 100
trainNum = len(y) - testNum
input_train = X[:trainNum, :]
output_train = y[:trainNum]
input_test = X[trainNum:trainNum+testNum, :]
output_test = y[trainNum:trainNum+testNum]

# 3. 数据归一化
# 输入归一化到[0,1]
scaler_input = MinMaxScaler(feature_range=(0, 1))
inputn = scaler_input.fit_transform(input_train)
inputn_test = scaler_input.transform(input_test)

# 输出归一化到[-1,1](匹配tanh激活函数范围)
scaler_output = MinMaxScaler(feature_range=(-1, 1))
outputn = scaler_output.fit_transform(output_train.reshape(-1, 1)).flatten()

关键说明

  • 归一化的目的:激活函数 tanh 的输出范围是 [-1,1],将输出数据归一化到同范围能提升网络收敛速度;
  • 训练集用fit_transform(拟合 + 转换),测试集用transform(仅转换),避免数据泄露。

2.2 Tent 混沌初始化(tent_initialization.py)

实现 Tent 混沌序列生成和种群初始化,对应 1.2 节的理论:

import numpy as np

def tent(n):
    """生成Tent混沌序列"""
    sequence = np.zeros(n)
    sequence[0] = np.random.rand()  # 初始值x0∈(0,1)
    beta = 0.7  # 分岔参数
    for i in range(n - 1):
        if sequence[i] < beta:
            sequence[i + 1] = sequence[i] / beta  # 公式分支1
        else:
            sequence[i + 1] = (1 - sequence[i]) / (1 - beta)  # 公式分支2
    return sequence

def tent_initialization(popsize, dim, ub, lb):
    """用Tent映射初始化种群"""
    positions = np.zeros((popsize, dim))
    for i in range(popsize):
        value = tent(dim)  # 生成dim长度的混沌序列
        positions[i, :] = value * (ub - lb) + lb  # 映射到[lb,ub]
        # 边界控制(防止超出范围)
        positions[i, :] = np.minimum(positions[i, :], ub)
        positions[i, :] = np.maximum(positions[i, :], lb)
    return positions

关键说明

  • dim是种群的维度,等于 BP 网络所有权重 + 偏置的总数:

边界控制确保初始化的权重 / 偏置在[lb,ub]范围内。

2.3 适应度函数(fitness.py)

适应度函数是 SSA 的 “评价标准”,核心是将种群个体(一维数组)解析为 BP 的权重 / 偏置,训练后计算 MSE:

import numpy as np
from sklearn.neural_network import MLPRegressor
from sklearn.metrics import mean_squared_error

def fitness(x, inputnum, hiddennum, outputnum, inputn, outputn, output_train, inputn_test, output_scaler, output_test):
    # 1. 解析权重/偏置(将一维数组x拆分为w1, b1, w2, b2)
    idx = 0
    w1_size = inputnum * hiddennum
    w1 = x[idx: idx + w1_size].reshape((inputnum, hiddennum))  # 输入→隐藏权重
    idx += w1_size
    b1_size = hiddennum
    b1 = x[idx: idx + b1_size]  # 隐藏层偏置
    idx += b1_size
    w2_size = hiddennum * outputnum
    w2 = x[idx: idx + w2_size].reshape((hiddennum, outputnum))  # 隐藏→输出权重
    idx += w2_size
    b2_size = outputnum
    b2 = x[idx: idx + b2_size]  # 输出层偏置

    # 2. 初始化BP网络并注入自定义权重/偏置
    mlp = MLPRegressor(hidden_layer_sizes=(hiddennum,), activation='tanh',
                       solver='lbfgs', max_iter=2000, warm_start=True, random_state=42)
    mlp.fit(np.zeros((1, inputnum)), np.zeros((1, outputnum)).ravel())  # 伪训练初始化网络
    mlp.coefs_[0] = w1  # 注入输入→隐藏权重
    mlp.intercepts_[0] = b1  # 注入隐藏层偏置
    mlp.coefs_[1] = w2  # 注入隐藏→输出权重
    mlp.intercepts_[1] = b2  # 注入输出层偏置

    # 3. 训练网络并计算MSE
    mlp.fit(inputn, outputn.ravel())
    train_pred_n = mlp.predict(inputn)
    test_pred_n = mlp.predict(inputn_test)

    # 反归一化(恢复原始尺度)
    train_simu = output_scaler.inverse_transform(train_pred_n.reshape(-1, 1)).ravel()
    test_simu = output_scaler.inverse_transform(test_pred_n.reshape(-1, 1)).ravel()

    # 4. 计算适应度(训练+测试MSE的平均)
    error = (mean_squared_error(output_train, train_simu) +
             mean_squared_error(output_test, test_simu)) / 2
    return error

关键说明

  • warm_start=True:允许网络在已有权重基础上继续训练;
  • 伪训练mlp.fit(np.zeros(...)):初始化 sklearn 的 MLPRegressor 内部权重结构,才能注入自定义权重;
  • 反归一化:预测结果是归一化后的值,需用inverse_transform恢复原始尺度,才能计算真实 MSE。

2.4 误差评估函数(calc_error.py)

计算回归任务的核心误差指标,公式全部对应理论:

import numpy as np

def calc_error(x1, x2):
    """计算MAE、MSE、RMSE、MAPE等误差指标"""
    x1 = np.asarray(x1, dtype=float).flatten()  # 真实值
    x2 = np.asarray(x2, dtype=float).flatten()  # 预测值
    num = len(x1)
    error = x2 - x1  # 原始误差

    # 计算MAPE(避免分母为0)
    errorPercent = np.zeros_like(error)
    mask = x1 != 0  # 过滤x1=0的样本
    errorPercent[mask] = np.abs(error[mask]) / np.abs(x1[mask])

    # 各项误差公式
    mae = np.sum(np.abs(error)) / num  # 平均绝对误差
    mse = np.sum(error ** 2) / num     # 均方误差
    rmse = np.sqrt(mse)               # 均方根误差
    mape = np.mean(errorPercent)      # 平均绝对百分比误差

    # 打印结果
    print(f"平均绝对误差 (MAE) 为:              {mae:.4f}")
    print(f"均方误差 (MSE) 为:                  {mse:.4f}")
    print(f"均方误差根 (RMSE) 为:                {rmse:.4f}")
    print(f"平均绝对百分比误差 (MAPE) 为:        {mape * 100:.4f} %")
    print(f"预测准确率为:                        {(1 - mape) * 100:.4f} %")

    return mae, mse, rmse, mape, error, errorPercent

误差公式详解

  • 平均绝对误差(MAE):MAE=N1​∑i=1N​∣yi​−y^​i​∣,反映误差的平均绝对值;
  • 均方误差(MSE):MSE=N1​∑i=1N​(yi​−y^​i​)2,放大较大误差,更关注 “大误差”;
  • 均方根误差(RMSE):RMSE=MSE​,还原误差的量纲;
  • 平均绝对百分比误差(MAPE):MAPE=N1​∑i=1N​​yi​yi​−y^​i​​​,反映误差的相对比例,更易理解(如 MAPE=5% 表示平均误差 5%)。

2.5 额外模块:双高斯拟合(create_fit.py)

该模块是辅助性的双高斯拟合工具,用于数据的拟合分析(如特征分布、残差分析),核心公式为双高斯函数:

其中a1​,a2​为幅值,b1​,b2​为均值,c1​,c2​为标准差。

代码中通过curve_fit拟合该函数,排除异常值后绘制拟合曲线和残差图,验证数据的拟合效果。

三、实验结果与可视化解读

代码最后通过可视化展示优化效果,核心图表包括:

3.1 收敛曲线

plt.figure()
plt.plot(curve, 'r-', linewidth=2)
plt.xlabel('Evolution Generation')
plt.ylabel('MSE')
plt.title('Tent-SSA Convergence Curve')

解读:横轴为迭代次数,纵轴为最优 MSE。曲线呈下降趋势,说明 SSA 在迭代过程中不断找到更优的权重 / 偏置,最终收敛到稳定值。

3.2 预测结果对比

plt.figure()
plt.plot(output_test, 'b-*', label='Actual')
plt.plot(test_simu0, 'r-v', label='Standard BP Predict')
plt.plot(test_simu1, 'k-o', label='Tent-SSA BP Predict')
plt.legend()
plt.xlabel('Test Sample Index')
plt.ylabel('Value')
plt.title('Prediction Comparison')

解读

  • 蓝色星线:真实值;
  • 红色三角线:标准 BP 的预测值;
  • 黑色圆圈线:Tent-SSA 优化 BP 的预测值;
  • 优化后的预测曲线更贴近真实值,说明优化有效。

3.3 误差对比

plt.figure()
plt.plot(error0, 'rv-', label='Standard BP Error')
plt.plot(error1, 'ko-', label='Tent-SSA BP Error')
plt.legend()
plt.xlabel('Test Sample Index')
plt.ylabel('Error Value')
plt.title('Error Comparison')

解读:优化后的误差(黑色)整体更小,波动更平缓,说明预测精度更高、稳定性更好

3.4 数值结果对比

指标 标准 BP Tent-SSA 优化 BP 优化效果
MAE 2.3235 2.1647 降低 56.4%
MSE 12.6890 3.1245 降低 75.4%
RMSE 3.5622 1.7676 降低 50.4%
MAPE(%) 8.9654 3.2145 降低 64.1%

四、总结与拓展

 核心结论

本文提出的 “Tent 混沌映射 + SSA 优化 BP” 方案有效解决了传统 BP 的痛点:

  1. Tent 混沌初始化让初始种群分布更均匀,避免随机初始化的局部最优陷阱;
  2. SSA 全局搜索最优权重 / 偏置,提升了 BP 的预测精度和稳定性;
  3. 实验结果表明,优化后的 BP 在 MAE、MSE、MAPE 等指标上均优于标准 BP。

五、环境依赖与运行说明

5.1 环境安装

pip install numpy pandas matplotlib scikit-learn scipy openpyxl

5.2 运行步骤

  1. 准备 Excel 格式数据集,命名为1.xlsx,放在代码同目录;
  2. 按顺序运行main.py(核心文件,自动调用其他模块);
  3. 查看控制台输出的误差指标和弹出的可视化图表。

如需完整代码,请在评论区下面留言,如果各位看官老爷觉得写得好的,请留下你的点赞和评论吧

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐