2017-08-22 4 views
2

Comment créer une fonction de perte personnalisée dans MXNET? Par exemple, au lieu de calculer une perte d'entropie croisée pour une étiquette (en utilisant la couche standard mx.sym.SoftmaxOutput qui calcule la perte d'entropie croisée et renvoie un symbole qui peut être transmis comme symbole de perte à la fonction d'ajustement), je veux calculer perte pondérée d'entropie croisée pour chaque étiquette possible. Les tutoriels MXNET mentionnent l'utilisationFonction de perte personnalisée MXNET et eval_metric

mx.symbol.MakeLoss(scalar_loss_symbol, normalization='batch') 

Cependant, quand j'utilise MakeLoss fonction, le eval_metric - "acc" standard ne fonctionne pas (évidemment que le modèle ne sait pas ce qui est mon vecteur de probabilité prédite). Par conséquent, je dois écrire mon propre eval_metric. De plus, au moment de la prédiction, je dois aussi prédire le vecteur de probabilité, auquel on ne peut accéder que si je regroupe le vecteur de probabilité final avec le symbole de perte et block_grad.

Répondre

1

Le code ci-dessous est une modification du tutoriel MXNET http://mxnet.io/tutorials/python/mnist.html où la fonction de perte de SoftmaxOutput standard est réécrite pour une fonction de perte pondérée personnalisée et eval_metric personnalisé requis est écrit.

import logging 
logging.getLogger().setLevel(logging.DEBUG) 
import mxnet as mx 
import numpy as np 
mnist = mx.test_utils.get_mnist() 

batch_size = 100 
weighted_train_labels =  
np.zeros((mnist['train_label'].shape[0],np.max(mnist['train_label'])+ 1)) 
weighted_train_labels[np.arange(mnist['train_label'].shape[0]),mnist['train_label']] = 1 
train_iter = mx.io.NDArrayIter(mnist['train_data'], {'label':weighted_train_labels}, batch_size, shuffle=True) 

weighted_test_labels = np.zeros((mnist['test_label'].shape[0],np.max(mnist['test_label'])+ 1)) 
weighted_test_labels[np.arange(mnist['test_label'].shape[0]),mnist['test_label']] = 1 
val_iter = mx.io.NDArrayIter(mnist['test_data'], {'label':weighted_test_labels}, batch_size) 

data = mx.sym.var('data') 
# first conv layer 
conv1 = mx.sym.Convolution(data=data, kernel=(5,5), num_filter=20) 
tanh1 = mx.sym.Activation(data=conv1, act_type="tanh") 
pool1 = mx.sym.Pooling(data=tanh1, pool_type="max", kernel=(2,2), stride=(2,2)) 
# second conv layer 
conv2 = mx.sym.Convolution(data=pool1, kernel=(5,5), num_filter=50) 
tanh2 = mx.sym.Activation(data=conv2, act_type="tanh") 
pool2 = mx.sym.Pooling(data=tanh2, pool_type="max", kernel=(2,2), stride=(2,2)) 
# first fullc layer 
flatten = mx.sym.flatten(data=pool2) 
fc1 = mx.symbol.FullyConnected(data=flatten, num_hidden=500) 
tanh3 = mx.sym.Activation(data=fc1, act_type="tanh") 
# second fullc 
fc2 = mx.sym.FullyConnected(data=tanh3, num_hidden=10) 
# softmax loss 
#lenet = mx.sym.SoftmaxOutput(data=fc2, name='softmax') 

label = mx.sym.var('label') 
softmax = mx.sym.log_softmax(data=fc2) 
softmax_output = mx.sym.BlockGrad(data = softmax,name = 'softmax') 
ce = ce = -mx.sym.sum(mx.sym.sum(mx.sym.broadcast_mul(softmax,label),1)) 
lenet = mx.symbol.MakeLoss(ce, normalization='batch') 

sym = mx.sym.Group([softmax_output,lenet]) 
print sym.list_outputs 

def custom_metric(label,softmax): 
    return len(np.where(np.argmax(softmax,1)==np.argmax(label,1))[0])/float(label.shape[0]) 

eval_metrics = mx.metric.CustomMetric(custom_metric,name='custom-accuracy', output_names=['softmax_output'],label_names=['label']) 

lenet_model = mx.mod.Module(symbol=sym, context=mx.gpu(),data_names=['data'], label_names=['label']) 
lenet_model.fit(train_iter, 
       eval_data=val_iter, 
       optimizer='sgd', 
       optimizer_params={'learning_rate':0.1}, 
       eval_metric=eval_metrics,#mx.metric.Loss(),#'acc', 
       #batch_end_callback = mx.callback.Speedometer(batch_size, 100), 
       num_epoch=10)