在本教程中,我将介绍一个简单的技巧,它允许您在Keras中构造自定义损失函数,这些函数可以接收除y_true和y_pred之外的其他参数。
背景 - Keras损失和指标
在Keras中编译机器学习模型时,我们为compile函数提供所需的损失和指标。例如:
model.compile(loss=’mean_squared_error’, optimizer=’sgd’, metrics=‘acc’)
出于可读性目的,我将关注损失函数。但是,大部分内容也适用于指标。
在Keras文档中:您可以传递现有loss函数的名称,也可以传递TensorFlow/Theano符号函数,该函数为每个数据点返回标量,并接受以下两个参数:
- y_true: 真实标签. TensorFlow/Theano 张量.
- y_pred: 预测. TensorFlow/Theano 张量(和y_true一样的形状).
因此,如果我们想要使用常见的损失函数,例如MSE或分类交叉熵,我们可以通过传递适当的名称来轻松实现。Keras的文档中提供了可用损失和指标的列表。
自定义损失函数
当我们需要使用除可用之外的损失函数(或指标)时,我们可以构造自己的自定义函数并传递给model.compile。
例如,构建自定义指标:
import keras.backend as K def mean_pred(y_true, y_pred): return K.mean(y_pred) model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy', mean_pred])
具有多个参数的损失/指标函数
您可能已经注意到,损失函数必须只接受2个参数:y_true并且y_pred,相应地,它们是目标张量和模型输出张量。但是,如果我们希望我们的损失/指标依赖于除这两个之外的其他张量呢?
为此,我们需要使用函数闭包。我们将创建一个损失函数(取参数我们喜欢)返回一个函数的y_true和y_pred。
例如,如果我们想(由于某种原因)创建一个损失函数,将第一层中所有激活的均方值添加到MSE:
# Build a model inputs = Input(shape=(128,)) layer1 = Dense(64, activation='relu')(inputs) layer2 = Dense(64, activation='relu')(layer1) predictions = Dense(10, activation='softmax')(layer2) model = Model(inputs=inputs, outputs=predictions) # Define custom loss def custom_loss(layer): # Create a loss function that adds the MSE loss to the mean of all squared activations of a specific layer def loss(y_true,y_pred): return K.mean(K.square(y_pred - y_true) + K.square(layer), axis=-1) # Return a function return loss # Compile the model model.compile(optimizer='adam', loss=custom_loss(layer), # Call the loss function with the selected layer metrics=['accuracy']) # train model.fit(data, labels)
注意,我们创建了一个函数(不限制参数的数量),它返回一个合法的loss函数,该函数可以访问enclosing function数的参数。
一个更具体的例子:
前面的例子是一个不太有用的用例的示例。那么我们何时想要使用这种损失函数呢?
假设您正在设计一个变分自动编码器。您希望模型能够从编码的潜在空间重建其输入。但是,您还希望潜在空间中的编码(近似)正态分布。
前者的目标可以通过设计只取决于你的输入和输出所需重建的损失来实现y_true和y_pred。对于后者,您需要设计一个对潜在张量进行操作的损失项(例如,Kullback Leibler损失)。为了让你的损失函数能够访问这个中间张量,我们刚学到的技巧可以派上用场。
使用示例的Python代码如下:
def model_loss(self): """" Wrapper function which calculates auxiliary values for the complete loss function. Returns a *function* which calculates the complete loss given only the input and target output """ # KL loss kl_loss = self.calculate_kl_loss # Reconstruction loss md_loss_func = self.calculate_md_loss # KL weight (to be used by total loss and by annealing scheduler) self.kl_weight = K.variable(self.hps['kl_weight_start'], name='kl_weight') kl_weight = self.kl_weight def seq2seq_loss(y_true, y_pred): """ Final loss calculation function to be passed to optimizer""" # Reconstruction loss md_loss = md_loss_func(y_true, y_pred) # Full loss model_loss = kl_weight*kl_loss() + md_loss return model_loss return seq2seq_loss
此示例是序列到序列变分自动编码器模型的一部分,更多上下文和完整代码访问:repo - Sketch-RNN算法的Keras实现(https://github.com/eyalzk/sketch_rnn_keras)。
虽然示例是针对损失函数的,但创建自定义度量函数的方式相同。