第三章:PyTorch 训练与评估


文档摘要

第三章:PyTorch 训练与评估 第三章:PyTorch 训练与评估 3.1 数据准备:模型的基石 训练和评估模型的第一步,也是至关重要的一步,是准备数据。高质量的数据是模型性能的基石。在PyTorch中,我们通常使用 和 来高效地加载和处理数据。 3.1.1 :定义数据访问方式 是一个抽象类,用于表示数据集。我们需要继承 并实现两个关键方法: : 返回数据集的样本数量。 : 根据给定的索引 返回一个样本。一个样本通常包含输入数据和对应的标签。 代码示例:自定义Dataset 假设我们有一个简单的线性回归数据集,包含输入特征 和目标值 。 3.1.2 :高效数据加载 负责从 中批量加载数据,并提供诸如数据打乱、多线程加载等功能,以加速训练过程。

第三章:PyTorch 训练与评估

第三章:PyTorch 训练与评估

3.1 数据准备:模型的基石

训练和评估模型的第一步,也是至关重要的一步,是准备数据。高质量的数据是模型性能的基石。在PyTorch中,我们通常使用 torch.utils.data.Datasettorch.utils.data.DataLoader 来高效地加载和处理数据。

3.1.1 Dataset:定义数据访问方式

Dataset 是一个抽象类,用于表示数据集。我们需要继承 Dataset 并实现两个关键方法:

  • __len__(self): 返回数据集的样本数量。

  • __getitem__(self, idx): 根据给定的索引 idx 返回一个样本。一个样本通常包含输入数据和对应的标签。

代码示例:自定义Dataset

假设我们有一个简单的线性回归数据集,包含输入特征 x 和目标值 y

import torch from torch.utils.data import Dataset class LinearRegressionDataset(Dataset): def __init__(self, x, y): self.x = torch.tensor(x, dtype=torch.float32) self.y = torch.tensor(y, dtype=torch.float32) self.n_samples = len(x) def __getitem__(self, index): return self.x[index], self.y[index] def __len__(self): return self.n_samples # 示例数据 X_train = [[1], [2], [3], [4]] Y_train = [[2], [4], [6], [8]] dataset = LinearRegressionDataset(X_train, Y_train) first_data = dataset[0] features, labels = first_data print(features, labels) # 输出: tensor([1.], dtype=torch.float32) tensor([2.], dtype=torch.float32) print(len(dataset)) # 输出: 4

3.1.2 DataLoader:高效数据加载

DataLoader 负责从 Dataset 中批量加载数据,并提供诸如数据打乱、多线程加载等功能,以加速训练过程。

代码示例:使用DataLoader

from torch.utils.data import DataLoader # 创建DataLoader train_loader = DataLoader(dataset=dataset, batch_size=2, shuffle=True) # 迭代DataLoader data_iter = iter(train_loader) first_batch = next(data_iter) features, labels = first_batch print(features, labels) # 输出类似: tensor([[3.], [1.]]) tensor([[6.], [2.]]) (由于shuffle=True,顺序可能不同) # 训练循环中使用DataLoader num_epochs = 2 for epoch in range(num_epochs): for i, (inputs, targets) in enumerate(train_loader): # 前向传播, 反向传播, 更新权重 (将在后续章节介绍) print(f'Epoch: {epoch+1}/{num_epochs}, Step: {i+1}, Inputs: {inputs.shape}, Labels: {targets.shape}')

mermaid 图:数据加载流程

内容详解:

  • Dataset 的作用: Dataset 将数据抽象成一个可迭代的对象,隐藏了数据加载和预处理的复杂性,使得我们可以专注于模型的设计和训练逻辑。

  • DataLoader 的作用: DataLoader 提供了更高级的数据加载功能,例如:

    • Batching: 将多个样本组合成一个批次,提高计算效率。

    • Shuffling: 在每个epoch开始前打乱数据顺序,避免模型学习到批次顺序的偏差。

    • 并行加载: 使用多线程或多进程加速数据加载,尤其是在数据量较大时。

  • 数据预处理: 实际应用中,数据预处理通常在 Dataset__getitem__ 方法中进行,例如数据标准化、归一化、数据增强等。

3.2 模型构建:定义网络结构

在PyTorch中,我们使用 torch.nn.Module 类来构建神经网络模型。模型由各种层(例如线性层、卷积层、循环层等)组成,这些层在 forward 方法中被组合起来,定义了数据在网络中的流动方式。

3.2.1 nn.Module:模型基类

所有PyTorch模型都必须继承 nn.Module 类。我们需要在子类中定义模型的层结构和 forward 方法。

代码示例:线性回归模型

import torch.nn as nn class LinearRegressionModel(nn.Module): def __init__(self, input_size, output_size): super(LinearRegressionModel, self).__init__() self.linear = nn.Linear(input_size, output_size) # 定义一个线性层 def forward(self, x): out = self.linear(x) # 前向传播 return out # 创建模型实例 input_dim = 1 output_dim = 1 model = LinearRegressionModel(input_dim, output_dim)

3.2.2 模型层和容器

PyTorch 提供了丰富的预定义层和容器,例如:

  • nn.Linear: 线性层(全连接层)。

  • nn.Conv2d, nn.ConvTranspose2d: 卷积层和转置卷积层(用于图像处理)。

  • nn.ReLU, nn.Sigmoid, nn.Tanh: 激活函数。

  • nn.MaxPool2d, nn.AvgPool2d: 池化层。

  • nn.RNN, nn.LSTM, nn.GRU: 循环神经网络层(用于序列数据)。

  • nn.Sequential: 顺序容器,用于按顺序组合多个层。

代码示例:多层感知机 (MLP)

class MLPModel(nn.Module): def __init__(self, input_size, hidden_size, output_size): super(MLPModel, self).__init__() self.fc1 = nn.Linear(input_size, hidden_size) self.relu = nn.ReLU() self.fc2 = nn.Linear(hidden_size, output_size) def forward(self, x): out = self.fc1(x) out = self.relu(out) out = self.fc2(out) return out # 创建MLP模型实例 input_dim = 28*28 # 假设输入是 MNIST 图像 (28x28) hidden_dim = 100 output_dim = 10 # MNIST 数字分类 (0-9) mlp_model = MLPModel(input_dim, hidden_dim, output_dim)

mermaid 图:MLP模型结构

内容详解:

  • nn.Module 的作用: nn.Module 是构建PyTorch模型的基石,它封装了模型的参数和操作,并提供了方便的模型管理和扩展机制。

  • forward 方法: forward 方法定义了数据通过模型的计算流程。当我们调用 model(input_data) 时,实际上是调用了模型的 forward 方法。

  • 模型层和容器的选择: 选择合适的模型层和容器取决于具体的任务类型和数据特征。例如,卷积层通常用于图像处理,循环层用于序列数据处理,线性层用于处理表格数据等。

3.3 损失函数与优化器:模型学习的驱动力

为了让模型学习到有用的知识,我们需要定义损失函数和优化器。

3.3.1 损失函数 (Loss Function / Criterion)

损失函数衡量模型预测结果与真实标签之间的差距。训练的目标是最小化损失函数。PyTorch 在 torch.nn 中提供了各种常用的损失函数,例如:

  • nn.MSELoss: 均方误差损失 (Mean Squared Error Loss),用于回归任务。

  • nn.CrossEntropyLoss: 交叉熵损失 (Cross-Entropy Loss),用于多分类任务。

  • nn.BCELoss: 二元交叉熵损失 (Binary Cross-Entropy Loss),用于二分类任务。

  • nn.L1Loss: L1 损失 (Mean Absolute Error Loss),平均绝对误差损失,用于回归任务。

代码示例:选择损失函数

# 回归任务使用 MSELoss criterion_regression = nn.MSELoss() # 分类任务使用 CrossEntropyLoss criterion_classification = nn.CrossEntropyLoss()

3.3.2 优化器 (Optimizer)

优化器负责根据损失函数的梯度更新模型参数,从而使模型逐渐逼近最优解。PyTorch 在 torch.optim 中提供了各种优化算法,例如:

  • optim.SGD: 随机梯度下降 (Stochastic Gradient Descent)。

  • optim.Adam: Adam 优化器 (Adaptive Moment Estimation)。

  • optim.RMSprop: RMSprop 优化器 (Root Mean Square Propagation)。

代码示例:选择优化器

import torch.optim as optim # 使用 SGD 优化器 optimizer_sgd = optim.SGD(model.parameters(), lr=0.01) # lr: 学习率 # 使用 Adam 优化器 optimizer_adam = optim.Adam(model.parameters(), lr=0.001)

mermaid 图:损失函数与优化器在训练中的作用

内容详解:

  • 损失函数的选择: 损失函数的选择取决于具体的任务类型。回归任务通常使用衡量数值差异的损失函数,分类任务通常使用衡量类别分布差异的损失函数。

  • 优化器的选择: 不同的优化器具有不同的特性和适用场景。Adam 和 RMSprop 通常比 SGD 收敛更快,但也可能更容易陷入局部最优解。SGD 具有更好的泛化性能,但需要仔细调整学习率等超参数。

  • 学习率 (Learning Rate): 学习率是优化器的一个重要超参数,它控制参数更新的步长。学习率过大可能导致模型震荡,学习率过小可能导致收敛速度过慢。

3.4 训练循环 (Training Loop):模型学习的核心流程

训练循环是模型学习的核心流程,它迭代地进行前向传播、计算损失、反向传播和参数更新。

伪代码:训练循环

for epoch in range(num_epochs): for inputs, targets in data_loader: # 1. 前向传播 (Forward Pass): 计算模型输出 outputs = model(inputs) # 2. 计算损失 (Calculate Loss): 衡量模型预测与真实标签的差距 loss = criterion(outputs, targets) # 3. 反向传播 (Backward Pass): 计算梯度 optimizer.zero_grad() # 清空之前的梯度 loss.backward() # 计算梯度 # 4. 参数更新 (Update Parameters): 根据梯度更新模型参数 optimizer.step() # 更新参数 # (可选) 打印训练信息,例如 epoch, step, loss if (step+1) % print_interval == 0: print(f'Epoch [{epoch+1}/{num_epochs}], Step [{step+1}/{total_steps}], Loss: {loss.item():.4f}')

代码示例:完整的训练循环 (线性回归)

# ... (数据准备, 模型构建, 损失函数, 优化器 已定义) ... num_epochs = 1000 learning_rate = 0.01 optimizer = optim.SGD(model.parameters(), lr=learning_rate) criterion = nn.MSELoss() for epoch in range(num_epochs): for inputs, targets in train_loader: # 前向传播 outputs = model(inputs) loss = criterion(outputs, targets) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() if (epoch+1) % 100 == 0: print (f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}') print('Training finished')

mermaid 图:训练循环流程

内容详解:

  • Epoch 和 Step:

    • Epoch: 指整个数据集被模型完整地训练一遍的次数。

    • Step (Iteration): 指模型参数更新的次数。在一个 epoch 中,通常会进行多次 step,每次 step 处理一个 batch 的数据。

  • optimizer.zero_grad(): 在每次反向传播之前,需要将优化器的梯度缓冲区清零。因为PyTorch默认会累积梯度,如果不清零,梯度会不断累加,导致参数更新错误。

  • loss.backward(): 调用 loss.backward() 触发反向传播,计算模型参数的梯度。

  • optimizer.step(): 调用 optimizer.step() 根据计算出的梯度更新模型参数。

  • 训练过程监控: 在训练循环中,通常会打印损失函数值、学习率等信息,以便监控训练进度和调整超参数。

3.5 模型评估 (Evaluation):衡量模型性能

模型训练完成后,我们需要在验证集或测试集上评估模型的性能,以了解模型的泛化能力。评估过程与训练过程类似,但不进行反向传播和参数更新。

3.5.1 评估模式 (model.eval())

在评估模型之前,需要将模型设置为评估模式 model.eval()。这会影响某些层的行为,例如 Dropout 和 BatchNorm 层,在评估模式下会停止随机失活和使用全局统计量。

3.5.2 关闭梯度计算 (torch.no_grad())

在评估过程中,我们不需要计算梯度,可以使用 torch.no_grad() 上下文管理器来关闭梯度计算,以节省计算资源并加速评估过程。

3.5.3 评估指标 (Metrics)

评估指标用于量化模型的性能。常用的评估指标取决于任务类型,例如:

  • 分类任务:

    • 准确率 (Accuracy): 预测正确的样本数占总样本数的比例。

    • 精确率 (Precision), 召回率 (Recall), F1-score: 用于更细致地评估分类模型的性能,尤其是在类别不平衡的情况下。

    • AUC-ROC: 受试者工作特征曲线下面积,用于评估二分类模型的排序能力。

  • 回归任务:

    • 均方根误差 (RMSE): 均方误差的平方根。

    • 平均绝对误差 (MAE): 平均绝对误差。

    • R 平方 (R-squared): 决定系数,衡量模型拟合数据的程度。

代码示例:模型评估 (分类任务 - 准确率)

# ... (模型构建, 数据准备 - 假设有测试集 test_dataset 和 test_loader) ... def evaluate_accuracy(model, data_loader): correct_predictions = 0 total_samples = 0 with torch.no_grad(): # 关闭梯度计算 model.eval() # 设置为评估模式 for inputs, labels in data_loader: outputs = model(inputs) _, predicted_labels = torch.max(outputs, 1) # 获取概率最大的类别 total_samples += labels.size(0) correct_predictions += (predicted_labels == labels).sum().item() accuracy = correct_predictions / total_samples return accuracy test_accuracy = evaluate_accuracy(model, test_loader) print(f'Test Accuracy: {test_accuracy:.4f}')

mermaid 图:模型评估流程

内容详解:

  • 评估模式的重要性: 评估模式确保模型在评估阶段的行为与训练阶段不同,例如 Dropout 层不进行随机失活,BatchNorm 层使用全局统计量,从而更准确地反映模型的泛化能力。

  • 评估指标的选择: 评估指标的选择取决于具体的任务类型和业务目标。例如,在医疗诊断领域,召回率可能比精确率更重要,因为我们更关注尽可能找出所有患病的人,即使误诊一些健康人。

  • 验证集与测试集:

    • 验证集 (Validation Set): 用于在训练过程中调整超参数和选择模型。

    • 测试集 (Test Set): 用于在模型开发完成后,最终评估模型的泛化能力。测试集在模型开发过程中不应该被使用,以避免模型过拟合测试集。

3.6 模型保存与加载

训练好的模型需要保存下来,以便后续部署和使用。PyTorch 提供了方便的模型保存和加载功能。

3.6.1 保存模型 (torch.save)

可以使用 torch.save 函数保存模型的 state_dict 或整个模型。

  • 保存 state_dict (推荐): 只保存模型的参数字典,文件较小,更灵活。

    # 保存 state_dict torch.save(model.state_dict(), 'model.pth')
  • 保存整个模型: 保存模型的结构和参数,文件较大,依赖于模型代码。

    # 保存整个模型 torch.save(model, 'model_complete.pth')

3.6.2 加载模型 (torch.load)

可以使用 torch.load 函数加载保存的模型。

  • 加载 state_dict: 需要先创建模型实例,然后加载 state_dict

    # 加载 state_dict model = LinearRegressionModel(input_dim, output_dim) # 创建模型实例 (结构需要与保存时一致) model.load_state_dict(torch.load('model.pth')) model.eval() # 设置为评估模式
  • 加载整个模型: 直接加载模型实例。

    # 加载整个模型 model = torch.load('model_complete.pth') model.eval() # 设置为评估模式

mermaid 图:模型保存与加载流程

内容详解:

  • state_dict vs. 完整模型: 推荐保存 state_dict,因为它更轻量级,更灵活,且与模型代码解耦。加载 state_dict 时,只需要模型结构与保存时一致即可,而不需要完全相同的代码环境。

  • 模型部署: 保存的模型可以用于模型部署,例如在 Web 应用、移动应用或嵌入式设备中使用。

3.7 总结与展望

掌握模型训练与评估是深度学习实践的基础。在实际应用中,我们还需要不断尝试不同的模型结构、超参数和训练策略,并结合有效的评估方法,才能构建出高性能的深度学习模型。

后续学习方向:

  • 更复杂的模型结构: 学习卷积神经网络 (CNN)、循环神经网络 (RNN)、Transformer 等更复杂的模型结构,以应对不同的任务需求。

  • 更高级的优化算法: 探索更高级的优化算法,例如 AdamW, LookAhead 等,以加速训练和提高模型性能。

  • 正则化技术: 学习 Dropout, BatchNorm, L1/L2 正则化等技术,以防止模型过拟合。

  • 模型调优: 学习超参数调优、模型集成等技术,以进一步提升模型性能。

希望本章内容能够帮助读者扎实掌握PyTorch模型训练与评估的基础知识,为后续的深度学习实践打下坚实的基础。


发布者: 作者: 转发
评论区 (0)
U