深度网络无法学习主导类之外的不平衡数据

数据挖掘 深度学习 喀拉斯 张量流 多类分类 阶级失衡
2021-09-15 05:33:10

我有 5 个输出类的数据。训练数据有以下 5 个类别的样本数:[706326, 32211, 2856, 3050, 901]

我正在使用以下 keras (tf.keras) 代码:

class_weights = class_weight.compute_class_weight('balanced',
                                                 np.unique(y_train),
                                                 y_train)

model = tf.keras.Sequential([
    tf.keras.layers.Dense(50, input_shape=(dataX.shape[1],)),
    tf.keras.layers.Dropout(rate = 0.5),
    tf.keras.layers.Dense(50, activation=tf.nn.relu),
    tf.keras.layers.Dropout(rate = 0.5),
    tf.keras.layers.Dense(50, activation=tf.nn.relu),
    tf.keras.layers.Dropout(rate = 0.5),
    tf.keras.layers.Dense(50, activation=tf.nn.relu),
    tf.keras.layers.Dropout(rate = 0.5),
    tf.keras.layers.Dense(5, activation=tf.nn.softmax) ])
     adam = tf.keras.optimizers.Adam(lr=0.5)

model.compile(optimizer=adam, 
              loss='sparse_categorical_crossentropy',
              metrics=[metrics.sparse_categorical_accuracy])    
     model.fit(X_train,y_train, epochs=5, batch_size=32, class_weight=class_weights)

y_pred = np.argmax(model.predict(X_test), axis=1)

class_weight 的第一行取自这个问题的一个答案:如何在 Keras 中为不平衡的类设置类权重?

我知道这个答案:Multi-class neural net always predicting 1 class after optimization不同之处在于,在这种情况下,当我使用它时,没有使用类权重。

我正在使用 sparse_categorical_crossentropy 它接受类别为整数(不需要将它们转换为单热编码),但我也尝试了 categorical_crossentropy 并且仍然存在同样的问题。

我当然尝试过不同的学习率、batch_size、时期数、优化器和网络的深度/长度。但它总是停留在 ~0.94 的准确度上,如果我一直预测第一类,这基本上是我会得到的。

不确定这里缺少什么。有什么错误吗?或者我应该使用其他一些专门的深度网络吗?

4个回答

1)五层神经网络对于少于 100 万个点的数据集来说是一个非常复杂的模型。(我正在尝试为此找到一个好的链接,但直觉是您对模型的选择应该由可用数据的复杂性驱动,而不是由您认为真正的目标函数是什么样的。)如果这是对于现实世界的项目,像 XGBoost 这样的工具可能在这个数据集上工作得更好——开箱即用,您将花费更少的时间来处理与不平衡类、不良扩展数据或异常值相关的问题。当然,如果这是专门用于学习神经网络的,那么这个建议并没有多大帮助!

2)对于与您的数据一样偏斜的类分布,您可能会通过重新采样训练数据而不是在训练期间重新加权类来获得更多里程。首先对多数类进行下采样(只是随机丢弃多数样本);如果这不令人满意,请尝试更复杂的方法,例如使用 SMOTE 对少数类进行上采样。尝试将其发挥到极致;通过从每个类中随机抽取 1,000 个点来构建(集合)新的训练集。

这里的直觉是,据我所知,对于神经网络,重新加权类基本上意味着在基于类权重的训练期间重新缩放梯度步骤。如果类以 10:1 的比例倾斜,这是有道理的:我们采取的步骤是少数样本的 10 倍。如果类以 1000:1 的比例倾斜,就像你的情况一样,这就没有意义了——我们将在优化多数类时采取 1,000 个小步骤,然后当我们碰巧看到时,我们会在一个基本上随机的方向上迈出一大步少数样本,然后是 1,000 个小步骤试图取消这项工作,等等。我们没有看到足够的少数样本来让关于他们的班级的信息平均下来。

要检查的一件重要事情是输入数据中是否有 NaN。

有同样的问题,原来NaN已经悄悄进入输入,现在工作得很好!

我认为它可能是在做一些事情,只是不足以改变整体分类。您是否检查过不同class_weights 的少数类测试示例的估计概率分布?我想这些例子的真实类的概率要高一些,即使预测的最有可能的类仍然是多数类。

如果是这种情况,那么您可以在取argmax. 即测试一系列值并选择提供最佳值的值F1score 或任何其他你想要优化的东西。像这样的东西:

# train neural net
# ... 

y_proba = model.predict(X_val)
best_score = 0.
best_value = 0.

# try every value from 0. to 1., in increments of 0.01
for i in np.linspace(0., 1., 101):
    alt_y_proba = y_proba - np.array([i, 0., 0., 0., 0.])
    alt_y_proba = np.clip(alt_y_proba, 0., 1.) # ensure no negative values!

    y_pred = np.argmax(alt_y_proba, axis=1)
    score = # some score function goes here

    if score > best_score:
        best_score = score
        best_value = i

print(best_value)    

是的,它有点老套,但它可能会给你带来好的结果。如果需要,您可以重新归一化为alt_y_proba适当的概率分布,但它不会改变分类。只需确保您用于优化此减法值的数据集未用于神经网络的训练,因为这可能会引入过度拟合。

为什么不尝试梯度提升或 adaBoost?它们应该在不平衡的数据中表现良好,因为在训练期间,它们倾向于为错误分类的观察赋予权重,从而提高性能。让我知道