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

TensorFlow中VGG16集成SENet后预测异常问题求助

问题解决:VGG16重构后预测异常(熊猫识别为斗篷)

问题现象

尝试在VGG16的关键位置集成SENet挤压激励模块,代码运行无报错,但预测结果完全异常:输入熊猫图片,模型识别为“cloak(斗篷)”。即使注释掉所有SENet模块,仅重构原始VGG16结构,依然出现相同错误,而直接使用官方VGG16测试则正常。对比模型结构和参数总量与官方一致,但预测结果完全偏离。

核心原因

重构模型时,虽然复用了VGG16的卷积层权重,但顶层的3个全连接层(Dense+Dropout)是全新初始化的随机参数,没有加载官方预训练权重,导致模型完全不具备ImageNet分类能力。此外代码还存在几处语法和配置错误:

  • SENet模块类定义有语法缺失(括号未闭合、build方法参数错误)
  • 分类任务误用MAE损失函数(应为交叉熵损失)
  • 禁用Eager Execution可能导致的张量处理异常
  • 部分层类未导入(如Layer、Dense、ReLU等)

解决步骤

1. 复用官方VGG16的全连接层权重

无需手动重新创建全连接层,直接从预训练VGG16实例中提取顶层层结构复用。

2. 修正SENet模块的语法错误

补全类定义中的括号、修正build方法参数、添加缺失的层导入。

3. 修正模型配置

  • 移除tf.compat.v1.disable_eager_execution(),保持默认的Eager模式
  • 分类任务使用categorical_crossentropy损失函数(或sparse_categorical_crossentropy)

修正后的完整代码

import tensorflow as tf
import numpy as np
from tensorflow.keras.layers import (
    Activation, Conv2D, Input, BatchNormalization, Reshape, 
    GlobalAveragePooling2D, Layer, Dense, ReLU, Flatten, Dropout
)
from tensorflow.keras.applications.vgg16 import preprocess_input, decode_predictions, VGG16
from tensorflow.keras.preprocessing.image import load_img

# 修正后的SENet模块
class SENET_Attn(Layer):
    def __init__(self, out_dim, ratio, layer_name="SENET"):
        super(SENET_Attn, self).__init__()
        self.out_dim = out_dim
        self.ratio = ratio
        self.layer_name = layer_name

    def build(self, input_shape):
        # build方法参数应为input_shape,而非自定义参数
        self.Global_Average_Pooling = GlobalAveragePooling2D(keepdims=True)
        # 确保Dense单元数为整数
        self.Fully_connected_1_1 = Dense(
            units=int(self.out_dim / self.ratio), 
            name=f"{self.layer_name}_fully_connected1"
        )
        self.Relu = ReLU()
        self.Fully_connected_2 = Dense(
            units=self.out_dim, 
            name=f"{self.layer_name}_fully_connected2"
        )
        self.Sigmoid = Activation("sigmoid")
        super().build(input_shape)

    def call(self, inputs):
        squeeze = self.Global_Average_Pooling(inputs)
        excitation = self.Fully_connected_1_1(squeeze)
        excitation = self.Relu(excitation)
        excitation = self.Fully_connected_2(excitation)
        excitation = self.Sigmoid(excitation)
        excitation = tf.reshape(excitation, [-1, 1, 1, self.out_dim])
        scale = inputs * excitation
        return scale

# 加载预训练VGG16
Vgg = VGG16(weights='imagenet', include_top=True)
ratio = 8

# 重构模型,复用卷积层和全连接层权重
input_layer = tf.keras.Input(shape=(224, 224, 3))
out = input_layer

# 遍历VGG16的卷积层(前19层,到block5_pool)
for layer in Vgg.layers[1:19]:
    out = layer(out)
    # 在block1_pool、block2_pool、block3_pool、block4_pool、block5_pool后添加SENet
    if layer.name in ["block1_pool", "block2_pool", "block3_pool", "block4_pool", "block5_pool"]:
        out = SENET_Attn(out.shape[-1], ratio, layer_name=f"senet_{layer.name.split('_')[1]}")(out)

# 复用VGG16的全连接层
for layer in Vgg.layers[19:]:
    out = layer(out)

model = tf.keras.Model(inputs=input_layer, outputs=out)
# 分类任务使用正确的损失函数
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()

# 预测测试
img = load_img('Panda.jpg', target_size=(224,224))
x = tf.keras.utils.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
preds = decode_predictions(model.predict(x), top=3)[0]
print('Top3预测结果:', preds)

关键说明

  • 复用预训练权重:通过遍历Vgg.layers的方式直接使用官方层,确保所有参数(包括卷积层和全连接层)都加载了ImageNet预训练权重。
  • SENet模块修正:修复了build方法参数错误、Dense单元数类型错误、括号缺失等语法问题,确保模块能正常工作。
  • 损失函数修正:分类任务必须使用交叉熵损失,MAE损失不适合用于类别预测任务。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 00:05:23