【实战篇】神经网络在回归任务中的应用

文章目录

    • [1. 任务目标](#1. 任务目标)
    • [2. 数据描述与预处理](#2. 数据描述与预处理)
      • [2.1 数据描述:](#2.1 数据描述:)
      • [2.2 数据划分](#2.2 数据划分)
    • [3. 研究方法与模型](#3. 研究方法与模型)
      • [3.1 整体研究流程](#3.1 整体研究流程)
      • [3.2 对比模型介绍](#3.2 对比模型介绍)
      • [3.3 评估指标](#3.3 评估指标)
    • [4. 结果与分析](#4. 结果与分析)
      • [4.1 模型性能对比](#4.1 模型性能对比)
      • [4.2 模型拟合效果可视化](#4.2 模型拟合效果可视化)
    • [5. 神经网络参数对泛化能力的影响](#5. 神经网络参数对泛化能力的影响)
      • [5.1 学习率的影响](#5.1 学习率的影响)
      • [5.2 网络结构深度的影响](#5.2 网络结构深度的影响)
      • [5.3 激活函数的影响](#5.3 激活函数的影响)
    • [6. 总结与讨论](#6. 总结与讨论)
    • 附录:完整代码

1. 任务目标

已知仿真数据集:

复制代码
n_samples = 500
x = 8 * np.random.rand(n_samples, 1) - 8  # 范围:-8到0
y_true = 0.5 * x ** 2 - 2 * x + 1
noise = 0.5 * np.random.randn(n_samples, 1)
y = y_true + noise

采用线性回归、多项式回归、神经网络进行回归预测,比较三者的泛化能力,同时研究神经网络参数对泛化能力的影响。

任务分析:该任务是机器学习-监督学习-回归。

2. 数据描述与预处理

2.1 数据描述:

  • 规模:共500个样本点。
  • 关系yx 之间存在确定的二次函数关系 y = 0.5x² - 2x + 1
  • 噪声:添加了标准差为0.5的加性高斯白噪声,模拟现实数据中的不确定性。

2.2 数据划分

采用train_test_split函数,按7:3的比例随机划分训练集和测试集,并固定随机种子(random_state=42)以保证每次划分一致。

python 复制代码
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=42)

3. 研究方法与模型

3.1 整体研究流程

本文遵循标准的机器学习建模流程,如下图所示:

主要包括训练推理评估三个阶段,形成一个完整的闭环。

3.2 对比模型介绍

本文构建了三个对比模型:

  1. 线性回归 (Linear Regression) : 直接拟合 y = w * x + b,作为性能基线。
  2. 二次多项式回归 (Polynomial Regression) : 通过特征工程,将特征变换为 [1, x, x²],再用线性回归拟合。其形式与数据真实生成函数一致,预期能获得极佳性能。
  3. 神经网络回归 (Neural Network Regression) : 使用多层感知机(MLP)。为提升训练稳定性,在输入前加入了StandardScaler进行标准化。基础网络结构为三层隐藏层(50, 30, 10),使用ReLU激活函数和Adam优化器。

模型定义如下:

python 复制代码
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
from sklearn.neural_network import MLPRegressor
from sklearn.pipeline import Pipeline

models = {
    '线性回归': LinearRegression(),
    '二次多项式回归': Pipeline([
        ('poly', PolynomialFeatures(degree=2)),
        ('linear', LinearRegression())
    ]),
    '神经网络回归': Pipeline([
        ('scaler', StandardScaler()),
        ('mlp', MLPRegressor(hidden_layer_sizes=(50, 30, 10),
                             activation='relu',
                             solver='adam',
                             alpha=0.1,
                             learning_rate_init=0.01,
                             max_iter=1000,
                             random_state=42,
                             early_stopping=True,
                             validation_fraction=0.1))
    ])
}

3.3 评估指标

采用均方误差 (MSE) 和决定系数 (R²) 作为模型性能的评估指标。

  • 均方误差 (MSE): 衡量预测值与真实值之间的平均平方误差,值越小越好。
  • 决定系数 (R²): 表示模型对数据方差解释的比例,取值范围为(-∞, 1],越接近1说明模型拟合越好。

4. 结果与分析

4.1 模型性能对比

在相同的数据集上训练并评估三个模型,结果如下表所示:

模型 训练集 R² 测试集 R² 训练集 MSE 测试集 MSE
线性回归 0.9699 0.9715 5.8421 5.8001
二次多项式回归 0.9985 0.9990 0.2843 0.2041
神经网络回归 0.9967 0.9970 0.6487 0.6088

结论

  1. 二次多项式回归在测试集上取得了最佳的R²(0.9985)和最低的MSE(0.2041),这与预期完全相符,因为它完美匹配了数据的真实内在结构。
  2. 神经网络回归表现优异,其测试集R²(0.9967)非常接近多项式回归,展现了强大的非线性拟合能力。
  3. 线性回归性能显著落后,其测试集R²仅为0.9699,这清晰地证明了其无法有效拟合非线性关系。

4.2 模型拟合效果可视化

下图直观展示了各模型在训练集和测试集上的拟合曲线:

  • 线性回归:只能拟合一条直线,对数据中的弯曲模式无能为力。
  • 二次多项式回归:拟合出的抛物线与数据分布高度吻合。
  • 神经网络回归:拟合出的曲线平滑且几乎与二次曲线重叠,表明其成功学习到了数据的底层规律。

5. 神经网络参数对泛化能力的影响

神经网络性能高度依赖其超参数设置。本节通过控制变量法进行消融实验,探究关键参数的影响。

5.1 学习率的影响

学习率控制参数更新的步长。固定其他参数,调整学习率learning_rate_init,结果如下:

学习率 训练集 R² 测试集 R² 训练集 MSE 测试集 MSE
1 -0.9574 -0.8049 380.0632 367.5347
0.1 0.9980 0.9984 0.3802 0.3257
0.01 0.9971 0.9975 0.5565 0.5040
0.001 0.9960 0.9964 0.7810 0.7281
0.0001 0.9924 0.9927 1.4756 1.4765

分析

  • 学习率过大(=1):模型完全无法收敛,损失值巨大,R²为负,说明预测比使用均值还差。
  • 学习率适中(=0.1):模型快速收敛至最优性能附近,表现最佳。
  • 学习率过小(=0.0001):收敛速度极慢,在有限迭代次数内未能达到最优,性能下降。同时,过小的学习率会增加训练时间成本。

结论:学习率是神经网络训练中最关键的参数之一,需要谨慎选择。

5.2 网络结构深度的影响

网络结构(隐藏层数与每层神经元数)决定了模型的容量。固定学习率为0.01,调整hidden_layer_sizes

网络结构 训练集 R² 测试集 R² 训练集 MSE 测试集 MSE
(10) 0.9888 0.9900 2.1821 2.0379
(20, 10) 0.9964 0.9966 0.7055 0.6989
(30, 20, 10) 0.9978 0.9981 0.4362 0.3852
(40, 30, 20, 10) 0.9972 0.9974 0.5369 0.5194

分析

  • 网络过浅(10):模型容量不足(欠拟合),无法充分捕捉数据的全部复杂性,性能最差。
  • 网络加深(20,10) -> (30,20,10):随着容量增加,模型拟合能力增强,性能提升。
  • 网络过深(40,30,20,10):性能并未继续提升,反而略有下降。更深的网络需要更精细的调参(如降低学习率、调整优化策略)以防止优化困难,同时也增加了计算开销和过拟合风险。

结论:网络结构并非越深越好,需要匹配任务复杂度。一个"中等"深度的网络在本任务中取得了最佳权衡。

5.3 激活函数的影响

激活函数为网络引入非线性。固定网络结构为(30,20,10)和学习率0.01,比较不同激活函数:

激活函数 训练集 R² 测试集 R² 训练集 MSE 测试集 MSE
relu 0.9978 0.9981 0.4362 0.3852
tanh 0.9963 0.9967 0.7116 0.6768
logistic (sigmoid) 0.9591 0.9551 7.9322 9.1399

分析

  • ReLU:表现最好,其稀疏激活特性有利于梯度传播和优化。
  • Tanh:性能稍逊于ReLU,但仍可有效工作。
  • Sigmoid:性能显著下降。Sigmoid函数在两端梯度饱和,容易导致梯度消失,使得深层网络训练困难。

结论:激活函数对模型性能有显著影响。ReLU因其简单有效,已成为大多数前馈网络的首选。更换激活函数通常需要重新调整学习率等配套参数。

6. 总结与讨论

  1. 模型选择 :对于已知形式 的非线性关系(如本例的二次关系),对应的多项式回归是最直接、高效且解释性强的选择,它能达到近乎完美的拟合。线性回归则因模型偏差过大而不适用。

  2. 神经网络的潜力与挑战 :通过适当调参,神经网络能够逼近多项式回归的性能,这证明了其强大的通用近似能力 。然而,这种能力是以复杂的调参过程为代价的。其性能对学习率、网络结构、激活函数等超参数非常敏感。

  3. 调参启示

    • 学习率是首要调优参数,需在"收敛速度"和"稳定性"之间取得平衡。
    • 网络结构应从简单开始逐步增加复杂度,直到验证集性能不再显著提升,避免不必要的过参数化。
    • 激活函数推荐首选ReLU及其变体(不同的任务需要根据实际的实验结果去选择)。更换激活函数往往需要重新调整学习率。
  4. 泛化能力 :在本实验中,二次多项式回归和调优后的神经网络在测试集上均表现优异,且训练集与测试集误差接近,表明两者均具有良好的泛化能力。神经网络的强大之处在于,对于形式未知的复杂非线性关系,它可能是更优甚至唯一可行的选择。

附录:完整代码

以下为实现本研究所有分析的完整Python代码,适用于Jupyter Notebook或脚本环境。

复制代码
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.neural_network import MLPRegressor
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.preprocessing import StandardScaler
import warnings
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False

warnings.filterwarnings('ignore')


# 设置随机种子以确保可重复性
np.random.seed(52)  # 设置numpy的随机种子为52,确保numpy相关的随机操作可重复

# 1. 生成数据
print("=== 生成数据 ===")
n_samples = 500
x = 8 * np.random.rand(n_samples, 1) - 8  # 范围:-8到0
y_true = 0.5 * x ** 2 - 2 * x + 1
noise = 0.5 * np.random.randn(n_samples, 1)
y = y_true + noise

# 2. 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(
    x, y, test_size=0.3, random_state=42
)
# 创建模型
models = {
    '线性回归': LinearRegression(),
    '二次多项式回归': Pipeline([
        ('poly', PolynomialFeatures(degree=2)),
        ('linear', LinearRegression())
    ]),
    '神经网络回归': Pipeline([
        ('scaler', StandardScaler()),
        ('mlp', MLPRegressor(
            hidden_layer_sizes=(30,20,10),
            activation='relu',
            solver='adam',
            alpha=0.1,
            learning_rate_init=0.001,
            max_iter=100000,  # 减少迭代次数以便观察
            random_state=42,
            early_stopping=True,
            validation_fraction=0.1,
            verbose=False
        ))
    ])
}
# 3. 训练和评估所有模型
results = {}
for name, model in models.items():
    #训练
    model.fit(x_train, y_train)
    #预测
    y_pred_train = model.predict(x_train) #训练集预测
    y_pred_test = model.predict(x_test) #测试集预测
    #计算误差
    mse_train = mean_squared_error(y_train, y_pred_train)
    mse_test = mean_squared_error(y_test, y_pred_test)
    r2_train = r2_score(y_train, y_pred_train)
    r2_test = r2_score(y_test, y_pred_test)

    # 保存结果
    results[name] = {
        'model': model,
        'y_pred_train': y_pred_train,
        'y_pred_test': y_pred_test,
        'mse_train': mse_train,
        'mse_test': mse_test,
        'r2_train': r2_train,
        'r2_test': r2_test
    }

    # 打印结果
    print(f"训练集MSE: {mse_train:.4f}")
    print(f"测试集MSE: {mse_test:.4f}")
    print(f"训练集R²: {r2_train:.4f}")
    print(f"测试集R²: {r2_test:.4f}")
    print()
# 4. 可视化比较
fig, axes = plt.subplots(2, 2, figsize=(16, 12))

# 4.1 原始数据
axes[0, 0].scatter(x_train, y_train, alpha=0.7, label='训练集', s=20)
axes[0, 0].scatter(x_test, y_test, alpha=0.7, label='测试集', s=20, marker='x')
axes[0, 0].set_xlabel('X',fontsize=25)
axes[0, 0].set_ylabel('y',fontsize=25)
axes[0, 0].set_title('原始数据分布',fontsize=30)
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

# 4.2-4.4 各模型拟合结果
colors = ['red', 'green', 'blue']
model_names = list(models.keys())

# 定义2x2网格的位置 (除了(0,0)之外的位置)
positions = [(0, 1), (1, 0), (1, 1)]

for idx, (name, color, pos) in enumerate(zip(model_names, colors, positions)):
    row, col = pos
    ax = axes[row, col]

    # 散点
    ax.scatter(x_train, y_train, alpha=0.3, s=10, label='训练集')
    ax.scatter(x_test, y_test, alpha=0.3, s=10, marker='x', label='测试集')

    # 为了画平滑曲线,生成密集的X值
    X_smooth = np.linspace(x.min(), x.max(), 300).reshape(-1, 1)
    y_smooth = results[name]['model'].predict(X_smooth)

    # 预测曲线
    ax.plot(X_smooth, y_smooth, color=color, linewidth=2,
            label=f'{name}\nR^2_test={results[name]["r2_test"]:.3f}')

    ax.set_xlabel('X',fontsize=25)
    ax.set_ylabel('y',fontsize=25)
    ax.set_title(f'{name}拟合结果',fontsize=30)
    ax.legend()
    ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 5. 模型性能对比表格
print("\n" + "=" * 60)
print("模型性能对比:")
print("=" * 60)
print(f"{'模型':<30} {'训练集R²':<12} {'测试集R²':<12} {'训练集MSE':<12} {'测试集MSE':<12}")
print("-" * 60)

best_model = None
best_r2 = -float('inf')

for name in model_names:
    r2_test = results[name]['r2_test']
    print(f"{name:<30} {results[name]['r2_train']:<12.4f} {r2_test:<12.4f} "
          f"{results[name]['mse_train']:<12.4f} {results[name]['mse_test']:<12.4f}")

> 推荐一个很通俗易懂的人工智能教程: 人工智能教程

相关推荐
AI2512242 小时前
主流AI视频生成工具技术测评对比:生成质量与性能分析
人工智能·音视频
laomocoder2 小时前
AI网关设计
人工智能·rust·系统架构
爱分享的阿Q2 小时前
VSCode1114-AI全面接管编辑器
人工智能·编辑器
嘿黑嘿呦2 小时前
17届蓝桥杯考前准备
算法·职场和发展·蓝桥杯
Q741_1472 小时前
每日一题 3740. 三个相等元素之间的最小距离 I 3741. 三个相等元素之间的最小距离 II 模拟 哈希表 C++ 题解
c++·算法·leetcode·模拟·数组·哈希表
橘子编程2 小时前
Hermes Agent 完整知识总结与使用教程
java·人工智能·ai·tomcat·maven·ai编程
PD我是你的真爱粉2 小时前
LangChain 与 LangGraph 完全指南:核心组件、架构原理、编排机制与 LlamaIndex 集成
算法·架构·langchain
珠海西格电力2 小时前
红区光伏与零碳园区:管理系统如何破解分布式光伏并网困局
大数据·人工智能·分布式·物联网·能源