You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法加载含自定义Lambda组合损失函数的Keras模型求解

加载带自定义Lambda组合损失的Keras模型并继续训练

嘿,我明白你遇到的问题了——用lambda把多个自定义损失拼起来训练模型,保存后再加载就卡壳了对吧?其实核心原因是Keras不会自动保存自定义函数的定义,咱们得手动告诉它这些函数的存在才行。下面给你两种可行的解决办法:

方法一:提前把Lambda损失改成具名函数(推荐)

当初你用匿名lambda写损失虽然方便,但序列化的时候很麻烦,不如改成一个有名字的函数,后续加载省心很多。

第一步:重构损失函数

把原来的lambda逻辑包装成一个具名函数,比如叫combined_loss:

def combined_loss(y_true, y_pred):
    return tf.keras.losses.binary_crossentropy(y_true, y_pred) + \
           pixelLevelLoss_weight * pixelLevelLoss(y_true, y_pred) + \
           totalVariationLoss_weight * totalVariationLoss(y_true, y_pred) + \
           featureLevelLoss_weight * featureLevelLoss(y_true, y_pred)

然后编译模型的时候直接用这个函数代替原来的lambda:

model.compile(loss=combined_loss, optimizer=opt)

第二步:加载模型时传入自定义函数

加载模型前,确保你在当前代码环境里已经定义了所有用到的自定义损失函数(包括combined_loss和那三个子损失),然后用custom_objects参数把它们传给load_model:

from tensorflow.keras.models import load_model

# 先把所有自定义损失的原实现搬过来
def pixelLevelLoss(y_true, y_pred):
    # 这里是你原来的像素级损失代码
    pass

def totalVariationLoss(y_true, y_pred):
    # 这里是你原来的总变差损失代码
    pass

def featureLevelLoss(y_true, y_pred):
    # 这里是你原来的特征级损失代码
    pass

def combined_loss(y_true, y_pred):
    return tf.keras.losses.binary_crossentropy(y_true, y_pred) + \
           pixelLevelLoss_weight * pixelLevelLoss(y_true, y_pred) + \
           totalVariationLoss_weight * totalVariationLoss(y_true, y_pred) + \
           featureLevelLoss_weight * featureLevelLoss(y_true, y_pred)

# 加载模型,把所有自定义函数注册进去
model = load_model('你的模型路径.h5', custom_objects={
    'combined_loss': combined_loss,
    'pixelLevelLoss': pixelLevelLoss,
    'totalVariationLoss': totalVariationLoss,
    'featureLevelLoss': featureLevelLoss
})

⚠️ 注意:pixelLevelLoss_weight这些权重变量,必须和你当初训练时的取值完全一致,不然损失计算会跑偏,影响后续训练效果。

方法二:如果已经用Lambda保存了模型(不想重构)

要是你已经用原来的lambda损失保存了模型,不想回头改训练代码,那也能解决——先找到模型保存时给lambda分配的名字,再映射到咱们重新定义的损失函数。

第一步:查看Lambda损失的名称

先加载模型的配置文件(或者直接读.h5文件),看看Keras给那个匿名lambda起了啥名字:

import h5py

with h5py.File('你的模型路径.h5', 'r') as f:
    print(f.attrs.get('training_config'))

在输出的字符串里,你能找到类似"loss": "<lambda>"或者"loss": "lambda_1"这样的内容,那个引号里的就是lambda的名字。

第二步:加载时映射名称到损失函数

把查到的lambda名称和咱们重新定义的组合损失(逻辑和原来的lambda完全一样)绑定,再加上三个子损失,一起传入custom_objects:

from tensorflow.keras.models import load_model

# 同样先定义所有自定义损失
def pixelLevelLoss(y_true, y_pred):
    # 原实现代码
    pass

# ... 其他两个损失函数定义 ...

def combined_loss(y_true, y_pred):
    return tf.keras.losses.binary_crossentropy(y_true, y_pred) + \
           pixelLevelLoss_weight * pixelLevelLoss(y_true, y_pred) + \
           totalVariationLoss_weight * totalVariationLoss(y_true, y_pred) + \
           featureLevelLoss_weight * featureLevelLoss(y_true, y_pred)

# 加载模型,把lambda名称映射到combined_loss
model = load_model('你的模型路径.h5', custom_objects={
    '<lambda>': combined_loss,  # 这里填你查到的lambda名字
    'pixelLevelLoss': pixelLevelLoss,
    'totalVariationLoss': totalVariationLoss,
    'featureLevelLoss': featureLevelLoss
})

加载后继续训练

搞定加载后,就可以像平时一样继续训练了:

# 用你的新数据继续训练
model.fit([new_sketch_inp, new_color_inp], new_disc_outputs, epochs=10, batch_size=32)

额外提醒

  • 所有自定义损失的代码必须和训练时完全一致,哪怕是微小的改动都会导致模型加载失败或者损失计算错误。
  • 要是你用了自定义的优化器或者其他自定义层,也要用同样的方法在custom_objects里注册它们。

内容的提问来源于stack exchange,提问作者mohamed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:22:26