神经网络总是预测同一个类别

Posted

技术标签:

【中文标题】神经网络总是预测同一个类别【英文标题】:Neural network always predicts the same class 【发布时间】:2017-05-20 04:30:31 【问题描述】:

我正在尝试实现一个神经网络,将图像分类为两个离散类别之一。然而,问题是它目前总是预测任何输入为 0,我不太确定为什么。

这是我的特征提取方法:

def extract(file):
    # Resize and subtract mean pixel
    img = cv2.resize(cv2.imread(file), (224, 224)).astype(np.float32)
    img[:, :, 0] -= 103.939
    img[:, :, 1] -= 116.779
    img[:, :, 2] -= 123.68
    # Normalize features
    img = (img.flatten() - np.mean(img)) / np.std(img)

    return np.array([img])

这是我的梯度下降例程:

def fit(x, y, t1, t2):
    """Training routine"""
    ils = x.shape[1] if len(x.shape) > 1 else 1
    labels = len(set(y))

    if t1 is None or t2 is None:
        t1 = randweights(ils, 10)
        t2 = randweights(10, labels)

    params = np.concatenate([t1.reshape(-1), t2.reshape(-1)])
    res = grad(params, ils, 10, labels, x, y)
    params -= 0.1 * res

    return unpack(params, ils, 10, labels)

这是我的前向和后向(梯度)传播:

def forward(x, theta1, theta2):
    """Forward propagation"""

    m = x.shape[0]

    # Forward prop
    a1 = np.vstack((np.ones([1, m]), x.T))
    z2 = np.dot(theta1, a1)

    a2 = np.vstack((np.ones([1, m]), sigmoid(z2)))
    a3 = sigmoid(np.dot(theta2, a2))

    return (a1, a2, a3, z2, m)

def grad(params, ils, hls, labels, x, Y, lmbda=0.01):
    """Compute gradient for hypothesis Theta"""

    theta1, theta2 = unpack(params, ils, hls, labels)

    a1, a2, a3, z2, m = forward(x, theta1, theta2)
    d3 = a3 - Y.T
    print('Current error: '.format(np.mean(np.abs(d3))))

    d2 = np.dot(theta2.T, d3) * (np.vstack([np.ones([1, m]), sigmoid_prime(z2)]))
    d3 = d3.T
    d2 = d2[1:, :].T

    t1_grad = np.dot(d2.T, a1.T)
    t2_grad = np.dot(d3.T, a2.T)

    theta1[0] = np.zeros([1, theta1.shape[1]])
    theta2[0] = np.zeros([1, theta2.shape[1]])

    t1_grad = t1_grad + (lmbda / m) * theta1
    t2_grad = t2_grad + (lmbda / m) * theta2

    return np.concatenate([t1_grad.reshape(-1), t2_grad.reshape(-1)])

这是我的预测函数:

def predict(theta1, theta2, x):
    """Predict output using learned weights"""
    m = x.shape[0]

    h1 = sigmoid(np.hstack((np.ones([m, 1]), x)).dot(theta1.T))
    h2 = sigmoid(np.hstack((np.ones([m, 1]), h1)).dot(theta2.T))

    return h2.argmax(axis=1)

我可以看到错误率随着每次迭代而逐渐降低,一般在 1.26e-05 左右收敛。

到目前为止我已经尝试过:

    主成分分析 不同的数据集(来自 sklearn 的虹膜和来自 Coursera ML 课程的手写数字,两者的准确率都达到了 95% 左右)。但是,这两个都是批量处理的,所以我可以假设我的一般实现是正确的,但是我提取特征的方式或训练分类器的方式有问题。 尝试了 sklearn 的 SGDClassifier,但它的性能并没有好多少,准确率约为 50%。那么这些功能有问题吗?

编辑: h2 的平均输出如下所示:

[0.5004899   0.45264441]
[0.50048522  0.47439413]
[0.50049019  0.46557124]
[0.50049261  0.45297816]

因此,所有验证示例的 sigmoid 输出都非常相似。

【问题讨论】:

想一想,你是在随机化你的训练集吗?如果第一批中有一堆0 类,它可能很早就开始关注它们。 数据是有序的,即:10000个0,然后10000个1。 刚刚意识到您说的是“批处理”。我想我对“小批量”感到困惑,这是一个常见问题。我需要再考虑一下。 仅供参考:我尝试随机化输入数据,结果仍然相同。 尝试从最终的 predict 调用中返回原始的 h2 值。它们也都一样吗? 【参考方案1】:

我的网络总是预测同一个类别。有什么问题?

我有过几次。虽然我目前懒得看你的代码,但我想我可以给出一些一般性的提示,这也可能对其他有相同症状但可能存在不同潜在问题的人有所帮助。

调试神经网络

拟合一项数据集

对于网络应该能够预测的每个类别,请尝试以下操作:

    创建一个仅包含一个 i 类数据点的数据集。 使网络适合此数据集。 网络是否学会预测“i 类”?

如果这不起作用,有四个可能的错误来源:

    Buggy 训练算法:尝试使用较小的模型,打印大量在两者之间计算的值,看看是否符合您的预期。
      除以 0:在分母上加一个小数 0 的对数/负数:如除以 0
    数据:您的数据类型可能有误。例如,您的数据可能必须是 float32 类型,但实际上是整数。 模型:也有可能您刚刚创建的模型无法预测您想要什么。当您尝试更简单的模型时,应该会发现这一点。 初始化/优化:根据模型的不同,您的初始化和优化算法可能起着至关重要的作用。对于使用标准随机梯度下降的初学者,我会说随机初始化权重非常重要(每个权重都有不同的值)。 - 另见:this question / answer

学习曲线

详情请见sklearn。

这个想法是从一个很小的训练数据集(可能只有一个项目)开始。那么模型应该能够完美地拟合数据。如果这可行,您将制作一个稍大的数据集。您的训练错误应该会在某个时候略微上升。这揭示了您的模型对数据进行建模的能力。

数据分析

检查其他类的出现频率。如果一个类支配其他类(例如,一个类占数据的 99.9%),这是一个问题。寻找“异常值检测”技术。

更多

学习率:如果您的网络没有改善并且仅比随机机会稍微好一点,请尝试降低学习率。对于计算机视觉,0.001 的学习率经常被使用/工作。如果您使用 Adam 作为优化器,这也很重要。 预处理:确保对训练和测试使用相同的预处理。您可能会在混淆矩阵中看到差异(请参阅this question)

常见错误

这是受到reddit的启发:

您忘记应用预处理 Dying ReLU 学习率太小/太大 最后一层的激活函数错误: 您的目标不是和一吗? -> 不要使用 softmax 目标的单个元素是负数 -> 不要使用 Softmax、ReLU、Sigmoid。 tanh 可能是一种选择 网络太深:您无法训练。先尝试一个更简单的神经网络。 严重不平衡的数据:您可能需要查看imbalanced-learn

【讨论】:

目标的单个元素是负数 -> 不要使用 Softmax、ReLU、Sigmoid。 tanh 可能是一种选择。您能否建议在这种情况下正确的激活函数? 你看到我建议tanh了吗?你还有什么期待? (您总是可以设计自己的;有时线性也是一个不错的选择) 我看错了。我认为 tanh 在不使用的函数列表中。也许应该是 Tanh,因为它是句子中的第一个词 “你的目标不是和一?-> 不要使用 softmax”和“你的目标的单个元素是负数” - 你所说的“目标”到底是什么意思? 谢谢先生,我遇到了学习率问题。你救了我。作为一般调试或模型构建步骤,对于阅读本文的任何人,我总是建议从一些琐碎的事情开始,并构建您的模型一次只更改一个东西,同时关注您的指标。由于变量太多,要查明问题总是会变得更加棘手。【参考方案2】:

经过一周半的研究,我想我明白了问题所在。代码本身没有任何问题。阻止我的实现成功分类的唯一两个问题是花费的学习时间和正确选择学习率/正则化参数。

我现在已经运行了一些学习例程,它已经将准确率提高到 75%,尽管仍有很大的改进空间。

【讨论】:

你能告诉我你之前运行了多少,注意到之后运行了多少?我自己也遇到了一些问题,但即使再过一段时间它似乎并没有自行纠正,最终仍然只能一遍又一遍地预测同一个班级.. 这里也有同样的问题 我遇到了同样的问题。尝试在调度程序中使用学习率,并对其进行了更多时期的训练,并在 500 个时期后以 100% 的准确率设法过度拟合我的数据 对于任何遇到相同问题的人,您需要花更多时间调整 LR - 这就是答案。 通常是学习率过高还是过低导致了这个问题?【参考方案3】:

同样的事情发生在我身上。我有一个不平衡的数据集(0 类和 1 类之间的样本分布分别约为 66%-33%),并且在第一次迭代后,网络总是为所有样本输出 0.0

我的问题只是学习率太高。将其切换到1e-05 解决了这个问题。

更一般地说,我建议在参数更新之前打印:

您的净产量(一批) 对应标签(同批次) 逐个样本或汇总的损失值(在同一批次上)。

然后在参数更新后检查同样的三项。您应该在下一批中看到净输出的逐渐变化。当我的学习率太高时,已经在第二次迭代中,对于批次中的所有样本,净输出将射向全部 1.0s 或全部 0.0s。

【讨论】:

【参考方案4】:

同样的事情发生在我身上。我的在deeplearning4jJAVA 库中用于图像分类。它不断为每次测试提供最后一个训练文件夹的最终输出。我能够通过降低学习率来解决它。

可以使用的方法:

    降低学习率。 (第一个我的是 0.01 - 降低到 1e-4 并且有效) 增加批量大小(有时随机梯度下降不起作用,那么您可以尝试增加批量大小(32,64,128,256,..) 打乱训练数据

【讨论】:

就我而言,我用你的解决方案解决了。我将学习率从 0.001 切换到 0.0001。谢谢。 感谢您的建议。批量大小是我模型中的问题。【参考方案5】:

以防其他人遇到此问题。我的是deeplearning4j Lenet(CNN) 架构,它不断地为每次测试提供最后一个训练文件夹的最终输出。 我能够通过 increasing my batchsizeshuffling the training data 解决它,因此每批至少包含来自多个文件夹的样本。我的数据类的批次大小为 1,实际上是 dangerous

编辑:尽管我最近观察到的另一件事是每个班级的训练样本集有限,尽管 dataset 很大。 例如 训练一个neural-network 来识别human faces,但对于1 person 最多只能说2 个不同的面孔。数据集由 10,000 persons 组成,因此总共有 20,000 facesdataset。一个更好的 dataset 将是 1000 不同的 faces 对于 10,000 persons 因此,dataset 总共 10,000,000 faces。如果您想避免将数据过度拟合到一个类,这是相对必要的,这样您的network 就可以轻松概括并产生更好的预测。

【讨论】:

【参考方案6】:

我也遇到了同样的问题,我通过 ResNet50 使用迁移学习进行二进制分类,我能够通过替换来解决它:

Dense(output_dim=2048, activation= 'relu')

Dense(output_dim=128, activation= 'relu')

并且还通过移除 Keras Augmentation 并重新训练 RestNet50 的最后一层

【讨论】:

【参考方案7】:

我遇到了模型总是预测相同标签的问题。困扰了我一个星期。最后,我通过将RELU替换为其他激活函数来解决。RELU会导致“Dying ReLU”问题。

在我解决问题之前。我试过了:

    检查正负采样率,从 1:25 到 1:3。但它不起作用 改变batchsize和learning rate等损失。但是不起作用

最后我发现将学习率从 0.005 降低到 0.0002 已经是有效的了。

【讨论】:

【参考方案8】:

在尝试了许多解决方案后,我发现问题出在预测阶段,而不是训练或模型架构。 我用于预测的方法在所有情况下都显示为零,即使我的验证准确度相对较高,因为这条线:

predicted_class_indices=np.argmax(scores,axis=1)

如果您正在处理二进制分类,请尝试:

predict = model.predict(
    validation_generator, steps=None, callbacks=None, max_queue_size=10, workers=1,
    use_multiprocessing=False, verbose=0
)

【讨论】:

【参考方案9】:

同样的事情发生在我身上。该模型仅预测 7 类 CNN 的一类。 我试图改变激活函数、批量大小但没有任何效果。 然后改变学习率也对我有用。

opt = keras.optimizers.Adam(learning_rate=1e-06)

如您所见,我不得不选择一个非常低的学习率。 我的训练样本数为 5250,验证样本数为 1575。

【讨论】:

【参考方案10】:

TOPUP 答案真的对我有用。我的情况是,当我使用大型数据集(超过 400 万个样本)训练 bert4reco 模型时,acc 和 log_loss 在整个时期始终保持在 0.5 和 0.8 之间(花费 8 小时,我每 100 步打印一次结果)。然后我使用了一个非常小的数据集和一个更小的模型,终于可以了!模型开始学习一些东西,acc 和 log_loss 开始增加并在 300 个 epoch 后达到收敛!

最后,TOPUP 答案是此类问题的一个很好的清单。有时,如果您在训练开始时看不到任何变化,那么您的模型可能需要很长时间才能真正学到一些东西。最好用户 mini dataset 来断言,然后你可以等待它学习或使用一些有效的设备,如 GPU 或 TPUs

【讨论】:

以上是关于神经网络总是预测同一个类别的主要内容,如果未能解决你的问题,请参考以下文章

分类:类中的数据偏斜

Keras LSTM 网络预测所有信号属于同一类别(在 3 个不同的类别中)

为啥带有 Dropout 的 DNN 总是预测一个?

Python,为啥我的概率神经网络(PNN)总是预测零?

用于回归的 tensorflow 深度神经网络总是在一批中预测相同的结果

判别或预测方法汇总(判别分析神经网络支持向量机SVM等)