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

保存Keras集成模型时报ValueError: Structure is a scalar错误如何解决

问题背景

运行环境:Python 3.7,keras2.3.1,tensorflow2.0.0
需要实现的需求:将两个已训练好的Keras模型集成后保存为新的模型,构建模型代码如下:

text_in = tensorflow.keras.layers.Input(shape=(MAX_SEQ_LEN,), dtype="int32", name='myinput')
mods = [model_0, model_1]
model_outputs = [model(text_in) for model in mods]
ensemble_output = tf.keras.layers.Average()(model_outputs)
ensemble_model = tf.keras.Model(inputs=text_in, outputs=ensemble_output)

执行ensemble_model.save(fname)时报错如下:

ValueError                                Traceback (most recent call last)
<ipython-input-65-0212c05a2372> in <module>
      1 fname = 'model_multiclass_multilabel_{}.h5'.format(datetime.utcnow())
      2 base = fname.split('.h5')[0]
----> 3 model.save(fname)

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/network.py in save(self, filepath, overwrite, include_optimizer, save_format, signatures, options)
    973     """
    974     saving.save_model(self, filepath, overwrite, include_optimizer, save_format,
--> 975                       signatures, options)
    976 
    977   def save_weights(self, filepath, overwrite=True, save_format=None):

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/keras/saving/save.py in save_model(model, filepath, overwrite, include_optimizer, save_format, signatures, options)
    110           'or using `save_weights`.')
    111     hdf5_format.save_model_to_hdf5(
--> 112         model, filepath, overwrite, include_optimizer)
    113   else:
    114     saved_model_save.save(model, filepath, overwrite, include_optimizer,

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/keras/saving/hdf5_format.py in save_model_to_hdf5(model, filepath, overwrite, include_optimizer)
     97 
     98   try:
--- 99     model_metadata = saving_utils.model_metadata(model, include_optimizer)
    100     for k, v in model_metadata.items():
    101       if isinstance(v, (dict, list, tuple)):

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/keras/saving/saving_utils.py in model_metadata(model, include_optimizer, require_config)
    160   model_config = {'class_name': model.__class__.__name__}
    161   try:
--> 162     model_config['config'] = model.get_config()
    163   except NotImplementedError as e:
    164     if require_config:

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/network.py in get_config(self)
    885     if not self._is_graph_network:
    886       raise NotImplementedError
--> 887     return copy.deepcopy(get_network_config(self))
    888 
    889   @classmethod

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/network.py in get_network_config(network, serialize_layer_fn)
   1940           filtered_inbound_nodes.append(node_data)
   1941 
-> 1942     layer_config = serialize_layer_fn(layer)
   1943     layer_config['name'] = layer.name
   1944     layer_config['inbound_nodes'] = filtered_inbound_nodes

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/keras/utils/generic_utils.py in serialize_keras_object(instance)
    138   if hasattr(instance, 'get_config'):
    139     return serialize_keras_class_and_config(instance.__class__.__name__,
--> 140                                             instance.get_config())
    141   if hasattr(instance, '__name__'):
    142     return instance.__name__

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/network.py in get_config(self)
    885     if not self._is_graph_network:
    886       raise NotImplementedError
--> 887     return copy.deepcopy(get_network_config(self))
    888 
    889   @classmethod

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/network.py in get_network_config(network, serialize_layer_fn)
   1956     model_inputs.append(
   1957         tf_utils.ListWrapper([layer.name, new_node_index, tensor_index]))
-> 1958   model_inputs = nest.pack_sequence_as(network._nested_inputs, model_inputs)
   1959   # Preserve external Keras compat for Models with single input.
   1960   if not nest.is_sequence(model_inputs):

/opt/miniconda3/envs/ml/lib/python3.7/site-packages/tensorflow_core/python/util/nest.py in pack_sequence_as(structure, flat_sequence, expand_composites)
    454     if len(flat_sequence) != 1:
    455       raise ValueError("Structure is a scalar but len(flat_sequence) == %d > 1"
--> 456                        % len(flat_sequence))
    457     return flat_sequence[0]
    458 

ValueError: Structure is a scalar but len(flat_sequence) == 0 > 1

已确认子模型训练使用的Keras/TF版本和当前环境一致,输入类型完全匹配。

报错原因

该错误是TensorFlow 2.0.0版本的已知缺陷:h5格式的序列化逻辑无法正确处理将多个预训练Keras子模型作为层嵌套进新模型的场景,识别子模型输入节点结构时出现判断错误,导致配置构建失败。

可行解决方案
  • 方案一:使用TensorFlow原生SavedModel格式保存(优先推荐)
    不需要修改任何模型结构,仅需要调整保存时的格式参数,该格式对嵌套模型的兼容性远高于h5:
    # 保存模型,会生成一个名为ensemble_model的文件夹
    ensemble_model.save("ensemble_model", save_format="tf")
    # 加载模型
    ensemble_model = tf.keras.models.load_model("ensemble_model")
    
  • 方案二:如果必须使用h5格式存储,采用权重单独保存的方案
    跳过模型结构的序列化步骤,仅保存权重,使用时先重建模型结构再加载权重,兼容性最高:
    # 保存权重
    ensemble_model.save_weights("ensemble_weights.h5")
    
    # 使用时先按照你原来的代码重新构建ensemble_model的结构,再执行加载
    ensemble_model.load_weights("ensemble_weights.h5")
    
  • 方案三:排查子模型加载逻辑
    确认两个子模型都是通过tf.keras.models.load_model加载,不要混用独立Keras库的加载接口,否则会导致子模型的图网络标记异常,触发序列化错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 00:06:01