如何修改Keras函数式(Functional)模型实现多分支输出?
多输出分支改造方法
针对非Sequential结构的EfficientNetV2模型,直接使用Keras函数式API复用已有模型的计算图和权重即可实现分叉结构,不需要逐层重新堆叠。
具体实现步骤
- 第一步:加载原始EfficientNetV2L模型,不管是加载公开预训练权重还是你自己训练保存的权重都可以正常使用。
import tensorflow as tf from tensorflow.keras import layers, Model # 按你的实际需求配置输入尺寸、权重路径 base_model = tf.keras.applications.efficientnet_v2.EfficientNetV2L( weights='imagenet', include_top=True, input_shape=(480, 480, 3) )
- 第二步:定位分叉节点。你需要去掉模型最后2层,所以直接取倒数第3层的输出作为两个分支共享的特征输入即可。如果不确定层的位置,可以先执行
base_model.summary()打印模型结构,核对找到你需要保留的最后一层的位置。
# 截断原模型,拿到共享特征张量 shared_feature = base_model.layers[-3].output
- 第三步:在共享特征后分别接分类、回归两个独立的输出头。
# 分类分支:num_classes替换成你的实际类别数,激活函数匹配任务类型(多分类softmax/二分类sigmoid) cls_output = layers.Dense(units=10, activation='softmax', name='cls_output')(shared_feature) # 回归分支:units替换成你的回归目标维度,回归任务默认用linear激活即可 reg_output = layers.Dense(units=1, activation='linear', name='reg_output')(shared_feature)
- 第四步:基于原模型的输入和两个新输出,组装成新的多输出模型。
multi_output_model = Model( inputs=base_model.input, outputs=[cls_output, reg_output] )
最终的模型结构和你预期的完全一致:
EfficientNetV2主体(截断至倒数第三层) | | / \ / \ / \ cls_output reg_output
注意事项
- 如果做迁移学习需要冻结backbone权重,直接遍历base_model设置层属性即可,不会影响新加的两个分支训练:
for layer in base_model.layers: layer.trainable = False
- 编译模型时需要给两个输出分别配置损失函数,还可以通过损失权重调整两个任务对总损失的贡献占比:
multi_output_model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4), loss={ 'cls_output': tf.keras.losses.SparseCategoricalCrossentropy(), 'reg_output': tf.keras.losses.MeanSquaredError() }, loss_weights={ 'cls_output': 1.0, 'reg_output': 0.5 } )
你之前用Sequential逐层add的方法不可行,核心原因是EfficientNet属于带残差跳连的多分支结构,层与层之间不是单输入单输出的线性链式关系,强行拆分层按顺序堆叠会破坏原有跳连的计算逻辑。上面的方法是直接复用原模型已经构建好的完整计算图,只在指定的特征节点挂载新的输出分支,不会破坏原模型的主体结构,也不需要你重新搭建一遍backbone,原模型加载的权重会自动继承到新模型里。
内容的提问来源于stack exchange,提问作者vernal123
相关产品推荐
相关产品推荐

