2017-08-21 5 views
0

Je suis nouveau à MXNet et je veux résoudre un exemple simple qui utilise le réseau 1 couche pour résoudre le problème de classification des chiffres. Mon programme se déroule comme suit:Pourquoi MXNet signale une exactitude de validation incorrecte?

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) 

Après l'exécution du programme avec l'étiquette d'évaluation 15000 à 16000, l'étape finale signale une précision de validation des 97%, que je soutiens personnellement est trop élevé pour un réseau 1-couche. Par conséquent, j'ai délibérément changé les étiquettes d'évaluation à 1200 à 2200 et j'ai vu que le programme rapporte toujours une précision autour de 83~86% (au début je pensais que c'était peut-être juste une coïncidence et essayé plusieurs étiquettes d'évaluation différentes mais obtenaient des résultats similaires).

Quelles sont les erreurs que j'ai commises dans mon programme?

Répondre

1

TLDR;

Vous pouvez résoudre le problème si vous arrêtez d'effectuer un codage à chaud unique. Au lieu de transmettre les étiquettes [0: 15000], les étiquettes [15000: 16000] et les étiquettes [16000: 18720], les étiquettes passent [0: 15000], les étiquettes [15000: 16000] et les étiquettes [16000: 18720]. Cela réduira votre précision à 0,796000 médiocre sur les étiquettes d'évaluation appropriées et jusqu'à 0,095000 sur vos étiquettes d'évaluation «aléatoires».

réponse détaillée

Vous obtenez cette grande précision due à un calcul trompeur de mxnet.metric.Accuracy. En interne, mesure de précision peut fonctionner en 2 « modes » en fonction des formes des arguments fournis « de preds » et « étiquettes »:

  1. Si des formes de « preds » et « étiquettes » ne correspondent pas, la précision interprète chaque ligne des "prédicats" en tant que probabilités d'appartenir à chaque classe. La classe est définie en tant qu'index d'élément dans le tableau.

Par exemple, si vous avez Preds = [[0,1, 0,9], [0,8, 0,2]] alors cela signifie que:

  • premier exemple appartient à la classe 0 avec 0,1 probabilité et à la classe 1 avec 0,9 probabilité
  • deuxième exemple appartient à la classe 0 à 0,8 et la probabilité de classe 1 avec 0,2 probabilité

travaillant dans ce mode, « labels » devraient être un tableau de classes réelles. Dans notre cas, en imaginant que le modèle est absolument correct, le tableau "labels" aurait dû être [1, 0].

2) Si les formes de "preds" et de "labels" correspondent, alors Accuracy traite les tableaux comme des classes prédites et des classes réelles. Chaque élément est donc traité comme une classe d'un échantillon. Ensuite, le calcul est effectué en tant que comparaison d'éléments dans des "étiquettes" "preds" avec les mêmes indices. Lorsque vous appliquez le codage à un seul codage à chaud aux étiquettes, le deuxième mode de calcul est utilisé, car la forme des prédictions du modèle correspond à celle du codage à codage à chaud unique. La précision interprète chaque élément des tableaux comme un échantillon autonome et les compare les uns aux autres.En interne, Accuracy converts float array to int, qui pour les flottants de moins de 1 produit toujours 0. Ce comportement convertit essentiellement toutes les prédictions à 0, sauf dans un cas rare où il existe une classe avec une probabilité de 1,0. Donc, dans la majorité des cas, nous obtenons preds = [0, 0, ..., 0].

Un tableau de codage à chaud a tous les éléments sauf un est égal à 0. Cela signifie que nous aurions quelque chose comme [0, 1, 0, ..., 0].

Lorsque la précision compare ces deux tableaux, ils constatent qu'ils sont presque égaux, à l'exception d'un endroit, renvoyant à tort une précision élevée.

Voici un exemple simple reproduction:

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()) 

Cela nous donnera

('accuracy', 0.90000000000000002) 

parce que l'encodage d'un chaud contient exactement 1 élément non nul.