数据科学新手求助:合并不同类别数的CNN模型实现多任务预测
实现多输出CNN:同时预测性别与种族
嘿,很高兴能帮到你!你想要的其实是一个多输出模型,而不是简单把两个独立模型的输出拼接起来——咱们可以复用两个模型里几乎完全相同的卷积特征提取部分,然后分支出两个不同的全连接预测头,这样输入一张图片就能同时得到性别和种族的预测结果啦。
思路拆解
你现有的两个模型,前面的卷积层结构完全一致,这简直是天然的共享特征提取器!我们可以:
- 先构建共享的卷积特征基(就是两个模型里从输入到
Flatten之前的所有卷积、池化层) - 从这个特征基分支出两个独立的全连接层:
- 一个用于性别二分类(输出1个节点,用
sigmoid激活) - 一个用于种族三分类(输出3个节点,用
softmax激活)
- 一个用于性别二分类(输出1个节点,用
- 把输入和两个输出组合成一个多输出模型,编译时分别指定对应的损失函数
完整代码实现
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
相关产品推荐
相关产品推荐

