我是 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)
在运行带有评估标签15000
到16000
的程序后,最后一步是报告97%
的验证准确度,我个人认为这对于单层网络来说太高了。因此,我故意将评估标签更改为1200
到2200
,并发现该计划仍然在83~86%
左右报告准确性(起初我认为这可能只是一个巧合,尝试了几种不同的评估标签,但仍然得到了类似的结果)。
我在程序中犯了哪些错误?
答案 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”的形状:
例如,如果你有preds = [[0.1,0.9],[0.8,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个非零元素。