web-dev-qa-db-fra.com

Comment créer une fonction d'objectif personnalisée dans Keras?

Il existe de nombreuses fonctions objectives dans Keras ici.

Mais comment pouvez-vous créer votre propre fonction objectif, j'ai essayé de créer une fonction objectif très basique mais cela donne une erreur et il n'y a aucun moyen de connaître la taille des paramètres passés à la fonction au moment de l'exécution.

def loss(y_true,y_pred):
    loss = T.vector('float64')
    for i in range(1):
        flag = True
        for j in range(y_true.ndim):
            if(y_true[i][j] == y_pred[i][j]):
                flag = False
        if(flag):
            loss = loss + 1.0
    loss /= y_true.shape[0]
    print loss.type
    print y_true.shape[0]
    return loss

Je reçois 2 erreurs contradictoires,

model.compile(loss=loss, optimizer=ada)
  File "/usr/local/lib/python2.7/dist-packages/Keras-0.0.1-py2.7.Egg/keras/models.py", line 75, in compile
    updates = self.optimizer.get_updates(self.params, self.regularizers, self.constraints, train_loss)
  File "/usr/local/lib/python2.7/dist-packages/Keras-0.0.1-py2.7.Egg/keras/optimizers.py", line 113, in get_updates
    grads = self.get_gradients(cost, params, regularizers)
  File "/usr/local/lib/python2.7/dist-packages/Keras-0.0.1-py2.7.Egg/keras/optimizers.py", line 23, in get_gradients
    grads = T.grad(cost, params)
  File "/usr/local/lib/python2.7/dist-packages/theano/gradient.py", line 432, in grad
    raise TypeError("cost must be a scalar.")
TypeError: cost must be a scalar.

Il dit que le coût ou la perte retourné dans la fonction doit être un scalaire mais si je change la ligne 2 de loss = T.vector ('float64')
à
perte = T.scalar ('float64')

il montre cette erreur

 model.compile(loss=loss, optimizer=ada)
  File "/usr/local/lib/python2.7/dist-packages/Keras-0.0.1-py2.7.Egg/keras/models.py", line 75, in compile
    updates = self.optimizer.get_updates(self.params, self.regularizers, self.constraints, train_loss)
  File "/usr/local/lib/python2.7/dist-packages/Keras-0.0.1-py2.7.Egg/keras/optimizers.py", line 113, in get_updates
    grads = self.get_gradients(cost, params, regularizers)
  File "/usr/local/lib/python2.7/dist-packages/Keras-0.0.1-py2.7.Egg/keras/optimizers.py", line 23, in get_gradients
    grads = T.grad(cost, params)
  File "/usr/local/lib/python2.7/dist-packages/theano/gradient.py", line 529, in grad
    handle_disconnected(elem)
  File "/usr/local/lib/python2.7/dist-packages/theano/gradient.py", line 516, in handle_disconnected
    raise DisconnectedInputError(message)
theano.gradient.DisconnectedInputError: grad method was asked to compute the gradient with respect to a variable that is not part of the computational graph of the cost, or is used only by a non-differentiable operator: <TensorType(float64, matrix)>
14
Vishesh Raimugia

Voici mon petit extrait pour écrire de nouvelles fonctions de perte et les tester avant d'utiliser:

import numpy as np

from keras import backend as K

_EPSILON = K.epsilon()

def _loss_tensor(y_true, y_pred):
    y_pred = K.clip(y_pred, _EPSILON, 1.0-_EPSILON)
    out = -(y_true * K.log(y_pred) + (1.0 - y_true) * K.log(1.0 - y_pred))
    return K.mean(out, axis=-1)

def _loss_np(y_true, y_pred):
    y_pred = np.clip(y_pred, _EPSILON, 1.0-_EPSILON)
    out = -(y_true * np.log(y_pred) + (1.0 - y_true) * np.log(1.0 - y_pred))
    return np.mean(out, axis=-1)

def check_loss(_shape):
    if _shape == '2d':
        shape = (6, 7)
    Elif _shape == '3d':
        shape = (5, 6, 7)
    Elif _shape == '4d':
        shape = (8, 5, 6, 7)
    Elif _shape == '5d':
        shape = (9, 8, 5, 6, 7)

    y_a = np.random.random(shape)
    y_b = np.random.random(shape)

    out1 = K.eval(_loss_tensor(K.variable(y_a), K.variable(y_b)))
    out2 = _loss_np(y_a, y_b)

    assert out1.shape == out2.shape
    assert out1.shape == shape[:-1]
    print np.linalg.norm(out1)
    print np.linalg.norm(out2)
    print np.linalg.norm(out1-out2)


def test_loss():
    shape_list = ['2d', '3d', '4d', '5d']
    for _shape in shape_list:
        check_loss(_shape)
        print '======================'

if __name__ == '__main__':
    test_loss()

Ici, comme vous pouvez le voir, je teste la perte binary_crossentropy, et j'ai 2 pertes distinctes définies, une version numpy (_loss_np) une autre version tensor (_loss_tensor) [Remarque: si vous utilisez simplement les fonctions keras, cela fonctionnera avec Theano et Tensorflow ... mais si vous dépendez de l'un d'eux, vous pouvez également les référencer par K.theano.tensor.function ou K.tf.function]

Plus tard, je compare les formes de sortie et la norme L2 des sorties (qui devraient être presque égales) et la norme L2 de la différence (qui devrait être vers 0)

Une fois que vous êtes convaincu que votre fonction de perte fonctionne correctement, vous pouvez l'utiliser comme:

model.compile(loss=_loss_tensor, optimizer=sgd)
19
indraforyou

(Réponse corrigée) Un moyen simple de le faire est d'appeler le backend Keras:

import keras.backend as K

def custom_loss(y_true,y_pred):
    return K.mean((y_true - y_pred)**2)

Ensuite:

model.compile(loss=custom_loss, optimizer=sgd,metrics = ['accuracy'])

c'est égal

model.compile(loss='mean_squared_error', optimizer=sgd,metrics = ['accuracy'])
4
Rubens_Zimbres