You need to enable JavaScript to run this app. 如何使用TensorFlow和Keras在UTKFace数据集上实现多标签分类
优惠活动
大模型
产品
解决方案
定价
更多

如何使用TensorFlow和Keras在UTKFace数据集上实现多标签分类

UTKFace人脸多属性预测实现修复

1. ImageDataGenerator的class_mode参数选择与报错根因

两个参数的适用边界和报错原因直接拆解:

  • class_mode="raw":适配统一格式的多列数值标签,返回形状为(batch_size, 标签总列数)的二维numpy数组,是当前场景的正确选择。
  • class_mode="multi_output":为旧版本Keras中不规则格式标签设计,会把每一列标签拆分为独立的数组组成元组返回,需要搭配多输出头模型使用。

你遇到的两个报错的直接原因:

  • 切换为multi_output时触发AttributeError: 'tuple' object has no attribute 'shape':使用的是单输出Sequential结构,无法解析多元素元组格式的返回标签,标签结构和模型结构不匹配。
  • 切换为raw时触发reshape维度不匹配错误:没有在flow_from_dataframe中指定target_size,生成器默认将图片读取为256x256尺寸,和模型定义的100x100输入要求不匹配,最终导致flatten层的张量维度和全连接层期望维度不一致。

修正后的生成器定义:

testdatagenerator = ImageDataGenerator(rescale=1. /255)
testdata = testdatagenerator.flow_from_dataframe(
    dataframe=test,
    directory=None,
    x_col="Filepath",
    y_col=["Age","Gender","Racevalues"],
    class_mode="raw",
    target_size=(100, 100),
    batch_size=20
)

traindatagenerator = ImageDataGenerator(rescale=1. /255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True)
traindata = traindatagenerator.flow_from_dataframe(
    dataframe=train,
    directory=None,
    x_col="Filepath",
    y_col=["Age","Gender","Racevalues"],
    class_mode="raw",
    target_size=(100, 100),
    batch_size=20,
    shuffle=True
)

2. 三类预测属性的损失函数选择

损失函数必须匹配每个属性对应的任务类型,不能统一使用binary_crossentropy:

  • 年龄:属于连续值回归任务,使用mean_absolute_error(MAE)作为损失函数。原因是年龄是有序连续量,MAE对年龄预测中的离群样本鲁棒性强,也是人脸年龄预测领域的通用评价指标。如果需要将年龄划分为离散组别做分类任务,可替换为sparse_categorical_crossentropy。
  • 性别:属于二分类任务,使用binary_crossentropy作为损失函数,对应输出头为1个神经元+sigmoid激活,适配0/1的二分类标签。
  • 种族:属于5类多分类任务,使用sparse_categorical_crossentropy作为损失函数,因为标签存储为0-4的类别整数索引,不需要手动做one-hot编码,对应输出头为5个神经元+softmax激活。

模型结构适配修正

单输出Sequential模型无法同时承接三个不同任务的标签和输出要求,需要调整为共享特征提取主干+独立任务输出头的多输出结构:

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input

# 共享卷积特征提取主干
input_layer = Input(shape=(100,100,3))
x = Conv2D(32, (3, 3), padding='same')(input_layer)
x = Activation('relu')(x)
x = Conv2D(32, (3, 3))(x)
x = Activation('relu')(x)
x = MaxPool2D(pool_size=(2, 2))(x)
x = Dropout(0.25)(x)

x = Conv2D(64, (3, 3), padding='same')(x)
x = Activation('relu')(x)
x = Conv2D(64, (3, 3))(x)
x = Activation('relu')(x)
x = MaxPool2D(pool_size=(2, 2))(x)
x = Dropout(0.25)(x)

x = Flatten()(x)
x = Dense(512)(x)
x = Activation('relu')(x)
x = Dropout(0.5)(x)

# 三个独立任务输出头
age_output = Dense(1, name='age_output')(x)  # 回归任务使用线性激活
gender_output = Dense(1, activation='sigmoid', name='gender_output')(x)  # 二分类
race_output = Dense(5, activation='softmax', name='race_output')(x)  # 5类多分类

model = Model(inputs=input_layer, outputs=[age_output, gender_output, race_output])

# 编译时为每个输出头单独匹配损失和权重
model.compile(
    optimizer='Adam',
    loss={
        'age_output': 'mean_absolute_error',
        'gender_output': 'binary_crossentropy',
        'race_output': 'sparse_categorical_crossentropy'
    },
    loss_weights={
        'age_output': 0.5,
        'gender_output': 1.0,
        'race_output': 1.0
    },
    metrics={
        'age_output': 'mae',
        'gender_output': 'accuracy',
        'race_output': 'accuracy'
    }
)

# 训练时不需要额外调整标签输入,flow_from_dataframe返回的3列标签会自动匹配三个输出头
model.fit(
    traindata,
    steps_per_epoch=100,
    epochs=100,
    validation_data=testdata,
    validation_steps=100
)

内容的提问来源于stack exchange,提问作者J. Doe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 06:45:08