神经网络总是预测相同的 class

Neural network always predicts the same class

我正在尝试实现一个将图像分类为两个离散类别之一的神经网络。然而,问题是,它目前总是预测任何输入为 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 左右。

到目前为止我尝试过的:

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

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

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

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

My network does always predict the same class. What is the problem?

我有过几次。尽管我目前懒得浏览您的代码,但我想我可以提供一些一般性提示,这些提示也可能会帮助其他具有相同症状但可能存在不同潜在问题的人。

调试神经网络

拟合一项数据集

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

  1. 创建只有一个数据点的数据集 class i.
  2. 使网络适合此数据集。
  3. 网络是否学会预测 "class i"?

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

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

学习曲线

详情见sklearn

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

数据分析

检查其他 class(es) 出现的频率。如果一个 class 支配其他(例如一个 class 是 99.9% 的数据),这是一个问题。寻找 "outlier detection" 技巧。

更多

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

常见错误

这是受reddit启发:

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

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

我现在已经有了一些学习例程 运行,它的准确率已经达到 75%,尽管还有很多 space 需要改进。

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

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

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

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

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

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

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

我也遇到过同样的情况。我的在 deeplearning4j JAVA 图像库中 classification.It 继续为每个测试提供最后一个训练文件夹的最终输出。我能够通过降低学习率来解决它。

可以使用的方法:

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

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

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

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

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

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

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

我遇到了模型总是预测相同的问题 label.It 最后一个 week.At 让我困惑,我通过用其他激活替换 RELU 来解决它 function.The RELU 会导致“垂死的 ReLU”问题。

在我解决 problem.I 之前试过:

  1. 检查正负样本率,从1:25到1:3。但是不行
  2. 更改批量大小和学习率以及其他 loss.But 它不起作用

最后我发现把学习率从0.005降到0.0002已经有效了

在尝试了很多解决方案之后,事实证明我的问题出在预测阶段,而不是训练或模型架构。 我用于预测的方法在所有情况下都显示为零,尽管我的验证准确度相对较高,因为这一行:

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
)

我也遇到过同样的情况。该模型仅针对七个 class 个 CNN 预测一个 class。 我尝试更改激活函数、批量大小但没有任何效果。 然后改变学习率对我也有用。

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

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