有条件地创建零梯度的自定义 Keras 损失函数
Custom Keras loss function that conditionally creates a zero gradient
我的问题是,如果 y_true
取某些值,我不想调整权重。由于我尝试使用的 RNN 的性质,我不想简单地从训练数据中删除这些示例。
有没有办法用这种行为在 Keras 中编写条件损失函数?
例如:如果 y_true
为负,则应用零梯度,以便模型中的参数不会改变,如果 y_true
为正 loss = losses.mean_squared_error(y_true, y_pred)
。
由于 y
是分批的,因此您需要 select 那些在自定义损失函数中非零的批次
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
您可以定义自定义损失函数并简单地使用 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
我的问题是,如果 y_true
取某些值,我不想调整权重。由于我尝试使用的 RNN 的性质,我不想简单地从训练数据中删除这些示例。
有没有办法用这种行为在 Keras 中编写条件损失函数?
例如:如果 y_true
为负,则应用零梯度,以便模型中的参数不会改变,如果 y_true
为正 loss = losses.mean_squared_error(y_true, y_pred)
。
由于 y
是分批的,因此您需要 select 那些在自定义损失函数中非零的批次
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
您可以定义自定义损失函数并简单地使用 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