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

Keras三层MLP训练categorical_accuracy异常及不平衡数据集优化咨询

为什么你的MLP训练时categorical_accuracy忽高忽低,且少数类检测率拉胯?

嘿,这个问题我之前帮不少人排查过,咱们一步步拆解:

首先,你看到的两种编码下accuracy的巨大差异,核心是指标和标签编码不匹配:

  • 当你把目标变量转成整数数值标签时,Keras的categorical_accuracy指标是给独热编码标签设计的——它会默认把你的整数标签当成独热向量去和模型输出对比,这完全是驴唇不对马嘴,所以得到的0.37其实是个无效的错误结果。这种情况下你应该用sparse_categorical_accuracy指标,搭配sparse_categorical_crossentropy损失函数才对。
  • 换成独热编码后,categorical_accuracy的计算逻辑终于对了,但那个0.90的高准确率其实是数据集不平衡带来的“假象”:模型只需要无脑预测占比最高的多数类,就能轻松拿到高准确率,但对你最关心的少数类,它根本没学到任何有效特征,自然检测率低得离谱。

接下来,针对你最核心的需求——提升少数类检测率,给你几个落地的解决办法:

1. 先把基础的指标和损失配对搞对

别再混用指标了,这是一切评估的前提:

  • 整数标签:损失用sparse_categorical_crossentropy,指标用sparse_categorical_accuracy
  • 独热编码:损失用categorical_crossentropy,指标用categorical_accuracy

2. 给少数类“加权”,强迫模型重视它

不平衡数据集的核心问题是多数类的样本量太大,模型会自动偏向多数类。解决这个最直接的办法是调整损失的权重:

  • 手动设置类别权重:在模型训练时传入class_weight参数,比如少数类的权重设为多数类的5-10倍(具体数值看你的数据不平衡程度)。比如class_weight={0:1, 1:8},假设类别1是你关心的少数类。
  • 自动计算权重:用sklearn.utils.class_weight.compute_class_weight函数,传入'balanced'参数就能自动根据样本量计算权重,避免手动调参的麻烦。
  • 试试Focal Loss:这是专门为不平衡问题设计的损失函数,它会降低已经被正确分类的多数类样本的权重,逼着模型去关注难分类的少数类。你可以自己写一个简单的实现,或者找现成的Keras扩展。

3. 调整数据集的分布

从数据层面平衡类别比例:

  • 过采样少数类:复制少数类样本,或者用SMOTE算法生成少数类的合成样本,让两类样本量接近。注意过采样容易导致过拟合,最好配合交叉验证一起用。
  • 欠采样多数类:随机删掉部分多数类样本,减少其主导性。但这种方法会丢失多数类的信息,只适合多数类样本量极大的情况。
  • 分层划分数据集:划分训练集和测试集时,一定要加stratify=y参数,保证训练集和测试集里各类别的比例和原数据集一致,不然模型可能在训练时根本碰不到几个少数类样本。

4. 别再盯着accuracy看了,换个靠谱的评估指标

categorical_accuracy在不平衡数据集里完全是个“骗子指标”,改用这些更能反映模型真实性能的指标:

  • Recall(召回率):直接衡量你的少数类被正确检测出来的比例,这才是你最该关注的指标
  • F1-Score:兼顾精确率和召回率,综合评估模型对少数类的分类能力
  • AUC-PR:比AUC-ROC更适合不平衡数据集,能直观体现模型对少数类的区分能力
  • 混淆矩阵:把各类别的分类对错情况列出来,一眼就能看到少数类是被误判成了哪个类别

5. 模型训练的小技巧

  • 早停(Early Stopping):别硬训满epochs,监控少数类的Recall或者AUC-PR,当指标不再提升时就停止训练,避免模型过度拟合多数类
  • 加Dropout层:在MLP的隐藏层之间加入Dropout层(比如Dropout(0.2)),降低过拟合风险,尤其是过采样后的数据集更需要
  • 调整模型容量:如果你的MLP隐藏层神经元太多,模型可能会记住多数类的噪声而忽略少数类的有效特征,适当减少神经元数量试试

给你贴个简单的代码示例,展示怎么用自动计算的类别权重训练模型:

from sklearn.utils.class_weight import compute_class_weight
import numpy as np

# 计算类别权重(假设y_train是整数标签)
class_weights = compute_class_weight('balanced', classes=np.unique(y_train), y=y_train)
class_weight_dict = dict(zip(np.unique(y_train), class_weights))

# 模型编译(假设用独热编码的标签y_train_onehot)
model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['categorical_accuracy', 'recall'])

# 传入类别权重训练
model.fit(X_train, y_train_onehot, 
          epochs=50, 
          batch_size=32,
          class_weight=class_weight_dict,
          validation_split=0.2)

总结一下:你之前看到的accuracy波动是指标用错了导致的,而少数类检测率低才是真正的核心问题——从损失加权、数据平衡、评估指标这三个方向入手,就能有效提升模型对少数类的检测能力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:50:44