为什么MXNet报告错误的验证准确度?

时间:2017-08-21 13:15:25

标签: mxnet

我是 MXNet 的新手,想要解决使用1层网络解决数字分类问题的简单示例。我的计划如下:

import math
import numpy as np
import mxnet as mx
import matplotlib.pyplot as plt
import logging
logging.getLogger().setLevel(logging.DEBUG)
#============================================================
with np.load("notMNIST.npz") as data:

    images, labels = data["images"], data["labels"]

# Reshape the images from 28x28 into 784 1D-array and flaten the labels. 
images = images.reshape(784, 18720) labels = labels.reshape(18720)

# Apply one-hot encoding. 
Images = images.T.astype(np.float32) 
Labels = np.zeros((18720, 10)).astype(np.float32) 
Labels[np.arange(18720), labels] = 1

# Segment the data into training, evaluation and testing. 
X_train = Images[0 : 15000] 
y_train = Labels[0 : 15000]

X_eval = Images[15000 : 16000] 
y_eval = Labels[ 1200 :  2200] # IMPORTANT!!!

X_test = Images[16000 : 18720] 
y_test = Labels[16000 : 18720]

train_iter = mx.io.NDArrayIter(X_train, y_train, 100, shuffle=False)
_eval_iter = mx.io.NDArrayIter(X_eval , y_eval , 100, shuffle=False)
#============================================================
# Variables
X = mx.sym.Variable(name='data')

# Neural Network Layers
fully_connected_layer = mx.sym.FullyConnected(data=X, name='fc1', num_hidden=10)

# Outputs
lro = mx.sym.SoftmaxOutput(data=fully_connected_layer, name="softmax")
#============================================================

model = mx.mod.Module(symbol=lro)

model.fit(train_data=train_iter, eval_data=_eval_iter, 
          optimizer='sgd', optimizer_params={
              'learning_rate' : 1e-5, 
              'momentum' : 0.1}, 
          eval_metric="acc",
          num_epoch=500)

在运行带有评估标签1500016000的程序后,最后一步是报告97%的验证准确度,我个人认为这对于单层网络来说太高了。因此,我故意将评估标签更改为12002200,并发现该计划仍然在83~86%左右报告准确性(起初我认为这可能只是一个巧合,尝试了几种不同的评估标签,但仍然得到了类似的结果)。

我在程序中犯了哪些错误?

1 个答案:

答案 0 :(得分:1)

<强> TLDR;

如果您停止执行单热编码,则可以解决此问题。

而不是传递标签[0:15000],标签[15000:16000]和标签[16000:18720]传递标签[0:15000],标签[15000:16000]和标签[16000:18720]。

这会使您在正确评估标签上的准确度降至0.796000,在“随机”评估标签上降至0.095000。

详细答案

由于mxnet.metric.Accuracy的误导性计算,您获得了如此高的准确性。在内部,Accuracy指标可以在2种“模式”下工作,具体取决于提供的参数“preds”和“labels”的形状:

  1. 如果“preds”和“labels”的形状不匹配,Accuracy会将“preds”的每一行解释为样本属于每个类的概率。该类被定义为数组中的项索引。
  2. 例如,如果你有preds = [[0.1,0.9],[0.8,0.2]]则意味着:

    • 第一个例子属于0级,概率为0.1,而1级属于0.9概率
    • 第二个例子属于0级,概率为0.8,属于1级,概率为0.2

    在此模式下工作,“标签”应该是一个真实类的数组。在我们的例子中,想象模型绝对正确,“标签”数组应该是[1,0]。

    2)如果“preds”和“labels”的形状匹配,则Accuracy将数组视为预测类和实数类。因此,每个项目都被视为一个样本的一类。然后计算作为“preds”“标签”中具有相同索引的项目的比较。

    当您对标签应用单热编码时,会使用第二种计算模式,因为模型中预测的形状与单热编码的形状相匹配。精度将数组中的每个项目解释为独立样本,并将它们相互比较。

    在内部,Accuracy converts float array to int,对于小于1的浮点数总是产生0.该行为实际上将所有预测转换为0,除了罕见的情况,当存在1.0概率的类时。所以在大多数情况下我们得到preds = [0,0,...,0]。

    单热编码数组包含除1之外的所有项目等于0.意思是我们会有类似[0,1,0,...,0]的内容。

    当精确度比较这两个阵列时,它发现它们大部分是相同的,除了一个地方,返回错误的高精度。

    这是一个简单的再现示例:

    import mxnet as mx
    predicts = mx.nd.array([[1.29206967e-09,   3.40120096e-05,   2.23299547e-12,   3.98692492e-07,
        1.21151755e-10,   2.59370694e-08,   1.95488334e-02,   1.13474562e-05,
        9.80405331e-01,   3.51648767e-12]])
    labels = mx.nd.array([[0, 0, 0, 0, 0, 0, 0, 0, 1, 0]])
    acc = mx.metric.Accuracy()
    acc.update(preds=predicts, labels=labels)
    print(acc.get())
    

    这会给我们

    ('accuracy', 0.90000000000000002)
    

    因为单热编码恰好包含1个非零元素。