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

新手上路,请多包涵

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

原文由 Yurii Dolhikh 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 254
2 个回答

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

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

原文由 Yurii Dolhikh 发布,翻译遵循 CC BY-SA 3.0 许可协议

我的网络确实总是预测同一类。问题是什么?

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

调试神经网络

拟合一项数据集

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

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

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

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

学习曲线

有关详细信息,请参阅 sklearn

学习曲线显示训练误差/测试误差曲线相互接近

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

数据分析

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

更多的

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

常见错误

这是受 reddit 的启发:

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

原文由 Martin Thoma 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进