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

如何在MobileNetV3Small前后组合层并冻结指定层?问题排查

问题与解决方案

需求

  • 在基础模型前添加数据增强层
  • 冻结基础模型中除最后一层外的所有层
  • 在基础模型后添加额外层

遇到的问题

  1. 数据增强层输出形状为(None, None, None, 3),导致MobileNetV3Small输入形状也变为该值,预期应为(None, 224, 224, 3)
  2. 模型摘要前的循环输出显示所有层均为可训练状态,但model.summary()显示大部分参数不可训练

原代码

def create_model(input_shape, output_shape):
    inputs = Input(shape=input_shape)
    data_augmentation = Sequential([
        RandomBrightness(0.2),
        RandomContrast(0.2),
        RandomFlip(),
        RandomRotation(0.2),
        RandomHeight(0.2),
        RandomWidth(0.2),
        RandomTranslation(0.2, 0.2),
        RandomZoom(0.2, 0.2)
    ])
    x = data_augmentation(inputs)
    base_model = MobileNetV3Small(include_top=False, weights='imagenet', pooling="avg")
    for layer in base_model.layers[:-1]: layer.trainable = False
    x = base_model(x)
    extra =Sequential([
        Dense(256),
        BatchNormalization(),
        Activation("relu"),
        Dropout(0.2)
    ])
    x = extra(x)
    outputs =Dense(output_shape,activation='softmax')(x)
    model=Model(inputs=inputs, outputs=outputs)
    model.compile(optimizer=Adam(1e-3), loss='categorical_crossentropy',metrics=['accuracy'])
    layers = model.layers
    for i in range(len(layers)):
        if layers[i].trainable: print(i, layers[i].name, "Trainable:", layers[i].trainable, "Input:", layers[i].input_shape, "Output:", layers[i].output_shape)
    print(model.summary())
    return model

输出结果

0 input_1 Trainable: True Input: [(None, 224, 224, 3)] Output: [(None, 224, 224, 3)]
1 sequential Trainable: True Input: (None, 224, 224, 3) Output: (None, None, None, 3)
2 MobilenetV3small Trainable: True Input: (None, None, None, 3) Output: (None, 576)
3 sequential_1 Trainable: True Input: (None, 576) Output: (None, 256)
4 dense_1 Trainable: True Input: (None, 256) Output: (None, 5)
Model: "model"
_________________________________________________________________
 Layer (type)                Output Shape              Param #
=================================================================
 input_1 (InputLayer)        [(None, 224, 224, 3)]     0

 sequential (Sequential)     (None, None, None, 3)     0

 MobilenetV3small (Functiona  (None, 576)              939120
 l)

 sequential_1 (Sequential)   (None, 256)               148736

 dense_1 (Dense)             (None, 5)                 1285

=================================================================
Total params: 1,089,141
Trainable params: 149,509
Non-trainable params: 939,632
_________________________________________________________________

解决方案

问题1:数据增强层输出形状不固定

原因:RandomHeight、RandomWidth这类变换会改变输入的空间维度,导致输出形状动态变化。解决方法是在数据增强层末尾添加Resize层,强制固定输出尺寸为输入的目标形状。

修改数据增强部分:

data_augmentation = Sequential([
    RandomBrightness(0.2),
    RandomContrast(0.2),
    RandomFlip(),
    RandomRotation(0.2),
    RandomHeight(0.2),
    RandomWidth(0.2),
    RandomTranslation(0.2, 0.2),
    RandomZoom(0.2, 0.2),
    Resize(input_shape[0], input_shape[1])  # 固定输出尺寸为输入指定的大小
])

修改后数据增强层的输出形状会保持为(None, 224, 224, 3),MobileNetV3Small的输入形状也会恢复预期值。

问题2:层的可训练状态显示不一致

原因:你遍历的是顶层模型的layers属性,其中MobilenetV3small是一个嵌套的Functional子模型,它自身的trainable属性为True,但内部大部分层已被冻结。model.summary()统计的是所有参数的真实可训练状态,而你的打印逻辑仅查看了顶层节点,未深入子模型内部。

若要准确查看所有层的可训练状态,需递归遍历子模型的内部层:

def print_all_layers(model):
    for layer in model.layers:
        if hasattr(layer, 'layers'):  # 判断是否为包含子层的模型节点
            print_all_layers(layer)
        else:
            print(f"{layer.name} - Trainable: {layer.trainable}")

# 在模型编译后调用该函数
print_all_layers(model)

你对基础模型层的冻结操作是有效的,model.summary()的参数统计结果准确,只是原打印逻辑存在局限性。

修改后的完整代码

from tensorflow.keras.layers import Input, Sequential, RandomBrightness, RandomContrast, RandomFlip, RandomRotation, RandomHeight, RandomWidth, RandomTranslation, RandomZoom, Resize, Dense, BatchNormalization, Activation, Dropout
from tensorflow.keras.applications import MobileNetV3Small
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam

def create_model(input_shape, output_shape):
    inputs = Input(shape=input_shape)
    data_augmentation = Sequential([
        RandomBrightness(0.2),
        RandomContrast(0.2),
        RandomFlip(),
        RandomRotation(0.2),
        RandomHeight(0.2),
        RandomWidth(0.2),
        RandomTranslation(0.2, 0.2),
        RandomZoom(0.2, 0.2),
        Resize(input_shape[0], input_shape[1])  # 固定输出尺寸
    ])
    x = data_augmentation(inputs)
    base_model = MobileNetV3Small(include_top=False, weights='imagenet', pooling="avg")
    # 冻结除最后一层外的所有基础模型层
    for layer in base_model.layers[:-1]:
        layer.trainable = False
    x = base_model(x)
    extra = Sequential([
        Dense(256),
        BatchNormalization(),
        Activation("relu"),
        Dropout(0.2)
    ])
    x = extra(x)
    outputs = Dense(output_shape, activation='softmax')(x)
    model = Model(inputs=inputs, outputs=outputs)
    model.compile(optimizer=Adam(1e-3), loss='categorical_crossentropy', metrics=['accuracy'])
    
    # 递归打印所有层的可训练状态
    def print_all_layers(model):
        for layer in model.layers:
            if hasattr(layer, 'layers'):
                print_all_layers(layer)
            else:
                print(f"{layer.name} - Trainable: {layer.trainable}")
    
    print_all_layers(model)
    print(model.summary())
    return model

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 17:20:35