使用自定义损失加载模型+keras

43

在Keras中,如果需要使用带有额外参数的自定义损失函数,可以按照https://datascience.stackexchange.com/questions/25029/custom-loss-function-with-additional-parameter-in-keras上所述进行。

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

当我训练模型时,上述方法是有效的。然而,一旦模型被训练,我在加载模型时遇到了困难。当我尝试在 load_model 中使用 custom_objects 参数时,如下所示:

model = load_model(modelFile, custom_objects={'penalized_loss': penalized_loss} )

它抱怨 ValueError: 未知的损失函数:loss

是否有办法将损失函数作为custom_objects中的自定义损失之一传递?据我所知,在load_model调用期间,内部函数不在名称空间中。是否有更简单的方法来加载模型或使用带有额外参数的自定义损失?

5个回答

42

有!custom_objects需要你在损失函数中使用的精确函数(在你的情况下是内部函数):

model = load_model(modelFile, custom_objects={ 'loss': penalized_loss(noise) })

很遗憾,keras不会将噪声的值存储在模型中,因此您需要手动将其提供给load_model函数。


1
你的意思是说,当我加载训练好的模型时,我需要创建一个随机变量噪声吗?我的训练中的“噪声”不断变化,从而影响了损失值。 - Jason
我不知道在你的情况下变量“noise”是什么,但是你需要传递一些东西给你的“penalized_loss”函数,以便返回损失函数。如果它是一个随机变量,你可能需要创建一个新的(或使用现有的)并将其传递给你的函数,就像你所说的那样。 - rickyalbert
如果您要使用已加载的模型进行测试,无论传递哪个噪声变量都无关紧要。您只需要能够加载您的模型 :) - rickyalbert
没问题!如果您觉得这个答案有用,请标记它 :) - rickyalbert
1
因为我遇到了这个问题:需要强调的是,您内部函数的名称必须与custom_objects中的键匹配。为避免错误,我执行loss=penalized_loss(noise); custom_objects={loss.__name__: loss} - F Lekschas
显示剩余2条评论

22

如果您仅为预测(而非训练)加载模型,则可以在以下代码中将编译标志设置为False

model = load_model(model_path, compile=False)

此处不会搜索损失函数,因为它仅在编译模型时需要。


1
这对我没有起作用。使用 keras/tensorflow 2.5.0,我仍然遇到了有关损失的错误。 - zwep
抱歉回复晚了。我的TensorFlow版本是1.14,keras版本是2.2.4。您保存模型时用的是什么格式?我会将它保存为.h5格式,如下所示: checkpointer = keras.callbacks.ModelCheckpoint(model_path, verbose=1, monitor=, save_best_only=True, save_weights_only=False, mode=) 其中model_path是带有.h5扩展名的模型路径。 - AZiZA Saber
你也可以尝试使用custom_objects。例如: model = load_model(model_path, custom_objects={ 'weighted_binary_crossentropy': weighted_binary_crossentropy(y_true, y_pred, weight=[1.,2.]) }) 这只是一个例子,我的损失函数名称为weighted_binary_crossentropy,并且我添加了权重。因此,在加载时需要给出一些权重。我不确定你如何定义你的损失函数,但是在测试时你可以随意给定一些变量;我可以给出weight=[1.,1.]。请搜索更多相关信息,如果有任何问题,请告诉我。 - AZiZA Saber

5

我曾经遇到过相同的问题,并进行了多次研究,可以假设以下方法有效:

  1. 首先加载模型并将compile=False分配给它。
  2. 使用自定义损失函数编译您的模型。
  3. 重新训练您的模型。

例如:

def custom_loss(y_true, y_pred):
   nn = np.square(y_true - y_pred)
   return nn

model = load_model("aaaa.h5", compile=False)
model.compile(loss=custom_loss, optimizer='adam', metrics=custom_loss)
model.fit(...)

这对我在最新的TF 2.12.0中有效。 - Ali

3
您可以尝试这样做:
import keras.losses
keras.losses.penalized_loss = penalized_loss

(在您当前的“py”文件中定义了“penalized_loss”函数后。)

2
这在最新的Keras中在TF 2.1版本中不起作用。而是使用custom_objects方法,它可以正常工作。在加载基于类的自定义损失时,TensorFlow 2.1 Keras存在一个错误,但在TF2.2.0rc2预发布版本中已经修复了该问题。 - asu

1

@rickyalbert

def custom_loss(y_true, y_pred):
   nn = np.square(y_true - y_pred)
   return nn

model = load_model(modelFile, custom_objects={'loss': custom_loss})

你应该将损失函数作为对象传递。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接