Keras:具有不同输入的公制和损耗

时间:2017-09-28 14:58:46

标签: python keras

在keras模型中创建自定义损失和指标函数时,它假设两种情况都是(y_true, y_pred)输入:

def custom_loss(y_true, y_pred):
    .
    return loss

def custom_metric(y_true, y_pred):
    .
    return metric

y_pred的输入是Model的输出。例如:

model = Model(inputs = [input1,..inputN], outputs=loss)
model.compile(loss=costum_loss, metrics=costum_metric)

在上面的这种情况下,对于损失和度量,y_pred将是损失。

如果我想要costum_loss中的不同输入和costum_metric中的不同输入,该怎么办?有办法吗?

修改

更具体地说,我希望我的损失是:

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)

和指标:

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)

所以前4行是相同的,并且在两个函数改变之后。是否可以使用Callback来打印mean_acc

1 个答案:

答案 0 :(得分:1)

您不需要loss成为模型的一部分,您可以使模型输出自己的输出,然后应用损失。

这是一个工作代码(可以通过将commom部分添加到模型中来优化它以避免在度量和损失中重复操作)

我的形状有些问题,然后我用任意形状做了。您的原始行已注释。

此代码适用于Keras 2.0.8,Tensorflow 1.3.0。我怀疑你正在使用Theano,对吧?

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