Reputation: 5001
When creating custom loss and metric function in a keras model it assumes for both cases that inputs are of (y_true, y_pred)
:
def custom_loss(y_true, y_pred):
.
return loss
def custom_metric(y_true, y_pred):
.
return metric
And the input of y_pred
is the output of the Model
. Example:
model = Model(inputs = [input1,..inputN], outputs=loss)
model.compile(loss=costum_loss, metrics=costum_metric)
In this case above for both loss and metric the y_pred will be the loss.
What if I want different input in costum_loss
and different in the costum_metric
. Is there a way to do it?
Edit:
More speciffically I want my loss to be:
def warp_loss(X):
z, positive_entity, negatives_entities = X
positiveSim = Lambda(lambda x: similarity(x[0], x[1]), output_shape=(1,), name="positive_sim")([z, positive_entity])
z_reshaped = Reshape((1, z.shape[1].value))(z)
negativeSim = Lambda(lambda x: similarity(x[0], x[1]), output_shape=(negatives_titles.shape[1].value, 1,), name="negative_sim")([z_reshaped, negatives_entities])
loss = Lambda(lambda x: max_margin_loss(x[0], x[1]), output_shape=(1,), name="max_margin")([positiveSim, negativeSim])
return loss
def mean_loss(y_true, y_pred):
return K.mean(y_pred - 0 * y_true)
and the metric:
def metric(X):
z, positive_entity, negatives_entities = X
positiveSim = Lambda(lambda x: similarity(x[0], x[1]), output_shape=(1,), name="positive_sim")([z, positive_entity])
z_reshaped = Reshape((1, z.shape[1].value))(z)
negativeSim = Lambda(lambda x: similarity(x[0], x[1]), output_shape=(negatives_titles.shape[1].value, 1,), name="negative_sim")([z_reshaped, negatives_entities])
position = K.sum(K.cast(K.greater(positiveSim, negativeSim), dtype="int32"), axis=1, keepdims=True)
accuracy = Lambda(lambda x: x / _NUMBER_OF_NEGATIVE_EXAMPLES)(position)
return accuracy
def mean_acc(y_true, y_pred):
return K.mean(y_pred - 0 * y_true)
So the first 4 lines are the same and after the two functions change. Could it be possible to use a Callback
to print mean_acc
?
Upvotes: 0
Views: 1193
Reputation: 86650
You don't need the loss
to be part of your model, you can make your model output its own outputs and later you apply the loss.
Here is a working code (it could be optimized to avoid repeating operations in both metrics and loss, by adding the commom part to the model)
I had some issues with your shapes, then I made it with arbitrary shapes. Your original lines are commented.
This code works for Keras 2.0.8, with Tensorflow 1.3.0. I suspect you're using Theano, right?
from keras.layers import *
from keras.models import *
import keras.backend as K
def get_divisor(x):
return K.sqrt(K.sum(K.square(x), axis=-1))
def similarity(a, b):
numerator = K.sum(a * b, axis=-1)
denominator = get_divisor(a) * get_divisor(b)
denominator = K.maximum(denominator, K.epsilon())
return numerator / denominator
def max_margin_loss(positive, negative):
#loss_matrix = K.maximum(0.0, 1.0 + negative - Reshape((1,))(positive))
loss_matrix = K.maximum(0.0, 1.0 + negative - positive)
loss = K.sum(loss_matrix, axis=-1, keepdims=True)
return loss
def warp_loss(X):
z = X[0]
positive_entity = X[1]
negative_entities = X[2]
positiveSim = similarity(z, positive_entity)
#z_reshaped = Reshape((1, z.shape[1].value))(z)
z_reshaped = K.expand_dims(z,axis=1)
negativeSim = similarity(z_reshaped, negative_entities)
#negativeSim = Reshape((negatives_titles.shape[1].value, 1,))
negativeSim = K.expand_dims(negativeSim,axis=-1)
loss = max_margin_loss(positiveSim, negativeSim)
return loss
def warp_metricsX(X):
z = X[0]
positive_entity = X[1]
negative_entities = X[2]
positiveSim = similarity(z, positive_entity)
#z_reshaped = Reshape((1, z.shape[1].value))(z)
z_reshaped = K.expand_dims(z,axis=1)
negativeSim = similarity(z_reshaped, negative_entities)
#Reshape((negatives_titles.shape[1].value, 1,))
negativeSim = K.expand_dims(negativeSim,axis=-1)
position = K.sum(K.cast(K.greater(positiveSim, negativeSim), dtype="int32"), axis=1, keepdims=True)
#accuracy = position / _NUMBER_OF_NEGATIVE_EXAMPLES
accuracy = position / 30
return accuracy
def mean_loss(yTrue,yPred):
return K.mean(warp_loss(yPred))
def warp_metrics(yTrue,yPred):
return warp_metricsX(yPred)
def build_nn_model():
#wl, tl = load_vector_lookups()
#embedded_layer_1 = initialize_embedding_matrix(wl)
#embedded_layer_2 = initialize_embedding_matrix(tl)
embedded_layer_1 = Embedding(200,25)
embedded_layer_2 = Embedding(200,25)
#sequence_input_1 = Input(shape=(_NUMBER_OF_LENGTH,), dtype='int32',name="text")
sequence_input_1 = Input(shape=(30,), dtype='int32',name="text")
sequence_input_positive = Input(shape=(1,), dtype='int32', name="positive")
sequence_input_negatives = Input(shape=(10,), dtype='int32', name="negatives")
embedded_sequences_1 = embedded_layer_1(sequence_input_1)
#embedded_sequences_positive = Reshape((tl.shape[1],))(embedded_layer_2(sequence_input_positive))
embedded_sequences_positive = Reshape((25,))(embedded_layer_2(sequence_input_positive))
embedded_sequences_negatives = embedded_layer_2(sequence_input_negatives)
conv_step1 = Convolution1D(
filters=1000,
kernel_size=5,
activation="tanh",
name="conv_layer_mp",
padding="valid")(embedded_sequences_1)
conv_step2 = GlobalMaxPooling1D(name="max_pool_mp")(conv_step1)
conv_step3 = Activation("tanh")(conv_step2)
conv_step4 = Dropout(0.2, name="dropout_mp")(conv_step3)
#z = Dense(wl.shape[1], name="predicted_vec")(conv_step4) # activation="linear"
z = Dense(25, name="predicted_vec")(conv_step4) # activation="linear"
model = Model(
inputs=[sequence_input_1, sequence_input_positive, sequence_input_negatives],
outputs = [z,embedded_sequences_positive,embedded_sequences_negatives]
)
model.compile(loss=mean_loss, optimizer='adam',metrics=[warp_metrics])
return model
Upvotes: 1