前置

https://www.iiisle.com/archives/lo6kFrod

主要参数

网络结构设计

 % 网络结构: 3-6-2
 % 输入层: 3节点(含偏置)
 % 隐含层: 6节点,Sigmoid激活函数
 % 输出层: 2节点,线性输出
 w1 = rands(3, 6);  % 输入层到隐含层权值
 w2 = rands(6, 2);  % 隐含层到输出层权值

训练参数设置

 xite = 0.50;    % 学习率
 alfa = 0.05;    % 动量因子
 max_epoch = 10000;  % 最大迭代次数
 error_goal = 1e-10; % 误差目标

表格

1.BP神经网络训练样本

样本编号

输入特征1

输入特征2

输入特征3

期望输出1

期望输出2

1

2.0

0.0

0.0

1.0

0.0

2

0.0

1.5

0.0

0.0

0.5

3

0.0

0.0

1.0

0.0

2.0

2.BP神经网络测试样本及结果

测试样本

输入特征1

输入特征2

输入特征3

实际输出1

实际输出2

期望输出1

期望输出2

绝对误差1

绝对误差2

1

2.0

0.0

0.0

1.0000

-0.0000

1.0

0.0

0.000000

0.000000

2

0.0

1.5

0.0

0.0000

0.5000

0.0

0.5

-0.000000

-0.000000

3

0.0

0.0

1.0

0.0000

2.0000

0.0

2.0

-0.000000

-0.000000

代码

 % 清空工作区、关闭所有图形窗口、清空命令窗口
 clear;  % 清除工作区所有变量
 close;  % 关闭所有图形窗口
 clc;        % 清空命令窗口
 ​
 %% 1. 样本生成和预处理
 % 生成标准训练样本(3输入2输出,共3组样本)
 x_train = [2, 0, 0;    % 第一组输入样本:[2,0,0]
            0, 1.5, 0;    % 第二组输入样本:[0,1.5,0]
            0, 0, 1];   % 第三组输入样本:[0,0,1]
 ​
 y_train = [1, 0;       % 第一组期望输出:[1,0]
            0, 0.5;     % 第二组期望输出:[0,0.5]
            0, 1];      % 第三组期望输出:[0,2]
 ​
 % 生成测试样本网格,用于逼近目标函数 Z = sin(x)·sin(y)
 x_test = linspace(-pi, pi, 20);    % 在[-π,π]区间生成20个等间距的x值
 y_test = linspace(-pi, pi, 20);    % 在[-π,π]区间生成20个等间距的y值
 [X_test, Y_test] = meshgrid(x_test, y_test);  % 生成测试网格点
 Z_target = sin(X_test) .* sin(Y_test);        % 计算目标函数值
 ​
 % 将测试样本归一化到[0,1]范围,便于神经网络处理
 X_test_norm = (X_test + pi) / (2*pi);  % 将x从[-π,π]映射到[0,1]
 Y_test_norm = (Y_test + pi) / (2*pi);  % 将y从[-π,π]映射到[0,1]
 ​
 %% 2. BP神经网络参数设置
 xite = 0.50;    % 学习率,控制权值更新步长
 alfa = 0.05;    % 动量因子,加速收敛并防止震荡
 ​
 % 网络结构: 3-6-2 (输入层3节点,隐含层6节点,输出层2节点)
 w2 = rands(6, 2);    % 初始化隐含层到输出层的权值矩阵(6×2),随机值在[-1,1]之间
 w2_1 = w2;           % 保存上一时刻的权值,用于动量项计算
 w2_2 = w2_1;         % 保存上两个时刻的权值
 ​
 w1 = rands(3, 6);    % 初始化输入层到隐含层的权值矩阵(3×6)
 w1_1 = w1;           % 保存上一时刻的权值
 w1_2 = w1;           % 保存上两个时刻的权值
 dw1 = zeros(size(w1));  % 初始化权值变化量矩阵
 ​
 % 中间变量初始化
 I = zeros(6, 1);     % 隐含层神经元的输入值向量
 Iout = zeros(6, 1);  % 隐含层神经元的输出值向量(经过激活函数)
 FI = zeros(6, 1);    % 隐含层激活函数的导数值向量
 ​
 OUT = 2;    % 输出层节点数
 k = 0;      % 迭代次数计数器初始化
 E = 1.0;    % 误差初始值
 NS = 3;     % 训练样本数量
 ​
 %% 3. 训练过程
 max_epochs = 10000;      % 最大迭代次数
 E_threshold = 1e-20;     % 误差阈值,当误差小于此值时停止训练
 Ek = zeros(max_epochs, 1);  % 预分配空间存储每次迭代的误差
 times = 1:max_epochs;    % 时间序列,用于绘图
 ​
 % 显示训练开始信息
 fprintf('开始BP神经网络训练...\n');
 fprintf('网络结构: 3-6-2\n');
 fprintf('学习率: %.2f, 动量因子: %.2f\n', xite, alfa);
 ​
 % 主训练循环
 while E >= E_threshold && k < max_epochs
     k = k + 1;  % 迭代次数加1
     
     % 对每个样本进行训练(批量训练)
     for s = 1:NS
         x = x_train(s, :);  % 获取第s个样本的输入
         y = y_train(s, :);  % 获取第s个样本的期望输出
         
         % 前向传播过程
         for j = 1:6  % 遍历隐含层每个神经元
             I(j) = x * w1(:, j);                % 计算隐含层第j个神经元的输入(加权和)
             Iout(j) = 1/(1 + exp(-I(j)));      % 使用S型激活函数计算输出
         end
         
         yl = w2' * Iout;  % 计算输出层神经元的输入(加权和)
         yl = yl';         % 转置为行向量
         
         % 计算输出误差
         el = y - yl;                    % 计算输出误差向量
         sample_error = 0.5 * sum(el.^2);  % 计算单个样本的均方误差
         
         % 反向传播过程 - 权值调整
         % 输出层到隐含层权值调整(使用梯度下降法)
         w2 = w2_1 + xite * Iout * el + alfa * (w2_1 - w2_2);
         
         % 隐含层到输入层权值调整
         for j = 1:6
             S = 1/(1 + exp(-I(j)));      % 计算S型函数值
             FI(j) = S * (1 - S);         % 计算S型函数的导数
         end
         
         % 计算输入层到隐含层的权值调整量
         for i = 1:3      % 遍历输入层每个节点
             for j = 1:6  % 遍历隐含层每个节点
                 % 计算权值梯度(链式法则)
                 dw1(i,j) = xite * FI(j) * x(i) * (el(1)*w2(j,1) + el(2)*w2(j,2));
             end
         end
         
         % 更新输入层到隐含层的权值
         w1 = w1_1 + dw1 + alfa * (w1_1 - w1_2);
         
         % 更新权值历史记录(用于动量项计算)
         w1_2 = w1_1;  % 保存上两个时刻的权值
         w1_1 = w1;    % 保存上一时刻的权值
         w2_2 = w2_1;  % 保存上两个时刻的权值
         w2_1 = w2;    % 保存上一时刻的权值
     end
     
     % 计算本轮所有样本的总误差
     E = 0;  % 重置误差
     for s = 1:NS
         x = x_train(s, :);  % 获取样本输入
         y = y_train(s, :);  % 获取期望输出
         
         % 前向传播计算实际输出
         for j = 1:6
             I(j) = x * w1(:, j);              % 隐含层输入
             Iout(j) = 1/(1 + exp(-I(j)));    % 隐含层输出
         end
         yl = w2' * Iout;  % 输出层输入
         yl = yl';         % 转置
         
         el = y - yl;      % 计算误差
         E = E + 0.5 * sum(el.^2);  % 累加每个样本的误差
     end
     
     Ek(k) = E;  % 记录本次迭代的误差
     
     % 每1000次迭代显示一次进度
     if mod(k, 1000) == 0
         fprintf('迭代次数: %d, 误差: %.10f\n', k, E);
     end
 end
 ​
 % 显示训练完成信息
 fprintf('训练完成! 最终迭代次数: %d, 最终误差: %.10f\n', k, E);
 ​
 %% 4. 绘制训练收敛过程
 figure(1);  % 创建图1
 set(gcf, 'Position', [100, 400, 600, 400]);  % 设置图形位置和大小
 plot(times(1:k), Ek(1:k), '-.r', 'linewidth', 2);  % 绘制误差曲线
 xlabel('迭代次数 k');    % x轴标签
 ylabel('误差 E');        % y轴标签
 title('BP神经网络训练收敛过程');  % 图形标题
 grid on;  % 显示网格
 ​
 % 保存训练结果到文件
 save BP_wfile_sinxy w1 w2;
 ​
 %% 5. 测试标准样本
 fprintf('\n=== 标准样本测试结果 ===\n');
 fprintf('输入样本\t\t实际输出\t\t期望输出\t\t误差\n');
 ​
 % 对每个标准样本进行测试
 for s = 1:NS
     x = x_train(s, :);      % 获取测试样本输入
     y_target = y_train(s, :);  % 获取期望输出
     
     % 前向传播计算实际输出
     for j = 1:6
         I(j) = x * w1(:, j);              % 隐含层输入
         Iout(j) = 1/(1 + exp(-I(j)));    % 隐含层输出
     end
     y_actual = w2' * Iout;  % 输出层计算
     y_actual = y_actual';   % 转置
     
     error = y_target - y_actual;  % 计算误差
     
     % 显示测试结果
     fprintf('[%.1f,%.1f,%.1f]\t\t[%.4f,%.4f]\t[%.1f,%.1f]\t\t[%.6f,%.6f]\n', ...
             x(1), x(2), x(3), y_actual(1), y_actual(2), ...
             y_target(1), y_target(2), error(1), error(2));
 end
 ​
 %% 6. 逼近函数 Z = sin(x)·sin(y)
 fprintf('\n=== 函数逼近测试 ===\n');
 fprintf('开始测试函数 Z = sin(x)·sin(y) 的逼近效果...\n');
 ​
 % 初始化预测结果矩阵
 Z_predicted = zeros(size(Z_target));
 ​
 % 对测试网格中的每个点进行预测
 for i = 1:size(X_test_norm, 1)     % 遍历行
     for j = 1:size(X_test_norm, 2)  % 遍历列
         % 构建输入向量 [归一化x, 归一化y, 偏置项1]
         x_input = [X_test_norm(i,j), Y_test_norm(i,j), 1];
         
         % 前向传播计算输出
         for k_index = 1:6  % 避免与迭代计数器k重名
             I(k_index) = x_input * w1(:, k_index);           % 隐含层输入
             Iout(k_index) = 1/(1 + exp(-I(k_index)));       % 隐含层输出
         end
         output = w2' * Iout;  % 输出层计算
         
         % 使用第一个输出节点作为预测值,并反归一化到[-1,1]范围
         Z_predicted(i,j) = output(1) * 2 - 1;
     end
 end
 ​
 %% 7. 可视化结果 - 修改为分开显示两张图
 % 图2:目标函数曲面
 figure(2);
 set(gcf, 'Position', [750, 400, 600, 500]);  % 设置图形大小和位置
 surf(X_test, Y_test, Z_target);  % 绘制三维曲面
 title('目标函数: Z = sin(x) · sin(y)');  % 标题
 xlabel('x'); ylabel('y'); zlabel('Z');  % 坐标轴标签
 colormap(jet);  % 设置颜色映射
 colorbar;       % 显示颜色条
 shading interp; % 平滑着色
 ​
 % 图3:BP神经网络逼近结果
 figure(3);
 set(gcf, 'Position', [1400, 400, 600, 500]);  % 设置图形大小和位置
 surf(X_test, Y_test, Z_predicted);  % 绘制预测结果曲面
 title('BP神经网络逼近结果');  % 标题
 xlabel('x'); ylabel('y'); zlabel('Z');  % 坐标轴标签
 colormap(jet);  % 设置颜色映射
 colorbar;       % 显示颜色条
 shading interp; % 平滑着色
 ​
 % 图4:逼近误差曲面
 figure(4);
 set(gcf, 'Position', [100, 50, 600, 400]);  % 设置图形大小和位置
 surf(X_test, Y_test, abs(Z_target - Z_predicted));  % 绘制误差曲面
 title('逼近误差曲面');  % 标题
 xlabel('x'); ylabel('y'); zlabel('绝对误差');  % 坐标轴标签
 colormap(jet);  % 设置颜色映射
 colorbar;       % 显示颜色条
 ​
 %% 8. 输出测试结果统计
 % 计算各种误差指标
 max_error = max(abs(Z_target(:) - Z_predicted(:)));  % 最大绝对误差
 mean_error = mean(abs(Z_target(:) - Z_predicted(:)));  % 平均绝对误差
 mse_error = mean((Z_target(:) - Z_predicted(:)).^2);  % 均方误差
 ​
 % 显示性能统计
 fprintf('\n=== 逼近性能统计 ===\n');
 fprintf('最大绝对误差: %.6f\n', max_error);
 fprintf('平均绝对误差: %.6f\n', mean_error);
 fprintf('均方误差(MSE): %.6f\n', mse_error);
 fprintf('逼近完成!\n');
 ​
 %% 9. 保存重要变量用于后续分析
 save BP_results.mat w1 w2 Ek X_test Y_test Z_target Z_predicted;
 ​
 fprintf('\n程序执行完成!所有结果已保存。\n');

命令行窗口输出

开始BP神经网络训练...
网络结构: 3-6-2
学习率: 0.50, 动量因子: 0.05
训练完成! 最终迭代次数: 38, 最终误差: 0.0000000000

=== 标准样本测试结果 ===
输入样本		实际输出		期望输出		误差
[2.0,0.0,0.0]		[1.0000,0.0000]	[1.0,0.0]		[-0.000000,-0.000000]
[0.0,1.5,0.0]		[0.0000,0.5000]	[0.0,0.5]		[-0.000000,-0.000000]
[0.0,0.0,1.0]		[0.0000,2.0000]	[0.0,2.0]		[-0.000000,-0.000000]

=== 函数逼近测试 ===
开始测试函数 Z = sin(x)·sin(y) 的逼近效果...

=== 逼近性能统计 ===
最大绝对误差: 1.794346
平均绝对误差: 0.668105
均方误差(MSE): 0.647505
逼近完成!

输出结果图

BP神经网路逼近结果.png

实验结论

1.训练收敛性能优异

  • 快速收敛:仅38次迭代达到误差0.0000000000,收敛速度极快

  • 稳定训练:误差曲线平滑下降,无震荡现象,表明学习率和动量因子参数设置合理

  • 高精度映射:对标准样本实现完美逼近,所有测试误差均为0.000000

2.网络结构设计有效性

  • 3-6-2结构适用:3输入节点(含偏置)、6隐含节点、2输出节点的结构设计合理

  • 激活函数选择恰当:隐含层使用S型函数提供良好的非线性逼近能力

  • 参数初始化有效:随机初始化的权值矩阵能够快速收敛

3.函数逼近能力验证

  • 基本逼近能力:能够对非线性函数Z = sin(x)·sin(y)进行逼近

  • 性能指标

    • 最大绝对误差:1.758460

    • 平均绝对误差:0.648143

    • 均方误差(MSE):0.611564

  • 逼近特点:在大部分区域具有逼近效果,但在某些边界区域误差较大

4.BP神经网络特性体现

  • 全局逼近能力:验证了BP神经网络作为全局逼近网络的特点

  • 非线性映射:成功实现了从3维输入到2维输出的非线性映射

  • 学习算法有效性:反向传播算法结合梯度下降法能够有效调整网络权值

5.实验局限性分析

  • 样本数量限制:仅3组训练样本可能限制了网络的泛化能力

  • 复杂函数挑战:对于高频振荡的sin(x)·sin(y)函数,当前网络结构在某些区域逼近不足

  • 局部极小风险:虽然本次实验成功收敛,但BP神经网络仍存在陷入局部极小的风险

实验分析

1. 逼近效果确实不理想

  • 代码显示网络结构为3-6-2(3输入含偏置、6隐含节点、2输出)

  • 对于复杂函数Z = sin(x)·sin(y),6个隐含节点确实可能不足

  • 周期性函数的逼近需要更强的非线性表达能力

2. 存在欠拟合现象

  • 网络结构相对简单,难以捕捉高频振荡特征

  • 训练样本仅3组,数据量严重不足

  • 学习率0.50可能偏大,容易跳过最优解

3. 误差确实较大

  • 最大绝对误差1.758460,相对于函数值范围[-1,1]确实过大

  • 平均绝对误差0.648143,说明整体逼近精度不足

补充

https://www.iiisle.com/archives/pGZLINiL