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

Keras 3加载.keras模型反序列化错误:Dense层权重加载异常求助

Keras 3中VAE模型保存加载失败:层权重无法加载的解决方法

迁移至Keras 3(TensorFlow v2.17.0、Keras v3.4.1)后,训练VAE模型时运行正常,但保存后加载出现权重加载错误。加载时提示z_mean、z_log_var等Dense层(或Conv2D层)预期变量未找到,尝试拆分保存架构和权重也无法解决,还出现优化器变量不匹配的警告。

核心原因

问题出在VAE的模型结构定义上:直接用函数式API拼接层而没有将整个VAE封装为自定义keras.Model子类,导致部分核心层(如z_mean、z_log_var)没有被模型实例正确跟踪,保存时未将这些层的权重写入文件,加载时自然找不到对应变量。

修复步骤

1. 将VAE封装为自定义Model子类

必须显式定义VAE类,包含encoder、decoder,并在call方法中实现前向传播,确保所有层都被模型跟踪。示例代码如下:

import keras
from keras import layers
import numpy as np
import keras.backend as K

latent_dim = 32
height, width, channels = 64, 64, 3  # 根据你的数据调整

# 注册采样函数(确保放在类定义前)
@keras.saving.register_keras_serializable()
def sampling(args):
    z_mean, z_log_var = args
    epsilon = K.random_normal(shape=(K.shape(z_mean)[0], latent_dim), mean=0., stddev=1.0)
    return z_mean + K.exp(z_log_var / 2) * epsilon

# 自定义VAE模型类
class VAE(keras.Model):
    def __init__(self, latent_dim, height, width, channels, **kwargs):
        super().__init__(**kwargs)
        self.latent_dim = latent_dim
        
        # 构建Encoder
        self.encoder_input = layers.Input(shape=(height, width, channels), name='encoder_input')
        x = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(self.encoder_input)
        shape_before_flattening = K.int_shape(x)[1:]
        x = layers.Flatten()(x)
        self.z_mean = layers.Dense(latent_dim, name='z_mean')(x)
        self.z_log_var = layers.Dense(latent_dim, name='z_log_var')(x)
        self.z = layers.Lambda(sampling, output_shape=(latent_dim,), name='z')([self.z_mean, self.z_log_var])
        
        # 构建Decoder
        self.decoder_input = layers.Input(K.int_shape(self.z)[1:])
        x = layers.Dense(np.prod(shape_before_flattening))(self.decoder_input)
        x = layers.Reshape(shape_before_flattening)(x)
        self.decoder_output = layers.Conv2D(channels, (3, 3), activation='sigmoid', padding='same')(x)
        
        # 定义完整模型的输入输出
        self.encoder = keras.Model(self.encoder_input, [self.z_mean, self.z_log_var, self.z], name='encoder')
        self.decoder = keras.Model(self.decoder_input, self.decoder_output, name='decoder')
        
    def call(self, inputs):
        z_mean, z_log_var, z = self.encoder(inputs)
        reconstruction = self.decoder(z)
        # 添加VAE自定义损失(重构损失+KL散度)
        reconstruction_loss = keras.losses.binary_crossentropy(K.flatten(inputs), K.flatten(reconstruction))
        reconstruction_loss *= height * width * channels
        kl_loss = -0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
        total_loss = K.mean(reconstruction_loss + kl_loss)
        self.add_loss(total_loss)
        return reconstruction

2. 训练与保存模型

使用自定义类实例化模型,训练后直接保存:

# 实例化模型
vae = VAE(latent_dim, height, width, channels)
vae.compile(optimizer='adam')

# 训练(假设x_train是你的训练数据)
vae.fit(x_train, epochs=10, batch_size=32)

# 保存模型
vae.save('vae_model.keras')

3. 加载模型

加载时传入自定义对象(包含采样函数和VAE类):

custom_objects = {'sampling': sampling, 'VAE': VAE}
loaded_vae = keras.models.load_model('vae_model.keras', custom_objects=custom_objects)

为什么之前的方法失败?

  • 直接用函数式API拼接层时,最终的模型可能只以encoder_input到decoder_output为输入输出,没有显式包含z_mean、z_log_var这些中间层,导致保存时这些层的权重被忽略。
  • 拆分保存json和weights的方式在Keras3中已不推荐,且同样会因为模型结构未完整定义而丢失层权重。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:48:09