当前位置: 首页 > news >正文

神经网络训练过程详解

神经网络训练过程详解

神经网络训练过程是一个动态的、迭代的学习过程,接下来基于一段代码展示模型是如何逐步学习数据规律的。

神经网络拟合二次函数:代码详解

下面将详细解释这段代码,它使用神经网络拟合一个带有噪声的二次函数 y = x² + 2x + 1

import torch
import numpy as np
import matplotlib.pyplot as plt# 1. 生成模拟数据
np.random.seed(22)  # 设置随机种子确保结果可重现
X = np.linspace(-5, 5, 100).reshape(-1,1)  # 创建100个点,范围-5到5
y_ = X**2 + 2* X + 1  # 二次函数:y = x² + 2x + 1
y = y_ + np.random.rand(100, 1) * 1.5  # 添加均匀分布噪声# 转换为PyTorch张量
X_tensor = torch.tensor(X, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.float32)# 打印数据信息
print("X 原类型:", type(X), " 形状:", X.shape)
print("X_tensor 类型:", type(X_tensor), " 形状:", X_tensor.shape)
print("\ny 原类型:", type(y), " 形状:", y.shape)
print("y_tensor 类型:", type(y_tensor), " 形状:", y_tensor.shape)
print("\nX_tensor 前 2 个元素:\n", X_tensor[:2])
print("y_tensor 前 2 个元素:\n", y_tensor[:2])

代码解析

1. 神经网络定义

import torch.nn as nnclass SimpleNN(nn.Module):def __init__(self):super(SimpleNN, self).__init__()# 定义三个全连接层self.layer1 = nn.Linear(1, 64)    # 输入层到隐藏层1 (1个特征->64个神经元)self.layer2 = nn.Linear(64, 128)  # 隐藏层1到隐藏层2 (64个神经元->128个神经元)self.layer3 = nn.Linear(128, 1)   # 隐藏层2到输出层 (128个神经元->1个输出)self.relu = nn.ReLU()             # ReLU激活函数def forward(self, x):# 前向传播过程(带激活函数)x = self.relu(self.layer1(x))  # 第一层后接ReLU激活x = self.relu(self.layer2(x))  # 第二层后接ReLU激活x = self.layer3(x)             # 输出层(无激活函数)return xdef forward_line(self, x):# 前向传播过程(不带激活函数)x = self.layer1(x)  # 无激活x = self.layer2(x)  # 无激活x = self.layer3(x)  # 输出层return x

网络结构详解

输入层(1个神经元) → [ReLU激活] → 隐藏层1(64个神经元) → [ReLU激活] → 隐藏层2(128个神经元) → 输出层(1个神经元)
  • 输入层:1个神经元,对应单个特征x
  • 隐藏层1:64个神经元,使用ReLU激活函数
  • 隐藏层2:128个神经元,使用ReLU激活函数
  • 输出层:1个神经元,无激活函数(回归问题)
  • 为什么需要多层和ReLU?:为了拟合非线性关系(二次函数)

2. 模型训练

import torch.optim as optim# 初始化模型、损失函数和优化器
model = SimpleNN()
criterion = nn.MSELoss()  # 均方误差损失(回归问题常用)
optimizer = optim.Adam(model.parameters(), lr=0.01)  # Adam优化器
epochs = 200  # 训练轮数# 训练循环
loss_history = []  # 记录损失变化
for epoch in range(epochs):# 前向传播outputs = model(X_tensor)loss = criterion(outputs, y_tensor)# 反向传播和优化optimizer.zero_grad()  # 清空梯度loss.backward()        # 反向传播计算梯度optimizer.step()       # 更新参数# 记录损失loss_history.append(loss.item())# 每50轮打印一次损失if(epoch + 1)%50 == 0:print(f'Epoch [{epoch + 1}/{epochs}], Loss: {loss.item():.4f}')

训练过程说明

  1. 前向传播:输入数据通过网络得到预测值
  2. 损失计算:比较预测值与真实值的差异(均方误差)
  3. 反向传播
    • zero_grad(): 清空之前的梯度
    • backward(): 计算新的梯度
  4. 参数更新step()使用梯度更新权重
  5. 损失记录:跟踪训练过程中的损失变化

3. 结果可视化

# 创建图表
plt.figure(figsize=(12,4))# 左图:训练损失曲线
plt.subplot(1,2,1)
plt.plot(loss_history)
plt.title('Training Loss')
plt.xlabel('Epochs')
plt.ylabel('MSE Loss')# 右图:预测结果对比
plt.subplot(1, 2, 2)
with torch.no_grad():  # 禁用梯度计算(预测时不需要)predictions = model(X_tensor).numpy()  # 获取预测值# 绘制三种数据:
plt.scatter(X, y, label='original data')  # 散点:带噪声的原始数据
plt.plot(X, y_, 'g--', label='True Relation', linewidth=4)  # 绿色虚线:真实二次函数
plt.plot(X, predictions, 'r--', label='prediction', linewidth=4)  # 红色虚线:神经网络预测plt.title('pre vs true')
plt.legend()  # 显示图例plt.tight_layout()
plt.show()

可视化解读

  1. 损失曲线:展示训练过程中损失值如何下降
  2. 预测对比
    • 散点:带噪声的原始数据
    • 绿色虚线:真实的二次函数 y = x² + 2x + 1
    • 红色虚线:神经网络预测的曲线

4. 模型保存与预测

# 1. 保存完整模型
torch.save(model, 'full_model.pth')# 2. 加载完整模型(无需提前定义模型结构)
loaded_model = torch.load('full_model.pth')
loaded_model.eval()  # 设置为评估模式(关闭dropout等)# 使用模型进行预测
new_data = torch.tensor([[3.0], [-2.5]], dtype=torch.float32)
predictions = loaded_model(new_data).detach().numpy()print("\nPrediction Examples:")
for x, pred in zip(new_data, predictions):# 计算真实值(注意:这里是二次函数,不是线性)true_value = x.item()**2 + 2 * x.item() + 1print(f"Input {x.item():.1f} -> Predicted: {pred[0]:.2f} | True: {true_value:.2f}")

模型保存与加载

  1. torch.save(model, 'full_model.pth'):保存整个模型结构+参数
  2. torch.load('full_model.pth'):加载完整模型
  3. model.eval():将模型设置为评估模式(影响dropout、batchnorm等层)

预测示例

  • 输入x=3.0:真实值=3² + 2×3 + 1 = 16.00
  • 输入x=-2.5:真实值=(-2.5)² + 2×(-2.5) + 1 = 2.25

代码关键点总结

  1. 数据生成

    • 创建二次函数 y = x² + 2x + 1
    • 添加均匀分布噪声模拟真实数据
  2. 网络结构

    • 深度网络(1-64-128-1)适合拟合非线性关系
    • 使用ReLU激活函数引入非线性能力
  3. 训练配置

    • 均方误差损失(MSE)适合回归问题
    • Adam优化器自动调整学习率
    • 200个训练轮次足够收敛
  4. 可视化

    • 损失曲线监控训练过程
    • 预测对比评估模型性能
  5. 模型部署

    • 保存和加载完整模型
    • 对新数据进行预测

为什么这个网络能拟合二次函数?

  1. 非线性激活函数:ReLU使网络能学习非线性关系
  2. 足够容量:两个隐藏层提供足够的表达能力
  3. 优化能力:Adam优化器有效调整参数
  4. 迭代训练:200轮训练使网络逐步逼近目标函数

这个示例展示了神经网络如何学习复杂的非线性关系,即使数据中存在噪声,网络也能捕捉到潜在的函数规律。

训练过程可视化

让我们通过一个动画来理解训练过程(想象以下动态变化):

Epoch 0:  损失: 35.42  | 预测线: 随机波动
Epoch 50: 损失: 2.65   | 预测线: 开始呈现线性趋势
Epoch 100:损失: 2.29   | 预测线: 接近真实关系但仍有偏差
Epoch 200:损失: 1.97   | 预测线: 几乎与真实关系重合
Epoch 500:损失: 1.97   | 预测线: 稳定在最优解附近

训练过程分步解析

1. 初始化阶段 (Epoch 0)

  • 权重和偏置随机初始化(通常使用正态分布或均匀分布)
  • 神经网络对数据一无所知
  • 预测结果完全随机
  • 损失值非常高(约35.42)

2. 早期训练阶段 (Epoch 1-50)

# 第一次迭代
outputs = model(X_tensor)  # 随机预测
loss = criterion(outputs, y_tensor)  # 计算损失(很大)
loss.backward()  # 计算梯度
optimizer.step()  # 首次更新参数
  • 网络开始识别数据的基本模式
  • 预测线开始呈现大致正确的斜率
  • 损失值快速下降(从35.42到约2.65)
  • 模型学习速度最快(梯度最大)

3. 中期训练阶段 (Epoch 50-200)

# 典型迭代
outputs = model(X_tensor)  # 预测接近真实值
loss = criterion(outputs, y_tensor)  # 中等损失
loss.backward()  # 计算较小梯度
optimizer.step()  # 微调参数
  • 网络捕捉到线性关系的基本特征
  • 预测线越来越接近绿色真实关系线
  • 损失值缓慢下降(从2.65到1.97)
  • 学习速度变慢(梯度变小)

4. 后期训练阶段 (Epoch 200-500)

# 后期迭代
outputs = model(X_tensor)  # 预测非常接近真实值
loss = criterion(outputs, y_tensor)  # 小损失
loss.backward()  # 计算微小梯度
optimizer.step()  # 微小调整参数
  • 网络优化细节
  • 预测线与真实关系线几乎重合
  • 损失值稳定在约1.97
  • 模型收敛(参数变化很小)

训练过程关键元素详解

1. 前向传播 (Forward Pass)

outputs = model(X_tensor)
  • 输入数据通过神经网络各层
  • 计算过程:
    输入x → 线性变换: z1 = w1*x + b1→ ReLU激活: a1 = max(0, z1)→ 线性变换: output = w2*a1 + b2
    

2. 损失计算 (Loss Calculation)

loss = criterion(outputs, y_tensor)
  • 计算预测值与真实值的差异
  • 使用均方误差公式:
    MSE = 1/N * Σ(预测值 - 真实值)²
    

3. 反向传播 (Backward Pass)

loss.backward()
  • 计算损失函数对每个参数的梯度
  • 使用链式法则从输出层向输入层反向传播
  • 梯度表示"参数应该如何调整以减少损失"

4. 参数更新 (Parameter Update)

optimizer.step()
  • Adam优化器根据梯度更新参数
  • 更新公式简化表示:
    新参数 = 旧参数 - 学习率 * 梯度
    
  • 学习率(0.01)控制更新步长

训练过程可视化分析

损失曲线图

损失值
35 |*················
30 | *···············
25 |  *··············
20 |   *·············
15 |    *············
10 |     *···········5 |      **·········2 |         ****····1 |             ****0 +-----------------→ Epoch0  50 100 200 500
  • 曲线特点:开始陡峭下降,后期平缓
  • 表明:初期学习快,后期优化细调

预测结果演变

真实关系: y = 2x + 1 (绿色虚线)Epoch 0:预测线: 随机波动 (红色线)Epoch 50:预测线: 大致正确斜率但截距偏差Epoch 100:预测线: 接近真实线,部分区域过拟合噪声Epoch 500:预测线: 几乎与绿色虚线重合

为什么训练有效?

  1. 梯度下降原理:每次更新都向减少损失的方向移动
  2. 链式法则:高效计算所有参数的梯度
  3. 自适应优化器:Adam自动调整学习率
  4. 非线性能力:ReLU激活函数使网络能拟合复杂模式
  5. 迭代优化:多次重复使模型逐步接近最优解

训练结束后的模型状态

  • 权重和偏置已优化到最佳值
  • 网络学习到了潜在规律 y = 2x + 1
  • 能够准确预测新数据点
  • 损失值稳定在最低点(约1.97)

这个训练过程展示了神经网络如何从随机初始状态开始,通过反复的预测、评估和调整,最终学习到数据背后的规律。即使数据中存在噪声,神经网络也能识别出真实的线性关系。

http://www.dtcms.com/a/340036.html

相关文章:

  • 电流采样实现方法
  • JavaScript 代码保护与混淆
  • Vue2+Vue3前端开发_Day1
  • 端口映射原理操作详解教程:实现外网访问内网服务,本地路由器端口映射公网ip和软件端口映射域名2种方法
  • Qwen2.5-vl源码解读系列:LLM的Embedding层
  • MySQL常用函数
  • 首届机器人足球运动会技术复盘:从赛场表现看智能机器人核心技术突破
  • Wireshark获取数据传输的码元速率
  • 中科米堆CASAIM提供机加工件来料自动化测量尺寸方案
  • Origin绘制气泡图|科研论文图表教程(附数据格式模板)
  • 【HarmonyOS】H5 实现在浏览器中正常跳转 AppLinking 至应用
  • Java基础 8.19
  • 基于SpringBoot的停车场管理系统【2026最新】
  • C文件/Linux内核级文件理解
  • 软考网工选择题-1
  • 路由器详解
  • Windows 8.1 补丁 KB2919355 安装方法 详细步骤
  • 【Netty4核心原理⑫】【异步处理双子星 Future 与 Promise】
  • 【AI】算法环境-显卡、GPU、Cuda、NVCC和cuDNN的区别与联系
  • Stimulsoft 发布 2025.3 版本:支持在报表计算中解释运行 C# 脚本
  • Apache ShenYu网关与Nacos的关联及如何配合使用
  • 基于Envoy的AI Gateway测试环境搭建
  • 基于决策树模型的汽车价格预测分析
  • DAY 50 预训练模型+CBAM模块
  • CiA402 伺服驱动标准与控制模式详解
  • STL——string的使用(快速入门详细)
  • 12.3.2设置背景色12.3.3 创建设置类12.4 添加飞船图像 12.4.1 创建Ship 类 12.4.2 在屏幕上绘制飞船
  • 【语法糖】什么是语法糖
  • RK3568 Linux驱动学习——Linux设备树
  • bun + vite7 的结合,孕育的 Robot Admin 【靓仔出道】(十四)