Keras/Tensorflow:单输出的组合损失函数
Keras/Tensorflow: Combined Loss function for single 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]
, ...)
但它抱怨说我需要两个输出,因为我定义了两个损失:
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>]
我能否在不必创建另一个损失函数的情况下编写我的最终损失函数(因为这会限制我在损失函数之外更改 alpha)?
我该如何做类似 (1-alpha)*mse + alpha*gse
的事情?
更新:
我的两个损失函数都等同于任何内置 keras 损失函数的函数签名,接受 y_true
和 y_pred
并给出损失的张量(可以减少为标量使用 K.mean()
),但我相信,只要它们 return 有效损失,这些损失函数的定义方式就不会影响答案。
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)
loss
函数应该是一个 function.You 正在为您的模型提供两个函数的列表
尝试:
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),
, ...)
为损失指定自定义函数:
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),
...)
或者,如果您不希望丑陋的 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, ...)
编辑:
如果您的 alpha
不是某个全局常量,您可以使用 "loss function factory":
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
参数:
def custom_loss(y_true, y_pred):
return (1-alpha) * K.mean(K.square(y_true-y_pred)) + alpha * gse
(不确定 gse
是什么意思)。查看 Keras 中如何实现原始损失可能会有所帮助:https://github.com/keras-team/keras/blob/master/keras/losses.py
并不是说这个答案特别解决了原始问题,我想写它是因为在尝试使用 keras.models.load_model
加载具有自定义损失的 keras 模型时发生同样的错误,并且没有得到正确的回答任何地方。具体来说,按照keras github repository中的VAE示例代码,在用model.save
保存后加载VAE模型时会出现此错误。
解决方案是使用 vae.save_weights('file.h5')
仅保存权重,而不是保存完整模型。但是,在使用 vae.load_weights('file.h5')
加载权重之前,您必须再次构建和编译模型。
以下是一个示例实现。
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
现在,
vae_cls = VAE()
vae = vae_cls.build_model()
# vae.fit()
vae.save_weights('file.h5')
加载模型并预测(如果在不同的脚本中,您需要导入 VAE
class),
vae_cls = VAE()
vae = vae_cls.build_model()
vae.load_weights('file.h5')
# vae.predict()
最后,差异:[ref]
Keras model.save
保存,
- 模型权重
- 模型架构
- 模型编译详细信息(损失函数和指标)
- 模型优化器和正则化器状态
Keras model.save_weights
只保存模型权重。 Keras model.to_json()
保存模型架构。
希望这对试验变分自动编码器的人有所帮助。
我的模型只有一个输出,但我想结合两种不同的损失函数:
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]
, ...)
但它抱怨说我需要两个输出,因为我定义了两个损失:
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>]
我能否在不必创建另一个损失函数的情况下编写我的最终损失函数(因为这会限制我在损失函数之外更改 alpha)?
我该如何做类似 (1-alpha)*mse + alpha*gse
的事情?
更新:
我的两个损失函数都等同于任何内置 keras 损失函数的函数签名,接受 y_true
和 y_pred
并给出损失的张量(可以减少为标量使用 K.mean()
),但我相信,只要它们 return 有效损失,这些损失函数的定义方式就不会影响答案。
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)
loss
函数应该是一个 function.You 正在为您的模型提供两个函数的列表
尝试:
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),
, ...)
为损失指定自定义函数:
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),
...)
或者,如果您不希望丑陋的 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, ...)
编辑:
如果您的 alpha
不是某个全局常量,您可以使用 "loss function factory":
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
参数:
def custom_loss(y_true, y_pred):
return (1-alpha) * K.mean(K.square(y_true-y_pred)) + alpha * gse
(不确定 gse
是什么意思)。查看 Keras 中如何实现原始损失可能会有所帮助:https://github.com/keras-team/keras/blob/master/keras/losses.py
并不是说这个答案特别解决了原始问题,我想写它是因为在尝试使用 keras.models.load_model
加载具有自定义损失的 keras 模型时发生同样的错误,并且没有得到正确的回答任何地方。具体来说,按照keras github repository中的VAE示例代码,在用model.save
保存后加载VAE模型时会出现此错误。
解决方案是使用 vae.save_weights('file.h5')
仅保存权重,而不是保存完整模型。但是,在使用 vae.load_weights('file.h5')
加载权重之前,您必须再次构建和编译模型。
以下是一个示例实现。
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
现在,
vae_cls = VAE()
vae = vae_cls.build_model()
# vae.fit()
vae.save_weights('file.h5')
加载模型并预测(如果在不同的脚本中,您需要导入 VAE
class),
vae_cls = VAE()
vae = vae_cls.build_model()
vae.load_weights('file.h5')
# vae.predict()
最后,差异:[ref]
Keras model.save
保存,
- 模型权重
- 模型架构
- 模型编译详细信息(损失函数和指标)
- 模型优化器和正则化器状态
Keras model.save_weights
只保存模型权重。 Keras model.to_json()
保存模型架构。
希望这对试验变分自动编码器的人有所帮助。