【问题标题】:How to correct unstable loss and accuracy during training? (binary classification)如何在训练过程中纠正不稳定的损失和准确率? (二分类)
【发布时间】:2019-09-17 12:48:01
【问题描述】:

我目前正在使用 tensorflow 中的新 keras API 进行一个小型二进制分类项目。问题是几年前在 Kaggle.com 上发布的希格斯玻色子挑战的简化版本。数据集形状为 2000x14,其中每行的前 13 个元素构成输入向量,第 14 个元素是对应的标签。这是所述数据集的示例:

86.043,52.881,61.231,95.475,0.273,77.169,-0.015,1.856,32.636,202.068, 2.432,-0.419,0.0,0
138.149,69.197,58.607,129.848,0.941,120.276,3.811,1.886,71.435,384.916,2.447,1.408,0.0,1
137.457,3.018,74.670,81.705,5.954,775.772,-8.854,2.625,1.942,157.231,1.193,0.873,0.824,1

我对机器学习和 TensorFlow 比较陌生,但我熟悉更高层次的概念,例如损失函数、优化器和激活函数。我尝试构建各种模型,这些模型的灵感来自网上找到的二元分类问题示例,但我在训练模型时遇到了困难。在训练期间,损失在同一时期内有时会增加,导致学习不稳定。准确率达到 70% 左右的稳定水平。我曾尝试更改学习率和其他超参数,但无济于事。相比之下,我硬编码了一个全连接的前馈神经网络,它在同一问题上的准确率约为 80-85%。

这是我目前的模型:

import tensorflow as tf
from tensorflow.python.keras.layers.core import Dense
import numpy as np
import pandas as pd

def normalize(array):
    return array/np.linalg.norm(array, ord=2, axis=1, keepdims=True)

x_train = pd.read_csv('data/labeled.csv', sep='\s+').iloc[:1800, :-1].values
y_train = pd.read_csv('data/labeled.csv', sep='\s+').iloc[:1800, -1:].values

x_test = pd.read_csv('data/labeled.csv', sep='\s+').iloc[1800:, :-1].values
y_test = pd.read_csv('data/labeled.csv', sep='\s+').iloc[1800:, -1:].values

x_train = normalize(x_train)
x_test = normalize(x_test)

model = tf.keras.Sequential()
model.add(Dense(9, input_dim=13, activation=tf.nn.sigmoid)
model.add(Dense(6, activation=tf.nn.sigmoid))
model.add(Dense(1, activation=tf.nn.sigmoid))

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=50)
model.evaluate(x_test, y_test)

如前所述,一些 epoch 开始时的准确度比结束时更高,导致学习不稳定。

  32/1800 [..............................] - ETA: 0s - loss: 0.6830 - acc: 0.5938
1152/1800 [==================>...........] - ETA: 0s - loss: 0.6175 - acc: 0.6727
1800/1800 [==============================] - 0s 52us/step - loss: 0.6098 - acc: 0.6861
Epoch 54/250

  32/1800 [..............................] - ETA: 0s - loss: 0.5195 - acc: 0.8125
1376/1800 [=====================>........] - ETA: 0s - loss: 0.6224 - acc: 0.6672
1800/1800 [==============================] - 0s 43us/step - loss: 0.6091 - acc: 0.6850
Epoch 55/250

在如此简单的模型中学习出现这些波动的原因可能是什么? 谢谢


编辑:

我听从了 cmets 的一些建议,并相应地修改了模型。现在看起来更像这样:

model = tf.keras.Sequential()
model.add(Dense(250, input_dim=13, activation=tf.nn.relu))
model.add(Dropout(0.4))
model.add(Dense(200, activation=tf.nn.relu))
model.add(Dropout(0.4))
model.add(Dense(100, activation=tf.nn.relu))
model.add(Dropout(0.3))
model.add(Dense(50, activation=tf.nn.relu))
model.add(Dense(1, activation=tf.nn.sigmoid))

model.compile(optimizer='adadelta',
              loss='binary_crossentropy',
              metrics=['accuracy'])

【问题讨论】:

  • 您能否链接到数据集,以便使用相同的数据和模型重现问题?

标签: python tensorflow machine-learning classification


【解决方案1】:

我曾经训练过一个连体网络,我意识到如果我使用更高的学习率,训练损失会平稳下降(正如预期的那样,因为这就是神经网络正在学习的内容),但是看到了 val loss 的巨大起伏.

这在我使用较低的学习率(大约 1e-05)之前从未发生过。我相信训练损失实际上是错误的,因为最近的论文已经证明大型神经网络(我的意思是更复杂的神经网络)可以在训练集中完美地学习随机数据,尽管它们在验证它们时表现得非常糟糕,我附上了下面的论文供您参考,它清楚地解释了与过度拟合相关的这种现象。所以仅仅通过观察训练数据是无法得出模型整体表现的。

虽然上面提到的其他参数也很重要,但我想在这种情况下应该先开始调整学习率,然后再调整模型本身。

论文链接:https://arxiv.org/pdf/1611.03530

如果我错了,请纠正我......

【讨论】:

    【解决方案2】:

    振荡

    这些绝对与您的网络规模有关;每一批通过都会大大改变你的神经网络,因为它没有足够的神经元来表示这些关系。

    它适用于一个批次,更新另一个批次的权重,并有效地“取消学习”更改先前学习的连接。这就是为什么当网络试图适应你给它的任务时,损失也很跳跃。

    Sigmoid 激活和它的饱和度也可能会给您带来麻烦(因为梯度被压缩成小区域并且大多数梯度更新为零)。快速修复 - 使用ReLU 激活,如下所述。

    此外,神经网络关心准确性,只关心最小化损失值(它大部分时间都试图这样做)。假设它预测概率:[0.55, 0.55, 0.55, 0.55, 0.45] for classes [1, 1, 1, 1, 0] 所以它的准确性是 100% 但它非常不确定。现在,假设下一次更新将网络推入概率预测:[0.8, 0.8, 0.8, 0.8, 0.55]。在这种情况下,损失会下降,但准确率也会下降,从 100% 下降到 80%

    顺便说一句。您可能想检查逻辑回归的分数,看看它在这项任务上的表现(因此只有一个输出层)。

    需要考虑的一些事项

    1。神经网络的大小

    从简单模型开始并在需要时将其放大总是好的(不建议反过来)。您可能想检查一个非常小的数据子样本(比如两/三批,160 个左右的元素),您的模型是否可以学习输入和输出之间的关系。

    在您的情况下,我怀疑模型是否能够学习这些与您提供的层大小的关系。尝试增加大小,尤其是在较早的层中(对于初学者来说可能是 50/100),看看它的行为。

    2。激活函数

    Sigmoid 容易饱和(发生变化的小区域,大部分值几乎为 0 或 1)。现在很少将其用作瓶颈(最后一层)之前的激活。现在最常见的是ReLU,它不容易饱和(至少在输入为正时)或其变化。这也可能有所帮助。

    3。学习率

    对于每个数据集和每个神经网络模型,学习率的最佳选择是不同的。默认值通常效果一般,但是当学习率太小时,它可能会卡在局部最小值(泛化能力会更差),而值太大会使你的网络不稳定(损失会高度振荡)。

    您可能想阅读Cyclical Learning Rate(或原始research paper by Leslie N. Smith)。在那里您可以找到有关如何启发式地选择良好学习率并设置一些简单的学习率调度程序的信息。这些技术被用于fast.ai 团队在 CIFAR10 比赛中取得了非常好的成绩。在他们的网站 or in documentation of their library 上,你可以找到 One Cycle Policy 和学习率查找器(基于上述研究员的工作)。我认为这应该让你开始在这个领域。

    4。归一化

    不确定,但这种规范化对我来说看起来很不标准(从未见过这样的做法)。良好的归一化是神经网络收敛的基础(除非数据已经非常接近正态分布)。通常减去平均值并除以每个特征的标准差。例如,您可以查看scikit-learn library 中的一些方案。

    5。深度

    这应该不是问题,但如果您的输入很复杂,您应该考虑在您的神经网络中添加更多层(现在它几乎肯定太薄了)。这将允许它学习更多的抽象特征并更多地转换输入空间。

    过拟合

    当网络对数据过度拟合时,您可能会采用一些正则化技术(很难说有什么帮助,您应该自行测试),其中一些包括:

    • 通过批量归一化平滑学习空间的学习率更高。
    • 较少数量的神经元(网络学习的关系直观地必须更具数据分布代表性)。
    • 小批量也有正则化效果。
    • 辍学,尽管很难确定良好的辍学率。将其作为最后一个。此外,它还与批量标准化技术相冲突(尽管有一些技术可以将它们结合起来,请参阅 herehere,您可以在网上找到更多信息)。
    • L1/L2 正则化,其中第二种应用更广泛(除非您有特定知识表明 L1 可能表现更好)
    • 数据增强 - 我会先尝试这个,主要是出于好奇。由于您的特征是连续的,您可能希望逐批添加一些从高斯分布生成的随机噪声。噪声必须很小,标准偏差约为 1e-21e-3,您必须通过实验测试这些值。
    • 提前停止 - 在 N epochs 之后验证集没有改进,您将结束训练。相当常见的技术,几乎每次都应该使用。记得将最好的模型保存在验证集上,并将patience(上面提到的N)设置为一些中等大小的值(不要将耐心设置为1个epoch左右,5个左右后神经网络可能很容易改善)。李>

    此外,您还可以找到大量其他技术。检查什么是直观的,你最喜欢哪个,并测试它的表现。

    【讨论】:

    • 嘿 Szymon,如果您有兴趣看一看,我已采纳了您的大部分建议并添加了新版本的模型。损失的行为更加稳定,在测试集上的准确率达到 80-85%。我仍然需要通读并实现动态学习率,我很快就会这样做。我只是想知道你是否有任何最后的建议来对抗过度拟合?训练集的准确率趋于 1,但测试集的准确率最高为 85%,即使有 dropout 层也是如此。添加神经元和层似乎只会使问题恶化。再次感谢!
    • @ÉricPfleiderer 您可以尝试检查数据以删除异常值。您可以尝试的其他方法是,与测试集相比,尽量减少训练集的大小,稍微降低 dropout 率,并查看“提前停止”是否对您的模型有帮助。
    • @ÉricPfleiderer 添加了适当的部分。 Federico S 提出的带有异常值的建议也是一个可行的选择(也是提前停止的选择)。另一方面,我反对降低辍学率(这会让你更倾向于过度拟合 IIUC 制度)。减少训练集(除了 bagging 等方法)可能弊大于利,因为每个训练样本对网络来说都是宝贵的。
    【解决方案3】:

    Symon 的所有观点都很好,但还有一个可能的原因:您是否正在改组您的数据集?如果不是,并且您的数据包含一些有序偏差,则您的模型可能会将自身调整到数据集的一个“末端”,而在另一个“末端”表现不佳。

    【讨论】:

    • 我想是的。根据 tensorflow 文档,fit() 方法默认会在每个 epoch 打乱训练集。
    猜你喜欢
    • 2018-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 2021-03-09
    • 2020-01-06
    • 2020-08-06
    相关资源
    最近更新 更多