keras-team / keras

Deep Learning for humans
http://keras.io/
Apache License 2.0
61.29k stars 19.38k forks source link

Issue in creating custom Objective function #1060

Closed vishesh49 closed 8 years ago

vishesh49 commented 8 years ago

How can you create your own objective function, I tried to create a very basic objective function but it gives an error and I there is no way to know the size of the parameters passed to the function at run time.

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

I get this error saying

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.

Now if I change the code at the second line , it shows this error

loss = T.scalar('float64')

Error:

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

Is there something I am missing about how to create new objective functions because this is all I was able to understand from the limited documentation and examples about creating custom objective functions

fchollet commented 8 years ago

Is there something I am missing

You are missing the basics of writing Theano code. It's a symbolic tensor manipulation language, it doesn't work like Numpy. Here's a start: http://deeplearning.net/software/theano/tutorial/index.html#tutorial

vishesh49 commented 8 years ago

Yes, I am new to writing Theano code. I also saw that all the objective functions in https://github.com/fchollet/keras/blob/master/keras/objectives.py call Theano tensor functions so tried doing this, I copy pasted the categorical crossentropy code from objectives.py and pasted it into my code no changes made

def categorical_crossentropy(y_true, y_pred):
    '''Expects a binary class matrix instead of a vector of scalar classes
    '''
    y_pred = T.clip(y_pred, epsilon, 1.0 - epsilon)
    # scale preds so that the class probas of each sample sum to 1
    y_pred /= y_pred.sum(axis=-1, keepdims=True)
    cce = T.nnet.categorical_crossentropy(y_pred, y_true)
    return cce

I still get the same error: TypeError: cost must be a scalar.

rpinsler commented 8 years ago

This should work if you have properly defined T and epsilon and your inputs are in the correct format. See the example below:

import theano.tensor as T
import theano
from keras.utils.np_utils import to_categorical
import numpy as np

if theano.config.floatX == 'float64':
  epsilon = 1.0e-9
else:
  epsilon = 1.0e-7

def categorical_crossentropy(y_true, y_pred):
    '''Expects a binary class matrix instead of a vector of scalar classes
    '''
    y_pred = T.clip(y_pred, epsilon, 1.0 - epsilon)
    # scale preds so that the class probas of each sample sum to 1
    y_pred /= y_pred.sum(axis=-1, keepdims=True)
    cce = T.nnet.categorical_crossentropy(y_pred, y_true)
    return cce

y_true = T.matrix()
y_pred = T.matrix()
loss_fun = theano.function([y_true, y_pred], categorical_crossentropy(y_true,y_pred))

ytrue = np.asarray(to_categorical(np.random.randint(5,size=10)), dtype=theano.config.floatX)
ypred = np.asarray(np.random.rand(10,5), dtype=theano.config.floatX)
ypred = ypred/np.expand_dims(np.sum(ypred,-1),1) # class probabilities should sum up to 1
loss = loss_fun(ytrue, ypred)

The output is a cost for every sample (here: 10), which keras will sum up automatically.

Note that keras will take care of compiling your loss function (theano.function(...)). You simply have to provide a function that can handle symbolic Theano expressions. Make sure that the outputs of the previous layer conform to what the cost function expects.