机器学习新手求助:CNN二分类文本模型仅输出单一类别,如何消除欠采样?
二分类CNN模型单一类别预测问题及数据不平衡解决方案
一、核心问题排查与数据层面调整
模型仅预测单一类别,大概率是类别不平衡导致(少数类样本占比极低,模型偏向多数类),针对欠采样带来的信息丢失问题,可采用以下替代方案:
1. 过采样少数类
- 避免直接欠采样多数类(会丢失大量有效信息),优先对少数类做过采样:
- 简单复制少数类样本;
- 使用SMOTE-NLP、ADASYN等文本专用的合成样本方法,生成语义相似的少数类文本样本。
2. 混合采样策略
结合欠采样与过采样:对多数类做轻度欠采样(比如保留原数量的50%),同时对少数类做SMOTE过采样,平衡两类样本数量的同时减少信息损失。
3. 类别权重加权
在训练时给少数类分配更高的权重,让模型更重视少数类的预测错误:
# 示例:假设0类占比80%,1类占比20%,权重设置为占比反比 class_weight = {0: 1.0, 1: 4.0} history_cnn=model_cnn.fit(x_train, y_train, epochs=50, batch_size=16, validation_data=(x_test, y_test), class_weight=class_weight)
二、模型与训练优化
1. 更换损失函数
用Focal Loss替代Binary Crossentropy,降低易分类样本的权重,迫使模型关注少数类:
import tensorflow as tf def focal_loss(y_true, y_pred, alpha=0.25, gamma=2): y_true = tf.cast(y_true, tf.float32) bce = tf.keras.losses.binary_crossentropy(y_true, y_pred) exp_bce = tf.exp(-bce) return alpha * tf.pow(1 - exp_bce, gamma) * bce # 编译模型时使用自定义损失 model_cnn.compile(loss=focal_loss, optimizer='adam', metrics=['accuracy'])
2. 修正模型结构问题
你的模型存在激活函数和复杂度问题,建议调整:
- 中间层的
linear和sigmoid激活替换为relu或gelu,避免梯度消失; - 减少Conv1D层数(比如保留2-3层),降低Dense层神经元数量(比如512改256,256改128),避免过拟合;
- 确认输入维度正确性:文本特征转成数组后,需确保形状为
(样本数, 序列长度, 1),可通过x_train = x_train.reshape(x_train.shape[0], x_train.shape[1], 1)调整。
3. 加强正则化与早停
- 提高Dropout比例至0.3-0.5,增强模型泛化能力;
- 添加早停回调,避免过拟合导致的偏向性:
from tensorflow.keras.callbacks import EarlyStopping early_stop = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True) history_cnn=model_cnn.fit(x_train, y_train, epochs=50, batch_size=16, validation_data=(x_test, y_test), callbacks=[early_stop])
4. 改用合理评估指标
不要只依赖准确率,添加精确率、召回率、F1、ROC-AUC等更适合不平衡数据集的指标:
model_cnn.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy', tf.keras.metrics.Precision(name='precision'), tf.keras.metrics.Recall(name='recall'), tf.keras.metrics.AUC(name='auc')])
三、基础检查
- 确认
y_train、y_test标签无错误,不存在单一类别标签的情况; - 检查预处理后的特征是否有效,避免大量全0样本;
- 调整Adam学习率至1e-4,避免学习率过高导致训练不稳定。
内容的提问来源于stack exchange,提问作者Umer
相关产品推荐
相关产品推荐

