Keras高级--构建复杂的自定义Losses和Metrics

Advanced Keras — Constructing Complex Custom Losses and Metrics

    • 1. 背景
    • 2. 自定义loss函数
    • 3. 多参数loss/metric函数

翻译自:https://towardsdatascience.com/advanced-keras-constructing-complex-custom-losses-and-metrics-c07ca130a618
作者:Eyal Zakkay
转载请注明出处以及本文链接

本文将介绍一个简单技巧来在Keras中构建自定义loss函数,它可以接收除 y_truey_pred 之外的参数。

1. 背景

在Keras中编译模型时,我们为compile函数提供所需的loss与metrics。例如:

model.compile(loss=’mean_squared_error’, optimizer=’sgd’, metrics=‘acc’)

出于可读性目的,从现在开始关注loss函数。但是,大部分内容也适用于metrics。
从Keras的有关loss函数的文档中能得到:

你可以传递一个现有的损失函数名,或者一个 TensorFlow/Theano 符号函数。该符号函数为每个数据点返回一个标量,有以下两个参数:
y_true: 真实标签。TensorFlow/Theano 张量。
y_pred: 预测值。TensorFlow/Theano 张量,其 shape 与 y_true 相同。

所以如果我们想使用常用的loss函数,比如MSE或者 Categorical Cross-entropy,我们可以通过传入合适的参数来很容易实现。
Keras的文档中提供了可用loss和metrics的列表。

2. 自定义loss函数

当我们需要使用实现更复杂的loss函数或者metric时,就需要构造自定义函数并且传给model.compile
例如,构建自定义metric(来自Keras文档):

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])

3. 多参数loss/metric函数

可能你已经注意到,loss函数必须只接受2个参数y_truey_pred,分别是target张量和模型output张量。但是如果我们希望loss/metric函数依赖于除这两个之外的其他张量呢?
为此,我们需要使用 function closure。首先创建一个loss函数(随意取参数)返回一个y_truey_pred的函数。
例如,如果我们想(由于某种原因)创建一个loss函数,其将第一层中所有activations的均方值添加到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函数,该函数可以访问其封闭函数的参数。
一个更具体的例子:

假设设计一个变分自动编码器。希望模型能够从编码的潜在空间重建其输入。但还希望潜在空间中的编码(近似)正态分布。
前者的目标可以通过设计一个仅依赖于输入和期望输出y_truey_pred的重建损失来实现。对于后者,需要设计一个对潜在张量进行操作的损失项(例如,Kullback Leibler损失)。为了让你的loss函数能够访问这个中间张量,我们刚学到的技巧可以派上用场。
使用示例:

    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

此示例是Sequence to Sequence Variational Autoencoder模型的一部分,更多上下文和完整代码访问此

使用的Keras版本=2.2.4

Reference

[1]. Keras — Losses
[2]. Keras — Metrics
[3]. Github Issue — Passing additional arguments to objective function

Thanks to Ludovic Benistant.

你可能感兴趣的:(1,机器学习,Keras,API,深度学习)