自定义Keras损失函数,有条件地创建零梯度

时间:2019-01-04 00:25:55

标签: python tensorflow machine-learning keras loss-function

我的问题是,如果y_true取某些值,我不希望调整权重。由于我要使用的RNN的性质,我不想简单地从训练数据中删除这些示例。

是否可以通过这种行为在Keras中编写条件损失函数?

例如:如果y_true为负,则应用零梯度,以使模型中的参数不变,如果y_true为正loss = losses.mean_squared_error(y_true, y_pred)

2 个答案:

答案 0 :(得分:1)

由于y是成批的,因此您需要从定制损失函数中从批次中选择非零的那些

def myloss(y_true, y_pred):
    idx  = tf.not_equal(y_true, 0)
    y_true = tf.boolean_mask(y_true, idx)
    y_pred = tf.boolean_mask(y_pred, idx)
    return losses.mean_squared_error(y_true, y_pred)

然后可以这样使用:

model = keras.Sequential([Dense(32, input_shape=(2,)), Dense(1)])
model.compile('adam', loss=myloss)

x = np.random.randn(2, 2)
y = np.array([1, 0])
model.fit(x, y)

但是,如果批次中的所有y_true均为零,则损失函数中可能需要额外的逻辑,在这种情况下,loss函数可以进行如下修改:

def myloss2(y_true, y_pred):
    idx  = tf.not_equal(y_true, 0)
    y_true = tf.boolean_mask(y_true, idx)
    y_pred = tf.boolean_mask(y_pred, idx)
    loss = tf.cond(tf.equal(tf.shape(y_pred)[0], 0), lambda: tf.constant(0, dtype=tf.float32), lambda: losses.mean_squared_error(y_true, y_pred))
    return loss

答案 1 :(得分:0)

您可以定义自定义损失函数,只需使用K.switch有条件地获得零损失:

from keras import backend as K
from keras import losses

def custom_loss(y_true, y_pred):
    loss = losses.mean_squared_error(y_true, y_pred)
    return K.switch(K.flatten(K.equal(y_true, 0.)), K.zeros_like(loss), loss)

测试:

from keras import models
from keras import layers

model = models.Sequential()
model.add(layers.Dense(1, input_shape=(1,)))

model.compile(loss=custom_loss, optimizer='adam')

weights, bias = model.layers[0].get_weights()

x = np.array([1, 2, 3])
y = np.array([0, 0, 0])

model.train_on_batch(x, y)

# check if the parameters has not changed after training on the batch
>>> (weights == model.layers[0].get_weights()[0]).all()
True

>>> (bias == model.layers[0].get_weights()[1]).all()
True