自定义损失函数通过梯度下降在每一步进行更新
从这篇文章中,我们可以编写一个自定义损失函数。现在,假设自定义损失函数取决于参数a:
def customLoss(yTrue,yPred):
return (K.log(yTrue) - K.log(yPred))**2+a*yPred
我们如何像梯度权重那样以梯度下降的方式在每一步更新参数a?
a_new= a_old - alpha * (derivative of custom loss with respect to a)
PS的实际海关损失与上述不同。请给我一个适用于任何自定义损失函数的通用答案,而不是上述示例的答案。
-
创建一个自定义层来保存可训练参数。该层不会在调用中返回输入,但是我们将使用输入来遵守如何创建层。
class TrainableLossLayer(Layer): def __init__(self, a_initializer, **kwargs): super(TrainableLossLayer, self).__init__(**kwargs) self.a_initializer = keras.initializers.get(a_initializer) #method where weights are defined def build(self, input_shape): self.kernel = self.add_weight(name='kernel_a', shape=(1,), initializer=self.a_initializer, trainable=True) self.built=True #method to define the layers operation (only return the weights) def call(self, inputs): return self.kernel #output shape def compute_output_shape(self, input_shape): return (1,)
使用模型中的图层获取
a
任何输入(这与顺序模型不兼容):a = TrainableLossLayer(a_init, name="somename")(anyInput)
现在,您可以尝试以某种丑陋的方式定义损失:
def customLoss(yTrue,yPred): return (K.log(yTrue) - K.log(yPred))**2+a*yPred
如果这可行,那就准备好了。
您也可以尝试使用更复杂的模型(如果您不希望
a
像这样在损失中使用跳过层,这可能会导致模型保存/加载问题)在这种情况下,您将需要将其
y_train
作为输入而不是输出:y_true_inputs = Input(...)
您的损失函数将进入一个
Lambda
正确接受所有参数的层:def lambdaLoss(x): yTrue, yPred, alpha = x return (K.log(yTrue) - K.log(yPred))**2+alpha*yPred loss = Lambda(lambdaLoss)([y_true_inputs, original_model_outputs, a])
您的模型将输出以下损失:
model = Model([original_model_inputs, y_true_inputs], loss)
您将具有虚拟损失功能:
def dummyLoss(true, pred): return pred model.compile(loss = dummyLoss, ...)
并训练为:
model.fit([x_train, y_train], anything_maybe_None_or_np_zeros ,....)