blog

Welcome to my blog!

Train VS Eval

ab's Avatar 2024-03-25 Accumulate

  1. 1. 目录
  2. 2. Train VS Eval
    1. 2.1. 设置模型状态
    2. 2.2. 训练流程
    3. 2.3. 验证/测试流程
    4. 2.4. 对比
    5. 2.5. 计算模型指标
  3. 3. 训练集、验证集和测试集
    1. 3.1. 模型设计
    2. 3.2. 模型训练的参数
    3. 3.3. 数据集分类
    4. 3.4. 数据集的作用与特点
    5. 3.5. 验证集和测试集的互相转化
    6. 3.6. 验证集的作用
  4. 4. 参考链接

目录


Train VS Eval

在完成模型的训练后,我们需要在测试集/验证集上完成模型的验证,以确保模型具有泛化能力、不会出现过拟合等问题。在PyTorch中,训练和评估的流程基本一致,区别在于训练过程需要更新模型的参数,而评估过程则不需要更新参数。

设置模型状态

  • 训练状态:模型的参数应该支持反向传播的修改。
    1
    model.train()
  • 验证/测试状态:不应该修改模型参数。
    1
    model.eval()

训练流程

  1. 读取数据:使用for循环从DataLoader中读取全部数据。
    1
    for data, label in train_loader:
  2. 将数据转移到GPU上(以.cuda()为例):
    1
    data, label = data.cuda(), label.cuda()
  3. 初始化优化器的梯度:
    1
    optimizer.zero_grad()
  4. 将数据输入模型进行训练,并计算损失函数:
    1
    2
    output = model(data)
    loss = criterion(output, label)
  5. 将损失反向传播回网络,并更新模型参数:
    1
    2
    loss.backward()
    optimizer.step()

验证/测试流程

与训练流程基本一致,但有以下不同:

  • 预先设置torch.no_grad(),并将模型调至eval模式。
  • 不需要将优化器的梯度置零
  • 不需要将损失反向传播回网络
  • 不需要更新优化器

对比

训练过程示例

1
2
3
4
5
6
7
8
9
10
11
12
13
def train(epoch):
model.train()
train_loss = 0
for data, label in train_loader:
data, label = data.cuda(), label.cuda()
optimizer.zero_grad()
output = model(data)
loss = criterion(output, label)
loss.backward()
optimizer.step()
train_loss += loss.item() * data.size(0)
train_loss /= len(train_loader.dataset)
print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch, train_loss))

验证过程示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def val(epoch):
model.eval()
val_loss = 0
running_accu = 0
with torch.no_grad():
for data, label in val_loader:
data, label = data.cuda(), label.cuda()
output = model(data)
preds = torch.argmax(output, 1)
loss = criterion(output, label)
val_loss += loss.item() * data.size(0)
running_accu += torch.sum(preds == label.data)
val_loss /= len(val_loader.dataset)
print('Epoch: {} \tValidation Loss: {:.6f}'.format(epoch, val_loss))

计算模型指标

可以使用sklearn.metrics中的classification_report函数来计算模型的准确率、召回率、F1值等指标:

1
2
3
4
5
from sklearn.metrics import classification_report

# 替换以下代码中的labels和preds为模型预测出来的所有label和preds
# target_names替换为类别名称,即可得到模型的分类报告
print(classification_report(labels.cpu(), preds.cpu(), target_names=class_names))

训练集、验证集和测试集

模型设计

  • 模型架构:包括模型的层数以及每层的神经元数量。
  • 可训练权重参数:模型内置的可训练参数。

模型训练的参数

这些是模型外置参数,如学习率、优化策略等。

数据集分类

  • 训练集(Train Set):用于模型拟合的数据样本,用于通过梯度下降进行学习。
  • 验证集(Validation Set):在模型训练过程中单独留出的样本集,用于调整模型的超参数和进行初步评估。
    • 可以用来发现模型或参数问题,如模型在验证集上的发散、奇怪的结果、mAP不增等情况。
    • 有助于验证模型的泛化能力,并通过对比不同模型来选择最优模型。
    • 通常在几个epoch后运行一次,以观察效果,但过于频繁会影响训练速度。
  • 测试集(Test Set):用来评估模型最终的泛化能力,不应用于调参或特征选择等。

测试集的分类:

  • “test-dev” 代表开发测试集(Development Test Set),通常用于开发和调试阶段,用来评估模型的表现,并且通常会反复使用以进行参数调整和模型改进。

  • “test-std” 代表标准测试集(Standard Test Set),通常用于最终评估模型的性能,并且不会用于模型的开发或者调整。它可以看作是一个独立的、固定的测试集,用于评估模型在真实场景下的表现。

数据集的作用与特点

类别 是否被训练到 作用 使用次数 缺陷
验证集 调超参数 多次使用 可能低估泛化误差
测试集 验证泛化性能 仅一次使用 数据量大,测试耗时

验证集和测试集的互相转化

  • 验证集是必需的,用于“人工调参”过程。
  • 训练集、验证集和测试集应遵循相同的数据分布,以进行有效的调参。
  • 测试集存在的目的是为了验证模型的泛化能力。

验证集的作用

  • 使用提前终止(early stopping)策略,基于validation_data的分类精度来防止过拟合。
  • 通过validation_data而非test_data设置超参数,避免对test_data过拟合。
  • validation_data被视为帮助学习合适超参数的训练数据,与test_data分离开,采用分离法(hold out method)。

参考链接

本文最后更新于 天前,文中所描述的信息可能已发生改变