为什么我的网络需要这么多 epoch 才能学习?

数据挖掘 机器学习 神经网络 深度学习 模型选择 超参数调整
2021-09-14 03:39:58

我正在从事自然语言处理的关系分类任务,我对学习过程有一些疑问。我使用 PyTorch 实现了一个卷积神经网络,我正在尝试选择最好的超参数。

我注意到的常见行为是,即使在 1000 个 epoch 之后,我的验证损失仍在缓慢下降,而我的指标(宏观 F1 分数)也在缓慢增加。这两个指标都在波动,可能是由于要分类的 4 个类别不平衡(5%、3%、30%、62%)。我使用的是 Adam,所以学习率不是我自己设定的(它是自适应的)。我在最大池化后使用 dropout 0.5,并使用大小为 50 的小批量。

1000 个 epoch 中的训练和验证损失 1000 个 epoch 的宏 f1 分数

在书籍和在线教程中,我看到关于何时停止训练的情节非常清楚。例如,当训练损失变得小于验证损失时,或者当验证损失达到平台时。情况似乎并非如此,所以我向更多导航神经网络用户寻求建议:

  • 为什么网络在这么多时期(而且如此缓慢)之后仍在学习?这是一种合理的行为吗?我是否需要运行模型 2000 甚至 3000 epoch 才能获得最佳的宏 f1 分数?过度拟合有风险,不是吗?
  • 我的网络仅由词嵌入和位置嵌入提供,所以我想知道这种行为是否可以由(i)对于任务而言过于复杂的网络架构,(ii)过于简单而无法建模的网络架构任务的复杂性,(iii)输入的信息量不足以区分类别,因此网络学习困难(因此学习缓慢)。我的网络架构并不深:它有一个嵌入层 + 卷积层 + 最大池层 + softmax。
  • 一个附带问题:假设 1000 个 epoch 就足够了。当我需要比较多个模型的性能(或比较不同的超参数组合)时,我需要选择和比较哪个分数?“最后最好的” f1 分数(比如在 980 纪元)或最后报告的分数(即在 1000 纪元的分数)?

你有什么建议吗?如果有不清楚的地方,请告诉我!

=====

更新

按照Djib2011的建议,我用不同的学习率训练了网络,特别是lr=0.001(默认)lr=0.01、、lr=0.1. 我使用更多的 epoch(即 3000 个)训练网络,以确定我可以停止训练的时刻。我注意到的是,提高学习率并没有帮助,默认情况下会给出最好的结果lr=0.001但是,目前还不清楚何时停止。

你有其他建议来解决这个问题吗?除了学习率,优化器背后可能还有其他问题(例如,网络容量小)?先感谢您!

使用不同的学习率报告

=====

更新#2

在尝试了具有不同学习率和 3000 个 epoch 的不同优化算法(即 RMSProp、AdaDelta、Admax、SGD)后,我注意到在这些不同设置下的行为仍然相同(没有收敛,许多 epoch 几乎没有减少训练和验证损失)。

因此,我通过在(训练)批处理循环内移动 3 行:、、、而不是在循环后运行它们来optimizer.zero_grad()修改loss.backward()pytorch实现。optimizer.step()因此,这是在每个 epoch 执行训练和测试的编辑代码:

# Iterate over epochs
for epoch in range(1, n_epochs+1):
    train_loss = 0
    model.train()

    train_predictions = []
    train_true_labels = []

    # Iterate over training batches
    for i, (inputs, labels) in enumerate(train_loader):
        inputs, labels = Variable(inputs).to(device), Variable(labels).to(device)

        optimizer.zero_grad() # set gradients to zero

        preds = model(inputs)
        preds.to(device)

        # Compute the loss and accumulate it to print it afterwards
        loss = loss_criterion(preds, labels)
        train_loss += loss.detach()

        pred_values, pred_encoded_labels = torch.max(preds.data, 1)
        pred_encoded_labels = pred_encoded_labels.cpu().numpy()

        train_predictions.extend(pred_encoded_labels)
        train_true_labels.extend(labels)

        loss.backward()       # backpropagate and compute gradients
        optimizer.step()      # perform a parameter update


    # Evaluate on development test
    predictions = []
    true_labels = []
    dev_loss = 0

    model.eval()
    for i, (inputs, labels) in enumerate(dev_loader):
        inputs, labels = Variable(inputs).to(device), Variable(labels).to(device)

        preds = model(inputs)
        preds.to(device)

        loss = loss_criterion(preds, labels)
        dev_loss += loss.detach()

        pred_values, pred_encoded_labels = torch.max(preds.data, 1)
        pred_encoded_labels = pred_encoded_labels.cpu().numpy()

        predictions.extend(pred_encoded_labels)
        true_labels.extend(labels)

因此,我使用我的默认配置(Adam,lr=0.001)再次训练了网络,令人惊讶的是,我在 epoch 22 处获得了收敛(见下图)。我认为问题就在那里,你同意吗?你有什么额外的建议吗?再次感谢!

在此处输入图像描述 在此处输入图像描述

3个回答

我的意见

您应该尝试增加模型的学习率(甚至优化器的其他参数 - 例如动量)。

要回答您的问题

为什么网络在这么多时期(而且如此缓慢)之后仍在学习?这是一种合理的行为吗?我是否需要运行模型 2000 甚至 3000 epoch 才能获得最佳的宏 f1 分数?过度拟合有风险,不是吗?

是的,据我所知,您的模型仍在学习(从您的验证损失仍在下降的事实中可以看出)。它肯定需要更多的 epoch 才能获得最佳性能。

我的网络仅由词嵌入和位置嵌入提供,所以我想知道这种行为是否可以由(i)对于任务而言过于复杂的网络架构,(ii)过于简单而无法建模的网络架构任务的复杂性,(iii)输入的信息量不足以区分类别,因此网络学习困难(因此学习缓慢)。我的网络架构并不深:它有一个嵌入层 + 卷积层 + 最大池层 + softmax。

一般来说,较大的网络需要更多的时间来收敛。但是,您描述的模型非常小,因此不会花费太长时间。

一个附带问题:假设 1000 个 epoch 就足够了。当我需要比较多个模型的性能(或比较不同的超参数组合)时,我需要选择和比较哪个分数?“最后最好的” f1 分数(比如在 980 纪元)或最后报告的分数(即在 1000 纪元的分数)?

如果要比较性能,则应比较每个模型的最佳 f1。如果你想比较收敛速度,那么你可以比较 X 时期的 f1。

正如我在评论中所写,您可以尝试使用回溯梯度下降,它会自动为您选择学习率,并且可以在迄今为止最弱的假设下严格证明收敛性。有关详细信息,您可以在此链接中查看我的答案:

梯度下降总是收敛到最优吗?

在那里,您还可以在 GitHub 上找到一些源代码的链接。

上面的答案是不言自明的。我想补充一件小事,太多的时期可能会导致过度拟合。该模型将继续学习我们可能允许的尽可能多的时期。所以必须对 epoch 的数量进行限制。