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

数据科学新手求助:合并不同类别数的CNN模型实现多任务预测

实现多输出CNN:同时预测性别与种族

嘿,很高兴能帮到你!你想要的其实是一个多输出模型,而不是简单把两个独立模型的输出拼接起来——咱们可以复用两个模型里几乎完全相同的卷积特征提取部分,然后分支出两个不同的全连接预测头,这样输入一张图片就能同时得到性别和种族的预测结果啦。

思路拆解

你现有的两个模型,前面的卷积层结构完全一致,这简直是天然的共享特征提取器!我们可以:

  1. 先构建共享的卷积特征基(就是两个模型里从输入到Flatten之前的所有卷积、池化层)
  2. 从这个特征基分支出两个独立的全连接层:
    • 一个用于性别二分类(输出1个节点,用sigmoid激活)
    • 一个用于种族三分类(输出3个节点,用softmax激活)
  3. 把输入和两个输出组合成一个多输出模型,编译时分别指定对应的损失函数

完整代码实现

from keras.models import Model
from keras.layers import Input, Convolution2D, Activation, BatchNormalization, MaxPooling2D, AveragePooling2D, Dropout, Flatten, Dense
import keras.backend as K

def build_shared_backbone(input_tensor):
    # 构建共享的卷积特征提取部分
    chanDim = -1
    if K.image_data_format() == 'channels_first':
        chanDim = 1
    
    x = Convolution2D(64, (3,3), padding='same')(input_tensor)
    x = Activation('relu')(x)
    x = BatchNormalization(axis=chanDim)(x)
    x = MaxPooling2D(pool_size=(3,3))(x)
    x = Dropout(0.25)(x)
    
    x = Convolution2D(128, (3,3), padding='same')(x)
    x = Activation('relu')(x)
    x = BatchNormalization(axis=chanDim)(x)
    x = Convolution2D(128, (3,3), padding='same')(x)
    x = Activation('relu')(x)
    x = BatchNormalization(axis=chanDim)(x)
    x = AveragePooling2D(pool_size=(3,3))(x)
    x = Dropout(0.25)(x)
    
    x = Convolution2D(256, (3,3), padding='same')(x)
    x = Activation('relu')(x)
    x = BatchNormalization(axis=chanDim)(x)
    x = MaxPooling2D(pool_size=(3,3))(x)
    x = Dropout(0.25)(x)
    
    x = Convolution2D(512, (3,3), padding='same')(x)
    x = Activation('relu')(x)
    x = BatchNormalization(axis=chanDim)(x)
    x = AveragePooling2D(pool_size=(3,3))(x)
    x = Dropout(0.25)(x)
    
    x = Flatten()(x)
    x = Dense(1024)(x)
    x = Activation('relu')(x)
    x = BatchNormalization()(x)
    x = Dropout(0.25)(x)
    
    x = Dense(512)(x)
    x = Activation('relu')(x)
    x = BatchNormalization()(x)
    x = Dropout(0.25)(x)
    
    return x

# 定义输入
img_size = 128 # 替换成你实际使用的图像尺寸,比如64、128
input_shape = (img_size, img_size, 3)
if K.image_data_format() == 'channels_first':
    input_shape = (3, img_size, img_size)

inputs = Input(shape=input_shape)

# 获取共享特征
shared_features = build_shared_backbone(inputs)

# 性别预测分支(二分类)
gender_output = Dense(1, name='gender')(shared_features)
gender_output = Activation('sigmoid')(gender_output)

# 种族预测分支(三分类)
race_output = Dense(3, name='race')(shared_features)
race_output = Activation('softmax')(race_output)

# 构建多输出模型
model = Model(inputs=inputs, outputs=[gender_output, race_output])

# 编译模型:分别指定两个输出的损失函数
model.compile(
    optimizer='adam', # 也可以用你原来的rmsprop,看实际效果调整
    loss={
        'gender': 'binary_crossentropy',
        'race': 'categorical_crossentropy'
    },
    metrics={
        'gender': 'accuracy',
        'race': 'accuracy'
    }
)

训练时的注意事项

训练的时候,你的数据需要包含两个标签:

  • 性别标签:0/1的二元数组(对应binary_crossentropy损失)
  • 种族标签:独热编码的3维数组(比如[1,0,0]对应第一个种族,对应categorical_crossentropy损失)

调用model.fit()时,标签可以传列表或字典:

# 示例:假设x_train是图像数据,y_gender是性别标签,y_race是种族独热标签
model.fit(
    x_train,
    [y_gender, y_race],
    epochs=20,
    batch_size=32,
    validation_split=0.2
)

为什么之前的concatenate不对?

你之前尝试的concatenate是把两个模型的输出拼合成一个向量,但这不是你需要的——你要的是两个独立的预测结果(一个性别概率,一个种族概率分布),而不是一个合并的输出向量。多输出模型的架构正好能满足这个需求,同时还能共享卷积层的权重,减少训练参数,提升效率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:52:34