【问题标题】:How to get a single value from softmax instead of probability & get confusion matrix如何从softmax而不是概率获取单个值并获取混淆矩阵
【发布时间】:2018-08-01 04:41:17
【问题描述】:
test_generator = test_datagen.flow_from_directory(
    test_dir,
    target_size=(150, 150),
    batch_size=20,
    class_mode='categorical')
test_loss, test_acc = model.evaluate_generator(test_generator, steps=28)
print('test acc:', test_acc)

predict = model.predict_generator(test_generator,steps =28, verbose=0)
print('Prediction: ', predict)

test_imgs, test_labels = next(test_generator)

print(test_labels)

cm =confusion_matrix(test_labels, predict)

我从上面的代码中遇到了 2 个问题。首先,我得到一个错误,即我的 test_labels 和 predict 之间的样本数量不同。我的 test_labels 只存储 20 个样本(如批量大小所写。同时,我从 model.predict_generator 预测共有 560 张图像(20*28 步)

ValueError: Found input variables with inconsistent numbers of samples: [20, 560]

第二个问题是,我如何改变我的 softmax 值(从我的 4 个图像类的概率在浮点数到整数)?当我将步骤更改为 1 时出现错误(仅测试 20 个样本,而不是上述问题中的总共 560 个)

ValueError: Classification metrics can't handle a mix of multilabel-indicator and continuous-multioutput targets

我认为这是错误的,因为当我进行预测时,我会得到一些像这样的 4-d 列表(来自 4 个类),例如

Prediction:  [[2.9905824e-12 5.5904431e-10 1.8195983e-11 1.0000000e+00]
 [2.7073351e-21 1.0000000e+00 8.3221777e-21 4.9091786e-22]
 [4.2152173e-05 6.1331893e-04 3.7486094e-05 9.9930704e-01]

无论如何我可以得到我的模型预测的确切类别(例如在我的测试损失和测试准确性中)。

或者有没有其他简单的方法可以在 Keras 中获取我不知道的混淆矩阵? :(

Edit1(从desertnaut获得) test_labels 变量的返回如下

array([[0., 0., 0., 1.],
   [0., 0., 0., 1.],
   [0., 1., 0., 0.],
   [0., 1., 0., 0.],
   [0., 1., 0., 0.],
   [0., 0., 0., 1.],
   [1., 0., 0., 0.],
   [0., 0., 0., 1.],
   [0., 1., 0., 0.],
   [0., 0., 0., 1.],
   [0., 0., 0., 1.],
   [0., 1., 0., 0.],
   [0., 0., 0., 1.],
   [0., 0., 0., 1.],
   [0., 0., 1., 0.],
   [0., 1., 0., 0.],
   [0., 1., 0., 0.],
   [0., 0., 0., 1.],
   [0., 0., 0., 1.],
   [0., 0., 1., 0.]], dtype=float32), array([[1., 0., 0., 0.],
   [0., 0., 0., 1.],

^ 这仅适用于 1 个周期(总共 28 个,另外还有 27 个此列表)。此快照位于输出中间的某个位置。列表太长,无法显示最顶部的数组(无法滚动到 Spyder 输出框的顶部)。我尝试使用 argmax 作为上面的第二个问题。例如

test_class = np.argmax(test_labels, axis=1)
test_class = test_class.tolist()
print(test_class)

但是我没有得到正确的答案。我认为因为循环不同。我认为您给出的 predict_class 的输出是 1 个列表,其中包含所有 560 个样本预测。但是对于 test_label,它算作 28 个不同的循环。 predict_class 的输出是这样的。例如

[3, 1, 1, 2, 0, 0, 3, 1, 2, 0, 0, 1, 2, 2, 1, 3, 2, 2, 0, 2, 0, 3, 0, 1, 3, 3, 1, 2, 0, 1, 1, 0, 2, 1, 0, 2, 1, 3, 1, 0, 1, 2, 2, 2, 1, 2, 2, 2, 2, 3, 2, 3, 1, 3, 1, 1, 3, 2, 2, 0, 1, 1, 0, 2, 1, 3, 3, 2, 0, 1, 1, 0, 3, 0, 0, 2, 3, 2, 1, 1, 2, 3, 0, 0, 2, 1, 3, 2, 3, 1, 0, 0, 3, 0, 3, 1, 1, 3, 1, 0, 1, 2, 0, 0, 0, 0, 3, 2, 2, 3, 3, 1, 3, 0, 3, 2, 0, 0, 0, 2, 1, 0, 2, 2, 1, 0, 1, 2, 2, 2, 3, 2, 1, 2, 2, 0, 0, 2, 3, 3, 1, 2, 2, 3, 0, 2, 1, 1, 3, 0, 1, 0, 1, 3, 3, 1, 3, 0, 1, 3, 0, 2, 1, 1, 3, 0, 1, 0, 1, 1, 3, 2, 3, 3, 0, 1, 1, 3, 2, 0, 3, 2, 0, 1, 3, 3, 2, 1, 1, 1, 0, 2, 0, 2, 2, 0, 2, 2, 0, 0, 1, 2, 2, 0, 0, 1, 1, 1, 0, 2, 2, 0, 3, 0, 3, 2, 2, 0, 1, 1, 1, 3, 0, 2, 2, 1, 3, 3, 3, 1, 2, 0, 3, 0, 0, 3, 1, 1, 3, 0, 2, 2, 2, 2, 3, 0, 2, 3, 0, 3, 2, 3, 2, 3, 3, 0, 0, 2, 3, 2, 0, 0, 3, 1, 3, 0, 0, 1, 1, 0, 1, 0, 0, 3, 0, 0, 1, 1, 3, 1, 3, 2, 1, 0, 1, 0, 2, 3, 0, 1, 2, 1, 2, 2, 2, 2, 0, 2, 2, 1, 3, 2, 2, 2, 1, 3, 3, 2, 0, 3, 0, 1, 2, 2, 2, 3, 1, 0, 2, 3, 2, 1, 0, 1, 2, 0, 2, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 3, 3, 2, 1, 0, 0, 3, 0, 0, 2, 1, 0, 2, 3, 2, 3, 2, 1, 3, 0, 2, 1, 0, 0, 0, 1, 2, 2, 3, 2, 3, 2, 0, 3, 2, 1, 0, 0, 3, 2, 3, 0, 2, 0, 1, 0, 0, 3, 2, 3, 1, 3, 2, 2, 2, 0, 1, 2, 0, 2, 0, 0, 0, 3, 1, 3, 2, 3, 2, 1, 2, 3, 3, 1, 3, 3, 0, 1, 1, 2, 0, 1, 2, 3, 0, 2, 2, 2, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 0, 1, 3, 0, 2, 3, 1, 0, 2, 3, 2, 3, 1, 1, 2, 1, 2, 3, 0, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 0, 0, 2, 0, 1, 0, 3, 1, 0, 0, 2, 1, 2, 3, 3, 2, 2, 1, 2, 2, 0, 2, 0, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 0, 3, 2, 2, 3, 0, 1, 3, 2, 3, 3, 0, 3, 1, 2, 3, 3, 0, 3, 3, 3, 2, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 0, 0, 0, 1, 2, 2, 2, 3, 0, 0, 1, 1, 0, 2, 0, 2, 0, 3, 3, 1, 0, 2, 2, 1, 0, 0, 3, 0, 3, 3, 3]

^ 560 个样本的 1 个列表。

test_class 的输出(带有 argmax 编辑)。例如

[[7, 3, 0, 2], [9, 3, 2, 0], [0, 2, 9, 6], [0, 2, 3, 1], [2, 3, 0, 1], [6, 0, 1, 4], [5, 0, 1, 2], [1, 3, 2, 0], [0, 2, 3, 5], [0, 1, 3, 7], [1, 0, 8, 4], [3, 7, 1, 0], [3, 5, 0, 2], [9, 0, 3, 1], [0, 2, 1, 9], [8, 5, 1, 0], [2, 0, 1, 8], [0, 5, 1, 3], [0, 17, 1, 4], [2, 1, 7, 0], [0, 4, 5, 1], [1, 2, 0, 4], [0, 2, 3, 1], [2, 0, 1, 3], [3, 2, 1, 0], [0, 2, 7, 6], [5, 0, 18, 2], [2, 0, 7, 1]]

numpy 或 scipy 中是否有一个函数可以使其成为 560 个样本的 1 个列表,而不是 28 个列表*20 批次。

编辑2

谢谢!两者现在都在 1 个列表中。但是,有没有办法检查样本是否以同样的方式洗牌?我获得了 87.8% 的分类准确率。但我得到的 conf_matrix 非常低。

[[33 26 35 46]
 [43 25 41 31]
 [38 36 36 30]
 [32 30 39 39]]

【问题讨论】:

    标签: python keras softmax


    【解决方案1】:

    对于您的第二个问题,由于您的预测是一次性编码的,因此您应该简单地获取最大参数;以您显示的 3 个预测为例:

    import numpy as np
    # your shown predictions:
    predict = np.array( [[2.9905824e-12, 5.5904431e-10, 1.8195983e-11 ,1.0000000e+00],
                         [2.7073351e-21, 1.0000000e+00, 8.3221777e-21, 4.9091786e-22],
                         [4.2152173e-05, 6.1331893e-04, 3.7486094e-05, 9.9930704e-01]])
    predict_class = np.argmax(predict, axis=1)
    predict_class = predict_class.tolist()
    predict_class
    # [3, 1, 3]
    

    关于您的第一个问题:我假设您无法独立获取整个数据集的 test_labels(否则您可能会使用这个长度为 560 的数组作为混淆矩阵);如果是这样,您可以使用类似 [updated after OP edit]:

    test_labels = []
    for i in range(28):
        test_imgs, batch_labels = next(test_generator)
        batch_labels = np.argmax(batch_labels, axis=1).tolist()
        test_labels = test_labels + batch_labels
    

    之后,您的 test_labels 和 predict_class 都将是长度为 560 的列表,并且您应该能够获得整个测试集的混淆矩阵

    cm =confusion_matrix(test_labels, predict_class)
    

    为确保预测和测试标签确实对齐,您应该将shuffle=False 参数添加到您的test_datagen.flow_from_directory()(默认值为True - docs)。

    鉴于混淆矩阵,如果您需要进一步的分类度量,例如精度、召回率等,请查看 my answer here。

    【讨论】:

    • 您好,先生,感谢您的反馈!我用你的答案得到了第二个问题。但是,对于第一个答案(在 range(28) 循环中),我得到了 28 个 20 个预测的列表。而在 predict_class 它是 560 的 1 个列表。我尝试使用 argmax 函数作为您的第二个问题。但我得到奇怪的答案,例如[[0, 1, 9, 5], [0, 13, 5, 2], [1, 0, 2, 3], (共有 28 个列表)
    • @JonSalji 欢迎您。请编辑您的帖子以添加在您自己的初始代码中返回的test_labels 变量示例(或我循环的batch_labels - 它们应该相同)
    • 谢谢!我已经用我得到的返回变量编辑了我的帖子。 python中是否有任何函数可以从20个列表中提取压缩并使其成为1个列表?
    • @JonSalji 所以,您的测试标签也是一次性编码的!没看到 - 备用更新我的答案
    • 谢谢!您提供的代码将其转换为 1 个列表。有没有办法检查用于评估这两者的洗牌是否相同?我得到的混淆矩阵非常糟糕(作为编辑)。和RNG种子有关系吗?
    【解决方案2】:

    你也可以使用sklearn

    import numpy as np
    # your shown predictions:
    predict = np.array( [[2.9905824e-12, 5.5904431e-10, 1.8195983e-11 ,1.0000000e+00],
                         [2.7073351e-21, 1.0000000e+00, 8.3221777e-21, 4.9091786e-22],
                         [4.2152173e-05, 6.1331893e-04, 3.7486094e-05, 9.9930704e-01]])
    
    labels = ['class1', 'class2', 'class3', 'class4']
    from sklearn.preprocessing import LabelBinarizer
    lb.fit(labels)
    
    predict_class = lb.inverse_transform(predict)
    print(predict_class)
    # ['class4', 'class2', 'class4']
    

    【讨论】:

      猜你喜欢
      • 2018-10-02
      • 1970-01-01
      • 2016-05-07
      • 2018-04-26
      • 2021-12-03
      • 2019-10-20
      • 2020-10-03
      • 2021-04-12
      • 2017-12-19
      相关资源
      最近更新 更多