加载VGG19模型遇AttributeError:'list'无'shape'属性的解决求助
问题:VGG19二分类模型加载时出现
AttributeError: 'list' object has no attribute 'shape' 问题背景
使用自有JPG图像和包含图像ID、二分类标签(0/1)的Pandas DataFrame训练VGG19二分类模型,训练及保存过程无异常,但加载模型时触发上述错误。尝试过保存为.json和.h5格式均未解决问题。
环境信息
Python: 3.10 keras: 3.1.1 tensorflow: 2.16.2 OS: Ubuntu 22.04
训练与保存代码
import os import pandas as pd import tensorflow as tf from keras import losses from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.optimizers import Adam from keras.metrics import Precision, Recall from keras.applications.vgg19 import VGG19 IMG_HEIGHT = 224 IMG_WIDTH = 224 MODELS_INPUT_SHAPE = (IMG_HEIGHT, IMG_WIDTH, 3) NUM_CLASSES = 2 EPOCHS = 1 BATCH_SIZE = 32 train_dataset = pd.read_csv('data/train-data.csv') train_images_location = 'data/train-images/' # 图像预处理辅助函数 def preprocess_image(image): image = tf.io.read_file(image) image = tf.image.decode_jpeg(image, channels=3) image = tf.image.resize(image, [224, 224]) image = tf.cast(image, tf.float32) / 255.0 # 归一化像素值到[0,1] return image train_image_paths = [os.path.join('data/train-images', img_path) for img_path in train_dataset['id']] one_hot_labels = tf.one_hot(train_dataset['T1'], NUM_CLASSES) train_dataset = tf.data.Dataset.from_tensor_slices((train_image_paths, one_hot_labels)) train_dataset = train_dataset.map(lambda x, y: (preprocess_image(x), y)) train_dataset = train_dataset.batch(BATCH_SIZE) models = { 'vgg19_binary.keras': VGG19(weights='imagenet', include_top=False, input_shape=MODELS_INPUT_SHAPE) } for model_name in models.keys(): base_model = models[model_name] # 冻结预训练模型层 for layer in base_model.layers: layer.trainable = False # 构建Sequential模型 model = Sequential() model.add(base_model) model.add(Flatten()) model.add(Dense(256, activation='relu')) model.add(Dense(128, activation='relu')) model.add(Dense(64, activation='relu')) model.add(Dense(32, activation='relu')) model.add(Dense(16, activation='relu')) model.add(Dense(NUM_CLASSES, activation='sigmoid')) # 编译模型 model.compile(loss=losses.BinaryCrossentropy(), optimizer=Adam(learning_rate=0.0001), metrics=['accuracy', Precision(), Recall()]) # 训练模型 model.fit(train_dataset, epochs=EPOCHS) # 保存模型 model_location = 'models/'+model_name model.save(model_location)
模型加载代码
from keras.models import load_model vgg19_model_location = 'models/vgg19_binary.keras' vgg19_model = load_model(vgg19_model_location)
完整报错信息
Traceback (most recent call last): File "/home/javier/PycharmProjects/thesis/thesis/binary_early_fusion.py", line 15, in <module> loaded_model = model_from_json(loaded_model_json) File "/home/javier/PycharmProjects/thesis/venv/lib/python3.10/site-packages/keras/src/models/model.py", line 586, in model_from_json return serialization_lib.deserialize_keras_object( File "/home/javier/PycharmProjects/thesis/venv/lib/python3.10/site-packages/keras/src/saving/serialization_lib.py", line 711, in deserialize_keras_object instance = cls.from_config(inner_config) File "/home/javier/PycharmProjects/thesis/venv/lib/python3.10/site-packages/keras/src/models/sequential.py", line 335, in from_config model.add(layer) File "/home/javier/PycharmProjects/thesis/venv/lib/python3.10/site-packages/keras/src/models/sequential.py", line 116, in add self._maybe_rebuild() File "/home/javier/PycharmProjects/thesis/venv/lib/python3.10/site-packages/keras/src/models/sequential.py", line 135, in _maybe_rebuild self.build(input_shape) File "/home/javier/PycharmProjects/thesis/venv/lib/python3.10/site-packages/keras/src/layers/layer.py", line 223, in build_wrapper original_build_method(*args, **kwargs) File "/home/javier/PycharmProjects/thesis/venv/lib/python3.10/site-packages/keras/src/models/sequential.py", line 176, in build x = layer(x) File "/home/javier/PycharmProjects/thesis/venv/lib/python3.10/site-packages/keras/src/utils/traceback_utils.py", line 122, in error_handler raise e.with_traceback(filtered_tb) from None File "/home/javier/PycharmProjects/thesis/venv/lib/python3.10/site-packages/keras/src/layers/reshaping/flatten.py", line 72, in compute_output_spec output_shape = self.compute_output_shape(inputs.shape) AttributeError: Exception encountered when calling Flatten.call(). 'list' object has no attribute 'shape' Arguments received by Flatten.call(): • args=(['<KerasTensor shape=(None, 7, 7, 512), dtype=float32, sparse=False, name=keras_tensor_70>'],) • kwargs=<class 'inspect._empty'>
解决方案
该问题源于Keras 3.x序列化包含预训练模型的Sequential模型时的兼容性问题:VGG19的输出被序列化为列表而非张量,导致Flatten层无法识别形状。以下是三种可行解决方法:
方法1:改用Functional API构建模型
替换原Sequential模型构建逻辑,使用Functional API可以避免序列化时的输出格式异常:
# 替换原Sequential模型构建代码 inputs = tf.keras.Input(shape=MODELS_INPUT_SHAPE) x = base_model(inputs, training=False) x = Flatten()(x) x = Dense(256, activation='relu')(x) x = Dense(128, activation='relu')(x) x = Dense(64, activation='relu')(x) x = Dense(32, activation='relu')(x) x = Dense(16, activation='relu')(x) outputs = Dense(NUM_CLASSES, activation='sigmoid')(x) model = tf.keras.Model(inputs, outputs)
方法2:保存前显式设置模型输入形状
在保存模型前,手动调用build()方法指定输入形状,确保序列化时能正确识别张量结构:
# 在model.save()前添加以下代码 model.build((None,) + MODELS_INPUT_SHAPE) model.save(model_location)
方法3:手动重建模型并加载权重
若不想重新训练,可先重建与原模型完全一致的结构,再单独加载权重:
# 1. 重建模型结构 base_model = VGG19(weights='imagenet', include_top=False, input_shape=MODELS_INPUT_SHAPE) for layer in base_model.layers: layer.trainable = False model = Sequential() model.add(base_model) model.add(Flatten()) model.add(Dense(256, activation='relu')) model.add(Dense(128, activation='relu')) model.add(Dense(64, activation='relu')) model.add(Dense(32, activation='relu')) model.add(Dense(16, activation='relu')) model.add(Dense(NUM_CLASSES, activation='sigmoid')) # 2. 加载已保存的权重 model.load_weights('models/vgg19_binary.keras')
内容的提问来源于stack exchange,提问作者Javier Romero.
相关产品推荐
相关产品推荐

