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

如何修正倾向于Class 0的时序LSTM二分类模型?

序列二分类模型偏差问题

我正在基于15个连续序列(含1个非连续但仍属序列的特征)做二分类预测,数据集共933k条数据,每条含15个特征。实际类别分布为Class 0占~45.09%,Class 1占~54.91%,存在轻微不平衡。目前模型始终偏向输出Class 0,训练后Recall持续下降,Loss、Accuracy、Precision略有上升但最终趋近54%,明显是模型在适应数据集偏差而非学习有效特征。

常规的欠采样/过采样方法因LSTM依赖连续滞后数据集,随机增减样本不可行。我已尝试以下优化手段:

  • 调整学习率
  • 增减模型复杂度
  • 添加输出层偏置初始化(bias_initializer)
  • 加入Dropout层
  • 调整时间步长
  • 移除数据平坦区
  • 小数据集过拟合测试(1000轮后准确率达55%-75%)

当前期望:测试集与验证集准确率达到55%以上,预测的类别分布落在40-60区间内(接近均衡)。

模型代码

data = pd.read_csv('data.csv')
X_train, y_train, X_cv, y_cv, X_test, y_test, init_bias = data_formatting.transform(data=data)
output_bias = tf.keras.initializers.Constant(init_bias)
model1 = Sequential([
    InputLayer(batch_input_shape=(64, 60, 15)),
    LSTM(units=64, return_sequences=True, stateful=True),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dropout(0.2),
    LSTM(units=64, return_sequences=True, stateful=True),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dropout(0.2),
    LSTM(units=64, stateful=True),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dropout(0.2),
    Dense(units=32, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    Dense(units=1, activation='sigmoid', bias_initializer=output_bias)
])

model1.summary()

cp = ModelCheckpoint('Model_NewF_3/', save_best_only=True)

model1.compile(loss=BinaryCrossentropy(), optimizer=AdamW(learning_rate=0.000001), metrics=['accuracy', tf.keras.metrics.Precision(), tf.keras.metrics.Recall()])

model1.fit(X_train, y_train, validation_data=(X_cv, y_cv), epochs=10, batch_size=64, callbacks=[cp])

混淆矩阵情况

  • 训练集:Class 0预测数量远高于实际占比,Class 1被大量误判为Class 0
  • 测试集:同样呈现Class 0预测偏向,Class 1召回率极低

优化方向建议

1. 类别加权损失函数

计算类别权重,让模型对被低估的Class 1给予更高损失权重,避免偏向多数类(此处模型反向偏向,本质是对Class 1学习不足):

import numpy as np
# 计算类别权重:n_samples/(n_classes*class_counts)
class_weight = {
    0: len(y_train)/(2 * np.sum(y_train == 0)),
    1: len(y_train)/(2 * np.sum(y_train == 1))
}
# 训练时传入参数
model1.fit(..., class_weight=class_weight)

也可直接在BinaryCrossentropy中设置weight参数,或自定义加权损失函数。

2. 序列感知的重采样

不破坏序列连续性的前提下调整数据分布:

  • 提取包含高占比Class 1的连续序列块,复制这些块补充到训练集
  • 裁剪掉连续的、纯Class 0的长序列块,减少冗余的偏向性数据

3. 修正Stateful LSTM训练逻辑

Stateful LSTM要求每个batch的样本是连续的序列片段,且需手动重置状态:

# 每个epoch结束后重置状态
for epoch in range(10):
    model1.fit(X_train, y_train, ...)
    model1.reset_states()

同时确保数据集划分是按连续序列切割,而非随机打乱,否则stateful的优势无法发挥。

4. 分类阈值优化

训练完成后,在验证集上搜索最优分类阈值(默认0.5可能不适用):

from sklearn.metrics import f1_score
y_pred_proba = model1.predict(X_cv)
thresholds = np.linspace(0.3, 0.7, 41)
best_thresh, best_f1 = 0.5, 0
for thresh in thresholds:
    y_pred = (y_pred_proba > thresh).astype(int)
    current_f1 = f1_score(y_cv, y_pred)
    if current_f1 > best_f1:
        best_f1 = current_f1
        best_thresh = thresh
print(f"最优阈值: {best_thresh}, 对应F1分数: {best_f1}")

用最优阈值替代0.5,可平衡预测的类别分布。

5. 增强序列特征捕捉

  • 尝试双向LSTM(tf.keras.layers.Bidirectional(LSTM(...))),捕捉序列前后的关联信息
  • 添加Attention层,让模型自动关注对分类关键的时间步特征
  • 提取序列的时间统计特征(滑动窗口均值、方差、趋势),补充到原有特征中

6. 调整训练策略

  • 增加训练轮数,配合EarlyStopping回调(监控验证集Recall或F1),避免过拟合同时保证充分训练
  • 尝试更大的学习率(当前1e-6过小,可逐步调整到1e-4~1e-5范围),提升模型收敛速度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 21:13:09