简体   繁体   English

Keras/Tensorflow:单个 output 的组合损失 function

[英]Keras/Tensorflow: Combined Loss function for single output

I have only one output for my model, but I would like to combine two different loss functions:我的 model 只有一个 output,但我想结合两种不同的损失函数:

def get_model():
    # create the model here
    model = Model(inputs=image, outputs=output)

    alpha = 0.2
    model.compile(loss=[mse, gse],
                      loss_weights=[1-alpha, alpha]
                      , ...)

but it complains that I need to have two outputs because I defined two losses:但它抱怨我需要有两个输出,因为我定义了两个损失:

ValueError: When passing a list as loss, it should have one entry per model outputs. 
The model has 1 outputs, but you passed loss=[<function mse at 0x0000024D7E1FB378>, <function gse at 0x0000024D7E1FB510>]

Can I possibly write my final loss function without having to create another loss function (because that would restrict me from changing the alpha outside the loss function)?我是否可以写下我的最终损失 function 而不必创建另一个损失 function (因为这会限制我改变损失函数之外的 alpha)?

How do I do something like (1-alpha)*mse + alpha*gse ?我该怎么做(1-alpha)*mse + alpha*gse类的事情?


Update:更新:

Both my loss functions are equivalent to the function signature of any builtin keras loss function, takes in y_true and y_pred and gives a tensor back for loss (which can be reduced to a scalar using K.mean() ), but I believe, how these loss functions are defined shouldn't affect the answer as long as they return valid losses.我的两个损失函数都等同于任何内置 keras 损失 function 的 function 签名,接受y_truey_pred并为损失返回一个张量(可以使用K.mean()将其简化为标量),但我相信,如何这些损失函数的定义不应影响答案,只要它们返回有效损失即可。

def gse(y_true, y_pred):
    # some tensor operation on y_pred and y_true
    return K.mean(K.square(y_pred - y_true), axis=-1)

Specify a custom function for the loss:为损失指定一个自定义函数:

model = Model(inputs=image, outputs=output)

alpha = 0.2
model.compile(
    loss=lambda y_true, y_pred: (1 - alpha) * mse(y_true, y_pred) + alpha * gse(y_true, y_pred),
    ...)

Or if you don't want an ugly lambda make it into an actual function:或者,如果您不希望丑陋的 lambda 成为实际函数:

def my_loss(y_true, y_pred):
    return (1 - alpha) * mse(y_true, y_pred) + alpha * gse(y_true, y_pred)

model = Model(inputs=image, outputs=output)

alpha = 0.2
model.compile(loss=my_loss, ...)

EDIT:编辑:

If your alpha is not some global constant, you can have a "loss function factory":如果您的alpha不是某个全局常量,您可以拥有一个“损失函数工厂”:

def make_my_loss(alpha):
    def my_loss(y_true, y_pred):
        return (1 - alpha) * mse(y_true, y_pred) + alpha * gse(y_true, y_pred)
    return my_loss

model = Model(inputs=image, outputs=output)

alpha = 0.2
my_loss = make_my_loss(alpha)
model.compile(loss=my_loss, ...)

loss function should be one function.You are giving your model a list of two functions loss函数应该是一个函数。你给你的模型一个包含两个函数的列表

try:尝试:

def mse(y_true, y_pred):
    return K.mean(K.square(y_pred - y_true), axis=-1)

model.compile(loss= (mse(y_true, y_pred)*(1-alpha) + gse(y_true, y_pred)*alpha),
              , ...)

Yes, define your own custom loss function and pass that to the loss argument upon compiling:是的,定义您自己的自定义损失函数并在编译时将其传递给loss参数:

def custom_loss(y_true, y_pred):
    return (1-alpha) * K.mean(K.square(y_true-y_pred)) + alpha * gse

(Not sure what you mean with gse ). (不确定你对gse意思)。 It can be helpful to have a look at how the vanilla losses are implemented in Keras:https://github.com/keras-team/keras/blob/master/keras/losses.py看看在 Keras 中如何实现 vanilla loss 会有所帮助:https ://github.com/keras-team/keras/blob/master/keras/losses.py

Not that this answer particularly addresses the original question, I thought of writing it because the same error occurs when trying to load a keras model that has a custom loss using keras.models.load_model , and it's not been properly answered anywhere.并不是说这个答案特别解决了最初的问题,我想写它是因为在尝试使用keras.models.load_model加载具有自定义损失的 keras 模型时会发生同样的错误,并且在任何地方都没有正确回答。 Specifically, following the VAE example code in keras github repository , this error occurs when loading the VAE model after been saved with model.save .具体来说,按照keras github repository中的VAE示例代码,用model.save保存后加载VAE模型时会出现这个错误。

The solution is to save only the weights using vae.save_weights('file.h5') instead of saving the full model.解决方案是使用vae.save_weights('file.h5')仅保存权重,而不是保存完整模型。 However, you would have to build and compile the model again before loading the weights using vae.load_weights('file.h5') .但是,在使用vae.load_weights('file.h5')加载权重之前,您必须再次构建和编译模型。

Following is an example implementation.下面是一个示例实现。

class VAE():
    def build_model(self): # latent_dim and intermediate_dim can be passed as arguments
        def sampling(args):
            """Reparameterization trick by sampling from an isotropic unit Gaussian.
            # Arguments
                args (tensor): mean and log of variance of Q(z|X)
            # Returns
                z (tensor): sampled latent vector
            """

            z_mean, z_log_var = args
            batch = K.shape(z_mean)[0]
            dim = K.int_shape(z_mean)[1]
            # by default, random_normal has mean = 0 and std = 1.0
            epsilon = K.random_normal(shape=(batch, dim))
            return z_mean + K.exp(0.5 * z_log_var) * epsilon

        # original_dim = self.no_features
        # intermediate_dim = 256
        latent_dim = 8
        inputs = Input(shape=(self.no_features,))
        x = Dense(256, activation='relu')(inputs)
        x = Dense(128, activation='relu')(x)
        x = Dense(64, activation='relu')(x)
        z_mean = Dense(latent_dim, name='z_mean')(x)
        z_log_var = Dense(latent_dim, name='z_log_var')(x)
        # use reparameterization trick to push the sampling out as input
        # note that "output_shape" isn't necessary with the TensorFlow backend
        z = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])
        # instantiate encoder model
        encoder = Model(inputs, [z_mean, z_log_var, z], name='encoder')


        # build decoder model
        latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
        x = Dense(32, activation='relu')(latent_inputs)
        x = Dense(48, activation='relu')(x)
        x = Dense(64, activation='relu')(x)
        outputs = Dense(self.no_features, activation='linear')(x)

        # instantiate decoder model
        decoder = Model(latent_inputs, outputs, name='decoder')

        # instantiate VAE model
        outputs = decoder(encoder(inputs)[2])
        VAE = Model(inputs, outputs, name='vae_mlp')
        reconstruction_loss = mse(inputs, outputs)
        reconstruction_loss *= self.no_features
        kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)
        kl_loss = K.sum(kl_loss, axis=-1)
        kl_loss *= -0.5
        vae_loss = K.mean(reconstruction_loss + kl_loss)
        VAE.add_loss(vae_loss)
        VAE.compile(optimizer='adam')
        return VAE

Now,现在,

vae_cls = VAE()
vae = vae_cls.build_model()
# vae.fit()
vae.save_weights('file.h5')

Load model and predict (if in a different script, you need to import the VAE class),加载模型并预测(如果在不同的脚本中,则需要导入VAE类),

vae_cls = VAE()
vae = vae_cls.build_model()
vae.load_weights('file.h5')
# vae.predict()

Finally, The Difference : [ ref ]最后,区别:[ 参考]

Keras model.save saves, model.save保存,

  1. Model weights模型权重
  2. Model architecture模型架构
  3. Model compilation details (loss function(s) and metrics)模型编译细节(损失函数和指标)
  4. Model optimizer and regularizer states模型优化器和正则化器状态

Keras model.save_weights saves only the model weights. model.save_weights只保存模型权重。 Keras model.to_json() saves the model architecture. model.to_json()保存模型架构。

Hope this helps someone experimenting with variational autoencoders.希望这对尝试变分自编码器的人有所帮助。

Combine MAE and RMSE together:MAERMSE结合在一起:

import tensorflow as tf
from tensorflow import keras

def loss_fn_mae_rmse(y_true, y_pred, alpha=0.8):
    mae = keras.losses.MeanAbsoluteError()
    mse = keras.losses.MeanSquaredError()
    return alpha * mae(y_true, y_pred) + (1 - alpha) * tf.sqrt(mse(y_true, y_pred))

model = keras.Model(inputs=..., outputs=...)
opt = keras.optimizers.Adam(learning_rate=1e-4)
model.compile(optimizer=opt, loss=loss_fn_mae_rmse, metrics=['mae'])

At the same time, if you want to load this model after training and saved to disk:同时,如果你想在训练后加载这个model并保存到磁盘:

model = keras.models.load_model('path/to/model.h5', custom_objects={'loss_fn_mae_rmse': loss_fn_mae_rmse})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM